NFM demod: added display of channel power in dB. Changed minus radio button for a iconified toggle button

This commit is contained in:
f4exb 2015-10-04 06:26:06 +02:00
parent f1cd4bf992
commit 438df2975e
7 changed files with 350 additions and 264 deletions

View File

@ -38,6 +38,9 @@ public:
MagSquaredAGC(int historySize, Real R);
virtual ~MagSquaredAGC();
virtual void feed(Complex& ci);
Real getMagSq() const { return m_magsq; }
private:
Real m_magsq;
};
class MagAGC : public AGC
@ -47,6 +50,9 @@ public:
MagAGC(int historySize, Real R);
virtual ~MagAGC();
virtual void feed(Complex& ci);
Real getMagSq() const { return m_magsq; }
private:
Real m_magsq;
};
class AlphaAGC : public AGC
@ -58,8 +64,10 @@ public:
virtual ~AlphaAGC();
void resize(int historySize, Real R, Real alpha);
virtual void feed(Complex& ci);
Real getMagSq() const { return m_magsq; }
private:
Real m_alpha;
Real m_magsq;
bool m_squelchOpen;
};

View File

@ -55,6 +55,7 @@ NFMDemod::NFMDemod() :
m_agcLevel = 1.0;
m_AGC.resize(240, m_agcLevel);
m_magsq = 0;
m_ctcssDetector.setCoefficients(3000, 6000.0); // 0.5s / 2 Hz resolution
m_afSquelch.setCoefficients(24, 600, 48000.0, 200, 0); // 4000 Hz span, 250us, 100ms attack
@ -134,6 +135,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
//ci *= (m_agcLevel / m_AGC.getValue());
m_AGC.feed(ci);
m_magsq = m_AGC.getMagSq();
// demod
/*

View File

@ -64,6 +64,8 @@ public:
m_ctcssIndexSelected = selectedCtcssIndex;
}
Real getMagSq() const { return m_magsq; }
private:
class MsgConfigureNFMDemod : public Message {
MESSAGE_CLASS_DECLARATION
@ -163,6 +165,7 @@ private:
AFSquelch m_afSquelch;
Real m_agcLevel; // AGC will aim to this level
Real m_agcFloor; // AGC will not go below this level
Real m_magsq;
AudioVector m_audioBuffer;
uint m_audioBufferFill;

View File

@ -10,8 +10,10 @@
#include "gui/glspectrum.h"
#include "plugin/pluginapi.h"
#include "util/simpleserializer.h"
#include "util/db.h"
#include "gui/basicchannelsettingswidget.h"
#include "dsp/dspengine.h"
#include "mainwindow.h"
const int NFMDemodGUI::m_rfBW[] = {
5000, 6250, 8330, 10000, 12500, 15000, 20000, 25000, 40000
@ -143,7 +145,7 @@ void NFMDemodGUI::viewChanged()
applySettings();
}
void NFMDemodGUI::on_deltaMinus_clicked(bool minus)
void NFMDemodGUI::on_deltaMinus_toggled(bool minus)
{
int deltaFrequency = m_channelMarker.getCenterFrequency();
bool minusDelta = (deltaFrequency < 0);
@ -229,7 +231,8 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
m_pluginAPI(pluginAPI),
m_channelMarker(this),
m_basicSettingsShown(false),
m_doApplySettings(true)
m_doApplySettings(true),
m_channelPowerDbAvg(20,0)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose, true);
@ -239,6 +242,8 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, QWidget* parent) :
m_nfmDemod = new NFMDemod();
m_nfmDemod->registerGUI(this);
connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick()));
int ctcss_nbTones;
const Real *ctcss_tones = m_nfmDemod->getCtcssToneSet(ctcss_nbTones);
@ -334,3 +339,9 @@ void NFMDemodGUI::blockApplySettings(bool block)
m_doApplySettings = !block;
}
void NFMDemodGUI::tick()
{
Real powDb = CalcDb::dbPower(m_nfmDemod->getMagSq());
m_channelPowerDbAvg.feed(powDb);
ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1));
}

View File

@ -5,6 +5,7 @@
#include "plugin/plugingui.h"
#include "dsp/dsptypes.h"
#include "dsp/channelmarker.h"
#include "dsp/movingaverage.h"
class PluginAPI;
@ -38,7 +39,7 @@ public:
private slots:
void viewChanged();
void on_deltaFrequency_changed(quint64 value);
void on_deltaMinus_clicked(bool minus);
void on_deltaMinus_toggled(bool minus);
void on_rfBW_valueChanged(int value);
void on_afBW_valueChanged(int value);
void on_volume_valueChanged(int value);
@ -47,6 +48,7 @@ private slots:
void on_ctcssOn_toggled(bool checked);
void onWidgetRolled(QWidget* widget, bool rollDown);
void onMenuDoubleClicked();
void tick();
private:
Ui::NFMDemodGUI* ui;
@ -59,6 +61,7 @@ private:
Channelizer* m_channelizer;
NFMDemod* m_nfmDemod;
bool m_ctcssOn;
MovingAverage<Real> m_channelPowerDbAvg;
static const int m_rfBW[];

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>263</width>
<height>151</height>
<width>167</width>
<height>433</height>
</rect>
</property>
<property name="windowTitle">
@ -18,14 +18,17 @@
<rect>
<x>6</x>
<y>35</y>
<width>251</width>
<height>111</height>
<width>122</width>
<height>395</height>
</rect>
</property>
<property name="windowTitle">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>2</number>
</property>
@ -38,268 +41,315 @@
<property name="bottomMargin">
<number>2</number>
</property>
<property name="spacing">
<number>3</number>
</property>
<item row="5" column="4">
<layout class="QHBoxLayout" name="CTCSSblock">
<item>
<layout class="QHBoxLayout" name="DeltaFrequencyLayout">
<item>
<widget class="QCheckBox" name="ctcssOn">
<property name="toolTip">
<string>Activate CTCSS</string>
</property>
<widget class="QToolButton" name="deltaMinus">
<property name="text">
<string/>
<string>...</string>
</property>
<property name="icon">
<iconset>
<selectedoff>:/plus.png</selectedoff>
<selectedon>:/minus.png</selectedon>
</iconset>
</property>
<property name="checkable">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="ctcss">
<property name="maximumSize">
<widget class="ValueDial" name="deltaFrequency" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>16777215</width>
<height>16777215</height>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>SizeVerCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Set CTCSS Frequency</string>
<string>Demod shift frequency from center in Hz</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="deltaUnits">
<property name="text">
<string>Hz </string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelPower">
<property name="toolTip">
<string>Channel power</string>
</property>
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>0.0</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="channelPowerUnits">
<property name="text">
<string> dB</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="3" column="4">
<widget class="QSlider" name="volume">
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<item>
<layout class="QHBoxLayout" name="rfBWLayout">
<item>
<widget class="QLabel" name="rfBWLabel">
<property name="text">
<string>RF BW</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="rfBW">
<property name="maximum">
<number>8</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>4</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="rfBWText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>12.5 k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="1" column="4">
<widget class="QSlider" name="rfBW">
<property name="maximum">
<number>8</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>4</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
<item>
<layout class="QHBoxLayout" name="afBWLayout">
<item>
<widget class="QLabel" name="afLabel">
<property name="text">
<string>AF BW</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="afBW">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>20</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>3</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="afBWText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>3 k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="0" column="0">
<widget class="QRadioButton" name="deltaMinus">
<property name="layoutDirection">
<enum>Qt::RightToLeft</enum>
</property>
<property name="text">
<string>Minus</string>
</property>
</widget>
<item>
<layout class="QHBoxLayout" name="volumeLayout">
<item>
<widget class="QLabel" name="volumeLabel">
<property name="text">
<string>Volume</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="volume">
<property name="maximum">
<number>100</number>
</property>
<property name="value">
<number>20</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="volumeText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>2.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="4" column="0">
<widget class="QLabel" name="squelchLabel">
<property name="text">
<string>Squelch</string>
</property>
</widget>
<item>
<layout class="QHBoxLayout" name="squelchLayout">
<item>
<widget class="QLabel" name="squelchLabel">
<property name="text">
<string>Squelch</string>
</property>
</widget>
</item>
<item>
<widget class="QSlider" name="squelch">
<property name="toolTip">
<string>Threshold min/max in dB</string>
</property>
<property name="minimum">
<number>-200</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>-150</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="squelchText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>-15.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
</layout>
</item>
<item row="2" column="0">
<widget class="QLabel" name="afLabel">
<property name="text">
<string>AF BW</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="rfBWLabel">
<property name="text">
<string>RF BW</string>
</property>
</widget>
</item>
<item row="4" column="4">
<widget class="QSlider" name="squelch">
<property name="toolTip">
<string>Threshold min/max in dB</string>
</property>
<property name="minimum">
<number>-200</number>
</property>
<property name="maximum">
<number>0</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>-150</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="volumeLabel">
<property name="text">
<string>Volume</string>
</property>
</widget>
</item>
<item row="1" column="6">
<widget class="QLabel" name="rfBWText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>12.5 k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="6">
<widget class="QLabel" name="afBWText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>3 k</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="4">
<widget class="QSlider" name="afBW">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>20</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>3</number>
</property>
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item row="4" column="6">
<widget class="QLabel" name="squelchText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>-15.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="3" column="6">
<widget class="QLabel" name="volumeText">
<property name="minimumSize">
<size>
<width>50</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>2.0</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="0" column="6">
<widget class="QLabel" name="deltaUnits">
<property name="text">
<string>Hz</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="ctcssLabel">
<property name="text">
<string>CTCSS</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="ValueDial" name="deltaFrequency" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Maximum">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>32</width>
<height>16</height>
</size>
</property>
<property name="font">
<font>
<family>Monospace</family>
<pointsize>12</pointsize>
</font>
</property>
<property name="cursor">
<cursorShape>SizeVerCursor</cursorShape>
</property>
<property name="focusPolicy">
<enum>Qt::StrongFocus</enum>
</property>
<property name="toolTip">
<string>Demod shift frequency from center in Hz</string>
</property>
</widget>
</item>
<item row="5" column="6">
<widget class="QLabel" name="ctcssText">
<property name="toolTip">
<string>CTCSS detected</string>
</property>
<property name="text">
<string>--</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<item>
<layout class="QHBoxLayout" name="ctcssLayout">
<item>
<widget class="QLabel" name="ctcssLabel">
<property name="text">
<string>CTCSS</string>
</property>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="CTCSSblock">
<item>
<widget class="QCheckBox" name="ctcssOn">
<property name="toolTip">
<string>Activate CTCSS</string>
</property>
<property name="text">
<string/>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="ctcss">
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="toolTip">
<string>Set CTCSS Frequency</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="ctcssText">
<property name="toolTip">
<string>CTCSS detected</string>
</property>
<property name="text">
<string>--</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
@ -318,6 +368,8 @@
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<resources>
<include location="../../../sdrbase/resources/res.qrc"/>
</resources>
<connections/>
</ui>

View File

@ -46,11 +46,13 @@ Real AGC::getAverage()
}
MagSquaredAGC::MagSquaredAGC() :
AGC()
AGC(),
m_magsq(0.0)
{}
MagSquaredAGC::MagSquaredAGC(int historySize, Real R) :
AGC(historySize, R)
AGC(historySize, R),
m_magsq(0.0)
{}
MagSquaredAGC::~MagSquaredAGC()
@ -58,19 +60,21 @@ MagSquaredAGC::~MagSquaredAGC()
void MagSquaredAGC::feed(Complex& ci)
{
Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
m_moving_average.feed(magsq);
m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
m_moving_average.feed(m_magsq);
m_u0 = m_R / m_moving_average.average();
ci *= m_u0;
}
MagAGC::MagAGC() :
AGC()
AGC(),
m_magsq(0.0)
{}
MagAGC::MagAGC(int historySize, Real R) :
AGC(historySize, R)
AGC(historySize, R),
m_magsq(0.0)
{}
MagAGC::~MagAGC()
@ -78,8 +82,8 @@ MagAGC::~MagAGC()
void MagAGC::feed(Complex& ci)
{
Real mag = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag());
m_moving_average.feed(mag);
m_magsq = sqrt(ci.real()*ci.real() + ci.imag()*ci.imag());
m_moving_average.feed(m_magsq);
m_u0 = m_R / m_moving_average.average();
ci *= m_u0;
}
@ -88,12 +92,14 @@ void MagAGC::feed(Complex& ci)
AlphaAGC::AlphaAGC() :
AGC(),
m_alpha(0.5),
m_magsq(0.0),
m_squelchOpen(true)
{}
AlphaAGC::AlphaAGC(int historySize, Real R) :
AGC(historySize, R),
m_alpha(0.5),
m_magsq(0.0),
m_squelchOpen(true)
{}
@ -101,6 +107,7 @@ AlphaAGC::AlphaAGC(int historySize, Real R) :
AlphaAGC::AlphaAGC(int historySize, Real R, Real alpha) :
AGC(historySize, R),
m_alpha(alpha),
m_magsq(0.0),
m_squelchOpen(true)
{}
@ -117,16 +124,16 @@ void AlphaAGC::resize(int historySize, Real R, Real alpha)
void AlphaAGC::feed(Complex& ci)
{
Real magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
m_magsq = ci.real()*ci.real() + ci.imag()*ci.imag();
if (m_squelchOpen && (magsq))
if (m_squelchOpen && (m_magsq))
{
m_moving_average.feed(m_moving_average.average() - m_alpha*(m_moving_average.average() - magsq));
m_moving_average.feed(m_moving_average.average() - m_alpha*(m_moving_average.average() - m_magsq));
}
else
{
//m_squelchOpen = true;
m_moving_average.feed(magsq);
m_moving_average.feed(m_magsq);
}
ci *= m_u0;
}