mirror of
https://github.com/f4exb/sdrangel.git
synced 2024-11-25 17:28:50 -05:00
Working unoptimzied WFM just mono (AF baseband)
This commit is contained in:
parent
b7c0e85329
commit
3f106ade9e
@ -5,7 +5,7 @@
|
||||
#ifndef _FFTFILT_H
|
||||
#define _FFTFILT_H
|
||||
|
||||
#include "complex.h"
|
||||
#include <complex>
|
||||
#include "gfft.h"
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
@ -13,6 +13,20 @@
|
||||
class fftfilt {
|
||||
enum {NONE, BLACKMAN, HAMMING, HANNING};
|
||||
|
||||
public:
|
||||
typedef std::complex<float> cmplx;
|
||||
|
||||
fftfilt(float f1, float f2, int len);
|
||||
fftfilt(float f, int len);
|
||||
~fftfilt();
|
||||
// f1 < f2 ==> bandpass
|
||||
// f1 > f2 ==> band reject
|
||||
void create_filter(float f1, float f2);
|
||||
void rtty_filter(float);
|
||||
|
||||
int runFilt(const cmplx& in, cmplx **out);
|
||||
int runSSB(const cmplx& in, cmplx **out, bool usb);
|
||||
|
||||
protected:
|
||||
int flen;
|
||||
int flen2;
|
||||
@ -36,18 +50,6 @@ protected:
|
||||
0.08 * cos(4.0 * M_PI * i / len));
|
||||
}
|
||||
void init_filter();
|
||||
|
||||
public:
|
||||
fftfilt(float f1, float f2, int len);
|
||||
fftfilt(float f, int len);
|
||||
~fftfilt();
|
||||
// f1 < f2 ==> bandpass
|
||||
// f1 > f2 ==> band reject
|
||||
void create_filter(float f1, float f2);
|
||||
void rtty_filter(float);
|
||||
|
||||
int runFilt(const cmplx& in, cmplx **out);
|
||||
int runSSB(const cmplx& in, cmplx **out, bool usb);
|
||||
};
|
||||
|
||||
|
||||
@ -55,6 +57,12 @@ public:
|
||||
/* Sliding FFT filter from Fldigi */
|
||||
class sfft {
|
||||
#define K1 0.99999
|
||||
public:
|
||||
typedef std::complex<float> cmplx;
|
||||
sfft(int len);
|
||||
~sfft();
|
||||
void run(const cmplx& input);
|
||||
void fetch(float *result);
|
||||
private:
|
||||
int fftlen;
|
||||
int first;
|
||||
@ -64,11 +72,6 @@ private:
|
||||
vrot_bins_pair *vrot_bins;
|
||||
cmplx *delay;
|
||||
float k2;
|
||||
public:
|
||||
sfft(int len);
|
||||
~sfft();
|
||||
void run(const cmplx& input);
|
||||
void fetch(float *result);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -5,5 +5,6 @@ add_subdirectory(am)
|
||||
add_subdirectory(nfm)
|
||||
add_subdirectory(ssb)
|
||||
add_subdirectory(tcpsrc)
|
||||
add_subdirectory(wfm)
|
||||
|
||||
#add_subdirectory(tetra)
|
||||
|
@ -62,7 +62,7 @@ void SSBDemod::configure(MessageQueue* messageQueue, Real Bandwidth, Real LowCut
|
||||
void SSBDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
|
||||
{
|
||||
Complex ci;
|
||||
cmplx *sideband;
|
||||
fftfilt::cmplx *sideband;
|
||||
int n_out;
|
||||
|
||||
for(SampleVector::const_iterator it = begin; it < end; ++it) {
|
||||
|
@ -70,7 +70,7 @@ void TCPSrc::setSpectrum(MessageQueue* messageQueue, bool enabled)
|
||||
void TCPSrc::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool positiveOnly)
|
||||
{
|
||||
Complex ci;
|
||||
cmplx* sideband;
|
||||
fftfilt::cmplx* sideband;
|
||||
Real l, r;
|
||||
|
||||
m_sampleBuffer.clear();
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "dsp/pidcontroller.h"
|
||||
#include "wfmdemod.h"
|
||||
|
||||
#include <iostream>
|
||||
//#include <iostream>
|
||||
|
||||
MESSAGE_CLASS_DEFINITION(WFMDemod::MsgConfigureWFMDemod, Message)
|
||||
|
||||
@ -31,13 +31,14 @@ WFMDemod::WFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
|
||||
m_sampleSink(sampleSink),
|
||||
m_audioFifo(audioFifo)
|
||||
{
|
||||
m_config.m_inputSampleRate = 96000;
|
||||
m_config.m_inputSampleRate = 384000;
|
||||
m_config.m_inputFrequencyOffset = 0;
|
||||
m_config.m_rfBandwidth = 180000;
|
||||
m_config.m_afBandwidth = 15000;
|
||||
m_config.m_squelch = -60.0;
|
||||
m_config.m_volume = 2.0;
|
||||
m_config.m_audioSampleRate = 48000;
|
||||
m_rfFilter = new fftfilt(-50000.0 / 384000.0, 50000.0 / 384000.0, rfFilterFftLength);
|
||||
|
||||
apply();
|
||||
|
||||
@ -49,6 +50,8 @@ WFMDemod::WFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
|
||||
|
||||
WFMDemod::~WFMDemod()
|
||||
{
|
||||
if (m_rfFilter)
|
||||
delete m_rfFilter;
|
||||
}
|
||||
|
||||
void WFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBandwidth, Real volume, Real squelch)
|
||||
@ -92,16 +95,51 @@ Real angleDist(Real a, Real b)
|
||||
void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst)
|
||||
{
|
||||
Complex ci;
|
||||
fftfilt::cmplx *rf;
|
||||
int rf_out;
|
||||
|
||||
if (m_audioFifo->size() <= 0)
|
||||
return;
|
||||
|
||||
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);
|
||||
c *= m_nco.nextIQ();
|
||||
|
||||
rf_out = m_rfFilter->runFilt(c, &rf); // filter RF before demod
|
||||
|
||||
for (int i =0 ; i <rf_out; i++)
|
||||
{
|
||||
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
|
||||
Real x = rf[i].real() * m_lastSample.real() + rf[i].imag() * m_lastSample.imag();
|
||||
Real y = rf[i].real() * m_lastSample.imag() - rf[i].imag() * m_lastSample.real();
|
||||
Real demod = atan2(x,y) / M_PI;
|
||||
m_lastSample = rf[i];
|
||||
|
||||
Complex e(demod, 0);
|
||||
|
||||
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, e, &ci))
|
||||
{
|
||||
quint16 sample = (qint16)(ci.real() * 3000 * m_running.m_volume);
|
||||
m_sampleBuffer.push_back(Sample(sample, sample));
|
||||
m_audioBuffer[m_audioBufferFill].l = sample;
|
||||
m_audioBuffer[m_audioBufferFill].r = sample;
|
||||
++m_audioBufferFill;
|
||||
|
||||
if(m_audioBufferFill >= m_audioBuffer.size())
|
||||
{
|
||||
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
|
||||
if(res != m_audioBufferFill)
|
||||
qDebug("lost %u samples", m_audioBufferFill - res);
|
||||
m_audioBufferFill = 0;
|
||||
}
|
||||
|
||||
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
{
|
||||
if(m_interpolator.interpolate(&m_interpolatorDistanceRemain, e, &ci))
|
||||
{
|
||||
m_sampleBuffer.push_back(Sample(ci.real() * 32767.0, ci.imag() * 32767.0));
|
||||
|
||||
@ -113,10 +151,12 @@ void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
|
||||
if(m_squelchState > 0) {
|
||||
m_squelchState--;
|
||||
|
||||
/*
|
||||
Real argument = arg(ci);
|
||||
argument /= M_PI;
|
||||
Real demod = argument - m_lastArgument;
|
||||
m_lastArgument = argument;
|
||||
*/
|
||||
|
||||
|
||||
//ci *= 32768.0;
|
||||
@ -178,7 +218,10 @@ void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
|
||||
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
if(m_audioBufferFill > 0) {
|
||||
uint res = m_audioFifo->write((const quint8*)&m_audioBuffer[0], m_audioBufferFill, 1);
|
||||
if(res != m_audioBufferFill)
|
||||
@ -234,20 +277,31 @@ void WFMDemod::apply()
|
||||
{
|
||||
|
||||
if((m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset) ||
|
||||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate)) {
|
||||
(m_config.m_inputSampleRate != m_running.m_inputSampleRate))
|
||||
{
|
||||
m_nco.setFreq(-m_config.m_inputFrequencyOffset, m_config.m_inputSampleRate);
|
||||
}
|
||||
|
||||
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
|
||||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth)) {
|
||||
std::cerr << "WFMDemod::apply: in=" << m_config.m_inputSampleRate << ", rf=" << m_config.m_rfBandwidth << std::endl;
|
||||
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2);
|
||||
m_interpolatorDistanceRemain = 0;
|
||||
(m_config.m_afBandwidth != m_running.m_afBandwidth))
|
||||
{
|
||||
m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_afBandwidth);
|
||||
m_interpolatorDistanceRemain = (Real) m_config.m_inputSampleRate / m_config.m_audioSampleRate;
|
||||
m_interpolatorDistance = m_config.m_inputSampleRate / m_config.m_audioSampleRate;
|
||||
}
|
||||
|
||||
if((m_config.m_inputSampleRate != m_running.m_inputSampleRate) ||
|
||||
(m_config.m_rfBandwidth != m_running.m_rfBandwidth) ||
|
||||
(m_config.m_inputFrequencyOffset != m_running.m_inputFrequencyOffset))
|
||||
{
|
||||
Real lowCut = (m_config.m_inputFrequencyOffset - (m_config.m_rfBandwidth / 2.0)) / m_config.m_inputSampleRate;
|
||||
Real hiCut = (m_config.m_inputFrequencyOffset + (m_config.m_rfBandwidth / 2.0)) / m_config.m_inputSampleRate;
|
||||
m_rfFilter->create_filter(lowCut, hiCut);
|
||||
}
|
||||
|
||||
if((m_config.m_afBandwidth != m_running.m_afBandwidth) ||
|
||||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate)) {
|
||||
(m_config.m_audioSampleRate != m_running.m_audioSampleRate))
|
||||
{
|
||||
m_lowpass.create(21, m_config.m_audioSampleRate, m_config.m_afBandwidth);
|
||||
}
|
||||
|
||||
@ -262,4 +316,13 @@ void WFMDemod::apply()
|
||||
m_running.m_squelch = m_config.m_squelch;
|
||||
m_running.m_volume = m_config.m_volume;
|
||||
m_running.m_audioSampleRate = m_config.m_audioSampleRate;
|
||||
|
||||
/*
|
||||
std::cerr << "WFMDemod::apply: in=" << m_config.m_inputSampleRate
|
||||
<< ", df=" << m_config.m_inputFrequencyOffset
|
||||
<< ", rfbw=" << m_config.m_rfBandwidth
|
||||
<< ", afbw=" << m_config.m_afBandwidth
|
||||
<< std::endl;
|
||||
*/
|
||||
|
||||
}
|
||||
|
@ -24,9 +24,12 @@
|
||||
#include "dsp/interpolator.h"
|
||||
#include "dsp/lowpass.h"
|
||||
#include "dsp/movingaverage.h"
|
||||
#include "dsp/fftfilt.h"
|
||||
#include "audio/audiofifo.h"
|
||||
#include "util/message.h"
|
||||
|
||||
#define rfFilterFftLength 1024
|
||||
|
||||
class AudioFifo;
|
||||
|
||||
class WFMDemod : public SampleSink {
|
||||
@ -111,6 +114,7 @@ private:
|
||||
Real m_interpolatorDistance;
|
||||
Real m_interpolatorDistanceRemain;
|
||||
Lowpass<Real> m_lowpass;
|
||||
fftfilt* m_rfFilter;
|
||||
|
||||
Real m_squelchLevel;
|
||||
int m_squelchState;
|
||||
|
@ -17,6 +17,16 @@ const int WFMDemodGUI::m_rfBW[] = {
|
||||
48000, 80000, 120000, 140000, 160000, 180000, 200000, 220000, 250000
|
||||
};
|
||||
|
||||
int requiredBW(int rfBW)
|
||||
{
|
||||
if (rfBW <= 48000)
|
||||
return 48000;
|
||||
else if (rfBW < 100000)
|
||||
return 96000;
|
||||
else
|
||||
return 384000;
|
||||
}
|
||||
|
||||
WFMDemodGUI* WFMDemodGUI::create(PluginAPI* pluginAPI)
|
||||
{
|
||||
WFMDemodGUI* gui = new WFMDemodGUI(pluginAPI);
|
||||
@ -208,7 +218,7 @@ void WFMDemodGUI::applySettings()
|
||||
{
|
||||
setTitleColor(m_channelMarker->getColor());
|
||||
m_channelizer->configure(m_threadedSampleSink->getMessageQueue(),
|
||||
256000, // TODO: this is where requested sample rate is specified
|
||||
requiredBW(m_rfBW[ui->rfBW->value()]), // TODO: this is where requested sample rate is specified
|
||||
m_channelMarker->getCenterFrequency());
|
||||
ui->deltaFrequency->setValue(abs(m_channelMarker->getCenterFrequency()));
|
||||
ui->deltaMinus->setChecked(m_channelMarker->getCenterFrequency() < 0);
|
||||
|
@ -96,11 +96,17 @@ bool Channelizer::handleMessage(Message* cmd)
|
||||
void Channelizer::applyConfiguration()
|
||||
{
|
||||
freeFilterChain();
|
||||
//std::cerr << "Channelizer::applyConfiguration in=" << m_inputSampleRate << ", req=" << m_requestedOutputSampleRate << std::endl;
|
||||
m_currentCenterFrequency = createFilterChain(
|
||||
m_inputSampleRate / -2, m_inputSampleRate / 2,
|
||||
m_requestedCenterFrequency - m_requestedOutputSampleRate / 2, m_requestedCenterFrequency + m_requestedOutputSampleRate / 2);
|
||||
m_currentOutputSampleRate = m_inputSampleRate / (1 << m_filterStages.size());
|
||||
/*
|
||||
std::cerr << "Channelizer::applyConfiguration in=" << m_inputSampleRate
|
||||
<< ", req=" << m_requestedOutputSampleRate
|
||||
<< ", out=" << m_currentOutputSampleRate
|
||||
<< ", fc=" << m_currentCenterFrequency
|
||||
<< std::endl;
|
||||
*/
|
||||
}
|
||||
|
||||
Channelizer::FilterStage::FilterStage(Mode mode) :
|
||||
|
Loading…
Reference in New Issue
Block a user