1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-25 17:28:50 -05:00

Full CTCSS support in NFM demod

This commit is contained in:
f4exb 2015-06-17 01:42:58 +02:00
parent 471364f540
commit 56d51e9fef
5 changed files with 127 additions and 28 deletions

View File

@ -19,6 +19,7 @@
#include <stdio.h>
#include <complex.h>
#include "nfmdemod.h"
#include "nfmdemodgui.h"
#include "audio/audiooutput.h"
#include "dsp/dspcommands.h"
#include "dsp/pidcontroller.h"
@ -28,6 +29,7 @@
MESSAGE_CLASS_DEFINITION(NFMDemod::MsgConfigureNFMDemod, Message)
NFMDemod::NFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
m_ctcssIndex(0),
m_sampleCount(0),
m_sampleSink(sampleSink),
m_audioFifo(audioFifo)
@ -49,7 +51,7 @@ NFMDemod::NFMDemod(AudioFifo* audioFifo, SampleSink* sampleSink) :
m_agcLevel = 0.003;
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()
@ -112,7 +114,8 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
m_squelchState = m_running.m_audioSampleRate/ 20;
qint16 sample;
if(m_squelchState > 0) {
if(m_squelchState > 0)
{
m_squelchState--;
m_AGC.feed(abs(ci));
@ -166,16 +169,39 @@ void NFMDemod::feed(SampleVector::const_iterator begin, SampleVector::const_iter
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);
demod *= m_running.m_volume;
sample = demod * ((1<<16)/301); // denominator = bandpass filter number of taps
if (m_ctcssIndexSelected && (m_ctcssIndexSelected != m_ctcssIndex))
{
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();
sample = 0;
}

View File

@ -31,6 +31,7 @@
#include "util/message.h"
class AudioFifo;
class NFMDemodGUI;
class NFMDemod : public SampleSink {
public:
@ -44,6 +45,19 @@ public:
void stop();
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:
class MsgConfigureNFMDemod : public Message {
MESSAGE_CLASS_DECLARATION
@ -92,6 +106,7 @@ private:
Real m_afBandwidth;
Real m_squelch;
Real m_volume;
int m_ctcssIndex;
quint32 m_audioSampleRate;
Config() :
@ -101,6 +116,7 @@ private:
m_afBandwidth(-1),
m_squelch(0),
m_volume(0),
m_ctcssIndex(0),
m_audioSampleRate(0)
{ }
};
@ -116,6 +132,8 @@ private:
Lowpass<Real> m_lowpass;
Bandpass<Real> m_bandpass;
CTCSSDetector m_ctcssDetector;
int m_ctcssIndex; // 0 for nothing detected
int m_ctcssIndexSelected;
int m_sampleCount;
Real m_squelchLevel;
@ -136,6 +154,8 @@ private:
AudioFifo* m_audioFifo;
SampleVector m_sampleBuffer;
NFMDemodGUI *m_nfmDemodGUI;
void apply();
};

View File

@ -151,6 +151,12 @@ void NFMDemodGUI::on_squelch_valueChanged(int value)
applySettings();
}
void NFMDemodGUI::on_ctcss_currentIndexChanged(int index)
{
if (m_nfmDemod != NULL) {
m_nfmDemod->setSelectedCtcssIndex(index);
}
}
void NFMDemodGUI::onWidgetRolled(QWidget* widget, bool rollDown)
{
@ -182,7 +188,19 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
m_audioFifo = new AudioFifo(4, 48000);
m_nullSink = new 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_threadedSampleSink = new ThreadedSampleSink(m_channelizer);
m_pluginAPI->addAudioSource(m_audioFifo);
@ -238,3 +256,15 @@ void NFMDemodGUI::enterEvent(QEvent*)
m_channelMarker->setHighlighted(true);
}
void NFMDemodGUI::setCtcssFreq(Real ctcssFreq)
{
if (ctcssFreq == 0)
{
ui->ctcssText->setText("--");
}
else
{
ui->ctcssText->setText(QString("%1").arg(ctcssFreq));
}
}

View File

@ -3,6 +3,7 @@
#include "gui/rollupwidget.h"
#include "plugin/plugingui.h"
#include "dsp/dsptypes.h"
class PluginAPI;
class ChannelMarker;
@ -32,6 +33,7 @@ public:
bool deserialize(const QByteArray& data);
bool handleMessage(Message* message);
void setCtcssFreq(Real ctcssFreq);
private slots:
void viewChanged();
@ -41,6 +43,7 @@ private slots:
void on_afBW_valueChanged(int value);
void on_volume_valueChanged(int value);
void on_squelch_valueChanged(int value);
void on_ctcss_currentIndexChanged(int index);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDoubleClicked();

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>302</width>
<height>138</height>
<height>151</height>
</rect>
</property>
<property name="windowTitle">
@ -19,7 +19,7 @@
<x>35</x>
<y>35</y>
<width>242</width>
<height>96</height>
<height>111</height>
</rect>
</property>
<property name="windowTitle">
@ -81,19 +81,26 @@
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_4">
<widget class="QLabel" name="squelchLabel">
<property name="text">
<string>Squelch</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_2">
<widget class="QLabel" name="afLabel">
<property name="text">
<string>AF Bandwidth</string>
</property>
</widget>
</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">
<widget class="QSlider" name="squelch">
<property name="minimum">
@ -126,13 +133,6 @@
</property>
</widget>
</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">
<widget class="QLabel" name="afBWText">
<property name="minimumSize">
@ -149,6 +149,13 @@
</property>
</widget>
</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">
<widget class="QSlider" name="afBW">
<property name="minimum">
@ -184,13 +191,6 @@
</property>
</widget>
</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">
<widget class="QLabel" name="volumeText">
<property name="minimumSize">
@ -207,6 +207,13 @@
</property>
</widget>
</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">
<widget class="ValueDial" name="deltaFrequency" native="true">
<property name="sizePolicy">
@ -238,10 +245,23 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="deltaUnits">
<item row="5" column="0">
<widget class="QLabel" name="ctcssLabel">
<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>
</widget>
</item>