From 93c7188a338abc6013853b343b53c9d275b2b36e Mon Sep 17 00:00:00 2001 From: f4exb Date: Fri, 15 May 2015 15:05:28 +0200 Subject: [PATCH] WFM demod: optimization (got rid of atan2) and implemented squelch --- Readme.md | 8 ++-- plugins/channel/wfm/wfmdemod.cpp | 69 ++++++++++++++++---------------- plugins/channel/wfm/wfmdemod.h | 3 +- 3 files changed, 41 insertions(+), 39 deletions(-) diff --git a/Readme.md b/Readme.md index 069d452fa..4ab839f74 100644 --- a/Readme.md +++ b/Readme.md @@ -59,9 +59,9 @@ Known Issues ============ - Actually NFM seems to be working pretty well - - WFM does not work for broadcast - - NFM audio seems wrong (too slow) for RTL-SDR rates other than 1536 kHz. Maybe in SSB too. + - Does not work properly for RTL-SDR sampling rates not multiple of AF sampling rate (48000 Hz). This is because the interpolator/decimator is not a rational resampler actually (just does one or the other). For now please use 288, 1152 or 1536 kHz sampling rates, - RTL frontend will have bad aliasing in noisy environments. Considering the size of the hardware there is no place for proper filters. With good filtering and a good antenna up front these devices work remarkably well for the price! + - Aliasing can be annoying for broadcast FM. In this case try to shift the signal until you find a clear background for your station. This is a limitation of the RTL hardware so just use this workaround. =================== Done since the fork @@ -81,12 +81,14 @@ Done since the fork - Added the possibility to change the brightness and/or color of the grid. - Make the low cutoff frequency of the SSB filter variable so it can be used for CW also. - NFM demodulation without using atan and smooth squelch with AGC suppressing most clicks on low level signals and hiss on carrier tails. Only useful modulation comes through. + - Added working WFM demodulation. ===== To Do ===== - - Fix and possibly enhance (stereo, RDS?) WFM. Maybe into two plugins one for plain WFM and the other for Broadcast FM + - Missing de-accentuation on WFM + - Optimize (no atan2) and enhance (stereo, RDS?) WFM. - Make the the SSB filter frequency bounds tunable so that it can be used for CW. Change marker overlay accordingly. - Possibility to completely undock the receiver in a separate window. Useful when there are many receivers - Larger decimation capability for narrowband and very narrowband work (32, 64, ...) diff --git a/plugins/channel/wfm/wfmdemod.cpp b/plugins/channel/wfm/wfmdemod.cpp index e9023748b..0961d4769 100644 --- a/plugins/channel/wfm/wfmdemod.cpp +++ b/plugins/channel/wfm/wfmdemod.cpp @@ -60,43 +60,12 @@ void WFMDemod::configure(MessageQueue* messageQueue, Real rfBandwidth, Real afBa cmd->submit(messageQueue, this); } -/* -float arctan2(Real y, Real x) -{ - Real coeff_1 = M_PI / 4; - Real coeff_2 = 3 * coeff_1; - Real abs_y = fabs(y) + 1e-10; // kludge to prevent 0/0 condition - Real angle; - if( x>= 0) { - Real r = (x - abs_y) / (x + abs_y); - angle = coeff_1 - coeff_1 * r; - } else { - Real r = (x + abs_y) / (abs_y - x); - angle = coeff_2 - coeff_1 * r; - } - if(y < 0) - return(-angle); - else return(angle); -} - -Real angleDist(Real a, Real b) -{ - Real dist = b - a; - - while(dist <= M_PI) - dist += 2 * M_PI; - while(dist >= M_PI) - dist -= 2 * M_PI; - - return dist; -} -*/ - void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iterator end, bool firstOfBurst) { Complex ci; fftfilt::cmplx *rf; int rf_out; + Real msq, demod; if (m_audioFifo->size() <= 0) return; @@ -110,10 +79,40 @@ void WFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter for (int i =0 ; i = m_squelchLevel) + m_squelchState = m_running.m_rfBandwidth / 20; // decay rate + + if(m_squelchState > 0) + { + m_squelchState--; + + // Alternative without atan + // http://www.embedded.com/design/configurable-systems/4212086/DSP-Tricks--Frequency-demodulation-algorithms- + // in addition it needs scaling by instantaneous magnitude squared and volume (0..10) adjustment factor + Real ip = rf[i].real() - m_m2Sample.real(); + Real qp = rf[i].imag() - m_m2Sample.imag(); + Real h1 = m_m1Sample.real() * qp; + Real h2 = m_m1Sample.imag() * ip; + demod = (h1 - h2) / (msq * 10.0); + } + else + { + demod = 0; + } + + m_m2Sample = m_m1Sample; + m_m1Sample = rf[i]; Complex e(demod, 0); @@ -241,7 +240,7 @@ void WFMDemod::start() m_interpolatorRegulation = 0.9999; m_interpolatorDistance = 1.0; m_interpolatorDistanceRemain = 0.0; - m_lastSample = 0; + m_m1Sample = 0; } void WFMDemod::stop() diff --git a/plugins/channel/wfm/wfmdemod.h b/plugins/channel/wfm/wfmdemod.h index 73c4317b8..585438871 100644 --- a/plugins/channel/wfm/wfmdemod.h +++ b/plugins/channel/wfm/wfmdemod.h @@ -120,7 +120,8 @@ private: int m_squelchState; Real m_lastArgument; - Complex m_lastSample; + Complex m_m1Sample; // x^-1 sample + Complex m_m2Sample; // x^-1 sample MovingAverage m_movingAverage; AudioVector m_audioBuffer;