@@ -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