mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2024-11-10 04:37:37 +01:00
more work on new clock recovery
This commit is contained in:
parent
63aa45de9e
commit
daf0f8c159
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
class POCSAGDecoder : public Decoder {
|
class POCSAGDecoder : public Decoder {
|
||||||
public:
|
public:
|
||||||
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, 320) {
|
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, 544) {
|
||||||
this->name = name;
|
this->name = name;
|
||||||
this->vfo = vfo;
|
this->vfo = vfo;
|
||||||
|
|
||||||
@ -26,7 +26,7 @@ public:
|
|||||||
vfo->setBandwidthLimits(12500, 12500, true);
|
vfo->setBandwidthLimits(12500, 12500, true);
|
||||||
vfo->setSampleRate(SAMPLERATE, 12500);
|
vfo->setSampleRate(SAMPLERATE, 12500);
|
||||||
dsp.init(vfo->output, SAMPLERATE, BAUDRATE);
|
dsp.init(vfo->output, SAMPLERATE, BAUDRATE);
|
||||||
reshape.init(&dsp.soft, 320, 0);
|
reshape.init(&dsp.soft, 544, 0);
|
||||||
dataHandler.init(&dsp.out, _dataHandler, this);
|
dataHandler.init(&dsp.out, _dataHandler, this);
|
||||||
diagHandler.init(&reshape.out, _diagHandler, this);
|
diagHandler.init(&reshape.out, _diagHandler, this);
|
||||||
|
|
||||||
|
@ -112,7 +112,7 @@ public:
|
|||||||
fir.init(NULL, shape);
|
fir.init(NULL, shape);
|
||||||
//recov.init(NULL, samplerate/baudrate, 1e-4, 1.0, 0.05);
|
//recov.init(NULL, samplerate/baudrate, 1e-4, 1.0, 0.05);
|
||||||
|
|
||||||
cs.init(NULL, PATTERN_DSDSDZED, sizeof(PATTERN_DSDSDZED)/sizeof(float), 0, 10);
|
cs.init(NULL, PATTERN_DSDSDZED, sizeof(PATTERN_DSDSDZED)/sizeof(float), 544, 10);
|
||||||
|
|
||||||
// Free useless buffers
|
// Free useless buffers
|
||||||
// dcBlock.out.free();
|
// dcBlock.out.free();
|
||||||
|
@ -43,6 +43,7 @@ namespace dsp {
|
|||||||
this->sampsPerSym = sampsPerSym;
|
this->sampsPerSym = sampsPerSym;
|
||||||
this->threshold = threshold;
|
this->threshold = threshold;
|
||||||
this->patternLen = patternLen;
|
this->patternLen = patternLen;
|
||||||
|
this->frameLen = frameLen;
|
||||||
|
|
||||||
// Plan FFT
|
// Plan FFT
|
||||||
plan = fftwf_plan_dft_r2c_1d(fftSize, fftIn, (fftwf_complex*)fftOut, FFTW_ESTIMATE);
|
plan = fftwf_plan_dft_r2c_1d(fftSize, fftIn, (fftwf_complex*)fftOut, FFTW_ESTIMATE);
|
||||||
@ -59,11 +60,16 @@ namespace dsp {
|
|||||||
|
|
||||||
// Normalize the amplitudes
|
// Normalize the amplitudes
|
||||||
float maxAmp = 0.0f;
|
float maxAmp = 0.0f;
|
||||||
for (int i = 0; i < patternLen; i++) {
|
for (int i = 0; i < fftSize/2; i++) {
|
||||||
if (patternFFTAmps[i] > maxAmp) { maxAmp = patternFFTAmps[i]; }
|
if (patternFFTAmps[i] > maxAmp) { maxAmp = patternFFTAmps[i]; }
|
||||||
}
|
}
|
||||||
volk_32f_s32f_multiply_32f(patternFFTAmps, patternFFTAmps, 1.0f/maxAmp, fftSize);
|
volk_32f_s32f_multiply_32f(patternFFTAmps, patternFFTAmps, 1.0f/maxAmp, fftSize);
|
||||||
|
|
||||||
|
// Initialize the phase control loop
|
||||||
|
float omegaRelLimit = 0.05;
|
||||||
|
pcl.init(1, 10e-4, 0.0, 0.0, 1.0, sampsPerSym, sampsPerSym * (1.0 - omegaRelLimit), sampsPerSym * (1.0 + omegaRelLimit));
|
||||||
|
generateInterpTaps();
|
||||||
|
|
||||||
// Init base
|
// Init base
|
||||||
base_type::init(in);
|
base_type::init(in);
|
||||||
}
|
}
|
||||||
@ -72,21 +78,55 @@ namespace dsp {
|
|||||||
// Copy to buffer
|
// Copy to buffer
|
||||||
memcpy(bufferStart, in, count * sizeof(float));
|
memcpy(bufferStart, in, count * sizeof(float));
|
||||||
|
|
||||||
int outCount = 0;
|
int outCount = 0;
|
||||||
bool first = true;
|
|
||||||
|
for (int i = 0; i < count;) {
|
||||||
|
// Run clock recovery if needed
|
||||||
|
while (toRead) {
|
||||||
|
// Interpolate symbol
|
||||||
|
float symbol;
|
||||||
|
int phase = std::clamp<int>(floorf(pcl.phase * (float)interpPhaseCount), 0, interpPhaseCount - 1);
|
||||||
|
volk_32f_x2_dot_prod_32f(&symbol, &buffer[offsetInt], interpBank.phases[phase], interpTapCount);
|
||||||
|
out[outCount++] = symbol;
|
||||||
|
|
||||||
|
// Compute symbol phase error
|
||||||
|
float error = (math::step(lastSymbol) * symbol) - (lastSymbol * math::step(symbol));
|
||||||
|
lastSymbol = symbol;
|
||||||
|
|
||||||
|
// Clamp symbol phase error
|
||||||
|
if (error > 1.0f) { error = 1.0f; }
|
||||||
|
if (error < -1.0f) { error = -1.0f; }
|
||||||
|
|
||||||
|
// Advance symbol offset and phase
|
||||||
|
pcl.advance(error);
|
||||||
|
float delta = floorf(pcl.phase);
|
||||||
|
offsetInt += delta;
|
||||||
|
i = offsetInt;
|
||||||
|
pcl.phase -= delta;
|
||||||
|
|
||||||
|
// Decrement read counter
|
||||||
|
toRead--;
|
||||||
|
|
||||||
|
if (offsetInt >= count) {
|
||||||
|
offsetInt -= count;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
// Measure correlation to the sync pattern
|
// Measure correlation to the sync pattern
|
||||||
float corr;
|
float corr;
|
||||||
volk_32f_x2_dot_prod_32f(&corr, &buffer[i], pattern, patternLen);
|
volk_32f_x2_dot_prod_32f(&corr, &buffer[i], pattern, patternLen);
|
||||||
|
|
||||||
// If not correlated enough, go to next sample. Otherwise continue with fine detection
|
// If not correlated enough, go to next sample. Otherwise continue with fine detection
|
||||||
if (corr/(float)patternLen < threshold) { continue; }
|
if (corr/(float)patternLen < threshold) {
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Copy samples into FFT input (only the part where we think the pattern is located)
|
// Copy samples into FFT input (only the part where we think the pattern is located)
|
||||||
// TODO: Instead, check the interval onto which correlation occurs to determine where the pattern is located (IMPORTANT)
|
// TODO: Instead, check the interval onto which correlation occurs to determine where the pattern is located (IMPORTANT)
|
||||||
memcpy(fftIn, &buffer[i], patternLen*sizeof(float));
|
memcpy(fftIn, &buffer[i], patternLen*sizeof(float));
|
||||||
memset(&fftIn[patternLen], 0, (fftSize-patternLen)*sizeof(float)); // TODO, figure out why we need this
|
|
||||||
|
|
||||||
// Compute FFT
|
// Compute FFT
|
||||||
fftwf_execute(plan);
|
fftwf_execute(plan);
|
||||||
@ -113,15 +153,15 @@ namespace dsp {
|
|||||||
|
|
||||||
// Compute the total offset
|
// Compute the total offset
|
||||||
float offset = (float)i - avgRate*(float)fftSize/(2.0f*FL_M_PI);
|
float offset = (float)i - avgRate*(float)fftSize/(2.0f*FL_M_PI);
|
||||||
|
flog::debug("Detected: {} -> {}", i, offset);
|
||||||
|
|
||||||
if (first) {
|
// Initialize clock recovery
|
||||||
outCount = 320;
|
offsetInt = floorf(offset) - 3; // TODO: Will be negative sometimes, has to be taken into account
|
||||||
memcpy(out, &buffer[(int)roundf(offset)], 320*sizeof(float));
|
pcl.phase = offset - (float)floorf(offset);
|
||||||
first = false;
|
pcl.freq = sampsPerSym;
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
flog::debug("Detected: {} -> {} ({})", i, offset, avgRate);
|
// Start reading symbols
|
||||||
|
toRead = frameLen;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move unused data
|
// Move unused data
|
||||||
@ -137,11 +177,20 @@ namespace dsp {
|
|||||||
count = process(count, base_type::_in->readBuf, base_type::out.writeBuf);
|
count = process(count, base_type::_in->readBuf, base_type::out.writeBuf);
|
||||||
|
|
||||||
base_type::_in->flush();
|
base_type::_in->flush();
|
||||||
//if (!base_type::out.swap(count)) { return -1; }
|
if (count) {
|
||||||
|
if (!base_type::out.swap(count)) { return -1; }
|
||||||
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void generateInterpTaps() {
|
||||||
|
double bw = 0.5 / (double)interpPhaseCount;
|
||||||
|
dsp::tap<float> lp = dsp::taps::windowedSinc<float>(interpPhaseCount * interpTapCount, dsp::math::hzToRads(bw, 1.0), dsp::window::nuttall, interpPhaseCount);
|
||||||
|
interpBank = dsp::multirate::buildPolyphaseBank<float>(interpPhaseCount, lp);
|
||||||
|
taps::free(lp);
|
||||||
|
}
|
||||||
|
|
||||||
int delayLen;
|
int delayLen;
|
||||||
float* buffer = NULL;
|
float* buffer = NULL;
|
||||||
float* bufferStart = NULL;
|
float* bufferStart = NULL;
|
||||||
@ -149,7 +198,7 @@ namespace dsp {
|
|||||||
int patternLen;
|
int patternLen;
|
||||||
bool locked;
|
bool locked;
|
||||||
int fftSize;
|
int fftSize;
|
||||||
|
int frameLen;
|
||||||
float threshold;
|
float threshold;
|
||||||
|
|
||||||
float* fftIn = NULL;
|
float* fftIn = NULL;
|
||||||
@ -160,5 +209,13 @@ namespace dsp {
|
|||||||
float* patternFFTAmps;
|
float* patternFFTAmps;
|
||||||
|
|
||||||
float sampsPerSym;
|
float sampsPerSym;
|
||||||
|
int toRead = 0;
|
||||||
|
|
||||||
|
loop::PhaseControlLoop<float, false> pcl;
|
||||||
|
dsp::multirate::PolyphaseBank<float> interpBank;
|
||||||
|
int interpTapCount = 8;
|
||||||
|
int interpPhaseCount = 128;
|
||||||
|
float lastSymbol = 0.0f;
|
||||||
|
int offsetInt;
|
||||||
};
|
};
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user