Add Sliding FFT.

This commit is contained in:
John Greb 2015-01-11 19:30:48 +00:00
parent ad1c436a7e
commit 429b4dbbff
4 changed files with 86 additions and 2 deletions

View File

@ -1,5 +1,5 @@
/*
* fftfilt.h -- Fast convolution FIR filter
* Filters from Fldigi.
*/
#ifndef _FFTFILT_H
@ -50,4 +50,24 @@ public:
int runSSB(const cmplx& in, cmplx **out, bool usb);
};
/* Sliding FFT filter from Fldigi */
class sfft {
#define K1 0.99999
private:
int fftlen;
int first;
int last;
int ptr;
struct vrot_bins_pair;
vrot_bins_pair *vrot_bins;
cmplx *delay;
float k2;
public:
sfft(int len);
~sfft();
void run(const cmplx& input, cmplx *result);
};
#endif

View File

@ -35,10 +35,14 @@ LoRaDemod::LoRaDemod(SampleSink* sampleSink) :
m_chirp = 0;
m_angle = 0;
loraFilter = new sfft(LORA_SFFT_LEN);
}
LoRaDemod::~LoRaDemod()
{
if (loraFilter)
delete loraFilter;
}
void LoRaDemod::configure(MessageQueue* messageQueue, Real Bandwidth)
@ -50,7 +54,7 @@ void LoRaDemod::configure(MessageQueue* messageQueue, Real Bandwidth)
void LoRaDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool pO)
{
Complex ci;
cmplx bins[LORA_SFFT_LEN];
m_sampleBuffer.clear();
for(SampleVector::const_iterator it = begin; it < end; ++it) {
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
@ -61,6 +65,7 @@ void LoRaDemod::feed(SampleVector::const_iterator begin, SampleVector::const_ite
m_angle = (m_angle + m_chirp) & (SPREADFACTOR - 1);
Complex cangle(cos(M_PI*2*m_angle/SPREADFACTOR),-sin(M_PI*2*m_angle/SPREADFACTOR));
ci *= cangle;
loraFilter->run(ci, bins);
m_sampleBuffer.push_back(Sample(ci.real() * 32000, ci.imag() * 32000));
m_sampleDistanceRemain += (Real)m_sampleRate / m_Bandwidth;
}

View File

@ -23,9 +23,13 @@
#include "dsp/nco.h"
#include "dsp/interpolator.h"
#include "util/message.h"
#include "dsp/fftfilt.h"
#define SPREADFACTOR (1<<8)
/* It takes a lot of CPU to run the sliding FFT */
#define LORA_SFFT_LEN (128)
class LoRaDemod : public SampleSink {
public:
LoRaDemod(SampleSink* sampleSink);
@ -66,6 +70,8 @@ private:
int m_chirp;
int m_angle;
sfft* loraFilter;
NCO m_nco;
Interpolator m_interpolator;
Real m_sampleDistanceRemain;

View File

@ -190,3 +190,56 @@ int fftfilt::runSSB(const cmplx & in, cmplx **out, bool usb)
return flen2;
}
/* Sliding FFT from Fldigi */
struct sfft::vrot_bins_pair {
cmplx vrot;
cmplx bins;
} ;
sfft::sfft(int len)
{
vrot_bins = new vrot_bins_pair[len];
delay = new cmplx[len];
fftlen = len;
first = 0;
last = len - 1;
ptr = 0;
double phi = 0.0, tau = 2.0 * M_PI/ len;
k2 = 1.0;
for (int i = 0; i < len; i++) {
vrot_bins[i].vrot = cmplx( K1 * cos (phi), K1 * sin (phi) );
phi += tau;
delay[i] = vrot_bins[i].bins = 0.0;
k2 *= K1;
}
}
sfft::~sfft()
{
delete [] vrot_bins;
delete [] delay;
}
// Sliding FFT, cmplx input, cmplx output
// FFT is computed for each value from first to last
// Values are not stable until more than "len" samples have been processed.
// Copies the frequencies to a pointer.
void sfft::run(const cmplx& input, cmplx *result)
{
cmplx & de = delay[ptr];
const cmplx z( input.real() - k2 * de.real(), input.imag() - k2 * de.imag());
de = input;
++ptr ;
if( ptr >= fftlen ) ptr = 0 ;
// It is more efficient to have vrot and bins very close to each other.
for( vrot_bins_pair
*itr = vrot_bins + first,
*end = vrot_bins + last ;
itr != end ;
++itr, result++ ) {
*result = itr->bins = itr->bins * itr->vrot + z * itr->vrot;
}
}