1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-23 08:28:36 -05:00

NFM demod: corrections applied to the audio sample rate depedent parameters

This commit is contained in:
f4exb 2018-04-11 01:31:48 +02:00
parent 4dc99f7ad8
commit dac48f9a6d
3 changed files with 25 additions and 17 deletions

View File

@ -55,7 +55,8 @@ NFMDemod::NFMDemod(DeviceSourceAPI *devieAPI) :
m_ctcssIndex(0), m_ctcssIndex(0),
m_sampleCount(0), m_sampleCount(0),
m_squelchCount(0), m_squelchCount(0),
m_squelchGate(2), m_squelchGate(4800),
m_squelchDecay(480),
m_squelchLevel(-990), m_squelchLevel(-990),
m_squelchOpen(false), m_squelchOpen(false),
m_afSquelchOpen(false), m_afSquelchOpen(false),
@ -75,12 +76,12 @@ NFMDemod::NFMDemod(DeviceSourceAPI *devieAPI) :
m_agcLevel = 1.0; m_agcLevel = 1.0;
m_ctcssDetector.setCoefficients(3000, 6000.0); // 0.5s / 2 Hz resolution
m_afSquelch.setCoefficients(24, 600, 48000.0, 200, 0); // 0.5ms test period, 300ms average span, 48kS/s SR, 100ms attack, no decay
DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue()); DSPEngine::instance()->getAudioDeviceManager()->addAudioSink(&m_audioFifo, getInputMessageQueue());
m_audioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate(); m_audioSampleRate = DSPEngine::instance()->getAudioDeviceManager()->getOutputSampleRate();
m_ctcssDetector.setCoefficients(m_audioSampleRate/16, m_audioSampleRate/8.0f); // 0.5s / 2 Hz resolution
m_afSquelch.setCoefficients(m_audioSampleRate/2000, 600, m_audioSampleRate, 200, 0); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay
m_lowpass.create(301, m_audioSampleRate, 250.0); m_lowpass.create(301, m_audioSampleRate, 250.0);
applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true); applyChannelSettings(m_inputSampleRate, m_inputFrequencyOffset, true);
@ -136,6 +137,7 @@ Real angleDist(Real a, Real b)
void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused))) void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool firstOfBurst __attribute__((unused)))
{ {
Complex ci; Complex ci;
float f = (m_audioSampleRate / 48000.0f);
if (!m_running) { if (!m_running) {
return; return;
@ -174,13 +176,13 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
if (m_settings.m_deltaSquelch) if (m_settings.m_deltaSquelch)
{ {
if (m_afSquelch.analyze(demod)) { if (m_afSquelch.analyze(demod * f)) {
m_afSquelchOpen = m_afSquelch.evaluate() ? m_squelchGate + 480 : 0; m_afSquelchOpen = m_afSquelch.evaluate() ? m_squelchGate + m_squelchDecay : 0;
} }
if (m_afSquelchOpen) if (m_afSquelchOpen)
{ {
if (m_squelchCount < m_squelchGate + 480) if (m_squelchCount < m_squelchGate + m_squelchDecay)
{ {
m_squelchCount++; m_squelchCount++;
} }
@ -204,7 +206,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
} }
else else
{ {
if (m_squelchCount < m_squelchGate + 480) if (m_squelchCount < m_squelchGate + m_squelchDecay)
{ {
m_squelchCount++; m_squelchCount++;
} }
@ -217,7 +219,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
{ {
if (m_settings.m_ctcssOn) if (m_settings.m_ctcssOn)
{ {
Real ctcss_sample = m_lowpass.filter(demod); Real ctcss_sample = m_lowpass.filter(demod * f);
if ((m_sampleCount & 7) == 7) // decimate 48k -> 6k if ((m_sampleCount & 7) == 7) // decimate 48k -> 6k
{ {
@ -257,8 +259,8 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
} }
else else
{ {
demod = m_bandpass.filter(demod); demod = m_bandpass.filter(demod * f);
Real squelchFactor = StepFunctions::smootherstep((Real) (m_squelchCount - m_squelchGate) / 480.0f); Real squelchFactor = StepFunctions::smootherstep((Real) (m_squelchCount - m_squelchGate) / (Real) m_squelchDecay);
sample = demod * m_settings.m_volume * squelchFactor; sample = demod * m_settings.m_volume * squelchFactor;
} }
} }
@ -407,6 +409,12 @@ void NFMDemod::applyAudioSampleRate(int sampleRate)
m_interpolatorDistance = (Real) m_inputSampleRate / (Real) sampleRate; m_interpolatorDistance = (Real) m_inputSampleRate / (Real) sampleRate;
m_lowpass.create(301, sampleRate, 250.0); m_lowpass.create(301, sampleRate, 250.0);
m_bandpass.create(301, sampleRate, 300.0, m_settings.m_afBandwidth); m_bandpass.create(301, sampleRate, 300.0, m_settings.m_afBandwidth);
m_squelchGate = (sampleRate / 100) * m_settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
m_squelchDecay = (sampleRate / 100); // decay is fixed at 10ms
m_squelchCount = 0; // reset squelch open counter
m_ctcssDetector.setCoefficients(sampleRate/16, sampleRate/8.0f); // 0.5s / 2 Hz resolution
m_afSquelch.setCoefficients(sampleRate/2000, 600, sampleRate, 200, 0); // 0.5ms test period, 300ms average span, audio SR, 100ms attack, no decay
m_phaseDiscri.setFMScaling((8.0f*sampleRate) / static_cast<float>(m_settings.m_fmDeviation)); // integrate 4x factor
m_audioFifo.setSize(sampleRate); m_audioFifo.setSize(sampleRate);
m_settingsMutex.unlock(); m_settingsMutex.unlock();
@ -464,10 +472,9 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
m_settingsMutex.unlock(); m_settingsMutex.unlock();
} }
if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || if ((settings.m_fmDeviation != m_settings.m_fmDeviation) || force)
(settings.m_rfBandwidth != m_settings.m_rfBandwidth) || force)
{ {
m_phaseDiscri.setFMScaling((8.0f*settings.m_rfBandwidth) / static_cast<float>(settings.m_fmDeviation)); // integrate 4x factor m_phaseDiscri.setFMScaling((8.0f*m_audioSampleRate) / static_cast<float>(settings.m_fmDeviation)); // integrate 4x factor
} }
if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force) if ((settings.m_afBandwidth != m_settings.m_afBandwidth) || force)
@ -479,7 +486,7 @@ void NFMDemod::applySettings(const NFMDemodSettings& settings, bool force)
if ((settings.m_squelchGate != m_settings.m_squelchGate) || force) if ((settings.m_squelchGate != m_settings.m_squelchGate) || force)
{ {
m_squelchGate = 480 * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate m_squelchGate = (m_audioSampleRate / 100) * settings.m_squelchGate; // gate is given in 10s of ms at 48000 Hz audio sample rate
m_squelchCount = 0; // reset squelch open counter m_squelchCount = 0; // reset squelch open counter
} }
@ -614,7 +621,7 @@ int NFMDemod::webapiSettingsPutPatch(
if (frequencyOffsetChanged) if (frequencyOffsetChanged)
{ {
MsgConfigureChannelizer* channelConfigMsg = MsgConfigureChannelizer::create( MsgConfigureChannelizer* channelConfigMsg = MsgConfigureChannelizer::create(
48000, settings.m_inputFrequencyOffset); m_audioSampleRate, settings.m_inputFrequencyOffset);
m_inputMessageQueue.push(channelConfigMsg); m_inputMessageQueue.push(channelConfigMsg);
} }

View File

@ -193,6 +193,7 @@ private:
int m_sampleCount; int m_sampleCount;
int m_squelchCount; int m_squelchCount;
int m_squelchGate; int m_squelchGate;
int m_squelchDecay;
Real m_squelchLevel; Real m_squelchLevel;
bool m_squelchOpen; bool m_squelchOpen;

View File

@ -9,7 +9,7 @@
const PluginDescriptor NFMPlugin::m_pluginDescriptor = { const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
QString("NFM Demodulator"), QString("NFM Demodulator"),
QString("3.14.1"), QString("3.14.2"),
QString("(c) Edouard Griffiths, F4EXB"), QString("(c) Edouard Griffiths, F4EXB"),
QString("https://github.com/f4exb/sdrangel"), QString("https://github.com/f4exb/sdrangel"),
true, true,