mirror of
https://github.com/f4exb/sdrangel.git
synced 2025-02-03 09:44:01 -05:00
Full CTCSS support in NFM demod
This commit is contained in:
parent
471364f540
commit
56d51e9fef
@ -19,6 +19,7 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <complex.h>
|
#include <complex.h>
|
||||||
#include "nfmdemod.h"
|
#include "nfmdemod.h"
|
||||||
|
#include "nfmdemodgui.h"
|
||||||
#include "audio/audiooutput.h"
|
#include "audio/audiooutput.h"
|
||||||
#include "dsp/dspcommands.h"
|
#include "dsp/dspcommands.h"
|
||||||
#include "dsp/pidcontroller.h"
|
#include "dsp/pidcontroller.h"
|
||||||
@ -28,6 +29,7 @@
|
|||||||
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureNFMDemod, Message)
|
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureNFMDemod, Message)
|
||||||
|
|
||||||
NFMDemod::NFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
|
NFMDemod::NFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
|
||||||
|
m_ctcssIndex(0),
|
||||||
m_sampleCount(0),
|
m_sampleCount(0),
|
||||||
m_sampleSink(sampleSink),
|
m_sampleSink(sampleSink),
|
||||||
m_audioFifo(audioFifo)
|
m_audioFifo(audioFifo)
|
||||||
@ -49,7 +51,7 @@ NFMDemod::NFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
|
|||||||
m_agcLevel = 0.003;
|
m_agcLevel = 0.003;
|
||||||
m_AGC.resize(4096, m_agcLevel, 0, 0.1*m_agcLevel);
|
m_AGC.resize(4096, m_agcLevel, 0, 0.1*m_agcLevel);
|
||||||
|
|
||||||
m_ctcssDetector.setCoefficients(1200, 6000.0); // 0.2s detection rate
|
m_ctcssDetector.setCoefficients(3000, 6000.0); // 0.5s / 2 Hz resolution
|
||||||
}
|
}
|
||||||
|
|
||||||
NFMDemod::~NFMDemod()
|
NFMDemod::~NFMDemod()
|
||||||
@ -112,7 +114,8 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
|
|||||||
m_squelchState = m_running.m_audioSampleRate/ 20;
|
m_squelchState = m_running.m_audioSampleRate/ 20;
|
||||||
|
|
||||||
qint16 sample;
|
qint16 sample;
|
||||||
if(m_squelchState > 0) {
|
if(m_squelchState > 0)
|
||||||
|
{
|
||||||
m_squelchState--;
|
m_squelchState--;
|
||||||
|
|
||||||
m_AGC.feed(abs(ci));
|
m_AGC.feed(abs(ci));
|
||||||
@ -166,16 +169,39 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
|
|||||||
|
|
||||||
if (m_ctcssDetector.getDetectedTone(maxToneIndex))
|
if (m_ctcssDetector.getDetectedTone(maxToneIndex))
|
||||||
{
|
{
|
||||||
std::cerr << "CTCSS tone detected: " << m_ctcssDetector.getToneSet()[maxToneIndex] << std::endl;
|
if (maxToneIndex+1 != m_ctcssIndex) {
|
||||||
|
m_nfmDemodGUI->setCtcssFreq(m_ctcssDetector.getToneSet()[maxToneIndex]);
|
||||||
|
m_ctcssIndex = maxToneIndex+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_ctcssIndex != 0) {
|
||||||
|
m_nfmDemodGUI->setCtcssFreq(0);
|
||||||
|
m_ctcssIndex = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
demod = m_bandpass.filter(demod);
|
if (m_ctcssIndexSelected && (m_ctcssIndexSelected != m_ctcssIndex))
|
||||||
demod *= m_running.m_volume;
|
{
|
||||||
sample = demod * ((1<<16)/301); // denominator = bandpass filter number of taps
|
sample = 0.0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
demod = m_bandpass.filter(demod);
|
||||||
|
demod *= m_running.m_volume;
|
||||||
|
sample = demod * ((1<<15)/301); // denominator = bandpass filter number of taps
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_ctcssIndex != 0) {
|
||||||
|
m_nfmDemodGUI->setCtcssFreq(0);
|
||||||
|
m_ctcssIndex = 0;
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
|
||||||
m_AGC.close();
|
m_AGC.close();
|
||||||
sample = 0;
|
sample = 0;
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "util/message.h"
|
#include "util/message.h"
|
||||||
|
|
||||||
class AudioFifo;
|
class AudioFifo;
|
||||||
|
class NFMDemodGUI;
|
||||||
|
|
||||||
class NFMDemod : public SampleSink {
|
class NFMDemod : public SampleSink {
|
||||||
public:
|
public:
|
||||||
@ -44,6 +45,19 @@ public:
|
|||||||
void stop();
|
void stop();
|
||||||
bool handleMessage(Message* cmd);
|
bool handleMessage(Message* cmd);
|
||||||
|
|
||||||
|
void registerGUI(NFMDemodGUI *nfmDemodGUI) {
|
||||||
|
m_nfmDemodGUI = nfmDemodGUI;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Real *getCtcssToneSet(int& nbTones) const {
|
||||||
|
nbTones = m_ctcssDetector.getNTones();
|
||||||
|
return m_ctcssDetector.getToneSet();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setSelectedCtcssIndex(int selectedCtcssIndex) {
|
||||||
|
m_ctcssIndexSelected = selectedCtcssIndex;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class MsgConfigureNFMDemod : public Message {
|
class MsgConfigureNFMDemod : public Message {
|
||||||
MESSAGE_CLASS_DECLARATION
|
MESSAGE_CLASS_DECLARATION
|
||||||
@ -92,6 +106,7 @@ private:
|
|||||||
Real m_afBandwidth;
|
Real m_afBandwidth;
|
||||||
Real m_squelch;
|
Real m_squelch;
|
||||||
Real m_volume;
|
Real m_volume;
|
||||||
|
int m_ctcssIndex;
|
||||||
quint32 m_audioSampleRate;
|
quint32 m_audioSampleRate;
|
||||||
|
|
||||||
Config() :
|
Config() :
|
||||||
@ -101,6 +116,7 @@ private:
|
|||||||
m_afBandwidth(-1),
|
m_afBandwidth(-1),
|
||||||
m_squelch(0),
|
m_squelch(0),
|
||||||
m_volume(0),
|
m_volume(0),
|
||||||
|
m_ctcssIndex(0),
|
||||||
m_audioSampleRate(0)
|
m_audioSampleRate(0)
|
||||||
{ }
|
{ }
|
||||||
};
|
};
|
||||||
@ -116,6 +132,8 @@ private:
|
|||||||
Lowpass<Real> m_lowpass;
|
Lowpass<Real> m_lowpass;
|
||||||
Bandpass<Real> m_bandpass;
|
Bandpass<Real> m_bandpass;
|
||||||
CTCSSDetector m_ctcssDetector;
|
CTCSSDetector m_ctcssDetector;
|
||||||
|
int m_ctcssIndex; // 0 for nothing detected
|
||||||
|
int m_ctcssIndexSelected;
|
||||||
int m_sampleCount;
|
int m_sampleCount;
|
||||||
|
|
||||||
Real m_squelchLevel;
|
Real m_squelchLevel;
|
||||||
@ -136,6 +154,8 @@ private:
|
|||||||
AudioFifo* m_audioFifo;
|
AudioFifo* m_audioFifo;
|
||||||
SampleVector m_sampleBuffer;
|
SampleVector m_sampleBuffer;
|
||||||
|
|
||||||
|
NFMDemodGUI *m_nfmDemodGUI;
|
||||||
|
|
||||||
void apply();
|
void apply();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -151,6 +151,12 @@ void NFMDemodGUI::on_squelch_valueChanged(int value)
|
|||||||
applySettings();
|
applySettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NFMDemodGUI::on_ctcss_currentIndexChanged(int index)
|
||||||
|
{
|
||||||
|
if (m_nfmDemod != NULL) {
|
||||||
|
m_nfmDemod->setSelectedCtcssIndex(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void NFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
void NFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
|
||||||
{
|
{
|
||||||
@ -182,7 +188,19 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
|
|||||||
|
|
||||||
m_audioFifo = new AudioFifo(4, 48000);
|
m_audioFifo = new AudioFifo(4, 48000);
|
||||||
m_nullSink = new NullSink();
|
m_nullSink = new NullSink();
|
||||||
|
|
||||||
m_nfmDemod = new NFMDemod(m_audioFifo, m_nullSink);
|
m_nfmDemod = new NFMDemod(m_audioFifo, m_nullSink);
|
||||||
|
m_nfmDemod->registerGUI(this);
|
||||||
|
|
||||||
|
int ctcss_nbTones;
|
||||||
|
const Real *ctcss_tones = m_nfmDemod->getCtcssToneSet(ctcss_nbTones);
|
||||||
|
|
||||||
|
ui->ctcss->addItem("--");
|
||||||
|
|
||||||
|
for (int i=0; i<ctcss_nbTones; i++) {
|
||||||
|
ui->ctcss->addItem(QString("%1").arg(ctcss_tones[i]));
|
||||||
|
}
|
||||||
|
|
||||||
m_channelizer = new Channelizer(m_nfmDemod);
|
m_channelizer = new Channelizer(m_nfmDemod);
|
||||||
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
|
m_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
|
||||||
m_pluginAPI->addAudioSource(m_audioFifo);
|
m_pluginAPI->addAudioSource(m_audioFifo);
|
||||||
@ -238,3 +256,15 @@ void NFMDemodGUI::enterEvent(QEvent*)
|
|||||||
m_channelMarker->setHighlighted(true);
|
m_channelMarker->setHighlighted(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NFMDemodGUI::setCtcssFreq(Real ctcssFreq)
|
||||||
|
{
|
||||||
|
if (ctcssFreq == 0)
|
||||||
|
{
|
||||||
|
ui->ctcssText->setText("--");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ui->ctcssText->setText(QString("%1").arg(ctcssFreq));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include "gui/rollupwidget.h"
|
#include "gui/rollupwidget.h"
|
||||||
#include "plugin/plugingui.h"
|
#include "plugin/plugingui.h"
|
||||||
|
#include "dsp/dsptypes.h"
|
||||||
|
|
||||||
class PluginAPI;
|
class PluginAPI;
|
||||||
class ChannelMarker;
|
class ChannelMarker;
|
||||||
@ -32,6 +33,7 @@ public:
|
|||||||
bool deserialize(const QByteArray& data);
|
bool deserialize(const QByteArray& data);
|
||||||
|
|
||||||
bool handleMessage(Message* message);
|
bool handleMessage(Message* message);
|
||||||
|
void setCtcssFreq(Real ctcssFreq);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void viewChanged();
|
void viewChanged();
|
||||||
@ -41,6 +43,7 @@ private slots:
|
|||||||
void on_afBW_valueChanged(int value);
|
void on_afBW_valueChanged(int value);
|
||||||
void on_volume_valueChanged(int value);
|
void on_volume_valueChanged(int value);
|
||||||
void on_squelch_valueChanged(int value);
|
void on_squelch_valueChanged(int value);
|
||||||
|
void on_ctcss_currentIndexChanged(int index);
|
||||||
void onWidgetRolled(QWidget* widget, bool rollDown);
|
void onWidgetRolled(QWidget* widget, bool rollDown);
|
||||||
void onMenuDoubleClicked();
|
void onMenuDoubleClicked();
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>302</width>
|
<width>302</width>
|
||||||
<height>138</height>
|
<height>151</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -19,7 +19,7 @@
|
|||||||
<x>35</x>
|
<x>35</x>
|
||||||
<y>35</y>
|
<y>35</y>
|
||||||
<width>242</width>
|
<width>242</width>
|
||||||
<height>96</height>
|
<height>111</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@ -81,19 +81,26 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="0">
|
<item row="4" column="0">
|
||||||
<widget class="QLabel" name="label_4">
|
<widget class="QLabel" name="squelchLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Squelch</string>
|
<string>Squelch</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="2" column="0">
|
<item row="2" column="0">
|
||||||
<widget class="QLabel" name="label_2">
|
<widget class="QLabel" name="afLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>AF Bandwidth</string>
|
<string>AF Bandwidth</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="rfBWLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>RF Bandwidth</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="4" column="1">
|
<item row="4" column="1">
|
||||||
<widget class="QSlider" name="squelch">
|
<widget class="QSlider" name="squelch">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
@ -126,13 +133,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string>RF Bandwidth</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="2" column="2">
|
<item row="2" column="2">
|
||||||
<widget class="QLabel" name="afBWText">
|
<widget class="QLabel" name="afBWText">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
@ -149,6 +149,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="volumeLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Volume</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="2" column="1">
|
<item row="2" column="1">
|
||||||
<widget class="QSlider" name="afBW">
|
<widget class="QSlider" name="afBW">
|
||||||
<property name="minimum">
|
<property name="minimum">
|
||||||
@ -184,13 +191,6 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="3" column="0">
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string>Volume</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="3" column="2">
|
<item row="3" column="2">
|
||||||
<widget class="QLabel" name="volumeText">
|
<widget class="QLabel" name="volumeText">
|
||||||
<property name="minimumSize">
|
<property name="minimumSize">
|
||||||
@ -207,6 +207,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="deltaUnits">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hz</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="ValueDial" name="deltaFrequency" native="true">
|
<widget class="ValueDial" name="deltaFrequency" native="true">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
@ -238,10 +245,23 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="0" column="2">
|
<item row="5" column="0">
|
||||||
<widget class="QLabel" name="deltaUnits">
|
<widget class="QLabel" name="ctcssLabel">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Hz</string>
|
<string>CTCSS</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QComboBox" name="ctcss"/>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="2">
|
||||||
|
<widget class="QLabel" name="ctcssText">
|
||||||
|
<property name="text">
|
||||||
|
<string>--</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignCenter</set>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
Loading…
Reference in New Issue
Block a user