SSB_HighSpeed_Modem/hsmodem/fft.cpp

127 lines
3.1 KiB
C++
Executable File

/*
* High Speed modem to transfer data in a 2,7kHz SSB channel
* =========================================================
* Author: DJ0ABR
*
* (c) DJ0ABR
* www.dj0abr.de
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "hsmodem.h"
#ifdef _WIN32_
#include "fftw_lib/fftw3.h"
#endif
#ifdef _LINUX_
#include <fftw3.h>
#endif
#define FFT_AUDIOSAMPLERATE 8000
double *din = NULL; // input data for fft
fftw_complex *cpout = NULL; // ouput data from fft
fftw_plan plan = NULL;
#define fft_rate (FFT_AUDIOSAMPLERATE / 10) // resolution: 10 Hz
int fftidx = 0;
int fftcnt = fft_rate/2+1; // number of output values
uint16_t fftout[FFT_AUDIOSAMPLERATE / 10/2+1];
int downsamp = 0;
int downphase = 0;
uint16_t *make_waterfall(float fre, int *retlen)
{
// Downsampling:
// needed 8000 bit/s
// caprate 48k: downsample by 6
// caprate 44,1k: downsample by 5,5
if (caprate == 48000)
{
if (++downsamp < 6) return NULL;
}
if (caprate == 44100)
{
if (downphase <= 1100)
{
if (++downsamp < 5) return NULL;
}
else
{
if (++downsamp < 6) return NULL;
}
if(++downphase >= 2000) downphase = 0;
}
downsamp = 0;
int fftrdy = 0;
// fre are the float samples
// fill into the fft input buffer
din[fftidx++] = fre;
if(fftidx == fft_rate)
{
fftidx = 0;
// the fft buffer is full, execute the FFT
fftw_execute(plan);
for (int j = 0; j < fftcnt; j++)
{
// calculate absolute value (magnitute without phase)
float fre = (float)cpout[j][0];
float fim = (float)cpout[j][1];
float mag = sqrt((fre * fre) + (fim * fim));
fftout[j] = (uint16_t)mag;
fftrdy = 1;
}
}
if(fftrdy == 1)
{
*retlen = fftcnt;
return fftout;
}
return NULL;
}
void init_fft()
{
char fn[300];
sprintf(fn, "capture_fft_%d", fft_rate); // wisdom file for each capture rate
fftw_import_wisdom_from_filename(fn);
din = (double *)fftw_malloc(sizeof(double) * fft_rate);
cpout = (fftw_complex *)fftw_malloc(sizeof(fftw_complex) * fft_rate);
plan = fftw_plan_dft_r2c_1d(fft_rate, din, cpout, FFTW_MEASURE);
fftw_export_wisdom_to_filename(fn);
}
void exit_fft()
{
if(plan) fftw_destroy_plan(plan);
if(din) fftw_free(din);
if(cpout) fftw_free(cpout);
}