mirror of https://github.com/f4exb/sdrangel.git
DATV demod: implement interpolator (decimator) so that DVB engine input rate is always twice the symbol rate
This commit is contained in:
parent
9f75b0647f
commit
afd8d492c5
|
@ -51,7 +51,6 @@ DATVDemodSink::DATVDemodSink() :
|
||||||
//*************** DATV PARAMETERS ***************
|
//*************** DATV PARAMETERS ***************
|
||||||
m_blnInitialized=false;
|
m_blnInitialized=false;
|
||||||
ResetDATVFrameworkPointers();
|
ResetDATVFrameworkPointers();
|
||||||
m_objRFFilter = new fftfilt(-256000.0 / 1024000.0, 256000.0 / 1024000.0, m_rfFilterFftLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DATVDemodSink::~DATVDemodSink()
|
DATVDemodSink::~DATVDemodSink()
|
||||||
|
@ -68,8 +67,6 @@ DATVDemodSink::~DATVDemodSink()
|
||||||
if (m_videoThread) {
|
if (m_videoThread) {
|
||||||
delete m_videoThread;
|
delete m_videoThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete m_objRFFilter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DATVDemodSink::stopVideo()
|
void DATVDemodSink::stopVideo()
|
||||||
|
@ -539,12 +536,13 @@ void DATVDemodSink::InitDATVFramework()
|
||||||
<< " RollOff: " << m_settings.m_rollOff
|
<< " RollOff: " << m_settings.m_rollOff
|
||||||
<< " Viterbi: " << m_settings.m_viterbi
|
<< " Viterbi: " << m_settings.m_viterbi
|
||||||
<< " Excursion: " << m_settings.m_excursion
|
<< " Excursion: " << m_settings.m_excursion
|
||||||
<< " Sample rate: " << m_channelSampleRate;
|
<< " channel Sample rate: " << m_channelSampleRate
|
||||||
|
<< " Input sample rate: " << 2 * m_settings.m_symbolRate;
|
||||||
|
|
||||||
m_objCfg.standard = m_settings.m_standard;
|
m_objCfg.standard = m_settings.m_standard;
|
||||||
|
|
||||||
m_objCfg.fec = (leansdr::code_rate) getLeanDVBCodeRateFromDATV(m_settings.m_fec);
|
m_objCfg.fec = (leansdr::code_rate) getLeanDVBCodeRateFromDATV(m_settings.m_fec);
|
||||||
m_objCfg.Fs = (float) m_channelSampleRate;
|
m_objCfg.Fs = (float) 2 * m_settings.m_symbolRate; // maintained at twice the symbol rate
|
||||||
m_objCfg.Fm = (float) m_settings.m_symbolRate;
|
m_objCfg.Fm = (float) m_settings.m_symbolRate;
|
||||||
m_objCfg.fastlock = m_settings.m_fastLock;
|
m_objCfg.fastlock = m_settings.m_fastLock;
|
||||||
|
|
||||||
|
@ -875,14 +873,15 @@ void DATVDemodSink::InitDATVS2Framework()
|
||||||
<< " RollOff: " << m_settings.m_rollOff
|
<< " RollOff: " << m_settings.m_rollOff
|
||||||
<< " Viterbi: " << m_settings.m_viterbi
|
<< " Viterbi: " << m_settings.m_viterbi
|
||||||
<< " Excursion: " << m_settings.m_excursion
|
<< " Excursion: " << m_settings.m_excursion
|
||||||
<< " Sample rate: " << m_channelSampleRate
|
<< " Channel sample rate: " << m_channelSampleRate
|
||||||
|
<< " Input sample rate: " << 2 * m_settings.m_symbolRate
|
||||||
<< " m_softLDPCMaxTrials: " << m_settings.m_softLDPCMaxTrials
|
<< " m_softLDPCMaxTrials: " << m_settings.m_softLDPCMaxTrials
|
||||||
<< " m_softLDPCToolPath: " << m_settings.m_softLDPCToolPath;
|
<< " m_softLDPCToolPath: " << m_settings.m_softLDPCToolPath;
|
||||||
|
|
||||||
m_objCfg.standard = m_settings.m_standard;
|
m_objCfg.standard = m_settings.m_standard;
|
||||||
|
|
||||||
m_objCfg.fec = (leansdr::code_rate) getLeanDVBCodeRateFromDATV(m_settings.m_fec);
|
m_objCfg.fec = (leansdr::code_rate) getLeanDVBCodeRateFromDATV(m_settings.m_fec);
|
||||||
m_objCfg.Fs = (float) m_channelSampleRate;
|
m_objCfg.Fs = (float) 2 * m_settings.m_symbolRate; // maintained at twice the symbol rate
|
||||||
m_objCfg.Fm = (float) m_settings.m_symbolRate;
|
m_objCfg.Fm = (float) m_settings.m_symbolRate;
|
||||||
m_objCfg.fastlock = m_settings.m_fastLock;
|
m_objCfg.fastlock = m_settings.m_fastLock;
|
||||||
|
|
||||||
|
@ -1271,56 +1270,52 @@ void DATVDemodSink::feed(const SampleVector::const_iterator& begin, const Sample
|
||||||
}
|
}
|
||||||
|
|
||||||
//********** Bis repetita : Let's rock and roll buddy ! **********
|
//********** Bis repetita : Let's rock and roll buddy ! **********
|
||||||
#ifdef EXTENDED_DIRECT_SAMPLE
|
|
||||||
|
|
||||||
qint16 * ptrBuffer;
|
|
||||||
qint32 intLen;
|
|
||||||
|
|
||||||
//********** Reading direct samples **********
|
|
||||||
|
|
||||||
SampleVector::const_iterator it = begin;
|
|
||||||
intLen = it->intLen;
|
|
||||||
ptrBuffer = it->ptrBuffer;
|
|
||||||
ptrBufferToRelease = ptrBuffer;
|
|
||||||
++it;
|
|
||||||
|
|
||||||
for(qint32 intInd=0; intInd<intLen-1; intInd +=2)
|
|
||||||
{
|
|
||||||
|
|
||||||
fltI= ((qint32) (*ptrBuffer)) << 4;
|
|
||||||
ptrBuffer ++;
|
|
||||||
fltQ= ((qint32) (*ptrBuffer)) << 4;
|
|
||||||
ptrBuffer ++;
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
for (SampleVector::const_iterator it = begin; it != end; ++it /* ++it **/)
|
for (SampleVector::const_iterator it = begin; it != end; ++it /* ++it **/)
|
||||||
{
|
{
|
||||||
fltI = it->real();
|
Complex c(it->real(), it->imag());
|
||||||
fltQ = it->imag();
|
|
||||||
#endif
|
|
||||||
//********** iq stream ****************
|
|
||||||
Complex objC(fltI,fltQ);
|
|
||||||
objC *= m_objNCO.nextIQ();
|
|
||||||
intRFOut = m_objRFFilter->runFilt(objC, &objRF); // filter RF before demod
|
|
||||||
|
|
||||||
for (int intI = 0 ; intI < intRFOut; intI++, objRF++)
|
if (m_interpolatorDistance < 1.0f) // interpolate - should never get there...
|
||||||
{
|
{
|
||||||
m_objMagSqAverage(norm(*objRF));
|
Complex ci;
|
||||||
|
c *= m_nco.nextIQ();
|
||||||
|
|
||||||
|
while (!m_interpolator.interpolate(&m_interpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // decimate
|
||||||
|
{
|
||||||
|
Complex ci;
|
||||||
|
c *= m_nco.nextIQ();
|
||||||
|
|
||||||
|
if (m_interpolator.decimate(&m_interpolatorDistanceRemain, c, &ci))
|
||||||
|
{
|
||||||
|
processOneSample(ci);
|
||||||
|
m_interpolatorDistanceRemain += m_interpolatorDistance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // Samples for loop
|
||||||
|
}
|
||||||
|
|
||||||
|
void DATVDemodSink::processOneSample(Complex &ci)
|
||||||
|
{
|
||||||
|
m_objMagSqAverage(norm(ci));
|
||||||
|
|
||||||
if (m_blnDVBInitialized
|
if (m_blnDVBInitialized
|
||||||
&& (p_rawiq_writer != nullptr)
|
&& (p_rawiq_writer != nullptr)
|
||||||
&& (m_objScheduler != nullptr))
|
&& (m_objScheduler != nullptr))
|
||||||
{
|
{
|
||||||
|
|
||||||
p_rawiq_writer->write(*objRF);
|
p_rawiq_writer->write(ci);
|
||||||
m_lngReadIQ++;
|
m_lngReadIQ++;
|
||||||
|
|
||||||
lngWritable = p_rawiq_writer->writable();
|
int writable = p_rawiq_writer->writable();
|
||||||
|
|
||||||
//Leave +1 by safety
|
//Leave +1 by safety
|
||||||
//if(((m_lngReadIQ+1)>=lngWritable) || (m_lngReadIQ>=768))
|
//if(((m_lngReadIQ+1)>=lngWritable) || (m_lngReadIQ>=768))
|
||||||
if ((m_lngReadIQ + 1) >= lngWritable)
|
if ((m_lngReadIQ + 1) >= writable)
|
||||||
{
|
{
|
||||||
m_objScheduler->step();
|
m_objScheduler->step();
|
||||||
|
|
||||||
|
@ -1328,8 +1323,6 @@ void DATVDemodSink::feed(const SampleVector::const_iterator& begin, const Sample
|
||||||
p_rawiq_writer->reset(m_RawIQMinWrite);
|
p_rawiq_writer->reset(m_RawIQMinWrite);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // Samples for loop
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DATVDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
|
void DATVDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force)
|
||||||
|
@ -1343,7 +1336,7 @@ void DATVDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequ
|
||||||
if ((m_settings.m_centerFrequency != channelFrequencyOffset) ||
|
if ((m_settings.m_centerFrequency != channelFrequencyOffset) ||
|
||||||
(m_channelSampleRate != channelSampleRate) || force)
|
(m_channelSampleRate != channelSampleRate) || force)
|
||||||
{
|
{
|
||||||
m_objNCO.setFreq(-(float) channelFrequencyOffset, (float) channelSampleRate);
|
m_nco.setFreq(-(float) channelFrequencyOffset, (float) channelSampleRate);
|
||||||
qDebug("DATVDemodSink::applyChannelSettings: NCO: IF: %d <> TF: %d ISR: %d",
|
qDebug("DATVDemodSink::applyChannelSettings: NCO: IF: %d <> TF: %d ISR: %d",
|
||||||
channelFrequencyOffset, m_settings.m_centerFrequency, channelSampleRate);
|
channelFrequencyOffset, m_settings.m_centerFrequency, channelSampleRate);
|
||||||
callApplySettings = true;
|
callApplySettings = true;
|
||||||
|
@ -1351,10 +1344,10 @@ void DATVDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequ
|
||||||
|
|
||||||
if ((m_channelSampleRate != channelSampleRate) || force)
|
if ((m_channelSampleRate != channelSampleRate) || force)
|
||||||
{
|
{
|
||||||
//Bandpass filter shaping
|
m_interpolator.create(m_interpolatorPhaseSteps, channelSampleRate, m_settings.m_rfBandwidth / 2.2, m_interpolatorTapsPerPhase);
|
||||||
Real fltLowCut = -((float) m_settings.m_rfBandwidth / 2.0) / (float) channelSampleRate;
|
m_interpolatorDistanceRemain = 0;
|
||||||
Real fltHiCut = ((float) m_settings.m_rfBandwidth / 2.0) / (float) channelSampleRate;
|
m_interpolatorDistance = (Real) channelSampleRate / (Real) (2 * m_settings.m_symbolRate);
|
||||||
m_objRFFilter->create_filter(fltLowCut, fltHiCut);
|
qDebug("DATVDemodSink::applyChannelSettings: m_interpolatorDistance: %f", m_interpolatorDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_channelSampleRate = channelSampleRate;
|
m_channelSampleRate = channelSampleRate;
|
||||||
|
@ -1400,17 +1393,15 @@ void DATVDemodSink::applySettings(const DATVDemodSettings& settings, bool force)
|
||||||
if ((m_settings.m_rfBandwidth != settings.m_rfBandwidth)
|
if ((m_settings.m_rfBandwidth != settings.m_rfBandwidth)
|
||||||
|| force)
|
|| force)
|
||||||
{
|
{
|
||||||
|
m_interpolator.create(m_interpolatorPhaseSteps, m_channelSampleRate, m_settings.m_rfBandwidth / 2.2, m_interpolatorTapsPerPhase);
|
||||||
//Bandpass filter shaping
|
m_interpolatorDistanceRemain = 0;
|
||||||
Real fltLowCut = -((float) settings.m_rfBandwidth / 2.0) / (float) m_channelSampleRate;
|
m_interpolatorDistance = (Real) m_channelSampleRate / (Real) (2 * m_settings.m_symbolRate);
|
||||||
Real fltHiCut = ((float) settings.m_rfBandwidth / 2.0) / (float) m_channelSampleRate;
|
|
||||||
m_objRFFilter->create_filter(fltLowCut, fltHiCut);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_centerFrequency != settings.m_centerFrequency)
|
if ((m_settings.m_centerFrequency != settings.m_centerFrequency)
|
||||||
|| force)
|
|| force)
|
||||||
{
|
{
|
||||||
m_objNCO.setFreq(-(float) settings.m_centerFrequency, (float) m_channelSampleRate);
|
m_nco.setFreq(-(float) settings.m_centerFrequency, (float) m_channelSampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((m_settings.m_udpTS != settings.m_udpTS) || force) {
|
if ((m_settings.m_udpTS != settings.m_udpTS) || force) {
|
||||||
|
@ -1489,4 +1480,3 @@ int DATVDemodSink::getLeanDVBModulationFromDATV(DATVDemodSettings::DATVModulatio
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "dsp/interpolator.h"
|
#include "dsp/interpolator.h"
|
||||||
#include "dsp/movingaverage.h"
|
#include "dsp/movingaverage.h"
|
||||||
#include "dsp/agc.h"
|
#include "dsp/agc.h"
|
||||||
|
#include "dsp/interpolator.h"
|
||||||
#include "audio/audiofifo.h"
|
#include "audio/audiofifo.h"
|
||||||
#include "util/messagequeue.h"
|
#include "util/messagequeue.h"
|
||||||
#include "util/movingaverage.h"
|
#include "util/movingaverage.h"
|
||||||
|
@ -175,6 +176,7 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
inline int decimation(float Fin, float Fout) { int d = Fin / Fout; return std::max(d, 1); }
|
inline int decimation(float Fin, float Fout) { int d = Fin / Fout; return std::max(d, 1); }
|
||||||
|
void processOneSample(Complex &ci);
|
||||||
|
|
||||||
void CleanUpDATVFramework();
|
void CleanUpDATVFramework();
|
||||||
void ResetDATVFrameworkPointers();
|
void ResetDATVFrameworkPointers();
|
||||||
|
@ -328,8 +330,12 @@ private:
|
||||||
// Audio
|
// Audio
|
||||||
AudioFifo m_audioFifo;
|
AudioFifo m_audioFifo;
|
||||||
|
|
||||||
fftfilt * m_objRFFilter;
|
NCO m_nco;
|
||||||
NCO m_objNCO;
|
Interpolator m_interpolator;
|
||||||
|
Real m_interpolatorDistance;
|
||||||
|
Real m_interpolatorDistanceRemain;
|
||||||
|
static const int m_interpolatorPhaseSteps = 4; // Higher than these two values will struggle to run in real-time
|
||||||
|
static const int m_interpolatorTapsPerPhase = 3.5f; // without gaining much improvement in PER
|
||||||
|
|
||||||
bool m_blnInitialized;
|
bool m_blnInitialized;
|
||||||
bool m_blnRenderingVideo;
|
bool m_blnRenderingVideo;
|
||||||
|
|
Loading…
Reference in New Issue