Skip to content

Commit daf0f8c

Browse files
more work on new clock recovery
1 parent 63aa45d commit daf0f8c

File tree

3 files changed

+75
-18
lines changed

3 files changed

+75
-18
lines changed

decoder_modules/pager_decoder/src/pocsag/decoder.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
class POCSAGDecoder : public Decoder {
1515
public:
16-
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, 320) {
16+
POCSAGDecoder(const std::string& name, VFOManager::VFO* vfo) : diag(0.6, 544) {
1717
this->name = name;
1818
this->vfo = vfo;
1919

@@ -26,7 +26,7 @@ class POCSAGDecoder : public Decoder {
2626
vfo->setBandwidthLimits(12500, 12500, true);
2727
vfo->setSampleRate(SAMPLERATE, 12500);
2828
dsp.init(vfo->output, SAMPLERATE, BAUDRATE);
29-
reshape.init(&dsp.soft, 320, 0);
29+
reshape.init(&dsp.soft, 544, 0);
3030
dataHandler.init(&dsp.out, _dataHandler, this);
3131
diagHandler.init(&reshape.out, _diagHandler, this);
3232

decoder_modules/pager_decoder/src/pocsag/dsp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ class POCSAGDSP : public dsp::Processor<dsp::complex_t, uint8_t> {
112112
fir.init(NULL, shape);
113113
//recov.init(NULL, samplerate/baudrate, 1e-4, 1.0, 0.05);
114114

115-
cs.init(NULL, PATTERN_DSDSDZED, sizeof(PATTERN_DSDSDZED)/sizeof(float), 0, 10);
115+
cs.init(NULL, PATTERN_DSDSDZED, sizeof(PATTERN_DSDSDZED)/sizeof(float), 544, 10);
116116

117117
// Free useless buffers
118118
// dcBlock.out.free();

decoder_modules/pager_decoder/src/pocsag/packet_clock_sync.h

Lines changed: 72 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ namespace dsp {
4343
this->sampsPerSym = sampsPerSym;
4444
this->threshold = threshold;
4545
this->patternLen = patternLen;
46+
this->frameLen = frameLen;
4647

4748
// Plan FFT
4849
plan = fftwf_plan_dft_r2c_1d(fftSize, fftIn, (fftwf_complex*)fftOut, FFTW_ESTIMATE);
@@ -59,11 +60,16 @@ namespace dsp {
5960

6061
// Normalize the amplitudes
6162
float maxAmp = 0.0f;
62-
for (int i = 0; i < patternLen; i++) {
63+
for (int i = 0; i < fftSize/2; i++) {
6364
if (patternFFTAmps[i] > maxAmp) { maxAmp = patternFFTAmps[i]; }
6465
}
6566
volk_32f_s32f_multiply_32f(patternFFTAmps, patternFFTAmps, 1.0f/maxAmp, fftSize);
6667

68+
// Initialize the phase control loop
69+
float omegaRelLimit = 0.05;
70+
pcl.init(1, 10e-4, 0.0, 0.0, 1.0, sampsPerSym, sampsPerSym * (1.0 - omegaRelLimit), sampsPerSym * (1.0 + omegaRelLimit));
71+
generateInterpTaps();
72+
6773
// Init base
6874
base_type::init(in);
6975
}
@@ -72,21 +78,55 @@ namespace dsp {
7278
// Copy to buffer
7379
memcpy(bufferStart, in, count * sizeof(float));
7480

75-
int outCount = 0;
76-
bool first = true;
81+
int outCount = 0;
82+
83+
for (int i = 0; i < count;) {
84+
// Run clock recovery if needed
85+
while (toRead) {
86+
// Interpolate symbol
87+
float symbol;
88+
int phase = std::clamp<int>(floorf(pcl.phase * (float)interpPhaseCount), 0, interpPhaseCount - 1);
89+
volk_32f_x2_dot_prod_32f(&symbol, &buffer[offsetInt], interpBank.phases[phase], interpTapCount);
90+
out[outCount++] = symbol;
91+
92+
// Compute symbol phase error
93+
float error = (math::step(lastSymbol) * symbol) - (lastSymbol * math::step(symbol));
94+
lastSymbol = symbol;
95+
96+
// Clamp symbol phase error
97+
if (error > 1.0f) { error = 1.0f; }
98+
if (error < -1.0f) { error = -1.0f; }
99+
100+
// Advance symbol offset and phase
101+
pcl.advance(error);
102+
float delta = floorf(pcl.phase);
103+
offsetInt += delta;
104+
i = offsetInt;
105+
pcl.phase -= delta;
106+
107+
// Decrement read counter
108+
toRead--;
109+
110+
if (offsetInt >= count) {
111+
offsetInt -= count;
112+
break;
113+
}
114+
}
115+
77116

78-
for (int i = 0; i < count; i++) {
79117
// Measure correlation to the sync pattern
80118
float corr;
81119
volk_32f_x2_dot_prod_32f(&corr, &buffer[i], pattern, patternLen);
82120

83121
// If not correlated enough, go to next sample. Otherwise continue with fine detection
84-
if (corr/(float)patternLen < threshold) { continue; }
122+
if (corr/(float)patternLen < threshold) {
123+
i++;
124+
continue;
125+
}
85126

86127
// Copy samples into FFT input (only the part where we think the pattern is located)
87128
// TODO: Instead, check the interval onto which correlation occurs to determine where the pattern is located (IMPORTANT)
88129
memcpy(fftIn, &buffer[i], patternLen*sizeof(float));
89-
memset(&fftIn[patternLen], 0, (fftSize-patternLen)*sizeof(float)); // TODO, figure out why we need this
90130

91131
// Compute FFT
92132
fftwf_execute(plan);
@@ -113,15 +153,15 @@ namespace dsp {
113153

114154
// Compute the total offset
115155
float offset = (float)i - avgRate*(float)fftSize/(2.0f*FL_M_PI);
156+
flog::debug("Detected: {} -> {}", i, offset);
116157

117-
if (first) {
118-
outCount = 320;
119-
memcpy(out, &buffer[(int)roundf(offset)], 320*sizeof(float));
120-
first = false;
121-
}
122-
158+
// Initialize clock recovery
159+
offsetInt = floorf(offset) - 3; // TODO: Will be negative sometimes, has to be taken into account
160+
pcl.phase = offset - (float)floorf(offset);
161+
pcl.freq = sampsPerSym;
123162

124-
flog::debug("Detected: {} -> {} ({})", i, offset, avgRate);
163+
// Start reading symbols
164+
toRead = frameLen;
125165
}
126166

127167
// Move unused data
@@ -137,19 +177,28 @@ namespace dsp {
137177
count = process(count, base_type::_in->readBuf, base_type::out.writeBuf);
138178

139179
base_type::_in->flush();
140-
//if (!base_type::out.swap(count)) { return -1; }
180+
if (count) {
181+
if (!base_type::out.swap(count)) { return -1; }
182+
}
141183
return count;
142184
}
143185

144186
private:
187+
void generateInterpTaps() {
188+
double bw = 0.5 / (double)interpPhaseCount;
189+
dsp::tap<float> lp = dsp::taps::windowedSinc<float>(interpPhaseCount * interpTapCount, dsp::math::hzToRads(bw, 1.0), dsp::window::nuttall, interpPhaseCount);
190+
interpBank = dsp::multirate::buildPolyphaseBank<float>(interpPhaseCount, lp);
191+
taps::free(lp);
192+
}
193+
145194
int delayLen;
146195
float* buffer = NULL;
147196
float* bufferStart = NULL;
148197
float* pattern = NULL;
149198
int patternLen;
150199
bool locked;
151200
int fftSize;
152-
201+
int frameLen;
153202
float threshold;
154203

155204
float* fftIn = NULL;
@@ -160,5 +209,13 @@ namespace dsp {
160209
float* patternFFTAmps;
161210

162211
float sampsPerSym;
212+
int toRead = 0;
213+
214+
loop::PhaseControlLoop<float, false> pcl;
215+
dsp::multirate::PolyphaseBank<float> interpBank;
216+
int interpTapCount = 8;
217+
int interpPhaseCount = 128;
218+
float lastSymbol = 0.0f;
219+
int offsetInt;
163220
};
164221
}

0 commit comments

Comments
 (0)