1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-09-27 07:16:48 -04:00

ATV Demod: FM mode using phaseDiscriminatorDelta with deviation scaling

This commit is contained in:
f4exb 2017-03-22 23:55:47 +01:00
parent b1c2f59a87
commit 016f7c1e37
7 changed files with 129 additions and 19 deletions

View File

@ -76,6 +76,8 @@ ATVDemod::ATVDemod(BasebandSampleSink* objScopeSink) :
memset((void*)m_fltBufferI,0,6*sizeof(float)); memset((void*)m_fltBufferI,0,6*sizeof(float));
memset((void*)m_fltBufferQ,0,6*sizeof(float)); memset((void*)m_fltBufferQ,0,6*sizeof(float));
m_objPhaseDiscri.setFMScaling(1.0f);
} }
ATVDemod::~ATVDemod() ATVDemod::~ATVDemod()
@ -119,7 +121,8 @@ void ATVDemod::configureRF(
float fltRFOppBandwidth, float fltRFOppBandwidth,
bool blnFFTFiltering, bool blnFFTFiltering,
bool blnDecimatorEnable, bool blnDecimatorEnable,
float fltBFOFrequency) float fltBFOFrequency,
float fmDeviation)
{ {
Message* msgCmd = MsgConfigureRFATVDemod::create( Message* msgCmd = MsgConfigureRFATVDemod::create(
enmModulation, enmModulation,
@ -127,7 +130,8 @@ void ATVDemod::configureRF(
fltRFOppBandwidth, fltRFOppBandwidth,
blnFFTFiltering, blnFFTFiltering,
blnDecimatorEnable, blnDecimatorEnable,
fltBFOFrequency); fltBFOFrequency,
fmDeviation);
objMessageQueue->push(msgCmd); objMessageQueue->push(msgCmd);
} }
@ -272,15 +276,14 @@ void ATVDemod::demod(Complex& c)
float& fltI = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].real() : c.real(); float& fltI = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].real() : c.real();
float& fltQ = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].imag() : c.imag(); float& fltQ = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].imag() : c.imag();
#endif #endif
double magSq = fltI*fltI + fltQ*fltQ; double magSq;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
if ((m_objRFRunning.m_enmModulation == ATV_FM1) || (m_objRFRunning.m_enmModulation == ATV_FM2)) if ((m_objRFRunning.m_enmModulation == ATV_FM1) || (m_objRFRunning.m_enmModulation == ATV_FM2))
{ {
//Amplitude FM //Amplitude FM
magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
fltNormI= fltI/fltNorm; fltNormI= fltI/fltNorm;
fltNormQ= fltQ/fltNorm; fltNormQ= fltQ/fltNorm;
@ -324,11 +327,13 @@ void ATVDemod::demod(Complex& c)
m_fltBufferI[0]=fltNormI; m_fltBufferI[0]=fltNormI;
m_fltBufferQ[0]=fltNormQ; m_fltBufferQ[0]=fltNormQ;
} }
else if (m_objRFRunning.m_enmModulation == ATV_AM) else if (m_objRFRunning.m_enmModulation == ATV_AM)
{ {
//Amplitude AM //Amplitude AM
magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
fltVal = fltNorm; fltVal = fltNorm;
//********** Mini and Maxi Amplitude tracking ********** //********** Mini and Maxi Amplitude tracking **********
@ -349,6 +354,10 @@ void ATVDemod::demod(Complex& c)
} }
else if ((m_objRFRunning.m_enmModulation == ATV_USB) || (m_objRFRunning.m_enmModulation == ATV_LSB)) else if ((m_objRFRunning.m_enmModulation == ATV_USB) || (m_objRFRunning.m_enmModulation == ATV_LSB))
{ {
magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
Real bfoValues[2]; Real bfoValues[2];
float fltFiltered = m_bfoFilter.run(fltI); float fltFiltered = m_bfoFilter.run(fltI);
m_bfoPLL.process(fltFiltered, bfoValues); m_bfoPLL.process(fltFiltered, bfoValues);
@ -380,12 +389,23 @@ void ATVDemod::demod(Complex& c)
fltVal -= m_fltAmpMin; fltVal -= m_fltAmpMin;
fltVal /=m_fltAmpDelta; fltVal /=m_fltAmpDelta;
} }
else if (m_objRFRunning.m_enmModulation == ATV_FM3)
{
float rawDeviation;
fltVal = (m_objPhaseDiscri.phaseDiscriminatorDelta(c, magSq, rawDeviation)/ m_objRFRunning.m_fmDeviation) + 0.5f;
fltVal = fltVal < 0.0f ? 0.0f : fltVal > 1.0f ? 1.0f : fltVal;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
}
else else
{ {
magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
fltVal = 0.0f; fltVal = 0.0f;
} }
m_objScopeSampleBuffer.push_back(Sample(fltVal*32768.0f, 0.0f)); m_objScopeSampleBuffer.push_back(Sample(fltVal*32767.0f, 0.0f));
fltVal = m_objRunning.m_blnInvertVideo ? 1.0f - fltVal : fltVal; fltVal = m_objRunning.m_blnInvertVideo ? 1.0f - fltVal : fltVal;
@ -640,7 +660,8 @@ bool ATVDemod::handleMessage(const Message& cmd)
<< " m_fltRFOppBandwidth:" << m_objRFConfig.m_fltRFOppBandwidth << " m_fltRFOppBandwidth:" << m_objRFConfig.m_fltRFOppBandwidth
<< " m_blnFFTFiltering:" << m_objRFConfig.m_blnFFTFiltering << " m_blnFFTFiltering:" << m_objRFConfig.m_blnFFTFiltering
<< " m_blnDecimatorEnable:" << m_objRFConfig.m_blndecimatorEnable << " m_blnDecimatorEnable:" << m_objRFConfig.m_blndecimatorEnable
<< " m_fltBFOFrequency:" << m_objRFConfig.m_fltBFOFrequency; << " m_fltBFOFrequency:" << m_objRFConfig.m_fltBFOFrequency
<< " m_fmDeviation:" << m_objRFConfig.m_fmDeviation;
applySettings(); applySettings();
@ -761,6 +782,11 @@ void ATVDemod::applySettings()
m_bfoFilter.setFrequencies(m_objRFConfig.m_fltBFOFrequency, m_objConfigPrivate.m_intTVSampleRate); m_bfoFilter.setFrequencies(m_objRFConfig.m_fltBFOFrequency, m_objConfigPrivate.m_intTVSampleRate);
} }
// if (m_objRFConfig.m_fmDeviation != m_objRFRunning.m_fmDeviation)
// {
// m_objPhaseDiscri.setFMScaling(m_objRFConfig.m_fmDeviation);
// }
m_objRunning = m_objConfig; m_objRunning = m_objConfig;
m_objRFRunning = m_objRFConfig; m_objRFRunning = m_objRFConfig;
m_objRunningPrivate = m_objConfigPrivate; m_objRunningPrivate = m_objConfigPrivate;

View File

@ -33,6 +33,7 @@
#include "dsp/agc.h" #include "dsp/agc.h"
#include "dsp/phaselock.h" #include "dsp/phaselock.h"
#include "dsp/recursivefilters.h" #include "dsp/recursivefilters.h"
#include "dsp/phasediscri.h"
#include "audio/audiofifo.h" #include "audio/audiofifo.h"
#include "util/message.h" #include "util/message.h"
#include "atvscreen.h" #include "atvscreen.h"
@ -47,6 +48,7 @@ public:
enum ATVModulation { enum ATVModulation {
ATV_FM1, //!< Classical frequency modulation with discriminator #1 ATV_FM1, //!< Classical frequency modulation with discriminator #1
ATV_FM2, //!< Classical frequency modulation with discriminator #2 ATV_FM2, //!< Classical frequency modulation with discriminator #2
ATV_FM3, //!< Classical frequency modulation with phase derivative discriminator
ATV_AM, //!< Classical amplitude modulation ATV_AM, //!< Classical amplitude modulation
ATV_USB, //!< AM with vestigial lower side band (main signal is in the upper side) ATV_USB, //!< AM with vestigial lower side band (main signal is in the upper side)
ATV_LSB //!< AM with vestigial upper side band (main signal is in the lower side) ATV_LSB //!< AM with vestigial upper side band (main signal is in the lower side)
@ -89,6 +91,7 @@ public:
bool m_blnFFTFiltering; bool m_blnFFTFiltering;
bool m_blndecimatorEnable; bool m_blndecimatorEnable;
float m_fltBFOFrequency; float m_fltBFOFrequency;
float m_fmDeviation;
ATVRFConfig() : ATVRFConfig() :
m_intFrequencyOffset(0), m_intFrequencyOffset(0),
@ -97,7 +100,8 @@ public:
m_fltRFOppBandwidth(0), m_fltRFOppBandwidth(0),
m_blnFFTFiltering(false), m_blnFFTFiltering(false),
m_blndecimatorEnable(false), m_blndecimatorEnable(false),
m_fltBFOFrequency(0.0f) m_fltBFOFrequency(0.0f),
m_fmDeviation(1.0f)
{ {
} }
}; };
@ -143,7 +147,8 @@ public:
float fltRFOppBandwidth, float fltRFOppBandwidth,
bool blnFFTFiltering, bool blnFFTFiltering,
bool blndecimatorEnable, bool blndecimatorEnable,
float fltBFOFrequency); float fltBFOFrequency,
float fmDeviation);
virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po); virtual void feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end, bool po);
virtual void start(); virtual void start();
@ -232,7 +237,8 @@ private:
float fltRFOppBandwidth, float fltRFOppBandwidth,
bool blnFFTFiltering, bool blnFFTFiltering,
bool blndecimatorEnable, bool blndecimatorEnable,
int intBFOFrequency) int intBFOFrequency,
float fmDeviation)
{ {
return new MsgConfigureRFATVDemod( return new MsgConfigureRFATVDemod(
enmModulation, enmModulation,
@ -240,7 +246,8 @@ private:
fltRFOppBandwidth, fltRFOppBandwidth,
blnFFTFiltering, blnFFTFiltering,
blndecimatorEnable, blndecimatorEnable,
intBFOFrequency); intBFOFrequency,
fmDeviation);
} }
ATVRFConfig m_objMsgConfig; ATVRFConfig m_objMsgConfig;
@ -252,7 +259,8 @@ private:
float fltRFOppBandwidth, float fltRFOppBandwidth,
bool blnFFTFiltering, bool blnFFTFiltering,
bool blndecimatorEnable, bool blndecimatorEnable,
float fltBFOFrequency) : float fltBFOFrequency,
float fmDeviation) :
Message() Message()
{ {
m_objMsgConfig.m_enmModulation = enmModulation; m_objMsgConfig.m_enmModulation = enmModulation;
@ -261,6 +269,7 @@ private:
m_objMsgConfig.m_blnFFTFiltering = blnFFTFiltering; m_objMsgConfig.m_blnFFTFiltering = blnFFTFiltering;
m_objMsgConfig.m_blndecimatorEnable = blndecimatorEnable; m_objMsgConfig.m_blndecimatorEnable = blndecimatorEnable;
m_objMsgConfig.m_fltBFOFrequency = fltBFOFrequency; m_objMsgConfig.m_fltBFOFrequency = fltBFOFrequency;
m_objMsgConfig.m_fmDeviation = fmDeviation;
} }
}; };
@ -322,6 +331,9 @@ private:
int m_DSBFilterBufferIndex; int m_DSBFilterBufferIndex;
static const int m_ssbFftLen; static const int m_ssbFftLen;
// Used for FM
PhaseDiscriminators m_objPhaseDiscri;
//QElapsedTimer m_objTimer; //QElapsedTimer m_objTimer;
ATVConfig m_objRunning; ATVConfig m_objRunning;

View File

@ -92,6 +92,7 @@ void ATVDemodGUI::resetToDefaults()
ui->rfBW->setValue(10); ui->rfBW->setValue(10);
ui->rfOppBW->setValue(10); ui->rfOppBW->setValue(10);
ui->bfo->setValue(0); ui->bfo->setValue(0);
ui->fmDeviation->setValue(100);
blockApplySettings(false); blockApplySettings(false);
lineTimeUpdate(); lineTimeUpdate();
@ -118,6 +119,7 @@ QByteArray ATVDemodGUI::serialize() const
s.writeS32(14, ui->bfo->value()); s.writeS32(14, ui->bfo->value());
s.writeBool(15, ui->invertVideo->isChecked()); s.writeBool(15, ui->invertVideo->isChecked());
s.writeS32(16, ui->nbLines->currentIndex()); s.writeS32(16, ui->nbLines->currentIndex());
s.writeS32(17, ui->fmDeviation->value());
return s.final(); return s.final();
} }
@ -179,6 +181,8 @@ bool ATVDemodGUI::deserialize(const QByteArray& arrData)
ui->invertVideo->setChecked(booltmp); ui->invertVideo->setChecked(booltmp);
d.readS32(16, &tmp, 0); d.readS32(16, &tmp, 0);
ui->nbLines->setCurrentIndex(tmp); ui->nbLines->setCurrentIndex(tmp);
d.readS32(17, &tmp, 100);
ui->fmDeviation->setValue(tmp);
blockApplySettings(false); blockApplySettings(false);
m_objChannelMarker.blockSignals(false); m_objChannelMarker.blockSignals(false);
@ -322,6 +326,9 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
ui->scopeGUI->focusOnTrigger(0); // re-focus to take changes into account in the GUI ui->scopeGUI->focusOnTrigger(0); // re-focus to take changes into account in the GUI
connect(m_objATVDemod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages())); connect(m_objATVDemod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
QChar delta = QChar(0x94, 0x03);
ui->fmDeviationLabel->setText(delta);
} }
ATVDemodGUI::~ATVDemodGUI() ATVDemodGUI::~ATVDemodGUI()
@ -378,7 +385,8 @@ void ATVDemodGUI::applyRFSettings()
ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f, ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f,
ui->rfFiltering->isChecked(), ui->rfFiltering->isChecked(),
ui->decimatorEnable->isChecked(), ui->decimatorEnable->isChecked(),
ui->bfo->value() * 10.0f); ui->bfo->value() * 10.0f,
ui->fmDeviation->value() / 100.0f);
} }
} }
@ -600,6 +608,12 @@ void ATVDemodGUI::on_bfo_valueChanged(int value)
applyRFSettings(); applyRFSettings();
} }
void ATVDemodGUI::on_fmDeviation_valueChanged(int value)
{
ui->fmDeviationText->setText(QString("%1").arg(value));
applyRFSettings();
}
void ATVDemodGUI::lineTimeUpdate() void ATVDemodGUI::lineTimeUpdate()
{ {
float nominalLineTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex()); float nominalLineTime = getNominalLineTime(ui->nbLines->currentIndex(), ui->fps->currentIndex());

View File

@ -83,6 +83,7 @@ private slots:
void on_deltaFrequency_changed(quint64 value); void on_deltaFrequency_changed(quint64 value);
void on_deltaFrequencyMinus_toggled(bool minus); void on_deltaFrequencyMinus_toggled(bool minus);
void on_bfo_valueChanged(int value); void on_bfo_valueChanged(int value);
void on_fmDeviation_valueChanged(int value);
private: private:
Ui::ATVDemodGUI* ui; Ui::ATVDemodGUI* ui;

View File

@ -40,7 +40,7 @@
<x>10</x> <x>10</x>
<y>10</y> <y>10</y>
<width>681</width> <width>681</width>
<height>81</height> <height>83</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
@ -275,6 +275,11 @@
<string>FM 2</string> <string>FM 2</string>
</property> </property>
</item> </item>
<item>
<property name="text">
<string>FM 3</string>
</property>
</item>
<item> <item>
<property name="text"> <property name="text">
<string>AM</string> <string>AM</string>
@ -292,6 +297,58 @@
</item> </item>
</widget> </widget>
</item> </item>
<item>
<widget class="QLabel" name="fmDeviationLabel">
<property name="text">
<string>D</string>
</property>
</widget>
</item>
<item>
<widget class="QDial" name="fmDeviation">
<property name="maximumSize">
<size>
<width>24</width>
<height>24</height>
</size>
</property>
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>125</number>
</property>
<property name="pageStep">
<number>1</number>
</property>
<property name="value">
<number>100</number>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="fmDeviationText">
<property name="minimumSize">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>100</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line_4">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item> <item>
<widget class="ButtonSwitch" name="rfFiltering"> <widget class="ButtonSwitch" name="rfFiltering">
<property name="toolTip"> <property name="toolTip">

View File

@ -156,7 +156,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
//m_AGC.feed(ci); //m_AGC.feed(ci);
//double magsqRaw = m_AGC.getMagSq(); //double magsqRaw = m_AGC.getMagSq();
long double magsqRaw; // = ci.real()*ci.real() + c.imag()*c.imag(); double magsqRaw; // = ci.real()*ci.real() + c.imag()*c.imag();
Real deviation; Real deviation;
Real demod = m_phaseDiscri.phaseDiscriminatorDelta(ci, magsqRaw, deviation); Real demod = m_phaseDiscri.phaseDiscriminatorDelta(ci, magsqRaw, deviation);

View File

@ -55,7 +55,7 @@ public:
* Discriminator with phase detection using atan2 and frequency by derivation. * Discriminator with phase detection using atan2 and frequency by derivation.
* This yields a precise deviation to sample rate ratio: Sample rate => +/-1.0 * This yields a precise deviation to sample rate ratio: Sample rate => +/-1.0
*/ */
Real phaseDiscriminatorDelta(const Complex& sample, long double& magsq, Real& fmDev) Real phaseDiscriminatorDelta(const Complex& sample, double& magsq, Real& fmDev)
{ {
Real fltI = sample.real(); Real fltI = sample.real();
Real fltQ = sample.imag(); Real fltQ = sample.imag();