1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2025-08-13 03:02:25 -04:00

NFM Demod: added signal meter. Corrected squelch. Turned frequency dial green

This commit is contained in:
f4exb 2016-12-05 02:09:08 +01:00
parent c31846a334
commit 7c3cebf2e1
11 changed files with 132 additions and 48 deletions

View File

@ -234,7 +234,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget
connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms connect(&m_pluginAPI->getMainWindow()->getMasterTimer(), SIGNAL(timeout()), this, SLOT(tick())); // 50 ms
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGreenYellow));
ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenYellow); ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenYellow);
//m_channelMarker = new ChannelMarker(this); //m_channelMarker = new ChannelMarker(this);

View File

@ -6,10 +6,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>303</width> <width>302</width>
<height>170</height> <height>170</height>
</rect> </rect>
</property> </property>
<property name="minimumSize">
<size>
<width>302</width>
<height>0</height>
</size>
</property>
<property name="font"> <property name="font">
<font> <font>
<family>Sans Serif</family> <family>Sans Serif</family>
@ -25,15 +31,15 @@
<widget class="QWidget" name="settingsContainer" native="true"> <widget class="QWidget" name="settingsContainer" native="true">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>10</x> <x>0</x>
<y>10</y> <y>0</y>
<width>280</width> <width>300</width>
<height>131</height> <height>131</height>
</rect> </rect>
</property> </property>
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
<width>280</width> <width>300</width>
<height>0</height> <height>0</height>
</size> </size>
</property> </property>
@ -61,8 +67,8 @@
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset>
<selectedoff>:/plus.png</selectedoff> <selectedoff>:/plusrx.png</selectedoff>
<selectedon>:/minus.png</selectedon> <selectedon>:/minusrx.png</selectedon>
</iconset> </iconset>
</property> </property>
<property name="checkable"> <property name="checkable">
@ -366,26 +372,6 @@
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../../../sdrbase/resources/res.qrc"/> <include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
<include location="../../../sdrbase/resources/res.qrc"/>
</resources> </resources>
<connections/> <connections/>
</ui> </ui>

View File

@ -38,6 +38,9 @@ NFMDemod::NFMDemod() :
m_agcAttack(2400), m_agcAttack(2400),
m_audioMute(false), m_audioMute(false),
m_squelchOpen(false), m_squelchOpen(false),
m_magsqSum(0.0f),
m_magsqPeak(0.0f),
m_magsqCount(0),
m_afSquelch(2, afSqTones), m_afSquelch(2, afSqTones),
m_audioFifo(4, 48000), m_audioFifo(4, 48000),
m_fmExcursion(2400), m_fmExcursion(2400),
@ -146,6 +149,16 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
qint16 sample; qint16 sample;
m_AGC.feed(ci); m_AGC.feed(ci);
Real magsq = m_AGC.getMagSq();
magsq /= (1<<30);
m_magsqSum += magsq;
if (magsq > m_magsqPeak)
{
m_magsqPeak = magsq;
}
m_magsqCount++;
Real demod = m_phaseDiscri.phaseDiscriminator2(ci); Real demod = m_phaseDiscri.phaseDiscriminator2(ci);
@ -155,7 +168,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
// AF processing // AF processing
if (getMag() > m_squelchLevel) if (m_AGC.getAverage()/(1<<30) > m_squelchLevel)
{ {
if (m_squelchCount < m_agcAttack) if (m_squelchCount < m_agcAttack)
{ {
@ -369,7 +382,7 @@ void NFMDemod::apply()
if (m_config.m_squelch != m_running.m_squelch) if (m_config.m_squelch != m_running.m_squelch)
{ {
// input is a value in tenths of dB // input is a value in tenths of dB
m_squelchLevel = std::pow(10.0, m_config.m_squelch / 200.0); m_squelchLevel = std::pow(10.0, m_config.m_squelch / 10.0);
//m_squelchLevel *= m_squelchLevel; //m_squelchLevel *= m_squelchLevel;
m_afSquelch.setThreshold(m_squelchLevel); m_afSquelch.setThreshold(m_squelchLevel);
} }

View File

@ -71,6 +71,16 @@ public:
Real getMag() { return m_AGC.getAverage() / (1<<15); } Real getMag() { return m_AGC.getAverage() / (1<<15); }
bool getSquelchOpen() const { return m_squelchOpen; } bool getSquelchOpen() const { return m_squelchOpen; }
void getMagSqLevels(Real& avg, Real& peak, int& nbSamples)
{
avg = m_magsqSum / m_magsqCount;
peak = m_magsqPeak;
nbSamples = m_magsqCount;
m_magsqSum = 0.0f;
m_magsqPeak = 0.0f;
m_magsqCount = 0;
}
private: private:
class MsgConfigureNFMDemod : public Message { class MsgConfigureNFMDemod : public Message {
MESSAGE_CLASS_DECLARATION MESSAGE_CLASS_DECLARATION
@ -187,6 +197,9 @@ private:
double m_squelchLevel; double m_squelchLevel;
bool m_squelchOpen; bool m_squelchOpen;
Real m_magsqSum;
Real m_magsqPeak;
int m_magsqCount;
Real m_lastArgument; Real m_lastArgument;
//Complex m_m1Sample; //Complex m_m1Sample;

View File

@ -291,7 +291,8 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
ui->ctcss->addItem(QString("%1").arg(ctcss_tones[i])); ui->ctcss->addItem(QString("%1").arg(ctcss_tones[i]));
} }
ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGold)); ui->deltaFrequency->setColorMapper(ColorMapper(ColorMapper::ReverseGreenYellow));
ui->channelPowerMeter->setColorTheme(LevelMeterSignalDB::ColorGreenYellow);
m_channelizer = new DownChannelizer(m_nfmDemod); m_channelizer = new DownChannelizer(m_nfmDemod);
m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this); m_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
@ -337,15 +338,15 @@ void NFMDemodGUI::applySettings()
ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency())); ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency()));
ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0); ui->deltaMinus->setChecked(m_channelMarker.getCenterFrequency() < 0);
ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0, 0, 'f', 0)); ui->squelchGateText->setText(QString("%1").arg(ui->squelchGate->value() * 10.0f, 0, 'f', 0));
m_nfmDemod->configure(m_nfmDemod->getInputMessageQueue(), m_nfmDemod->configure(m_nfmDemod->getInputMessageQueue(),
m_rfBW[ui->rfBW->currentIndex()], m_rfBW[ui->rfBW->currentIndex()],
ui->afBW->value() * 1000.0, ui->afBW->value() * 1000.0f,
m_fmDev[ui->rfBW->currentIndex()], m_fmDev[ui->rfBW->currentIndex()],
ui->volume->value() / 10.0, ui->volume->value() / 10.0f,
ui->squelchGate->value(), // in 10ths of ms ui->squelchGate->value(), // in 10ths of ms
ui->squelch->value(), ui->squelch->value() / 10.0f,
ui->ctcssOn->isChecked(), ui->ctcssOn->isChecked(),
ui->audioMute->isChecked()); ui->audioMute->isChecked());
} }
@ -384,9 +385,32 @@ void NFMDemodGUI::blockApplySettings(bool block)
void NFMDemodGUI::tick() void NFMDemodGUI::tick()
{ {
Real powDb = CalcDb::dbPower(m_nfmDemod->getMag()) * 2; if (m_powerMeterTickCount < 4) // 200 ms
m_channelPowerDbAvg.feed(powDb); {
ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1)); m_powerMeterTickCount++;
}
else
{
Real magsqAvg, magsqPeak;
int nbMagsqSamples;
m_nfmDemod->getMagSqLevels(magsqAvg, magsqPeak, nbMagsqSamples);
Real powDbAvg = CalcDb::dbPower(magsqAvg);
Real powDbPeak = CalcDb::dbPower(magsqPeak);
ui->channelPowerMeter->levelChanged(
(100.0f + powDbAvg) / 100.0f,
(100.0f + powDbPeak) / 100.0f,
nbMagsqSamples);
ui->channelPower->setText(QString::number(powDbAvg, 'f', 1));
m_powerMeterTickCount = 0;
}
// Real powDb = CalcDb::dbPower(m_nfmDemod->getMag()) * 2;
// m_channelPowerDbAvg.feed(powDb);
// ui->channelPower->setText(QString::number(m_channelPowerDbAvg.average(), 'f', 1));
bool squelchOpen = m_nfmDemod->getSquelchOpen(); bool squelchOpen = m_nfmDemod->getSquelchOpen();
if (squelchOpen != m_squelchOpen) if (squelchOpen != m_squelchOpen)

View File

@ -69,6 +69,7 @@ private:
bool m_ctcssOn; bool m_ctcssOn;
bool m_audioMute; bool m_audioMute;
bool m_squelchOpen; bool m_squelchOpen;
int m_powerMeterTickCount;
MovingAverage<Real> m_channelPowerDbAvg; MovingAverage<Real> m_channelPowerDbAvg;
static const int m_rfBW[]; static const int m_rfBW[];

View File

@ -6,10 +6,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>287</width> <width>302</width>
<height>156</height> <height>178</height>
</rect> </rect>
</property> </property>
<property name="minimumSize">
<size>
<width>302</width>
<height>0</height>
</size>
</property>
<property name="font"> <property name="font">
<font> <font>
<family>Sans Serif</family> <family>Sans Serif</family>
@ -24,10 +30,16 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>271</width> <width>300</width>
<height>141</height> <height>141</height>
</rect> </rect>
</property> </property>
<property name="minimumSize">
<size>
<width>300</width>
<height>0</height>
</size>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Settings</string> <string>Settings</string>
</property> </property>
@ -52,8 +64,8 @@
</property> </property>
<property name="icon"> <property name="icon">
<iconset> <iconset>
<selectedoff>:/plus.png</selectedoff> <selectedoff>:/plusrx.png</selectedoff>
<selectedon>:/minus.png</selectedon> <selectedon>:/minusrx.png</selectedon>
</iconset> </iconset>
</property> </property>
<property name="checkable"> <property name="checkable">
@ -143,6 +155,36 @@
</item> </item>
</layout> </layout>
</item> </item>
<item>
<layout class="QHBoxLayout" name="levelMeterLayout">
<item>
<widget class="QLabel" name="channelPowerMeterUnits">
<property name="text">
<string>dB</string>
</property>
</widget>
</item>
<item>
<widget class="LevelMeterSignalDB" name="channelPowerMeter" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>30</height>
</size>
</property>
<property name="toolTip">
<string>Level meter (dB) light: average, dark: peak, tip: peak hold</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<layout class="QHBoxLayout" name="rfBWLayout"> <layout class="QHBoxLayout" name="rfBWLayout">
<item> <item>
@ -522,9 +564,6 @@
</item> </item>
</layout> </layout>
</widget> </widget>
<zorder>settingsContainer</zorder>
<zorder>afBW</zorder>
<zorder>afBWText</zorder>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>
@ -539,6 +578,12 @@
<header>gui/valuedial.h</header> <header>gui/valuedial.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>LevelMeterSignalDB</class>
<extends>QWidget</extends>
<header>gui/levelmeter.h</header>
<container>1</container>
</customwidget>
</customwidgets> </customwidgets>
<resources> <resources>
<include location="../../../sdrbase/resources/res.qrc"/> <include location="../../../sdrbase/resources/res.qrc"/>

View File

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 231 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

View File

@ -1,5 +1,7 @@
<RCC> <RCC>
<qresource prefix="/"> <qresource prefix="/">
<file>minusrx.png</file>
<file>plusrx.png</file>
<file>microphone.png</file> <file>microphone.png</file>
<file>checkmark.png</file> <file>checkmark.png</file>
<file>questionmark.png</file> <file>questionmark.png</file>