blob: fcda5fa74fee22ed37e2b73833cbf4159c7e1171 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
kurtis.heimerla198d452011-11-26 03:19:28 +00002* Copyright 2008, 2011 Free Software Foundation, Inc.
dburgessb3a0ca42011-10-12 07:44:40 +00003*
4* This software is distributed under the terms of the GNU Affero Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
19
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23*/
24
Thomas Tsou7e4e5362013-10-30 21:18:55 -040025#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
dburgessb3a0ca42011-10-12 07:44:40 +000029#include "sigProcLib.h"
30#include "GSMCommon.h"
Alexander Chemeris954b1182015-06-04 15:39:41 -040031#include "Logger.h"
Tom Tsoud3253432016-03-06 03:08:01 -080032#include "Resampler.h"
dburgessb3a0ca42011-10-12 07:44:40 +000033
Thomas Tsou3eaae802013-08-20 19:31:14 -040034extern "C" {
35#include "convolve.h"
Thomas Tsou7e4e5362013-10-30 21:18:55 -040036#include "scale.h"
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -050037#include "mult.h"
Thomas Tsou3eaae802013-08-20 19:31:14 -040038}
39
Thomas Tsou7e4e5362013-10-30 21:18:55 -040040using namespace GSM;
41
Thomas Tsouf79c4d02013-11-09 15:51:56 -060042#define TABLESIZE 1024
43#define DELAYFILTS 64
dburgessb3a0ca42011-10-12 07:44:40 +000044
Tom Tsou577cd022015-05-18 13:57:54 -070045/* Clipping detection threshold */
46#define CLIP_THRESH 30000.0f
47
dburgessb3a0ca42011-10-12 07:44:40 +000048/** Lookup tables for trigonometric approximation */
Tom Tsoubb0c68a2017-06-16 17:08:40 -070049static float sincTable[TABLESIZE+1]; // add 1 element for wrap around
dburgessb3a0ca42011-10-12 07:44:40 +000050
51/** Constants */
52static const float M_PI_F = (float)M_PI;
dburgessb3a0ca42011-10-12 07:44:40 +000053
Thomas Tsouc1f7c422013-10-11 13:49:55 -040054/* Precomputed rotation vectors */
Tom Tsou2079a3c2016-03-06 00:58:56 -080055static signalVector *GMSKRotation4 = NULL;
56static signalVector *GMSKReverseRotation4 = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040057static signalVector *GMSKRotation1 = NULL;
58static signalVector *GMSKReverseRotation1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000059
Thomas Tsouf79c4d02013-11-09 15:51:56 -060060/* Precomputed fractional delay filters */
61static signalVector *delayFilters[DELAYFILTS];
62
Tom Tsou70134a02017-06-12 14:23:53 -070063static const Complex<float> psk8_table[8] = {
Tom Tsoud3253432016-03-06 03:08:01 -080064 Complex<float>(-0.70710678, 0.70710678),
65 Complex<float>( 0.0, -1.0),
66 Complex<float>( 0.0, 1.0),
67 Complex<float>( 0.70710678, -0.70710678),
68 Complex<float>(-1.0, 0.0),
69 Complex<float>(-0.70710678, -0.70710678),
70 Complex<float>( 0.70710678, 0.70710678),
71 Complex<float>( 1.0, 0.0),
72};
73
74/* Downsampling filterbank - 4 SPS to 1 SPS */
75#define DOWNSAMPLE_IN_LEN 624
76#define DOWNSAMPLE_OUT_LEN 156
77
78static Resampler *dnsampler = NULL;
Tom Tsoud3253432016-03-06 03:08:01 -080079
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040080/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040081 * RACH and midamble correlation waveforms. Store the buffer separately
82 * because we need to allocate it explicitly outside of the signal vector
83 * constructor. This is because C++ (prior to C++11) is unable to natively
84 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040085 */
86struct CorrelationSequence {
Pau Espin Pedrolf7331762018-12-03 17:46:04 +010087 CorrelationSequence() : sequence(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040088 {
89 }
90
91 ~CorrelationSequence()
92 {
93 delete sequence;
94 }
95
dburgessb3a0ca42011-10-12 07:44:40 +000096 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040097 void *buffer;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040098 float toa;
dburgessb3a0ca42011-10-12 07:44:40 +000099 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400100};
dburgessb3a0ca42011-10-12 07:44:40 +0000101
Thomas Tsou83e06892013-08-20 16:10:01 -0400102/*
Thomas Tsou3eaae802013-08-20 19:31:14 -0400103 * Gaussian and empty modulation pulses. Like the correlation sequences,
104 * store the runtime (Gaussian) buffer separately because of needed alignment
105 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -0400106 */
107struct PulseSequence {
Pau Espin Pedrolf7331762018-12-03 17:46:04 +0100108 PulseSequence() : c0(NULL), c1(NULL), c0_inv(NULL), empty(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -0400109 {
110 }
111
112 ~PulseSequence()
113 {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800114 delete c0;
115 delete c1;
Tom Tsoud3253432016-03-06 03:08:01 -0800116 delete c0_inv;
Thomas Tsou83e06892013-08-20 16:10:01 -0400117 delete empty;
118 }
119
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800120 signalVector *c0;
121 signalVector *c1;
Tom Tsoud3253432016-03-06 03:08:01 -0800122 signalVector *c0_inv;
Thomas Tsou83e06892013-08-20 16:10:01 -0400123 signalVector *empty;
124};
125
Tom Tsoud3253432016-03-06 03:08:01 -0800126static CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
127static CorrelationSequence *gEdgeMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
Vadim Yanitskiya79bc702018-10-17 11:01:58 +0200128static CorrelationSequence *gRACHSequences[] = {NULL,NULL,NULL};
Tom Tsoud3253432016-03-06 03:08:01 -0800129static PulseSequence *GSMPulse1 = NULL;
130static PulseSequence *GSMPulse4 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000131
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400132void sigProcLibDestroy()
133{
dburgessb3a0ca42011-10-12 07:44:40 +0000134 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400135 delete gMidambles[i];
Tom Tsoud3253432016-03-06 03:08:01 -0800136 delete gEdgeMidambles[i];
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400137 gMidambles[i] = NULL;
Tom Tsoud3253432016-03-06 03:08:01 -0800138 gEdgeMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000139 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400140
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600141 for (int i = 0; i < DELAYFILTS; i++) {
142 delete delayFilters[i];
143 delayFilters[i] = NULL;
144 }
145
Vadim Yanitskiya79bc702018-10-17 11:01:58 +0200146 for (int i = 0; i < 3; i++) {
147 delete gRACHSequences[i];
148 gRACHSequences[i] = NULL;
149 }
150
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400151 delete GMSKRotation1;
152 delete GMSKReverseRotation1;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800153 delete GMSKRotation4;
154 delete GMSKReverseRotation4;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400155 delete GSMPulse1;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800156 delete GSMPulse4;
Tom Tsoud3253432016-03-06 03:08:01 -0800157 delete dnsampler;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400158
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400159 GMSKRotation1 = NULL;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800160 GMSKRotation4 = NULL;
161 GMSKReverseRotation4 = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400162 GMSKReverseRotation1 = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400163 GSMPulse1 = NULL;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800164 GSMPulse4 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000165}
166
Tom Tsou70134a02017-06-12 14:23:53 -0700167static float vectorNorm2(const signalVector &x)
dburgessb3a0ca42011-10-12 07:44:40 +0000168{
169 signalVector::const_iterator xPtr = x.begin();
170 float Energy = 0.0;
171 for (;xPtr != x.end();xPtr++) {
172 Energy += xPtr->norm2();
173 }
174 return Energy;
175}
176
Tom Tsou2079a3c2016-03-06 00:58:56 -0800177/*
178 * Initialize 4 sps and 1 sps rotation tables
179 */
180static void initGMSKRotationTables()
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400181{
Tom Tsou2079a3c2016-03-06 00:58:56 -0800182 size_t len1 = 157, len4 = 625;
183
184 GMSKRotation4 = new signalVector(len4);
185 GMSKReverseRotation4 = new signalVector(len4);
186 signalVector::iterator rotPtr = GMSKRotation4->begin();
187 signalVector::iterator revPtr = GMSKReverseRotation4->begin();
Tom Tsoubb0c68a2017-06-16 17:08:40 -0700188 auto phase = 0.0;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800189 while (rotPtr != GMSKRotation4->end()) {
Tom Tsoubb0c68a2017-06-16 17:08:40 -0700190 *rotPtr++ = complex(cos(phase), sin(phase));
191 *revPtr++ = complex(cos(-phase), sin(-phase));
192 phase += M_PI / 2.0 / 4.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000193 }
dburgessb3a0ca42011-10-12 07:44:40 +0000194
Tom Tsou2079a3c2016-03-06 00:58:56 -0800195 GMSKRotation1 = new signalVector(len1);
196 GMSKReverseRotation1 = new signalVector(len1);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400197 rotPtr = GMSKRotation1->begin();
198 revPtr = GMSKReverseRotation1->begin();
199 phase = 0.0;
200 while (rotPtr != GMSKRotation1->end()) {
Tom Tsoubb0c68a2017-06-16 17:08:40 -0700201 *rotPtr++ = complex(cos(phase), sin(phase));
202 *revPtr++ = complex(cos(-phase), sin(-phase));
203 phase += M_PI / 2.0;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400204 }
dburgessb3a0ca42011-10-12 07:44:40 +0000205}
206
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400207static void GMSKRotate(signalVector &x, int sps)
208{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500209#if HAVE_NEON
210 size_t len;
211 signalVector *a, *b, *out;
212
213 a = &x;
214 out = &x;
215 len = out->size();
216
217 if (len == 157)
218 len--;
219
220 if (sps == 1)
221 b = GMSKRotation1;
222 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800223 b = GMSKRotation4;
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500224
225 mul_complex((float *) out->begin(),
226 (float *) a->begin(),
227 (float *) b->begin(), len);
228#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400229 signalVector::iterator rotPtr, xPtr = x.begin();
230
231 if (sps == 1)
232 rotPtr = GMSKRotation1->begin();
233 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800234 rotPtr = GMSKRotation4->begin();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400235
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500236 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000237 while (xPtr < x.end()) {
238 *xPtr = *rotPtr++ * (xPtr->real());
239 xPtr++;
240 }
241 }
242 else {
243 while (xPtr < x.end()) {
244 *xPtr = *rotPtr++ * (*xPtr);
245 xPtr++;
246 }
247 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500248#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000249}
250
Tom Tsou2079a3c2016-03-06 00:58:56 -0800251static bool GMSKReverseRotate(signalVector &x, int sps)
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400252{
253 signalVector::iterator rotPtr, xPtr= x.begin();
254
255 if (sps == 1)
256 rotPtr = GMSKReverseRotation1->begin();
Tom Tsou2079a3c2016-03-06 00:58:56 -0800257 else if (sps == 4)
258 rotPtr = GMSKReverseRotation4->begin();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400259 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800260 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400261
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500262 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000263 while (xPtr < x.end()) {
264 *xPtr = *rotPtr++ * (xPtr->real());
265 xPtr++;
266 }
267 }
268 else {
269 while (xPtr < x.end()) {
270 *xPtr = *rotPtr++ * (*xPtr);
271 xPtr++;
272 }
273 }
Tom Tsou2079a3c2016-03-06 00:58:56 -0800274
275 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000276}
277
Tom Tsou70134a02017-06-12 14:23:53 -0700278/** Convolution type indicator */
279enum ConvType {
280 START_ONLY,
281 NO_DELAY,
282 CUSTOM,
283 UNDEFINED,
284};
285
286static signalVector *convolve(const signalVector *x, const signalVector *h,
287 signalVector *y, ConvType spanType,
Sylvain Munauta3934a12018-12-20 19:10:26 +0100288 size_t start = 0, size_t len = 0)
dburgessb3a0ca42011-10-12 07:44:40 +0000289{
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500290 int rc;
291 size_t head = 0, tail = 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400292 bool alloc = false, append = false;
293 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000294
Thomas Tsou3eaae802013-08-20 19:31:14 -0400295 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000296 return NULL;
297
Thomas Tsou3eaae802013-08-20 19:31:14 -0400298 switch (spanType) {
299 case START_ONLY:
300 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500301 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400302 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500303
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500304 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500305 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000306 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400307 case NO_DELAY:
308 start = h->size() / 2;
309 head = start;
310 tail = start;
311 len = x->size();
312 append = true;
313 break;
314 case CUSTOM:
315 if (start < h->size() - 1) {
316 head = h->size() - start;
317 append = true;
318 }
319 if (start + len > x->size()) {
320 tail = start + len - x->size();
321 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000322 }
323 break;
324 default:
325 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000326 }
dburgessb3a0ca42011-10-12 07:44:40 +0000327
Thomas Tsou3eaae802013-08-20 19:31:14 -0400328 /*
329 * Error if the output vector is too small. Create the output vector
330 * if the pointer is NULL.
331 */
332 if (y && (len > y->size()))
333 return NULL;
334 if (!y) {
Pau Espin Pedrolf7331762018-12-03 17:46:04 +0100335 y = new signalVector(len, convolve_h_alloc, free);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400336 alloc = true;
337 }
338
339 /* Prepend or post-pend the input vector if the parameters require it */
340 if (append)
341 _x = new signalVector(*x, head, tail);
342 else
343 _x = x;
344
345 /*
346 * Four convovle types:
347 * 1. Complex-Real (aligned)
348 * 2. Complex-Complex (aligned)
349 * 3. Complex-Real (!aligned)
350 * 4. Complex-Complex (!aligned)
351 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500352 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400353 rc = convolve_real((float *) _x->begin(), _x->size(),
354 (float *) h->begin(), h->size(),
355 (float *) y->begin(), y->size(),
Sylvain Munauta3934a12018-12-20 19:10:26 +0100356 start, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500357 } else if (!h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400358 rc = convolve_complex((float *) _x->begin(), _x->size(),
359 (float *) h->begin(), h->size(),
360 (float *) y->begin(), y->size(),
Sylvain Munauta3934a12018-12-20 19:10:26 +0100361 start, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500362 } else if (h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400363 rc = base_convolve_real((float *) _x->begin(), _x->size(),
364 (float *) h->begin(), h->size(),
365 (float *) y->begin(), y->size(),
Sylvain Munauta3934a12018-12-20 19:10:26 +0100366 start, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500367 } else if (!h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400368 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
369 (float *) h->begin(), h->size(),
370 (float *) y->begin(), y->size(),
Sylvain Munauta3934a12018-12-20 19:10:26 +0100371 start, len);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400372 } else {
373 rc = -1;
374 }
375
376 if (append)
377 delete _x;
378
379 if (rc < 0) {
380 if (alloc)
381 delete y;
382 return NULL;
383 }
384
385 return y;
386}
dburgessb3a0ca42011-10-12 07:44:40 +0000387
Tom Tsoud3253432016-03-06 03:08:01 -0800388/*
389 * Generate static EDGE linear equalizer. This equalizer is not adaptive.
390 * Filter taps are generated from the inverted 1 SPS impulse response of
391 * the EDGE pulse shape captured after the downsampling filter.
392 */
393static bool generateInvertC0Pulse(PulseSequence *pulse)
394{
395 if (!pulse)
396 return false;
397
Pau Espin Pedrolf7331762018-12-03 17:46:04 +0100398 pulse->c0_inv = new signalVector((complex *) convolve_h_alloc(5), 0, 5, convolve_h_alloc, free);
Tom Tsoud3253432016-03-06 03:08:01 -0800399 pulse->c0_inv->isReal(true);
400 pulse->c0_inv->setAligned(false);
401
402 signalVector::iterator xP = pulse->c0_inv->begin();
403 *xP++ = 0.15884;
404 *xP++ = -0.43176;
405 *xP++ = 1.00000;
406 *xP++ = -0.42608;
407 *xP++ = 0.14882;
408
409 return true;
410}
411
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400412static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800413{
414 int len;
415
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400416 if (!pulse)
417 return false;
418
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800419 switch (sps) {
420 case 4:
421 len = 8;
422 break;
423 default:
424 return false;
425 }
426
Pau Espin Pedrolf7331762018-12-03 17:46:04 +0100427 pulse->c1 = new signalVector((complex *) convolve_h_alloc(len), 0, len, convolve_h_alloc, free);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500428 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800429
430 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400431 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800432
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400433 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800434
435 switch (sps) {
436 case 4:
437 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400438 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800439 *xP++ = 8.16373112e-03;
440 *xP++ = 2.84385729e-02;
441 *xP++ = 5.64158904e-02;
442 *xP++ = 7.05463553e-02;
443 *xP++ = 5.64158904e-02;
444 *xP++ = 2.84385729e-02;
445 *xP++ = 8.16373112e-03;
446 }
447
448 return true;
449}
450
Tom Tsou2079a3c2016-03-06 00:58:56 -0800451static PulseSequence *generateGSMPulse(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +0000452{
Thomas Tsou83e06892013-08-20 16:10:01 -0400453 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800454 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400455 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400456
Tom Tsoud3253432016-03-06 03:08:01 -0800457 if ((sps != 1) && (sps != 4))
458 return NULL;
459
Thomas Tsou83e06892013-08-20 16:10:01 -0400460 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400461 pulse = new PulseSequence();
462 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500463 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400464 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400465
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400466 /*
467 * For 4 samples-per-symbol use a precomputed single pulse Laurent
468 * approximation. This should yields below 2 degrees of phase error at
469 * the modulator output. Use the existing pulse approximation for all
470 * other oversampling factors.
471 */
472 switch (sps) {
473 case 4:
474 len = 16;
475 break;
Tom Tsoud3253432016-03-06 03:08:01 -0800476 case 1:
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400477 default:
Tom Tsou2079a3c2016-03-06 00:58:56 -0800478 len = 4;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400479 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400480
Pau Espin Pedrolf7331762018-12-03 17:46:04 +0100481 pulse->c0 = new signalVector((complex *) convolve_h_alloc(len), 0, len, convolve_h_alloc, free);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500482 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400483
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800484 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400485 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800486
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400487 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400488
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400489 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800490 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400491 *xP++ = 4.46348606e-03;
492 *xP++ = 2.84385729e-02;
493 *xP++ = 1.03184855e-01;
494 *xP++ = 2.56065552e-01;
495 *xP++ = 4.76375085e-01;
496 *xP++ = 7.05961177e-01;
497 *xP++ = 8.71291644e-01;
498 *xP++ = 9.29453645e-01;
499 *xP++ = 8.71291644e-01;
500 *xP++ = 7.05961177e-01;
501 *xP++ = 4.76375085e-01;
502 *xP++ = 2.56065552e-01;
503 *xP++ = 1.03184855e-01;
504 *xP++ = 2.84385729e-02;
505 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400506 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400507 } else {
508 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400509
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400510 /* GSM pulse approximation */
511 for (int i = 0; i < len; i++) {
512 arg = ((float) i - center) / (float) sps;
513 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
514 0.527 * arg * arg * arg * arg);
515 }
dburgessb3a0ca42011-10-12 07:44:40 +0000516
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400517 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
518 xP = pulse->c0->begin();
519 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800520 *xP++ /= avg;
521 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400522
Tom Tsoud3253432016-03-06 03:08:01 -0800523 /*
524 * Current form of the EDGE equalization filter non-realizable at 4 SPS.
525 * Load the onto both 1 SPS and 4 SPS objects for convenience. Note that
526 * the EDGE demodulator downsamples to 1 SPS prior to equalization.
527 */
528 generateInvertC0Pulse(pulse);
529
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400530 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000531}
532
Tom Tsoud3253432016-03-06 03:08:01 -0800533bool vectorSlicer(SoftVector *x)
534{
535 SoftVector::iterator xP = x->begin();
536 SoftVector::iterator xPEnd = x->end();
537 while (xP < xPEnd) {
538 *xP = 0.5 * (*xP + 1.0f);
539 if (*xP > 1.0)
540 *xP = 1.0;
541 if (*xP < 0.0)
542 *xP = 0.0;
543 xP++;
544 }
545 return true;
546}
547
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800548static signalVector *rotateBurst(const BitVector &wBurst,
549 int guardPeriodLength, int sps)
550{
551 int burst_len;
Tom Tsou7278a872017-06-14 14:50:39 -0700552 signalVector *pulse, rotated;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800553 signalVector::iterator itr;
554
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400555 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800556 burst_len = sps * (wBurst.size() + guardPeriodLength);
557 rotated = signalVector(burst_len);
558 itr = rotated.begin();
559
560 for (unsigned i = 0; i < wBurst.size(); i++) {
561 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
562 itr += sps;
563 }
564
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400565 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500566 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800567
568 /* Dummy filter operation */
Tom Tsou7278a872017-06-14 14:50:39 -0700569 return convolve(&rotated, pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800570}
571
Tom Tsoud3253432016-03-06 03:08:01 -0800572static void rotateBurst2(signalVector &burst, double phase)
573{
574 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
575
576 for (size_t i = 0; i < burst.size(); i++)
577 burst[i] = burst[i] * rot;
578}
579
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800580/*
581 * Ignore the guard length argument in the GMSK modulator interface
582 * because it results in 624/628 sized bursts instead of the preferred
583 * burst length of 625. Only 4 SPS is supported.
584 */
585static signalVector *modulateBurstLaurent(const BitVector &bits)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800586{
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800587 int burst_len, sps = 4;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800588 float phase;
Tom Tsou7278a872017-06-14 14:50:39 -0700589 signalVector *c0_pulse, *c1_pulse, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800590 signalVector::iterator c0_itr, c1_itr;
591
Tom Tsou2079a3c2016-03-06 00:58:56 -0800592 c0_pulse = GSMPulse4->c0;
593 c1_pulse = GSMPulse4->c1;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800594
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800595 if (bits.size() > 156)
596 return NULL;
597
598 burst_len = 625;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800599
Tom Tsou7278a872017-06-14 14:50:39 -0700600 signalVector c0_burst(burst_len, c0_pulse->size());
601 c0_burst.isReal(true);
602 c0_itr = c0_burst.begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800603
Tom Tsou7278a872017-06-14 14:50:39 -0700604 signalVector c1_burst(burst_len, c1_pulse->size());
605 c1_itr = c1_burst.begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800606
Tom Tsouaa15d622016-08-11 14:36:23 -0700607 /* Padded differential tail bits */
608 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800609 c0_itr += sps;
610
611 /* Main burst bits */
612 for (unsigned i = 0; i < bits.size(); i++) {
613 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
614 c0_itr += sps;
615 }
616
Tom Tsouaa15d622016-08-11 14:36:23 -0700617 /* Padded differential tail bits */
618 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800619
620 /* Generate C0 phase coefficients */
Tom Tsou7278a872017-06-14 14:50:39 -0700621 GMSKRotate(c0_burst, sps);
622 c0_burst.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800623
Tom Tsou7278a872017-06-14 14:50:39 -0700624 c0_itr = c0_burst.begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800625 c0_itr += sps * 2;
626 c1_itr += sps * 2;
627
628 /* Start magic */
629 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
630 *c1_itr = *c0_itr * Complex<float>(0, phase);
631 c0_itr += sps;
632 c1_itr += sps;
633
634 /* Generate C1 phase coefficients */
635 for (unsigned i = 2; i < bits.size(); i++) {
636 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
637 *c1_itr = *c0_itr * Complex<float>(0, phase);
638
639 c0_itr += sps;
640 c1_itr += sps;
641 }
642
643 /* End magic */
644 int i = bits.size();
645 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
646 *c1_itr = *c0_itr * Complex<float>(0, phase);
647
648 /* Primary (C0) and secondary (C1) pulse shaping */
Tom Tsou7278a872017-06-14 14:50:39 -0700649 c0_shaped = convolve(&c0_burst, c0_pulse, NULL, START_ONLY);
650 c1_shaped = convolve(&c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800651
652 /* Sum shaped outputs into C0 */
653 c0_itr = c0_shaped->begin();
654 c1_itr = c1_shaped->begin();
655 for (unsigned i = 0; i < c0_shaped->size(); i++ )
656 *c0_itr++ += *c1_itr++;
657
658 delete c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800659 return c0_shaped;
660}
661
Tom Tsoud3253432016-03-06 03:08:01 -0800662static signalVector *rotateEdgeBurst(const signalVector &symbols, int sps)
663{
664 signalVector *burst;
665 signalVector::iterator burst_itr;
666
667 burst = new signalVector(symbols.size() * sps);
668 burst_itr = burst->begin();
669
670 for (size_t i = 0; i < symbols.size(); i++) {
671 float phase = i * 3.0f * M_PI / 8.0f;
672 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
673
674 *burst_itr = symbols[i] * rot;
675 burst_itr += sps;
676 }
677
678 return burst;
679}
680
681static signalVector *derotateEdgeBurst(const signalVector &symbols, int sps)
682{
683 signalVector *burst;
684 signalVector::iterator burst_itr;
685
686 if (symbols.size() % sps)
687 return NULL;
688
689 burst = new signalVector(symbols.size() / sps);
690 burst_itr = burst->begin();
691
692 for (size_t i = 0; i < burst->size(); i++) {
693 float phase = (float) (i % 16) * 3.0f * M_PI / 8.0f;
694 Complex<float> rot = Complex<float>(cosf(phase), -sinf(phase));
695
696 *burst_itr = symbols[sps * i] * rot;
697 burst_itr++;
698 }
699
700 return burst;
701}
702
703static signalVector *mapEdgeSymbols(const BitVector &bits)
704{
705 if (bits.size() % 3)
706 return NULL;
707
708 signalVector *symbols = new signalVector(bits.size() / 3);
709
710 for (size_t i = 0; i < symbols->size(); i++) {
711 unsigned index = (((unsigned) bits[3 * i + 0] & 0x01) << 0) |
712 (((unsigned) bits[3 * i + 1] & 0x01) << 1) |
713 (((unsigned) bits[3 * i + 2] & 0x01) << 2);
714
715 (*symbols)[i] = psk8_table[index];
716 }
717
718 return symbols;
719}
720
Tom Tsoud2b07032016-04-26 19:28:59 -0700721/*
722 * EDGE 8-PSK rotate and pulse shape
723 *
724 * Delay the EDGE downlink bursts by one symbol in order to match GMSK pulse
725 * shaping group delay. The difference in group delay arises from the dual
726 * pulse filter combination of the GMSK Laurent represenation whereas 8-PSK
727 * uses a single pulse linear filter.
728 */
Tom Tsoud3253432016-03-06 03:08:01 -0800729static signalVector *shapeEdgeBurst(const signalVector &symbols)
730{
Tom Tsoud2b07032016-04-26 19:28:59 -0700731 size_t nsyms, nsamps = 625, sps = 4;
Tom Tsoud3253432016-03-06 03:08:01 -0800732 signalVector::iterator burst_itr;
733
734 nsyms = symbols.size();
735
Tom Tsoud2b07032016-04-26 19:28:59 -0700736 if (nsyms * sps > nsamps)
Tom Tsoud3253432016-03-06 03:08:01 -0800737 nsyms = 156;
738
Tom Tsou7278a872017-06-14 14:50:39 -0700739 signalVector burst(nsamps, GSMPulse4->c0->size());
Tom Tsoud3253432016-03-06 03:08:01 -0800740
Tom Tsoud2b07032016-04-26 19:28:59 -0700741 /* Delay burst by 1 symbol */
Tom Tsou7278a872017-06-14 14:50:39 -0700742 burst_itr = burst.begin() + sps;
Tom Tsou06676ea2016-07-19 12:50:21 -0700743 for (size_t i = 0; i < nsyms; i++) {
Tom Tsoud3253432016-03-06 03:08:01 -0800744 float phase = i * 3.0f * M_PI / 8.0f;
745 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
746
747 *burst_itr = symbols[i] * rot;
Tom Tsoud2b07032016-04-26 19:28:59 -0700748 burst_itr += sps;
Tom Tsoud3253432016-03-06 03:08:01 -0800749 }
750
751 /* Single Gaussian pulse approximation shaping */
Tom Tsou7278a872017-06-14 14:50:39 -0700752 return convolve(&burst, GSMPulse4->c0, NULL, START_ONLY);
Tom Tsoud3253432016-03-06 03:08:01 -0800753}
754
755/*
Tom Tsou8ee2f382016-03-06 20:57:34 -0800756 * Generate a random GSM normal burst.
757 */
758signalVector *genRandNormalBurst(int tsc, int sps, int tn)
759{
760 if ((tsc < 0) || (tsc > 7) || (tn < 0) || (tn > 7))
761 return NULL;
762 if ((sps != 1) && (sps != 4))
763 return NULL;
764
765 int i = 0;
Tom Tsou7278a872017-06-14 14:50:39 -0700766 BitVector bits(148);
Tom Tsou8ee2f382016-03-06 20:57:34 -0800767
768 /* Tail bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700769 for (; i < 3; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700770 bits[i] = 0;
Tom Tsou8ee2f382016-03-06 20:57:34 -0800771
772 /* Random bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700773 for (; i < 60; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700774 bits[i] = rand() % 2;
Tom Tsou8ee2f382016-03-06 20:57:34 -0800775
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700776 /* Stealing bit */
Tom Tsou7278a872017-06-14 14:50:39 -0700777 bits[i++] = 0;
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700778
Tom Tsou8ee2f382016-03-06 20:57:34 -0800779 /* Training sequence */
780 for (int n = 0; i < 87; i++, n++)
Tom Tsou7278a872017-06-14 14:50:39 -0700781 bits[i] = gTrainingSequence[tsc][n];
Tom Tsou8ee2f382016-03-06 20:57:34 -0800782
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700783 /* Stealing bit */
Tom Tsou7278a872017-06-14 14:50:39 -0700784 bits[i++] = 0;
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700785
Tom Tsou8ee2f382016-03-06 20:57:34 -0800786 /* Random bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700787 for (; i < 145; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700788 bits[i] = rand() % 2;
Tom Tsou8ee2f382016-03-06 20:57:34 -0800789
790 /* Tail bits */
791 for (; i < 148; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700792 bits[i] = 0;
Tom Tsou8ee2f382016-03-06 20:57:34 -0800793
794 int guard = 8 + !(tn % 4);
Tom Tsou7278a872017-06-14 14:50:39 -0700795 return modulateBurst(bits, guard, sps);
Tom Tsou8ee2f382016-03-06 20:57:34 -0800796}
797
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300798/*
799 * Generate a random GSM access burst.
800 */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300801signalVector *genRandAccessBurst(int delay, int sps, int tn)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300802{
803 if ((tn < 0) || (tn > 7))
804 return NULL;
805 if ((sps != 1) && (sps != 4))
806 return NULL;
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300807 if (delay > 68)
808 return NULL;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300809
810 int i = 0;
Tom Tsou7278a872017-06-14 14:50:39 -0700811 BitVector bits(88 + delay);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300812
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300813 /* delay */
814 for (; i < delay; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700815 bits[i] = 0;
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300816
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300817 /* head and synch bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300818 for (int n = 0; i < 49+delay; i++, n++)
Tom Tsou7278a872017-06-14 14:50:39 -0700819 bits[i] = gRACHBurst[n];
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300820
821 /* Random bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300822 for (; i < 85+delay; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700823 bits[i] = rand() % 2;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300824
825 /* Tail bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300826 for (; i < 88+delay; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700827 bits[i] = 0;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300828
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300829 int guard = 68-delay + !(tn % 4);
Tom Tsou7278a872017-06-14 14:50:39 -0700830 return modulateBurst(bits, guard, sps);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300831}
832
Tom Tsou8ee2f382016-03-06 20:57:34 -0800833signalVector *generateEmptyBurst(int sps, int tn)
834{
835 if ((tn < 0) || (tn > 7))
836 return NULL;
837
838 if (sps == 4)
839 return new signalVector(625);
840 else if (sps == 1)
841 return new signalVector(148 + 8 + !(tn % 4));
842 else
843 return NULL;
844}
845
846signalVector *generateDummyBurst(int sps, int tn)
847{
848 if (((sps != 1) && (sps != 4)) || (tn < 0) || (tn > 7))
849 return NULL;
850
851 return modulateBurst(gDummyBurst, 8 + !(tn % 4), sps);
852}
853
854/*
Tom Tsoud3253432016-03-06 03:08:01 -0800855 * Generate a random 8-PSK EDGE burst. Only 4 SPS is supported with
856 * the returned burst being 625 samples in length.
857 */
858signalVector *generateEdgeBurst(int tsc)
859{
860 int tail = 9 / 3;
861 int data = 174 / 3;
862 int train = 78 / 3;
863
864 if ((tsc < 0) || (tsc > 7))
865 return NULL;
866
Tom Tsou7278a872017-06-14 14:50:39 -0700867 signalVector burst(148);
Tom Tsoud3253432016-03-06 03:08:01 -0800868 const BitVector *midamble = &gEdgeTrainingSequence[tsc];
869
870 /* Tail */
871 int n, i = 0;
872 for (; i < tail; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700873 burst[i] = psk8_table[7];
Tom Tsoud3253432016-03-06 03:08:01 -0800874
875 /* Body */
876 for (; i < tail + data; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700877 burst[i] = psk8_table[rand() % 8];
Tom Tsoud3253432016-03-06 03:08:01 -0800878
879 /* TSC */
880 for (n = 0; i < tail + data + train; i++, n++) {
881 unsigned index = (((unsigned) (*midamble)[3 * n + 0] & 0x01) << 0) |
882 (((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
883 (((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
884
Tom Tsou7278a872017-06-14 14:50:39 -0700885 burst[i] = psk8_table[index];
Tom Tsoud3253432016-03-06 03:08:01 -0800886 }
887
888 /* Body */
889 for (; i < tail + data + train + data; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700890 burst[i] = psk8_table[rand() % 8];
Tom Tsoud3253432016-03-06 03:08:01 -0800891
892 /* Tail */
893 for (; i < tail + data + train + data + tail; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700894 burst[i] = psk8_table[7];
Tom Tsoud3253432016-03-06 03:08:01 -0800895
Tom Tsou7278a872017-06-14 14:50:39 -0700896 return shapeEdgeBurst(burst);
Tom Tsoud3253432016-03-06 03:08:01 -0800897}
898
899/*
900 * Modulate 8-PSK burst. When empty pulse shaping (rotation only)
901 * is enabled, the output vector length will be bit sequence length
902 * times the SPS value. When pulse shaping is enabled, the output
Alexander Chemeris9270a5a2017-03-17 13:03:41 -0700903 * vector length is fixed at 625 samples (156.25 symbols at 4 SPS).
Tom Tsoud3253432016-03-06 03:08:01 -0800904 * Pulse shaped bit sequences that go beyond one burst are truncated.
905 * Pulse shaping at anything but 4 SPS is not supported.
906 */
907signalVector *modulateEdgeBurst(const BitVector &bits,
908 int sps, bool empty)
909{
910 signalVector *shape, *burst;
911
912 if ((sps != 4) && !empty)
913 return NULL;
914
915 burst = mapEdgeSymbols(bits);
916 if (!burst)
917 return NULL;
918
919 if (empty)
920 shape = rotateEdgeBurst(*burst, sps);
921 else
922 shape = shapeEdgeBurst(*burst);
923
924 delete burst;
925 return shape;
926}
927
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800928static signalVector *modulateBurstBasic(const BitVector &bits,
929 int guard_len, int sps)
930{
931 int burst_len;
Tom Tsou7278a872017-06-14 14:50:39 -0700932 signalVector *pulse;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800933 signalVector::iterator burst_itr;
934
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400935 if (sps == 1)
936 pulse = GSMPulse1->c0;
937 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800938 pulse = GSMPulse4->c0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400939
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800940 burst_len = sps * (bits.size() + guard_len);
941
Tom Tsou7278a872017-06-14 14:50:39 -0700942 signalVector burst(burst_len, pulse->size());
943 burst.isReal(true);
944 burst_itr = burst.begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800945
946 /* Raw bits are not differentially encoded */
947 for (unsigned i = 0; i < bits.size(); i++) {
948 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
949 burst_itr += sps;
950 }
951
Tom Tsou7278a872017-06-14 14:50:39 -0700952 GMSKRotate(burst, sps);
953 burst.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800954
955 /* Single Gaussian pulse approximation shaping */
Tom Tsou7278a872017-06-14 14:50:39 -0700956 return convolve(&burst, pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800957}
958
Thomas Tsou3eaae802013-08-20 19:31:14 -0400959/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400960signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
961 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000962{
Thomas Tsou83e06892013-08-20 16:10:01 -0400963 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800964 return rotateBurst(wBurst, guardPeriodLength, sps);
965 else if (sps == 4)
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800966 return modulateBurstLaurent(wBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -0400967 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800968 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000969}
970
Tom Tsou2079a3c2016-03-06 00:58:56 -0800971static void generateSincTable()
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500972{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500973 for (int i = 0; i < TABLESIZE; i++) {
Tom Tsoua3dce852017-06-16 17:14:31 -0700974 auto x = (double) i / TABLESIZE * 8 * M_PI;
975 auto y = sin(x) / x;
Tom Tsou35474132017-06-19 16:00:34 -0700976 sincTable[i] = std::isnan(y) ? 1.0 : y;
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500977 }
978}
979
Tom Tsou70134a02017-06-12 14:23:53 -0700980static float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000981{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500982 if (fabs(x) >= 8 * M_PI)
983 return 0.0;
984
985 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
986
987 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +0000988}
989
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600990/*
991 * Create fractional delay filterbank with Blackman-harris windowed
992 * sinc function generator. The number of filters generated is specified
993 * by the DELAYFILTS value.
994 */
Tom Tsou70134a02017-06-12 14:23:53 -0700995static void generateDelayFilters()
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600996{
997 int h_len = 20;
998 complex *data;
999 signalVector *h;
1000 signalVector::iterator itr;
1001
1002 float k, sum;
1003 float a0 = 0.35875;
1004 float a1 = 0.48829;
1005 float a2 = 0.14128;
1006 float a3 = 0.01168;
1007
1008 for (int i = 0; i < DELAYFILTS; i++) {
1009 data = (complex *) convolve_h_alloc(h_len);
Pau Espin Pedrolf7331762018-12-03 17:46:04 +01001010 h = new signalVector(data, 0, h_len, convolve_h_alloc, free);
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001011 h->setAligned(true);
1012 h->isReal(true);
1013
1014 sum = 0.0;
1015 itr = h->end();
1016 for (int n = 0; n < h_len; n++) {
1017 k = (float) n;
1018 *--itr = (complex) sinc(M_PI_F *
1019 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
1020 *itr *= a0 -
1021 a1 * cos(2 * M_PI * n / (h_len - 1)) +
1022 a2 * cos(4 * M_PI * n / (h_len - 1)) -
1023 a3 * cos(6 * M_PI * n / (h_len - 1));
1024
1025 sum += itr->real();
1026 }
1027
1028 itr = h->begin();
1029 for (int n = 0; n < h_len; n++)
1030 *itr++ /= sum;
1031
1032 delayFilters[i] = h;
1033 }
1034}
1035
Alexander Chemerise0c12182017-03-18 13:27:48 -07001036signalVector *delayVector(const signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +00001037{
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001038 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001039 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001040 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001041
Thomas Tsou2c282f52013-10-08 21:34:35 -04001042 whole = floor(delay);
1043 frac = delay - whole;
1044
1045 /* Sinc interpolated fractional shift (if allowable) */
1046 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001047 index = floorf(frac * (float) DELAYFILTS);
1048 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -04001049
Thomas Tsou94edaae2013-11-09 22:19:19 -05001050 fshift = convolve(in, h, NULL, NO_DELAY);
1051 if (!fshift)
1052 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001053 }
1054
Thomas Tsou94edaae2013-11-09 22:19:19 -05001055 if (!fshift)
1056 shift = new signalVector(*in);
1057 else
1058 shift = fshift;
1059
Thomas Tsou2c282f52013-10-08 21:34:35 -04001060 /* Integer sample shift */
1061 if (whole < 0) {
1062 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001063 signalVector::iterator wBurstItr = shift->begin();
1064 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001065
Thomas Tsou94edaae2013-11-09 22:19:19 -05001066 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +00001067 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001068
Thomas Tsou94edaae2013-11-09 22:19:19 -05001069 while (wBurstItr < shift->end())
1070 *wBurstItr++ = 0.0;
1071 } else if (whole >= 0) {
1072 signalVector::iterator wBurstItr = shift->end() - 1;
1073 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
1074
1075 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001076 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001077
1078 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001079 *wBurstItr-- = 0.0;
1080 }
Thomas Tsou2c282f52013-10-08 21:34:35 -04001081
Thomas Tsou94edaae2013-11-09 22:19:19 -05001082 if (!out)
1083 return shift;
1084
1085 out->clone(*shift);
1086 delete shift;
1087 return out;
dburgessb3a0ca42011-10-12 07:44:40 +00001088}
Thomas Tsou2c282f52013-10-08 21:34:35 -04001089
Tom Tsou70134a02017-06-12 14:23:53 -07001090static complex interpolatePoint(const signalVector &inSig, float ix)
dburgessb3a0ca42011-10-12 07:44:40 +00001091{
dburgessb3a0ca42011-10-12 07:44:40 +00001092 int start = (int) (floor(ix) - 10);
1093 if (start < 0) start = 0;
1094 int end = (int) (floor(ix) + 11);
1095 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001096
dburgessb3a0ca42011-10-12 07:44:40 +00001097 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001098 if (!inSig.isReal()) {
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001099 for (int i = start; i < end; i++)
dburgessb3a0ca42011-10-12 07:44:40 +00001100 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
1101 }
1102 else {
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001103 for (int i = start; i < end; i++)
dburgessb3a0ca42011-10-12 07:44:40 +00001104 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
1105 }
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001106
dburgessb3a0ca42011-10-12 07:44:40 +00001107 return pVal;
1108}
1109
Thomas Tsou8181b012013-08-20 21:17:19 -04001110static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1111{
1112 float val, max = 0.0f;
1113 complex amp;
1114 int _index = -1;
1115
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001116 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001117 val = rxBurst[i].norm2();
1118 if (val > max) {
1119 max = val;
1120 _index = i;
1121 amp = rxBurst[i];
1122 }
1123 }
1124
1125 if (index)
1126 *index = (float) _index;
1127
1128 return amp;
1129}
1130
Tom Tsou70134a02017-06-12 14:23:53 -07001131static complex peakDetect(const signalVector &rxBurst,
1132 float *peakIndex, float *avgPwr)
dburgessb3a0ca42011-10-12 07:44:40 +00001133{
dburgessb3a0ca42011-10-12 07:44:40 +00001134 complex maxVal = 0.0;
1135 float maxIndex = -1;
1136 float sumPower = 0.0;
1137
1138 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1139 float samplePower = rxBurst[i].norm2();
1140 if (samplePower > maxVal.real()) {
1141 maxVal = samplePower;
1142 maxIndex = i;
1143 }
1144 sumPower += samplePower;
1145 }
1146
1147 // interpolate around the peak
1148 // to save computation, we'll use early-late balancing
1149 float earlyIndex = maxIndex-1;
1150 float lateIndex = maxIndex+1;
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001151
dburgessb3a0ca42011-10-12 07:44:40 +00001152 float incr = 0.5;
1153 while (incr > 1.0/1024.0) {
1154 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1155 complex lateP = interpolatePoint(rxBurst,lateIndex);
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001156 if (earlyP < lateP)
dburgessb3a0ca42011-10-12 07:44:40 +00001157 earlyIndex += incr;
1158 else if (earlyP > lateP)
1159 earlyIndex -= incr;
1160 else break;
1161 incr /= 2.0;
1162 lateIndex = earlyIndex + 2.0;
1163 }
1164
1165 maxIndex = earlyIndex + 1.0;
1166 maxVal = interpolatePoint(rxBurst,maxIndex);
1167
1168 if (peakIndex!=NULL)
1169 *peakIndex = maxIndex;
1170
1171 if (avgPwr!=NULL)
1172 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1173
1174 return maxVal;
1175
1176}
1177
1178void scaleVector(signalVector &x,
1179 complex scale)
1180{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001181#ifdef HAVE_NEON
1182 int len = x.size();
1183
1184 scale_complex((float *) x.begin(),
1185 (float *) x.begin(),
1186 (float *) &scale, len);
1187#else
dburgessb3a0ca42011-10-12 07:44:40 +00001188 signalVector::iterator xP = x.begin();
1189 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001190 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001191 while (xP < xPEnd) {
1192 *xP = *xP * scale;
1193 xP++;
1194 }
1195 }
1196 else {
1197 while (xP < xPEnd) {
1198 *xP = xP->real() * scale;
1199 xP++;
1200 }
1201 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001202#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001203}
1204
1205/** in-place conjugation */
Tom Tsou70134a02017-06-12 14:23:53 -07001206static void conjugateVector(signalVector &x)
dburgessb3a0ca42011-10-12 07:44:40 +00001207{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001208 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001209 signalVector::iterator xP = x.begin();
1210 signalVector::iterator xPEnd = x.end();
1211 while (xP < xPEnd) {
1212 *xP = xP->conj();
1213 xP++;
1214 }
1215}
1216
Tom Tsou2079a3c2016-03-06 00:58:56 -08001217static bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001218{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001219 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001220 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001221 complex *data = NULL;
1222 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001223 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001224
Thomas Tsou3eaae802013-08-20 19:31:14 -04001225 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001226 return false;
1227
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001228 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001229
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001230 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1231 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1232 if (!midMidamble)
1233 return false;
1234
Thomas Tsou3eaae802013-08-20 19:31:14 -04001235 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001236 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1237 if (!midamble) {
1238 status = false;
1239 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001240 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001241
dburgessb3a0ca42011-10-12 07:44:40 +00001242 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1243 // the ideal TSC has an + 180 degree phase shift,
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001244 // due to the pi/2 frequency shift, that
dburgessb3a0ca42011-10-12 07:44:40 +00001245 // needs to be accounted for.
1246 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001247 scaleVector(*midMidamble, complex(-1.0, 0.0));
1248 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001249
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001250 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001251
Thomas Tsou3eaae802013-08-20 19:31:14 -04001252 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1253 data = (complex *) convolve_h_alloc(midMidamble->size());
Pau Espin Pedrolf7331762018-12-03 17:46:04 +01001254 _midMidamble = new signalVector(data, 0, midMidamble->size(), convolve_h_alloc, free);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001255 _midMidamble->setAligned(true);
Pau Espin Pedrol5e68cde2018-08-30 20:45:14 +02001256 midMidamble->copyTo(*_midMidamble);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001257
1258 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001259 if (!autocorr) {
1260 status = false;
1261 goto release;
1262 }
dburgessb3a0ca42011-10-12 07:44:40 +00001263
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001264 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001265 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001266 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1267
1268 /* For 1 sps only
1269 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1270 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1271 */
1272 if (sps == 1)
1273 gMidambles[tsc]->toa = toa - 13.5;
1274 else
1275 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001276
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001277release:
dburgessb3a0ca42011-10-12 07:44:40 +00001278 delete autocorr;
1279 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001280 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001281
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001282 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001283 delete _midMidamble;
1284 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001285 gMidambles[tsc] = NULL;
1286 }
1287
1288 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001289}
1290
Tom Tsou70134a02017-06-12 14:23:53 -07001291static CorrelationSequence *generateEdgeMidamble(int tsc)
Tom Tsoud3253432016-03-06 03:08:01 -08001292{
1293 complex *data = NULL;
1294 signalVector *midamble = NULL, *_midamble = NULL;
1295 CorrelationSequence *seq;
1296
1297 if ((tsc < 0) || (tsc > 7))
1298 return NULL;
1299
1300 /* Use middle 48 bits of each TSC. Correlation sequence is not pulse shaped */
1301 const BitVector *bits = &gEdgeTrainingSequence[tsc];
1302 midamble = modulateEdgeBurst(bits->segment(15, 48), 1, true);
1303 if (!midamble)
1304 return NULL;
1305
1306 conjugateVector(*midamble);
1307
1308 data = (complex *) convolve_h_alloc(midamble->size());
Pau Espin Pedrolf7331762018-12-03 17:46:04 +01001309 _midamble = new signalVector(data, 0, midamble->size(), convolve_h_alloc, free);
Tom Tsoud3253432016-03-06 03:08:01 -08001310 _midamble->setAligned(true);
Pau Espin Pedrol5e68cde2018-08-30 20:45:14 +02001311 midamble->copyTo(*_midamble);
Tom Tsoud3253432016-03-06 03:08:01 -08001312
1313 /* Channel gain is an empirically measured value */
1314 seq = new CorrelationSequence;
Tom Tsoud3253432016-03-06 03:08:01 -08001315 seq->sequence = _midamble;
1316 seq->gain = Complex<float>(-19.6432, 19.5006) / 1.18;
1317 seq->toa = 0;
1318
1319 delete midamble;
1320
1321 return seq;
1322}
1323
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001324static bool generateRACHSequence(CorrelationSequence **seq, const BitVector &bv, int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001325{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001326 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001327 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001328 complex *data = NULL;
1329 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001330 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001331
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001332 if (*seq != NULL)
1333 delete *seq;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001334
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001335 seq0 = modulateBurst(bv, 0, sps, false);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001336 if (!seq0)
1337 return false;
1338
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001339 seq1 = modulateBurst(bv.segment(0, 40), 0, sps, true);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001340 if (!seq1) {
1341 status = false;
1342 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001343 }
1344
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001345 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001346
Thomas Tsou3eaae802013-08-20 19:31:14 -04001347 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1348 data = (complex *) convolve_h_alloc(seq1->size());
Pau Espin Pedrolf7331762018-12-03 17:46:04 +01001349 _seq1 = new signalVector(data, 0, seq1->size(), convolve_h_alloc, free);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001350 _seq1->setAligned(true);
Pau Espin Pedrol5e68cde2018-08-30 20:45:14 +02001351 seq1->copyTo(*_seq1);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001352
1353 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1354 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001355 status = false;
1356 goto release;
1357 }
dburgessb3a0ca42011-10-12 07:44:40 +00001358
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001359 *seq = new CorrelationSequence;
1360 (*seq)->sequence = _seq1;
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001361 (*seq)->gain = peakDetect(*autocorr, &toa, NULL);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001362
1363 /* For 1 sps only
1364 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1365 * 20.5 = (40 / 2 - 1) + 1.5
1366 */
1367 if (sps == 1)
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001368 (*seq)->toa = toa - 20.5;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001369 else
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001370 (*seq)->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001371
1372release:
dburgessb3a0ca42011-10-12 07:44:40 +00001373 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001374 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001375 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001376
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001377 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001378 delete _seq1;
1379 free(data);
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001380 *seq = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001381 }
dburgessb3a0ca42011-10-12 07:44:40 +00001382
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001383 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001384}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001385
Tom Tsoua84e1622016-06-29 14:50:25 -07001386/*
1387 * Peak-to-average computation +/- range from peak in symbols
1388 */
1389#define COMPUTE_PEAK_MIN 2
1390#define COMPUTE_PEAK_MAX 5
1391
1392/*
1393 * Minimum number of values needed to compute peak-to-average
1394 */
1395#define COMPUTE_PEAK_CNT 5
1396
Thomas Tsou865bca42013-08-21 20:58:00 -04001397static float computePeakRatio(signalVector *corr,
1398 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001399{
Thomas Tsou865bca42013-08-21 20:58:00 -04001400 int num = 0;
1401 complex *peak;
1402 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001403
Thomas Tsou865bca42013-08-21 20:58:00 -04001404 /* Check for bogus results */
1405 if ((toa < 0.0) || (toa > corr->size()))
1406 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001407
Alexander Chemeris1e9b4d52015-06-04 19:05:28 -04001408 peak = corr->begin() + (int) rint(toa);
1409
Tom Tsoua84e1622016-06-29 14:50:25 -07001410 for (int i = COMPUTE_PEAK_MIN * sps; i <= COMPUTE_PEAK_MAX * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001411 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001412 avg += (peak - i)->norm2();
1413 num++;
1414 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001415 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001416 avg += (peak + i)->norm2();
1417 num++;
1418 }
dburgessb3a0ca42011-10-12 07:44:40 +00001419 }
1420
Tom Tsoua84e1622016-06-29 14:50:25 -07001421 if (num < COMPUTE_PEAK_CNT)
Thomas Tsou865bca42013-08-21 20:58:00 -04001422 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001423
Thomas Tsou3eaae802013-08-20 19:31:14 -04001424 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001425
Thomas Tsou865bca42013-08-21 20:58:00 -04001426 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001427}
1428
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001429float energyDetect(const signalVector &rxBurst, unsigned windowLength)
dburgessb3a0ca42011-10-12 07:44:40 +00001430{
1431
1432 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1433 float energy = 0.0;
Tom Tsou2af14402017-03-23 14:54:00 -07001434 if (windowLength == 0) return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001435 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1436 for (unsigned i = 0; i < windowLength; i++) {
1437 energy += windowItr->norm2();
1438 windowItr+=4;
1439 }
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +03001440 return energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001441}
dburgessb3a0ca42011-10-12 07:44:40 +00001442
Tom Tsou70134a02017-06-12 14:23:53 -07001443static signalVector *downsampleBurst(const signalVector &burst)
1444{
Tom Tsou7278a872017-06-14 14:50:39 -07001445 signalVector in(DOWNSAMPLE_IN_LEN, dnsampler->len());
1446 signalVector *out = new signalVector(DOWNSAMPLE_OUT_LEN);
Pau Espin Pedrol5e68cde2018-08-30 20:45:14 +02001447 burst.copyToSegment(in, 0, DOWNSAMPLE_IN_LEN);
Tom Tsou70134a02017-06-12 14:23:53 -07001448
Tom Tsou7278a872017-06-14 14:50:39 -07001449 if (dnsampler->rotate((float *) in.begin(), DOWNSAMPLE_IN_LEN,
Tom Tsou70134a02017-06-12 14:23:53 -07001450 (float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
1451 delete out;
1452 out = NULL;
1453 }
1454
Tom Tsou70134a02017-06-12 14:23:53 -07001455 return out;
1456};
1457
Thomas Tsou865bca42013-08-21 20:58:00 -04001458/*
1459 * Detect a burst based on correlation and peak-to-average ratio
1460 *
1461 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1462 * for initial gating. We do this because energy detection should be disabled.
1463 * For higher oversampling values, we assume the energy detector is in place
1464 * and we run full interpolating peak detection.
1465 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001466static int detectBurst(const signalVector &burst,
Thomas Tsou865bca42013-08-21 20:58:00 -04001467 signalVector &corr, CorrelationSequence *sync,
1468 float thresh, int sps, complex *amp, float *toa,
1469 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001470{
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001471 const signalVector *corr_in;
1472 signalVector *dec = NULL;
Tom Tsoud3253432016-03-06 03:08:01 -08001473
1474 if (sps == 4) {
1475 dec = downsampleBurst(burst);
1476 corr_in = dec;
1477 sps = 1;
1478 } else {
1479 corr_in = &burst;
1480 }
1481
Thomas Tsou865bca42013-08-21 20:58:00 -04001482 /* Correlate */
Tom Tsoud3253432016-03-06 03:08:01 -08001483 if (!convolve(corr_in, sync->sequence, &corr,
Sylvain Munauta3934a12018-12-20 19:10:26 +01001484 CUSTOM, start, len)) {
Tom Tsoud3253432016-03-06 03:08:01 -08001485 delete dec;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001486 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001487 }
1488
Tom Tsoud3253432016-03-06 03:08:01 -08001489 delete dec;
1490
1491 /* Running at the downsampled rate at this point */
1492 sps = 1;
1493
Thomas Tsou865bca42013-08-21 20:58:00 -04001494 /* Peak detection - place restrictions at correlation edges */
1495 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001496
Thomas Tsou865bca42013-08-21 20:58:00 -04001497 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1498 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001499
Thomas Tsou865bca42013-08-21 20:58:00 -04001500 /* Peak -to-average ratio */
1501 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1502 return 0;
1503
1504 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1505 *amp = peakDetect(corr, toa, NULL);
1506
1507 /* Normalize our channel gain */
1508 *amp = *amp / sync->gain;
1509
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001510 /* Compensate for residuate time lag */
1511 *toa = *toa - sync->toa;
1512
Thomas Tsou865bca42013-08-21 20:58:00 -04001513 return 1;
1514}
1515
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001516static float maxAmplitude(const signalVector &burst)
Tom Tsou577cd022015-05-18 13:57:54 -07001517{
Alexander Chemeris954b1182015-06-04 15:39:41 -04001518 float max = 0.0;
1519 for (size_t i = 0; i < burst.size(); i++) {
1520 if (fabs(burst[i].real()) > max)
1521 max = fabs(burst[i].real());
1522 if (fabs(burst[i].imag()) > max)
1523 max = fabs(burst[i].imag());
1524 }
Tom Tsou577cd022015-05-18 13:57:54 -07001525
Alexander Chemeris954b1182015-06-04 15:39:41 -04001526 return max;
Tom Tsou577cd022015-05-18 13:57:54 -07001527}
1528
Alexander Chemeris130a8002015-06-09 20:52:11 -04001529/*
1530 * RACH/Normal burst detection with clipping detection
Thomas Tsou865bca42013-08-21 20:58:00 -04001531 *
1532 * Correlation window parameters:
Alexander Chemeris130a8002015-06-09 20:52:11 -04001533 * target: Tail bits + burst length
1534 * head: Search symbols before target
1535 * tail: Search symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001536 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001537static int detectGeneralBurst(const signalVector &rxBurst,
1538 float thresh,
1539 int sps,
1540 complex &amp,
1541 float &toa,
1542 int target, int head, int tail,
1543 CorrelationSequence *sync)
Thomas Tsou865bca42013-08-21 20:58:00 -04001544{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001545 int rc, start, len;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001546 bool clipping = false;
Thomas Tsou865bca42013-08-21 20:58:00 -04001547
1548 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001549 return -SIGERR_UNSUPPORTED;
1550
Alexander Chemeris954b1182015-06-04 15:39:41 -04001551 // Detect potential clipping
1552 // We still may be able to demod the burst, so we'll give it a try
1553 // and only report clipping if we can't demod.
1554 float maxAmpl = maxAmplitude(rxBurst);
1555 if (maxAmpl > CLIP_THRESH) {
1556 LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
1557 clipping = true;
1558 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001559
Tom Tsoud3253432016-03-06 03:08:01 -08001560 start = target - head - 1;
1561 len = head + tail;
Tom Tsou7278a872017-06-14 14:50:39 -07001562 signalVector corr(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001563
Tom Tsou7278a872017-06-14 14:50:39 -07001564 rc = detectBurst(rxBurst, corr, sync,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001565 thresh, sps, &amp, &toa, start, len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001566 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001567 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001568 } else if (!rc) {
Alexander Chemeris130a8002015-06-09 20:52:11 -04001569 amp = 0.0f;
1570 toa = 0.0f;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001571 return clipping?-SIGERR_CLIP:SIGERR_NONE;
dburgessb3a0ca42011-10-12 07:44:40 +00001572 }
1573
Thomas Tsou865bca42013-08-21 20:58:00 -04001574 /* Subtract forward search bits from delay */
Tom Tsoud3253432016-03-06 03:08:01 -08001575 toa -= head;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001576
Thomas Tsou865bca42013-08-21 20:58:00 -04001577 return 1;
1578}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001579
Alexander Chemeris130a8002015-06-09 20:52:11 -04001580
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001581/*
Alexander Chemeris130a8002015-06-09 20:52:11 -04001582 * RACH burst detection
1583 *
1584 * Correlation window parameters:
1585 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Tom Tsoue90c24c2016-06-21 16:14:39 -07001586 * head: Search 8 symbols before target
1587 * tail: Search 8 symbols + maximum expected delay
Alexander Chemeris130a8002015-06-09 20:52:11 -04001588 */
Tom Tsou70134a02017-06-12 14:23:53 -07001589static int detectRACHBurst(const signalVector &burst, float threshold, int sps,
Vadim Yanitskiy444ff342018-10-22 02:25:23 +02001590 complex &amplitude, float &toa, unsigned max_toa, bool ext)
Alexander Chemeris130a8002015-06-09 20:52:11 -04001591{
1592 int rc, target, head, tail;
Vadim Yanitskiy444ff342018-10-22 02:25:23 +02001593 int i, num_seq;
Alexander Chemeris130a8002015-06-09 20:52:11 -04001594
1595 target = 8 + 40;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001596 head = 8;
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001597 tail = 8 + max_toa;
Vadim Yanitskiy444ff342018-10-22 02:25:23 +02001598 num_seq = ext ? 3 : 1;
Alexander Chemeris130a8002015-06-09 20:52:11 -04001599
Vadim Yanitskiy444ff342018-10-22 02:25:23 +02001600 for (i = 0; i < num_seq; i++) {
1601 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
1602 target, head, tail, gRACHSequences[i]);
1603 if (rc > 0)
1604 break;
1605 }
Alexander Chemeris130a8002015-06-09 20:52:11 -04001606
1607 return rc;
1608}
1609
Pau Espin Pedrol21ce05c2018-08-30 20:47:20 +02001610/*
Thomas Tsou865bca42013-08-21 20:58:00 -04001611 * Normal burst detection
1612 *
1613 * Correlation window parameters:
1614 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Tom Tsoue90c24c2016-06-21 16:14:39 -07001615 * head: Search 6 symbols before target
1616 * tail: Search 6 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001617 */
Tom Tsou70134a02017-06-12 14:23:53 -07001618static int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float threshold,
1619 int sps, complex &amplitude, float &toa, unsigned max_toa)
Thomas Tsou865bca42013-08-21 20:58:00 -04001620{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001621 int rc, target, head, tail;
Thomas Tsou865bca42013-08-21 20:58:00 -04001622 CorrelationSequence *sync;
1623
Tom Tsouae91f132017-03-28 14:40:38 -07001624 if (tsc > 7)
Tom Tsou577cd022015-05-18 13:57:54 -07001625 return -SIGERR_UNSUPPORTED;
1626
Thomas Tsou865bca42013-08-21 20:58:00 -04001627 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001628 head = 6;
1629 tail = 6 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001630 sync = gMidambles[tsc];
Thomas Tsou865bca42013-08-21 20:58:00 -04001631
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001632 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001633 target, head, tail, sync);
Alexander Chemeris130a8002015-06-09 20:52:11 -04001634 return rc;
dburgessb3a0ca42011-10-12 07:44:40 +00001635}
1636
Tom Tsou70134a02017-06-12 14:23:53 -07001637static int detectEdgeBurst(const signalVector &burst, unsigned tsc, float threshold,
1638 int sps, complex &amplitude, float &toa, unsigned max_toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001639{
1640 int rc, target, head, tail;
1641 CorrelationSequence *sync;
1642
Tom Tsouae91f132017-03-28 14:40:38 -07001643 if (tsc > 7)
Tom Tsoud3253432016-03-06 03:08:01 -08001644 return -SIGERR_UNSUPPORTED;
1645
1646 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001647 head = 6;
1648 tail = 6 + max_toa;
Tom Tsoud3253432016-03-06 03:08:01 -08001649 sync = gEdgeMidambles[tsc];
1650
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001651 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Tom Tsoud3253432016-03-06 03:08:01 -08001652 target, head, tail, sync);
1653 return rc;
1654}
1655
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001656int detectAnyBurst(const signalVector &burst, unsigned tsc, float threshold,
Alexander Chemeris4e6c9382017-03-17 15:24:18 -07001657 int sps, CorrType type, complex &amp, float &toa,
1658 unsigned max_toa)
1659{
1660 int rc = 0;
1661
1662 switch (type) {
1663 case EDGE:
1664 rc = detectEdgeBurst(burst, tsc, threshold, sps,
1665 amp, toa, max_toa);
1666 if (rc > 0)
1667 break;
1668 else
1669 type = TSC;
1670 case TSC:
1671 rc = analyzeTrafficBurst(burst, tsc, threshold, sps,
1672 amp, toa, max_toa);
1673 break;
Vadim Yanitskiy444ff342018-10-22 02:25:23 +02001674 case EXT_RACH:
Alexander Chemeris4e6c9382017-03-17 15:24:18 -07001675 case RACH:
1676 rc = detectRACHBurst(burst, threshold, sps, amp, toa,
Vadim Yanitskiy444ff342018-10-22 02:25:23 +02001677 max_toa, type == EXT_RACH);
Alexander Chemeris4e6c9382017-03-17 15:24:18 -07001678 break;
1679 default:
1680 LOG(ERR) << "Invalid correlation type";
1681 }
1682
1683 if (rc > 0)
1684 return type;
1685
1686 return rc;
1687}
1688
Tom Tsoud3253432016-03-06 03:08:01 -08001689/*
1690 * Soft 8-PSK decoding using Manhattan distance metric
1691 */
1692static SoftVector *softSliceEdgeBurst(signalVector &burst)
1693{
1694 size_t nsyms = 148;
1695
1696 if (burst.size() < nsyms)
1697 return NULL;
1698
1699 signalVector::iterator itr;
1700 SoftVector *bits = new SoftVector(nsyms * 3);
1701
1702 /*
1703 * Bits 0 and 1 - First and second bits of the symbol respectively
1704 */
1705 rotateBurst2(burst, -M_PI / 8.0);
1706 itr = burst.begin();
1707 for (size_t i = 0; i < nsyms; i++) {
1708 (*bits)[3 * i + 0] = -itr->imag();
1709 (*bits)[3 * i + 1] = itr->real();
1710 itr++;
1711 }
1712
1713 /*
1714 * Bit 2 - Collapse symbols into quadrant 0 (positive X and Y).
1715 * Decision area is then simplified to X=Y axis. Rotate again to
1716 * place decision boundary on X-axis.
1717 */
1718 itr = burst.begin();
1719 for (size_t i = 0; i < burst.size(); i++) {
1720 burst[i] = Complex<float>(fabs(itr->real()), fabs(itr->imag()));
1721 itr++;
1722 }
1723
1724 rotateBurst2(burst, -M_PI / 4.0);
1725 itr = burst.begin();
1726 for (size_t i = 0; i < nsyms; i++) {
1727 (*bits)[3 * i + 2] = -itr->imag();
1728 itr++;
1729 }
1730
1731 signalVector soft(bits->size());
1732 for (size_t i = 0; i < bits->size(); i++)
1733 soft[i] = (*bits)[i];
1734
1735 return bits;
1736}
1737
1738/*
Alexander Chemeris132fb242017-03-17 17:22:33 -07001739 * Convert signalVector to SoftVector by taking real part of the signal.
1740 */
1741static SoftVector *signalToSoftVector(signalVector *dec)
1742{
1743 SoftVector *bits = new SoftVector(dec->size());
1744
1745 SoftVector::iterator bit_itr = bits->begin();
1746 signalVector::iterator burst_itr = dec->begin();
1747
1748 for (; burst_itr < dec->end(); burst_itr++)
1749 *bit_itr++ = burst_itr->real();
1750
1751 return bits;
1752}
1753
1754/*
Tom Tsou7fec3032016-03-06 22:33:20 -08001755 * Shared portion of GMSK and EDGE demodulators consisting of timing
1756 * recovery and single tap channel correction. For 4 SPS (if activated),
1757 * the output is downsampled prior to the 1 SPS modulation specific
1758 * stages.
1759 */
Alexander Chemerise0c12182017-03-18 13:27:48 -07001760static signalVector *demodCommon(const signalVector &burst, int sps,
Tom Tsou7fec3032016-03-06 22:33:20 -08001761 complex chan, float toa)
1762{
1763 signalVector *delay, *dec;
1764
1765 if ((sps != 1) && (sps != 4))
1766 return NULL;
1767
Tom Tsou7fec3032016-03-06 22:33:20 -08001768 delay = delayVector(&burst, NULL, -toa * (float) sps);
Alexander Chemerise0c12182017-03-18 13:27:48 -07001769 scaleVector(*delay, (complex) 1.0 / chan);
Tom Tsou7fec3032016-03-06 22:33:20 -08001770
1771 if (sps == 1)
1772 return delay;
1773
1774 dec = downsampleBurst(*delay);
1775
1776 delete delay;
1777 return dec;
1778}
1779
1780/*
Tom Tsoud3253432016-03-06 03:08:01 -08001781 * Demodulate GSMK burst. Prior to symbol rotation, operate at
1782 * 4 SPS (if activated) to minimize distortion through the fractional
1783 * delay filters. Symbol rotation and after always operates at 1 SPS.
1784 */
Tom Tsou70134a02017-06-12 14:23:53 -07001785static SoftVector *demodGmskBurst(const signalVector &rxBurst,
1786 int sps, complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001787{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001788 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08001789 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001790
Tom Tsou7fec3032016-03-06 22:33:20 -08001791 dec = demodCommon(rxBurst, sps, channel, TOA);
1792 if (!dec)
1793 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001794
Tom Tsoud3253432016-03-06 03:08:01 -08001795 /* Shift up by a quarter of a frequency */
1796 GMSKReverseRotate(*dec, 1);
Alexander Chemeris132fb242017-03-17 17:22:33 -07001797 /* Take real part of the signal */
1798 bits = signalToSoftVector(dec);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001799 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001800
Thomas Tsou94edaae2013-11-09 22:19:19 -05001801 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001802}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001803
Tom Tsoud3253432016-03-06 03:08:01 -08001804/*
1805 * Demodulate an 8-PSK burst. Prior to symbol rotation, operate at
1806 * 4 SPS (if activated) to minimize distortion through the fractional
1807 * delay filters. Symbol rotation and after always operates at 1 SPS.
1808 *
1809 * Allow 1 SPS demodulation here, but note that other parts of the
1810 * transceiver restrict EDGE operatoin to 4 SPS - 8-PSK distortion
1811 * through the fractional delay filters at 1 SPS renders signal
1812 * nearly unrecoverable.
1813 */
Tom Tsou70134a02017-06-12 14:23:53 -07001814static SoftVector *demodEdgeBurst(const signalVector &burst,
1815 int sps, complex chan, float toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001816{
1817 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08001818 signalVector *dec, *rot, *eq;
Tom Tsoud3253432016-03-06 03:08:01 -08001819
Tom Tsou7fec3032016-03-06 22:33:20 -08001820 dec = demodCommon(burst, sps, chan, toa);
1821 if (!dec)
Tom Tsoud3253432016-03-06 03:08:01 -08001822 return NULL;
1823
Tom Tsou7fec3032016-03-06 22:33:20 -08001824 /* Equalize and derotate */
Tom Tsoud3253432016-03-06 03:08:01 -08001825 eq = convolve(dec, GSMPulse4->c0_inv, NULL, NO_DELAY);
1826 rot = derotateEdgeBurst(*eq, 1);
1827
Tom Tsou7fec3032016-03-06 22:33:20 -08001828 /* Soft slice and normalize */
Tom Tsou04795622016-04-26 21:17:36 -07001829 bits = softSliceEdgeBurst(*rot);
Tom Tsoud3253432016-03-06 03:08:01 -08001830
1831 delete dec;
1832 delete eq;
1833 delete rot;
1834
1835 return bits;
1836}
1837
Alexander Chemerise0c12182017-03-18 13:27:48 -07001838SoftVector *demodAnyBurst(const signalVector &burst, int sps, complex amp,
Alexander Chemeris6e1dffd2017-03-17 16:13:51 -07001839 float toa, CorrType type)
1840{
1841 if (type == EDGE)
1842 return demodEdgeBurst(burst, sps, amp, toa);
1843 else
1844 return demodGmskBurst(burst, sps, amp, toa);
1845}
1846
Tom Tsou2079a3c2016-03-06 00:58:56 -08001847bool sigProcLibSetup()
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001848{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001849 generateSincTable();
Tom Tsou2079a3c2016-03-06 00:58:56 -08001850 initGMSKRotationTables();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001851
Tom Tsou2079a3c2016-03-06 00:58:56 -08001852 GSMPulse1 = generateGSMPulse(1);
1853 GSMPulse4 = generateGSMPulse(4);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001854
Vadim Yanitskiya79bc702018-10-17 11:01:58 +02001855 generateRACHSequence(&gRACHSequences[0], gRACHSynchSequenceTS0, 1);
1856 generateRACHSequence(&gRACHSequences[1], gRACHSynchSequenceTS1, 1);
1857 generateRACHSequence(&gRACHSequences[2], gRACHSynchSequenceTS2, 1);
1858
Tom Tsoud3253432016-03-06 03:08:01 -08001859 for (int tsc = 0; tsc < 8; tsc++) {
Tom Tsou2079a3c2016-03-06 00:58:56 -08001860 generateMidamble(1, tsc);
Tom Tsoud3253432016-03-06 03:08:01 -08001861 gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);
1862 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001863
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001864 generateDelayFilters();
1865
Tom Tsoud3253432016-03-06 03:08:01 -08001866 dnsampler = new Resampler(1, 4);
1867 if (!dnsampler->init()) {
1868 LOG(ALERT) << "Rx resampler failed to initialize";
1869 goto fail;
1870 }
1871
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001872 return true;
Tom Tsoud3253432016-03-06 03:08:01 -08001873
1874fail:
1875 sigProcLibDestroy();
1876 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001877}