mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-10-01 01:06:35 -04: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
|
#ifndef _FFTFILT_H
|
||||||
@ -50,4 +50,24 @@ public:
|
|||||||
int runSSB(const cmplx& in, cmplx **out, bool usb);
|
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
|
#endif
|
||||||
|
@ -35,10 +35,14 @@ LoRaDemod::LoRaDemod(SampleSink* sampleSink) :
|
|||||||
|
|
||||||
m_chirp = 0;
|
m_chirp = 0;
|
||||||
m_angle = 0;
|
m_angle = 0;
|
||||||
|
|
||||||
|
loraFilter = new sfft(LORA_SFFT_LEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
LoRaDemod::~LoRaDemod()
|
LoRaDemod::~LoRaDemod()
|
||||||
{
|
{
|
||||||
|
if (loraFilter)
|
||||||
|
delete loraFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoRaDemod::configure(MessageQueue* messageQueue, Real Bandwidth)
|
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)
|
void LoRaDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool pO)
|
||||||
{
|
{
|
||||||
Complex ci;
|
Complex ci;
|
||||||
|
cmplx bins[LORA_SFFT_LEN];
|
||||||
m_sampleBuffer.clear();
|
m_sampleBuffer.clear();
|
||||||
for(SampleVector::const_iterator it = begin; it < end; ++it) {
|
for(SampleVector::const_iterator it = begin; it < end; ++it) {
|
||||||
Complex c(it->real() / 32768.0, it->imag() / 32768.0);
|
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);
|
m_angle = (m_angle + m_chirp) & (SPREADFACTOR - 1);
|
||||||
Complex cangle(cos(M_PI*2*m_angle/SPREADFACTOR),-sin(M_PI*2*m_angle/SPREADFACTOR));
|
Complex cangle(cos(M_PI*2*m_angle/SPREADFACTOR),-sin(M_PI*2*m_angle/SPREADFACTOR));
|
||||||
ci *= cangle;
|
ci *= cangle;
|
||||||
|
loraFilter->run(ci, bins);
|
||||||
m_sampleBuffer.push_back(Sample(ci.real() * 32000, ci.imag() * 32000));
|
m_sampleBuffer.push_back(Sample(ci.real() * 32000, ci.imag() * 32000));
|
||||||
m_sampleDistanceRemain += (Real)m_sampleRate / m_Bandwidth;
|
m_sampleDistanceRemain += (Real)m_sampleRate / m_Bandwidth;
|
||||||
}
|
}
|
||||||
|
@ -23,9 +23,13 @@
|
|||||||
#include "dsp/nco.h"
|
#include "dsp/nco.h"
|
||||||
#include "dsp/interpolator.h"
|
#include "dsp/interpolator.h"
|
||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
|
#include "dsp/fftfilt.h"
|
||||||
|
|
||||||
#define SPREADFACTOR (1<<8)
|
#define SPREADFACTOR (1<<8)
|
||||||
|
|
||||||
|
/* It takes a lot of CPU to run the sliding FFT */
|
||||||
|
#define LORA_SFFT_LEN (128)
|
||||||
|
|
||||||
class LoRaDemod : public SampleSink {
|
class LoRaDemod : public SampleSink {
|
||||||
public:
|
public:
|
||||||
LoRaDemod(SampleSink* sampleSink);
|
LoRaDemod(SampleSink* sampleSink);
|
||||||
@ -66,6 +70,8 @@ private:
|
|||||||
int m_chirp;
|
int m_chirp;
|
||||||
int m_angle;
|
int m_angle;
|
||||||
|
|
||||||
|
sfft* loraFilter;
|
||||||
|
|
||||||
NCO m_nco;
|
NCO m_nco;
|
||||||
Interpolator m_interpolator;
|
Interpolator m_interpolator;
|
||||||
Real m_sampleDistanceRemain;
|
Real m_sampleDistanceRemain;
|
||||||
|
@ -190,3 +190,56 @@ int fftfilt::runSSB(const cmplx & in, cmplx **out, bool usb)
|
|||||||
return flen2;
|
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