mirror of
				https://github.com/f4exb/sdrangel.git
				synced 2025-11-03 21:20:31 -05:00 
			
		
		
		
	NFM Demod: added signal meter. Corrected squelch. Turned frequency dial green
This commit is contained in:
		
							parent
							
								
									c31846a334
								
							
						
					
					
						commit
						7c3cebf2e1
					
				@ -234,7 +234,7 @@ AMDemodGUI::AMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidget
 | 
			
		||||
 | 
			
		||||
	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);
 | 
			
		||||
 | 
			
		||||
	//m_channelMarker = new ChannelMarker(this);
 | 
			
		||||
 | 
			
		||||
@ -6,10 +6,16 @@
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>303</width>
 | 
			
		||||
    <width>302</width>
 | 
			
		||||
    <height>170</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="minimumSize">
 | 
			
		||||
   <size>
 | 
			
		||||
    <width>302</width>
 | 
			
		||||
    <height>0</height>
 | 
			
		||||
   </size>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="font">
 | 
			
		||||
   <font>
 | 
			
		||||
    <family>Sans Serif</family>
 | 
			
		||||
@ -25,15 +31,15 @@
 | 
			
		||||
  <widget class="QWidget" name="settingsContainer" native="true">
 | 
			
		||||
   <property name="geometry">
 | 
			
		||||
    <rect>
 | 
			
		||||
     <x>10</x>
 | 
			
		||||
     <y>10</y>
 | 
			
		||||
     <width>280</width>
 | 
			
		||||
     <x>0</x>
 | 
			
		||||
     <y>0</y>
 | 
			
		||||
     <width>300</width>
 | 
			
		||||
     <height>131</height>
 | 
			
		||||
    </rect>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="minimumSize">
 | 
			
		||||
    <size>
 | 
			
		||||
     <width>280</width>
 | 
			
		||||
     <width>300</width>
 | 
			
		||||
     <height>0</height>
 | 
			
		||||
    </size>
 | 
			
		||||
   </property>
 | 
			
		||||
@ -61,8 +67,8 @@
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="icon">
 | 
			
		||||
           <iconset>
 | 
			
		||||
            <selectedoff>:/plus.png</selectedoff>
 | 
			
		||||
            <selectedon>:/minus.png</selectedon>
 | 
			
		||||
            <selectedoff>:/plusrx.png</selectedoff>
 | 
			
		||||
            <selectedon>:/minusrx.png</selectedon>
 | 
			
		||||
           </iconset>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="checkable">
 | 
			
		||||
@ -366,26 +372,6 @@
 | 
			
		||||
 </customwidgets>
 | 
			
		||||
 <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"/>
 | 
			
		||||
 </resources>
 | 
			
		||||
 <connections/>
 | 
			
		||||
</ui>
 | 
			
		||||
 | 
			
		||||
@ -38,6 +38,9 @@ NFMDemod::NFMDemod() :
 | 
			
		||||
	m_agcAttack(2400),
 | 
			
		||||
	m_audioMute(false),
 | 
			
		||||
	m_squelchOpen(false),
 | 
			
		||||
    m_magsqSum(0.0f),
 | 
			
		||||
    m_magsqPeak(0.0f),
 | 
			
		||||
    m_magsqCount(0),
 | 
			
		||||
	m_afSquelch(2, afSqTones),
 | 
			
		||||
	m_audioFifo(4, 48000),
 | 
			
		||||
	m_fmExcursion(2400),
 | 
			
		||||
@ -146,6 +149,16 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
 | 
			
		||||
				qint16 sample;
 | 
			
		||||
 | 
			
		||||
				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);
 | 
			
		||||
 | 
			
		||||
@ -155,7 +168,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
 | 
			
		||||
 | 
			
		||||
				// AF processing
 | 
			
		||||
 | 
			
		||||
				if (getMag() > m_squelchLevel)
 | 
			
		||||
				if (m_AGC.getAverage()/(1<<30) > m_squelchLevel)
 | 
			
		||||
				{
 | 
			
		||||
					if (m_squelchCount < m_agcAttack)
 | 
			
		||||
					{
 | 
			
		||||
@ -369,7 +382,7 @@ void NFMDemod::apply()
 | 
			
		||||
	if (m_config.m_squelch != m_running.m_squelch)
 | 
			
		||||
	{
 | 
			
		||||
		// 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_afSquelch.setThreshold(m_squelchLevel);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -71,6 +71,16 @@ public:
 | 
			
		||||
	Real getMag() { return m_AGC.getAverage() / (1<<15); }
 | 
			
		||||
	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:
 | 
			
		||||
	class MsgConfigureNFMDemod : public Message {
 | 
			
		||||
		MESSAGE_CLASS_DECLARATION
 | 
			
		||||
@ -187,6 +197,9 @@ private:
 | 
			
		||||
 | 
			
		||||
	double m_squelchLevel;
 | 
			
		||||
	bool m_squelchOpen;
 | 
			
		||||
    Real m_magsqSum;
 | 
			
		||||
    Real m_magsqPeak;
 | 
			
		||||
    int  m_magsqCount;
 | 
			
		||||
 | 
			
		||||
	Real m_lastArgument;
 | 
			
		||||
	//Complex m_m1Sample;
 | 
			
		||||
 | 
			
		||||
@ -291,7 +291,8 @@ NFMDemodGUI::NFMDemodGUI(PluginAPI* pluginAPI, DeviceSourceAPI *deviceAPI, QWidg
 | 
			
		||||
		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_threadedChannelizer = new ThreadedBasebandSampleSink(m_channelizer, this);
 | 
			
		||||
@ -337,15 +338,15 @@ void NFMDemodGUI::applySettings()
 | 
			
		||||
 | 
			
		||||
		ui->deltaFrequency->setValue(abs(m_channelMarker.getCenterFrequency()));
 | 
			
		||||
		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_rfBW[ui->rfBW->currentIndex()],
 | 
			
		||||
			ui->afBW->value() * 1000.0,
 | 
			
		||||
			ui->afBW->value() * 1000.0f,
 | 
			
		||||
			m_fmDev[ui->rfBW->currentIndex()],
 | 
			
		||||
			ui->volume->value() / 10.0,
 | 
			
		||||
			ui->volume->value() / 10.0f,
 | 
			
		||||
			ui->squelchGate->value(), // in 10ths of ms
 | 
			
		||||
			ui->squelch->value(),
 | 
			
		||||
			ui->squelch->value() / 10.0f,
 | 
			
		||||
			ui->ctcssOn->isChecked(),
 | 
			
		||||
			ui->audioMute->isChecked());
 | 
			
		||||
	}
 | 
			
		||||
@ -384,10 +385,33 @@ void NFMDemodGUI::blockApplySettings(bool block)
 | 
			
		||||
 | 
			
		||||
void NFMDemodGUI::tick()
 | 
			
		||||
{
 | 
			
		||||
	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();
 | 
			
		||||
    if (m_powerMeterTickCount < 4) // 200 ms
 | 
			
		||||
    {
 | 
			
		||||
        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();
 | 
			
		||||
 | 
			
		||||
	if (squelchOpen != m_squelchOpen)
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
@ -69,6 +69,7 @@ private:
 | 
			
		||||
	bool m_ctcssOn;
 | 
			
		||||
	bool m_audioMute;
 | 
			
		||||
	bool m_squelchOpen;
 | 
			
		||||
	int m_powerMeterTickCount;
 | 
			
		||||
	MovingAverage<Real> m_channelPowerDbAvg;
 | 
			
		||||
 | 
			
		||||
	static const int m_rfBW[];
 | 
			
		||||
 | 
			
		||||
@ -6,10 +6,16 @@
 | 
			
		||||
   <rect>
 | 
			
		||||
    <x>0</x>
 | 
			
		||||
    <y>0</y>
 | 
			
		||||
    <width>287</width>
 | 
			
		||||
    <height>156</height>
 | 
			
		||||
    <width>302</width>
 | 
			
		||||
    <height>178</height>
 | 
			
		||||
   </rect>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="minimumSize">
 | 
			
		||||
   <size>
 | 
			
		||||
    <width>302</width>
 | 
			
		||||
    <height>0</height>
 | 
			
		||||
   </size>
 | 
			
		||||
  </property>
 | 
			
		||||
  <property name="font">
 | 
			
		||||
   <font>
 | 
			
		||||
    <family>Sans Serif</family>
 | 
			
		||||
@ -24,10 +30,16 @@
 | 
			
		||||
    <rect>
 | 
			
		||||
     <x>0</x>
 | 
			
		||||
     <y>0</y>
 | 
			
		||||
     <width>271</width>
 | 
			
		||||
     <width>300</width>
 | 
			
		||||
     <height>141</height>
 | 
			
		||||
    </rect>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="minimumSize">
 | 
			
		||||
    <size>
 | 
			
		||||
     <width>300</width>
 | 
			
		||||
     <height>0</height>
 | 
			
		||||
    </size>
 | 
			
		||||
   </property>
 | 
			
		||||
   <property name="windowTitle">
 | 
			
		||||
    <string>Settings</string>
 | 
			
		||||
   </property>
 | 
			
		||||
@ -52,8 +64,8 @@
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="icon">
 | 
			
		||||
           <iconset>
 | 
			
		||||
            <selectedoff>:/plus.png</selectedoff>
 | 
			
		||||
            <selectedon>:/minus.png</selectedon>
 | 
			
		||||
            <selectedoff>:/plusrx.png</selectedoff>
 | 
			
		||||
            <selectedon>:/minusrx.png</selectedon>
 | 
			
		||||
           </iconset>
 | 
			
		||||
          </property>
 | 
			
		||||
          <property name="checkable">
 | 
			
		||||
@ -143,6 +155,36 @@
 | 
			
		||||
      </item>
 | 
			
		||||
     </layout>
 | 
			
		||||
    </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>
 | 
			
		||||
     <layout class="QHBoxLayout" name="rfBWLayout">
 | 
			
		||||
      <item>
 | 
			
		||||
@ -522,9 +564,6 @@
 | 
			
		||||
    </item>
 | 
			
		||||
   </layout>
 | 
			
		||||
  </widget>
 | 
			
		||||
  <zorder>settingsContainer</zorder>
 | 
			
		||||
  <zorder>afBW</zorder>
 | 
			
		||||
  <zorder>afBWText</zorder>
 | 
			
		||||
 </widget>
 | 
			
		||||
 <customwidgets>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
@ -539,6 +578,12 @@
 | 
			
		||||
   <header>gui/valuedial.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
  <customwidget>
 | 
			
		||||
   <class>LevelMeterSignalDB</class>
 | 
			
		||||
   <extends>QWidget</extends>
 | 
			
		||||
   <header>gui/levelmeter.h</header>
 | 
			
		||||
   <container>1</container>
 | 
			
		||||
  </customwidget>
 | 
			
		||||
 </customwidgets>
 | 
			
		||||
 <resources>
 | 
			
		||||
  <include location="../../../sdrbase/resources/res.qrc"/>
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@
 | 
			
		||||
 | 
			
		||||
const PluginDescriptor NFMPlugin::m_pluginDescriptor = {
 | 
			
		||||
	QString("NFM Demodulator"),
 | 
			
		||||
	QString("2.0.0"),
 | 
			
		||||
	QString("2.4.0"),
 | 
			
		||||
	QString("(c) Edouard Griffiths, F4EXB"),
 | 
			
		||||
	QString("https://github.com/f4exb/sdrangel"),
 | 
			
		||||
	true,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								sdrbase/resources/minusrx.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sdrbase/resources/minusrx.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 231 B  | 
							
								
								
									
										
											BIN
										
									
								
								sdrbase/resources/plusrx.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sdrbase/resources/plusrx.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 373 B  | 
@ -1,5 +1,7 @@
 | 
			
		||||
<RCC>
 | 
			
		||||
  <qresource prefix="/">
 | 
			
		||||
    <file>minusrx.png</file>
 | 
			
		||||
    <file>plusrx.png</file>
 | 
			
		||||
    <file>microphone.png</file>
 | 
			
		||||
    <file>checkmark.png</file>
 | 
			
		||||
    <file>questionmark.png</file>
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user