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_fltBufferQ,0,6*sizeof(float));
m_objPhaseDiscri.setFMScaling(1.0f);
}
ATVDemod::~ATVDemod()
@ -119,7 +121,8 @@ void ATVDemod::configureRF(
float fltRFOppBandwidth,
bool blnFFTFiltering,
bool blnDecimatorEnable,
float fltBFOFrequency)
float fltBFOFrequency,
float fmDeviation)
{
Message* msgCmd = MsgConfigureRFATVDemod::create(
enmModulation,
@ -127,7 +130,8 @@ void ATVDemod::configureRF(
fltRFOppBandwidth,
blnFFTFiltering,
blnDecimatorEnable,
fltBFOFrequency);
fltBFOFrequency,
fmDeviation);
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& fltQ = m_objRFRunning.m_blnFFTFiltering ? m_DSBFilterBuffer[m_DSBFilterBufferIndex-1].imag() : c.imag();
#endif
double magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
double magSq;
if ((m_objRFRunning.m_enmModulation == ATV_FM1) || (m_objRFRunning.m_enmModulation == ATV_FM2))
{
//Amplitude FM
magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
fltNormI= fltI/fltNorm;
fltNormQ= fltQ/fltNorm;
@ -324,11 +327,13 @@ void ATVDemod::demod(Complex& c)
m_fltBufferI[0]=fltNormI;
m_fltBufferQ[0]=fltNormQ;
}
else if (m_objRFRunning.m_enmModulation == ATV_AM)
{
//Amplitude AM
magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
fltVal = fltNorm;
//********** 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))
{
magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
Real bfoValues[2];
float fltFiltered = m_bfoFilter.run(fltI);
m_bfoPLL.process(fltFiltered, bfoValues);
@ -380,12 +389,23 @@ void ATVDemod::demod(Complex& c)
fltVal -= m_fltAmpMin;
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
{
magSq = fltI*fltI + fltQ*fltQ;
m_objMagSqAverage.feed(magSq);
fltNorm = sqrt(magSq);
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;
@ -640,7 +660,8 @@ bool ATVDemod::handleMessage(const Message& cmd)
<< " m_fltRFOppBandwidth:" << m_objRFConfig.m_fltRFOppBandwidth
<< " m_blnFFTFiltering:" << m_objRFConfig.m_blnFFTFiltering
<< " 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();
@ -761,6 +782,11 @@ void ATVDemod::applySettings()
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_objRFRunning = m_objRFConfig;
m_objRunningPrivate = m_objConfigPrivate;

View File

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

View File

@ -92,6 +92,7 @@ void ATVDemodGUI::resetToDefaults()
ui->rfBW->setValue(10);
ui->rfOppBW->setValue(10);
ui->bfo->setValue(0);
ui->fmDeviation->setValue(100);
blockApplySettings(false);
lineTimeUpdate();
@ -118,6 +119,7 @@ QByteArray ATVDemodGUI::serialize() const
s.writeS32(14, ui->bfo->value());
s.writeBool(15, ui->invertVideo->isChecked());
s.writeS32(16, ui->nbLines->currentIndex());
s.writeS32(17, ui->fmDeviation->value());
return s.final();
}
@ -179,6 +181,8 @@ bool ATVDemodGUI::deserialize(const QByteArray& arrData)
ui->invertVideo->setChecked(booltmp);
d.readS32(16, &tmp, 0);
ui->nbLines->setCurrentIndex(tmp);
d.readS32(17, &tmp, 100);
ui->fmDeviation->setValue(tmp);
blockApplySettings(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
connect(m_objATVDemod->getOutputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleSourceMessages()));
QChar delta = QChar(0x94, 0x03);
ui->fmDeviationLabel->setText(delta);
}
ATVDemodGUI::~ATVDemodGUI()
@ -378,7 +385,8 @@ void ATVDemodGUI::applyRFSettings()
ui->rfOppBW->value() * m_rfSliderDivisor * 1.0f,
ui->rfFiltering->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();
}
void ATVDemodGUI::on_fmDeviation_valueChanged(int value)
{
ui->fmDeviationText->setText(QString("%1").arg(value));
applyRFSettings();
}
void ATVDemodGUI::lineTimeUpdate()
{
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_deltaFrequencyMinus_toggled(bool minus);
void on_bfo_valueChanged(int value);
void on_fmDeviation_valueChanged(int value);
private:
Ui::ATVDemodGUI* ui;

View File

@ -40,7 +40,7 @@
<x>10</x>
<y>10</y>
<width>681</width>
<height>81</height>
<height>83</height>
</rect>
</property>
<property name="windowTitle">
@ -275,6 +275,11 @@
<string>FM 2</string>
</property>
</item>
<item>
<property name="text">
<string>FM 3</string>
</property>
</item>
<item>
<property name="text">
<string>AM</string>
@ -292,6 +297,58 @@
</item>
</widget>
</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>
<widget class="ButtonSwitch" name="rfFiltering">
<property name="toolTip">

View File

@ -156,7 +156,7 @@ void NFMDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
//m_AGC.feed(ci);
//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 demod = m_phaseDiscri.phaseDiscriminatorDelta(ci, magsqRaw, deviation);

View File

@ -55,7 +55,7 @@ public:
* Discriminator with phase detection using atan2 and frequency by derivation.
* 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 fltQ = sample.imag();