Files
cpp/radio/tests/interpolation/farrow/test.cpp
T
2022-06-26 20:46:52 +00:00

200 lines
4.7 KiB
C++

#include <cpp/radio/Vector.hpp>
#include <cpp/radio/FirComplex.hpp>
#include <cpp/radio/interpolation/Farrow.hpp>
#include <cpp/radio/interpolation/PolyPhase.hpp>
#include <cpp/radio/interpolation/TimingGenerator.hpp>
#include <radio/synchronization.h>
#include <wav/wav.h>
#include <string.h>
#include <iostream>
#include <type_traits>
using namespace std;
using namespace Radio;
using namespace Processor;
CVec wavLoad(const char *pName, WAVEHEADER &format)
{
WAV wav;
WavOpen(&wav, pName);
CVec res(wav.m_numSamples);
const size_t BLOCK_SIZE = 65536;
int16_t *pWavInterleaved = (int16_t*)malloc(BLOCK_SIZE*wav.m_nChannels*sizeof(int16_t));
float *pWav[2];
pWav[0] = (float*)malloc(BLOCK_SIZE*sizeof(float));
pWav[1] = (float*)malloc(BLOCK_SIZE*sizeof(float));
size_t remain = wav.m_numSamples;
size_t k=0;
while(remain)
{
size_t size = std::min(remain, BLOCK_SIZE);
size_t numRead = WavRead(&wav, pWavInterleaved, size);
WavDeIlvdFloat(&wav, pWavInterleaved, pWav, numRead);
for (int j=0; j < numRead; j++)
{
res[k++] = ComplexScalar(pWav[0][j], pWav[1][j]);
}
remain -= numRead;
}
format = wav.m_Format;
WavClose(&wav);
return res;
}
void wavSave(const char *pName, WAVEHEADER const &format, CVec &iq)
{
WAV wav;
WavCreate(&wav, pName, FILETYPE_WAV, &format);
const size_t BLOCK_SIZE = 65536;
int16_t *pWavInterleaved = (int16_t*)malloc(BLOCK_SIZE*wav.m_nChannels*sizeof(int16_t));
float *pWav[2];
pWav[0] = (float*)malloc(BLOCK_SIZE*sizeof(float));
pWav[1] = (float*)malloc(BLOCK_SIZE*sizeof(float));
size_t remain = iq.size();
size_t k=0;
while(remain)
{
size_t size = std::min(remain, BLOCK_SIZE);
for (int j=0; j < size; j++)
{
pWav[0][j] = iq[k].real();
pWav[1][j] = iq[k].imag();
k++;
}
WavIlvdFloat(&wav, pWav, pWavInterleaved, size);
WavWrite(&wav, pWavInterleaved, size);
remain -= size;
}
WavClose(&wav);
}
const radio_float_t STR_GAIN_LEAD_AQU = (radio_float_t)2.00E-2; // 2E-3
const radio_float_t STR_GAIN_LAG_AQU = (radio_float_t)5.00E-4; // 5E-7
const radio_float_t STR_GAIN_LEAD_TRK = (radio_float_t)4.00E-6; // 8E-4
const radio_float_t STR_GAIN_LAG_TRK = (radio_float_t)1.00E-9; // 1E-6
class TimingGeneratorGardner : public Interpolation::TimingGenerator
{
// Loop-Filter
lead_lag_filter_t loop_filter_str;
lead_lag_coeff_t str_loopfilter_coeff;
// Gardner Symbol Timing Recovery
str_t m_SymbolTimingRevovery;
bool is_time;
radio_float_t m_dOmega;
public:
TimingGeneratorGardner()
: Interpolation::TimingGenerator()
{
LeadLagInit(&loop_filter_str, 0.01);
LeadLagSetCoeff(&str_loopfilter_coeff, STR_GAIN_LEAD_AQU, STR_GAIN_LAG_AQU);
STRGardnerInit(&m_SymbolTimingRevovery);
is_time = true;
}
virtual ~TimingGeneratorGardner() = default;
bool process(ComplexScalar const &iq)
{
// @2 x symbolrate
// Symbol timing recovery
radio_float_t vd = STRGardnerProcess(&m_SymbolTimingRevovery, toCpx(iq));
if (is_time)
{
// @1 x symbolrate
#ifdef TEST_DEBUG
cout << "Vd = " << vd << ", omega = " << m_dOmega << ", mu = " << getMu() << endl;
#endif
m_dOmega = LeadLagProcess(&loop_filter_str, &str_loopfilter_coeff, vd);
}
is_time = not is_time;
update(m_dOmega);
// Control producing of samples for decimatiion
return not is_time;
}
};
void test()
{
// Setup timing generator
TimingGeneratorGardner timingGenerator;
timingGenerator.setOmega(1.0);
// Setup Farrow
Interpolation::Farrow farrow(timingGenerator);
farrow.load("/home/jens/farrow_coeff.dat");
// Setup IQ data
WAVEHEADER header;
#ifdef TEST_DEBUG
CVec iq_in = wavLoad("m2_12k_12k_i_q_short_2sps.wav", header);
// CVec iq_in = wavLoad("sine.wav", header);
#else
CVec iq_in = wavLoad("m2_12k_12k_i_q_2sps.wav", header);
#endif
CVec iq_out;
iq_out.reserve(8*iq_in.size());
ComplexScalar iq_ip;
size_t k=0;
size_t n=0;
size_t remain = iq_in.size();
const size_t BLOCKSIZE=2048;
// Create input buffer for Farrow Block
auto farrow_buf_in = new Buffer<ComplexScalar>(BLOCKSIZE);
// Create output buffer for Farrow Block
auto farrow_buf_out = new Buffer<ComplexScalar>(BLOCKSIZE);
// Assign buffers to Farrow Block
farrow.buffer_in_add(farrow_buf_in);
farrow.buffer_out_add(farrow_buf_out);
while(remain)
{
// @2 x symbolrate
// Matched filtering and interpolation
size_t size = std::min(farrow_buf_in->free(), remain);
farrow_buf_in->write(&iq_in.data()[n], size);
farrow.process();
while(farrow_buf_out->len())
{
size_t size = std::min(BLOCKSIZE, farrow_buf_out->len());
iq_out.resize(k+size);
for (size_t i=0; i < size; i++)
{
iq_out[k++] = farrow_buf_out->readAt(0);
}
}
remain -= size;
n += size;
}
// Save timing aligned data @1sps
wavSave("out.wav", header, iq_out);
cout << "End of program" << endl;
}