diff --git a/include-gpl/dsp/fftfilt.h b/include-gpl/dsp/fftfilt.h index 618d23d86..4aed393c8 100644 --- a/include-gpl/dsp/fftfilt.h +++ b/include-gpl/dsp/fftfilt.h @@ -5,7 +5,7 @@ #ifndef _FFTFILT_H #define _FFTFILT_H -#include "complex.h" +#include #include "gfft.h" //---------------------------------------------------------------------- @@ -13,6 +13,20 @@ class fftfilt { enum {NONE, BLACKMAN, HAMMING, HANNING}; +public: + typedef std::complex 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 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 diff --git a/plugins/channel/CMakeLists.txt b/plugins/channel/CMakeLists.txt index 4d6c557ae..a2a86ed41 100644 --- a/plugins/channel/CMakeLists.txt +++ b/plugins/channel/CMakeLists.txt @@ -5,5 +5,6 @@ add_subdirectory(am) add_subdirectory(nfm) add_subdirectory(ssb) add_subdirectory(tcpsrc) +add_subdirectory(wfm) #add_subdirectory(tetra) diff --git a/plugins/channel/ssb/ssbdemod.cpp b/plugins/channel/ssb/ssbdemod.cpp index b17dd3e41..a75eec6fb 100644 --- a/plugins/channel/ssb/ssbdemod.cpp +++ b/plugins/channel/ssb/ssbdemod.cpp @@ -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) { diff --git a/plugins/channel/tcpsrc/tcpsrc.cpp b/plugins/channel/tcpsrc/tcpsrc.cpp index 7f98ae231..f49264484 100644 --- a/plugins/channel/tcpsrc/tcpsrc.cpp +++ b/plugins/channel/tcpsrc/tcpsrc.cpp @@ -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(); diff --git a/plugins/channel/wfm/wfmdemod.cpp b/plugins/channel/wfm/wfmdemod.cpp index 55155a3d8..e9023748b 100644 --- a/plugins/channel/wfm/wfmdemod.cpp +++ b/plugins/channel/wfm/wfmdemod.cpp @@ -23,7 +23,7 @@ #include "dsp/pidcontroller.h" #include "wfmdemod.h" -#include +//#include 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) + 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 = 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; + */ + } diff --git a/plugins/channel/wfm/wfmdemod.h b/plugins/channel/wfm/wfmdemod.h index f11e17151..73c4317b8 100644 --- a/plugins/channel/wfm/wfmdemod.h +++ b/plugins/channel/wfm/wfmdemod.h @@ -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 m_lowpass; + fftfilt* m_rfFilter; Real m_squelchLevel; int m_squelchState; diff --git a/plugins/channel/wfm/wfmdemodgui.cpp b/plugins/channel/wfm/wfmdemodgui.cpp index cae7c7e4b..a0cec29df 100644 --- a/plugins/channel/wfm/wfmdemodgui.cpp +++ b/plugins/channel/wfm/wfmdemodgui.cpp @@ -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); diff --git a/sdrbase/dsp/channelizer.cpp b/sdrbase/dsp/channelizer.cpp index eb5b8765c..91cc4dcfd 100644 --- a/sdrbase/dsp/channelizer.cpp +++ b/sdrbase/dsp/channelizer.cpp @@ -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) :