mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-10 10:33:29 -05:00
Add Sliding FFT.
This commit is contained in:
parent
ad1c436a7e
commit
429b4dbbff
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user