1
0
mirror of https://github.com/f4exb/sdrangel.git synced 2024-11-29 19:28:47 -05:00

ATV Demod: implement NCO and interpolator change

This commit is contained in:
f4exb 2017-03-18 00:11:48 +01:00
parent 529e2c2c27
commit c3c6b79de4
6 changed files with 74 additions and 4 deletions

View File

@ -63,6 +63,7 @@ ATVDemod::ATVDemod() :
m_intSynchroPoints=0; m_intSynchroPoints=0;
m_intNumberOfLines=0; m_intNumberOfLines=0;
m_intNumberOfRowsToDisplay=0; m_intNumberOfRowsToDisplay=0;
m_intTVSampleRate = 0;
m_objMagSqAverage.resize(32, 1.0); m_objMagSqAverage.resize(32, 1.0);
@ -190,7 +191,10 @@ void ATVDemod::feed(const SampleVector::const_iterator& begin, const SampleVecto
fltI = it->real(); fltI = it->real();
fltQ = it->imag(); fltQ = it->imag();
#endif #endif
if (m_objRFRunning.m_intFrequencyOffset != 0)
{
m_nco.nextIQMul(fltI, fltQ);
}
//********** demodulation ********** //********** demodulation **********
@ -494,9 +498,11 @@ bool ATVDemod::handleMessage(const Message& cmd)
{ {
DownChannelizer::MsgChannelizerNotification& objNotif = (DownChannelizer::MsgChannelizerNotification&) cmd; DownChannelizer::MsgChannelizerNotification& objNotif = (DownChannelizer::MsgChannelizerNotification&) cmd;
m_objConfig.m_intSampleRate = objNotif.getSampleRate(); m_objConfig.m_intSampleRate = objNotif.getSampleRate();
m_objRFConfig.m_intFrequencyOffset = objNotif.getFrequencyOffset();
qDebug() << "ATVDemod::handleMessage: MsgChannelizerNotification:" qDebug() << "ATVDemod::handleMessage: MsgChannelizerNotification:"
<< " m_intMsps: " << m_objConfig.m_intSampleRate; << " m_intSampleRate: " << m_objConfig.m_intSampleRate
<< " m_intFrequencyOffset: " << m_objRFConfig.m_intFrequencyOffset;
applySettings(); applySettings();
@ -553,6 +559,32 @@ void ATVDemod::applySettings()
return; return;
} }
if((m_objRFConfig.m_intFrequencyOffset != m_objRFRunning.m_intFrequencyOffset) ||
(m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate))
{
m_nco.setFreq(-m_objRFConfig.m_intFrequencyOffset, m_objConfig.m_intSampleRate);
}
if ((m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate)
|| (m_objRFConfig.m_fltRFBandwidth != m_objRFRunning.m_fltRFBandwidth))
{
m_intTVSampleRate = (m_objConfig.m_intSampleRate / 1000000) * 1000000; // make sure working sample rate is a multiple of rate units
if (m_intTVSampleRate > 0)
{
m_interpolatorDistance = (Real) m_intTVSampleRate / (Real) m_objConfig.m_intSampleRate;
}
else
{
m_intTVSampleRate = m_objConfig.m_intSampleRate;
m_interpolatorDistanceRemain = 0;
m_interpolatorDistance = 1.0f;
}
m_interpolatorDistanceRemain = 0;
m_interpolator.create(48, m_intTVSampleRate, m_objRFConfig.m_fltRFBandwidth / 2.2, 3.0);
}
if((m_objConfig.m_fltFramePerS != m_objRunning.m_fltFramePerS) if((m_objConfig.m_fltFramePerS != m_objRunning.m_fltFramePerS)
|| (m_objConfig.m_fltLineDurationUs != m_objRunning.m_fltLineDurationUs) || (m_objConfig.m_fltLineDurationUs != m_objRunning.m_fltLineDurationUs)
|| (m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate) || (m_objConfig.m_intSampleRate != m_objRunning.m_intSampleRate)

View File

@ -78,6 +78,7 @@ public:
struct ATVRFConfig struct ATVRFConfig
{ {
int64_t m_intFrequencyOffset;
ATVModulation m_enmModulation; ATVModulation m_enmModulation;
float m_fltRFBandwidth; float m_fltRFBandwidth;
float m_fltRFOppBandwidth; float m_fltRFOppBandwidth;
@ -85,6 +86,7 @@ public:
bool m_blndecimatorEnable; bool m_blndecimatorEnable;
ATVRFConfig() : ATVRFConfig() :
m_intFrequencyOffset(0),
m_enmModulation(ATV_FM1), m_enmModulation(ATV_FM1),
m_fltRFBandwidth(0), m_fltRFBandwidth(0),
m_fltRFOppBandwidth(0), m_fltRFOppBandwidth(0),
@ -252,6 +254,9 @@ private:
MovingAverage<double> m_objMagSqAverage; MovingAverage<double> m_objMagSqAverage;
int m_intTVSampleRate;
NCO m_nco;
// Interpolator group for decimation and/or double sideband RF filtering // Interpolator group for decimation and/or double sideband RF filtering
Interpolator m_interpolator; Interpolator m_interpolator;
Real m_interpolatorDistance; Real m_interpolatorDistance;

View File

@ -296,7 +296,7 @@ ATVDemodGUI::ATVDemodGUI(PluginAPI* objPluginAPI, DeviceSourceAPI *objDeviceAPI,
m_objChannelMarker.setCenterFrequency(0); m_objChannelMarker.setCenterFrequency(0);
m_objChannelMarker.setVisible(true); m_objChannelMarker.setVisible(true);
//connect(&m_objChannelMarker, SIGNAL(changed()), this, SLOT(viewChanged())); connect(&m_objChannelMarker, SIGNAL(changed()), this, SLOT(viewChanged()));
m_objDeviceAPI->registerChannelInstance(m_strChannelID, this); m_objDeviceAPI->registerChannelInstance(m_strChannelID, this);
m_objDeviceAPI->addChannelMarker(&m_objChannelMarker); m_objDeviceAPI->addChannelMarker(&m_objChannelMarker);
@ -333,7 +333,6 @@ void ATVDemodGUI::applySettings()
ui->deltaFrequencyMinus->setChecked(m_objChannelMarker.getCenterFrequency() < 0); ui->deltaFrequencyMinus->setChecked(m_objChannelMarker.getCenterFrequency() < 0);
m_objChannelizer->configure(m_objChannelizer->getInputMessageQueue(), m_objChannelizer->configure(m_objChannelizer->getInputMessageQueue(),
//m_objATVDemod->GetSampleRate(),
m_objChannelizer->getInputSampleRate(), // always use maximum available bandwidth m_objChannelizer->getInputSampleRate(), // always use maximum available bandwidth
m_objChannelMarker.getCenterFrequency()); m_objChannelMarker.getCenterFrequency());
@ -584,3 +583,23 @@ void ATVDemodGUI::on_decimator_toggled(bool checked)
applyRFSettings(); applyRFSettings();
} }
void ATVDemodGUI::on_deltaFrequency_changed(quint64 value)
{
if (ui->deltaFrequencyMinus->isChecked()) {
m_objChannelMarker.setCenterFrequency(-value);
} else {
m_objChannelMarker.setCenterFrequency(value);
}
}
void ATVDemodGUI::on_deltaFrequencyMinus_toggled(bool minus)
{
int deltaFrequency = m_objChannelMarker.getCenterFrequency();
bool minusDelta = (deltaFrequency < 0);
if (minus ^ minusDelta) // sign change
{
m_objChannelMarker.setCenterFrequency(-deltaFrequency);
}
}

View File

@ -76,6 +76,8 @@ private slots:
void on_rfOppBW_valueChanged(int value); void on_rfOppBW_valueChanged(int value);
void on_rfFiltering_toggled(bool checked); void on_rfFiltering_toggled(bool checked);
void on_decimator_toggled(bool checked); void on_decimator_toggled(bool checked);
void on_deltaFrequency_changed(quint64 value);
void on_deltaFrequencyMinus_toggled(bool minus);
private: private:
Ui::ATVDemodGUI* ui; Ui::ATVDemodGUI* ui;

View File

@ -65,6 +65,17 @@ Complex NCO::nextQI()
return Complex(-m_table[(m_phase + TableSize / 4) % TableSize], m_table[m_phase]); return Complex(-m_table[(m_phase + TableSize / 4) % TableSize], m_table[m_phase]);
} }
void NCO::nextIQMul(Real& i, Real& q)
{
nextPhase();
Real x = i;
Real y = q;
const Real& u = m_table[m_phase];
const Real& v = -m_table[(m_phase + TableSize / 4) % TableSize];
i = x*u - y*v;
q = x*v + y*u;
}
float NCO::get() float NCO::get()
{ {
return m_table[m_phase]; return m_table[m_phase];

View File

@ -52,6 +52,7 @@ public:
Real next(); //!< Return next real sample Real next(); //!< Return next real sample
Complex nextIQ(); //!< Return next complex sample Complex nextIQ(); //!< Return next complex sample
Complex nextQI(); //!< Return next complex sample (reversed) Complex nextQI(); //!< Return next complex sample (reversed)
void nextIQMul(Real& i, Real& q); //!< multiply I,Q separately with next sample
Real get(); //!< Return current real sample (no phase increment) Real get(); //!< Return current real sample (no phase increment)
Complex getIQ(); //!< Return current complex sample (no phase increment) Complex getIQ(); //!< Return current complex sample (no phase increment)
void getIQ(Complex& c); //!< Sets to the current complex sample (no phase increment) void getIQ(Complex& c); //!< Sets to the current complex sample (no phase increment)