From 302835771869600a92db0c0176a83bb181640315 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 17 Dec 2015 00:45:44 +0100 Subject: [PATCH] NFM demod: phase discriminator refactoring. Review volume boundaries --- include/dsp/phasediscri.hpp | 74 ++++++++++++++++++++---------- plugins/channel/nfm/nfmdemod.cpp | 18 ++++---- plugins/channel/nfm/nfmdemod.h | 9 ++-- plugins/channel/nfm/nfmdemodgui.ui | 5 +- 4 files changed, 68 insertions(+), 38 deletions(-) diff --git a/include/dsp/phasediscri.hpp b/include/dsp/phasediscri.hpp index b230001df..479dac558 100644 --- a/include/dsp/phasediscri.hpp +++ b/include/dsp/phasediscri.hpp @@ -18,33 +18,59 @@ #ifndef INCLUDE_DSP_PHASEDISCRI_H_ #define INCLUDE_DSP_PHASEDISCRI_H_ -/** - * Standard discriminator using atan2. On modern processors this is as efficient as the non atan2 one. - * This is better for high fidelity. - */ -Real phaseDiscriminator(const Complex& sample) +class PhaseDiscriminators { - Complex d(std::conj(m_m1Sample) * sample); - m_m1Sample = sample; - return (std::atan2(d.imag(), d.real()) / M_PI_2) * m_fmScaling; -} +public: + /** + * Reset stored values + */ + void reset() + { + m_m1Sample = 0; + m_m2Sample = 0; + } -/** - * Alternative without atan at the expense of a slight distorsion on very wideband signals - * 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 phaseDiscriminator2(const Complex& sample) -{ - Real ip = sample.real() - m_m2Sample.real(); - Real qp = sample.imag() - m_m2Sample.imag(); - Real h1 = m_m1Sample.real() * qp; - Real h2 = m_m1Sample.imag() * ip; + /** + * Scaling factor so that resulting excursion maps to [-1,+1] + */ + void setFMScaling(Real fmScaling) + { + m_fmScaling = fmScaling; + } - m_m2Sample = m_m1Sample; - m_m1Sample = sample; + /** + * Standard discriminator using atan2. On modern processors this is as efficient as the non atan2 one. + * This is better for high fidelity. + */ + Real phaseDiscriminator(const Complex& sample) + { + Complex d(std::conj(m_m1Sample) * sample); + m_m1Sample = sample; + return (std::atan2(d.imag(), d.real()) / M_PI_2) * m_fmScaling; + } - return ((h1 - h2) / M_PI) * m_fmScaling; -} + /** + * Alternative without atan at the expense of a slight distorsion on very wideband signals + * 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 phaseDiscriminator2(const Complex& sample) + { + Real ip = sample.real() - m_m2Sample.real(); + Real qp = sample.imag() - m_m2Sample.imag(); + Real h1 = m_m1Sample.real() * qp; + Real h2 = m_m1Sample.imag() * ip; + + m_m2Sample = m_m1Sample; + m_m1Sample = sample; + + return ((h1 - h2) / M_PI) * m_fmScaling; + } + +private: + Complex m_m1Sample; + Complex m_m2Sample; + Real m_fmScaling; +}; #endif /* INCLUDE_DSP_PHASEDISCRI_H_ */ diff --git a/plugins/channel/nfm/nfmdemod.cpp b/plugins/channel/nfm/nfmdemod.cpp index 60f6aab58..5674cff6b 100644 --- a/plugins/channel/nfm/nfmdemod.cpp +++ b/plugins/channel/nfm/nfmdemod.cpp @@ -39,7 +39,6 @@ NFMDemod::NFMDemod() : m_afSquelch(2, afSqTones), m_audioFifo(4, 48000), m_fmExcursion(2400), - m_fmScaling(384000/2400), m_settingsMutex(QMutex::Recursive) { setObjectName("NFMDemod"); @@ -49,10 +48,11 @@ NFMDemod::NFMDemod() : m_config.m_rfBandwidth = 12500; m_config.m_afBandwidth = 3000; m_config.m_squelch = -30.0; - m_config.m_volume = 2.0; + m_config.m_volume = 1.0; m_config.m_ctcssOn = false; m_config.m_audioMute = false; m_config.m_audioSampleRate = DSPEngine::instance()->getAudioSampleRate(); + m_phaseDiscri.setFMScaling(384000/2400); apply(); @@ -141,10 +141,10 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto m_AGC.feed(ci); - Real demod = phaseDiscriminator2(ci); + Real demod = m_phaseDiscri.phaseDiscriminator2(ci); - m_m2Sample = m_m1Sample; - m_m1Sample = ci; + //m_m2Sample = m_m1Sample; + //m_m1Sample = ci; m_sampleCount++; // AF processing @@ -263,7 +263,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto void NFMDemod::start() { m_audioFifo.clear(); - m_m1Sample = 0; + m_phaseDiscri.reset(); } void NFMDemod::stop() @@ -331,7 +331,7 @@ void NFMDemod::apply() m_interpolator.create(16, m_config.m_inputSampleRate, m_config.m_rfBandwidth / 2.2); m_interpolatorDistanceRemain = 0; m_interpolatorDistance = (Real) m_config.m_inputSampleRate / (Real) m_config.m_audioSampleRate; - m_fmScaling = m_config.m_inputSampleRate / m_fmExcursion; + m_phaseDiscri.setFMScaling(m_config.m_inputSampleRate / m_fmExcursion); m_settingsMutex.unlock(); } @@ -342,14 +342,14 @@ void NFMDemod::apply() m_lowpass.create(301, m_config.m_audioSampleRate, 250.0); m_bandpass.create(301, m_config.m_audioSampleRate, 300.0, m_config.m_afBandwidth); m_fmExcursion = m_config.m_afBandwidth / 2.0f; - m_fmScaling = m_config.m_inputSampleRate / m_fmExcursion; + m_phaseDiscri.setFMScaling(m_config.m_inputSampleRate / m_fmExcursion); m_settingsMutex.unlock(); } if (m_config.m_squelch != m_running.m_squelch) { // input is a value in tenths of dB - m_squelchLevel = pow(10.0, m_config.m_squelch / 200.0); + m_squelchLevel = std::pow(10.0, m_config.m_squelch / 200.0); //m_squelchLevel *= m_squelchLevel; m_afSquelch.setThreshold(m_squelchLevel); } diff --git a/plugins/channel/nfm/nfmdemod.h b/plugins/channel/nfm/nfmdemod.h index f739d24ad..1375e3940 100644 --- a/plugins/channel/nfm/nfmdemod.h +++ b/plugins/channel/nfm/nfmdemod.h @@ -29,6 +29,7 @@ #include "dsp/agc.h" #include "dsp/ctcssdetector.h" #include "dsp/afsquelch.h" +#include "dsp/phasediscri.hpp" #include "audio/audiofifo.h" #include "util/message.h" @@ -170,15 +171,15 @@ private: double m_squelchLevel; Real m_lastArgument; - Complex m_m1Sample; - Complex m_m2Sample; + //Complex m_m1Sample; + //Complex m_m2Sample; MagAGC m_AGC; AFSquelch m_afSquelch; Real m_agcLevel; // AGC will aim to this level Real m_agcFloor; // AGC will not go below this level Real m_fmExcursion; - Real m_fmScaling; + //Real m_fmScaling; AudioVector m_audioBuffer; uint m_audioBufferFill; @@ -188,7 +189,7 @@ private: NFMDemodGUI *m_nfmDemodGUI; QMutex m_settingsMutex; -#include "dsp/phasediscri.hpp" + PhaseDiscriminators m_phaseDiscri; void apply(); }; diff --git a/plugins/channel/nfm/nfmdemodgui.ui b/plugins/channel/nfm/nfmdemodgui.ui index d55c3b613..d685e59ef 100644 --- a/plugins/channel/nfm/nfmdemodgui.ui +++ b/plugins/channel/nfm/nfmdemodgui.ui @@ -244,7 +244,10 @@ - 100 + 40 + + + 1 20