blob: a72ec431daea220b82ddef956e4712c1c9edee71 [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 Tsou70134a02017-06-12 14:23:53 -070049static float cosTable[TABLESIZE+1]; // add 1 element for wrap around
50static float sinTable[TABLESIZE+1];
51static float sincTable[TABLESIZE+1];
dburgessb3a0ca42011-10-12 07:44:40 +000052
53/** Constants */
54static const float M_PI_F = (float)M_PI;
55static const float M_2PI_F = (float)(2.0*M_PI);
56static const float M_1_2PI_F = 1/M_2PI_F;
57
Thomas Tsouc1f7c422013-10-11 13:49:55 -040058/* Precomputed rotation vectors */
Tom Tsou2079a3c2016-03-06 00:58:56 -080059static signalVector *GMSKRotation4 = NULL;
60static signalVector *GMSKReverseRotation4 = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040061static signalVector *GMSKRotation1 = NULL;
62static signalVector *GMSKReverseRotation1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000063
Thomas Tsouf79c4d02013-11-09 15:51:56 -060064/* Precomputed fractional delay filters */
65static signalVector *delayFilters[DELAYFILTS];
66
Tom Tsou70134a02017-06-12 14:23:53 -070067static const Complex<float> psk8_table[8] = {
Tom Tsoud3253432016-03-06 03:08:01 -080068 Complex<float>(-0.70710678, 0.70710678),
69 Complex<float>( 0.0, -1.0),
70 Complex<float>( 0.0, 1.0),
71 Complex<float>( 0.70710678, -0.70710678),
72 Complex<float>(-1.0, 0.0),
73 Complex<float>(-0.70710678, -0.70710678),
74 Complex<float>( 0.70710678, 0.70710678),
75 Complex<float>( 1.0, 0.0),
76};
77
78/* Downsampling filterbank - 4 SPS to 1 SPS */
79#define DOWNSAMPLE_IN_LEN 624
80#define DOWNSAMPLE_OUT_LEN 156
81
82static Resampler *dnsampler = NULL;
Tom Tsoud3253432016-03-06 03:08:01 -080083
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040084/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040085 * RACH and midamble correlation waveforms. Store the buffer separately
86 * because we need to allocate it explicitly outside of the signal vector
87 * constructor. This is because C++ (prior to C++11) is unable to natively
88 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040089 */
90struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040091 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040092 {
93 }
94
95 ~CorrelationSequence()
96 {
97 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040098 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040099 }
100
dburgessb3a0ca42011-10-12 07:44:40 +0000101 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400102 void *buffer;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400103 float toa;
dburgessb3a0ca42011-10-12 07:44:40 +0000104 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400105};
dburgessb3a0ca42011-10-12 07:44:40 +0000106
Thomas Tsou83e06892013-08-20 16:10:01 -0400107/*
Thomas Tsou3eaae802013-08-20 19:31:14 -0400108 * Gaussian and empty modulation pulses. Like the correlation sequences,
109 * store the runtime (Gaussian) buffer separately because of needed alignment
110 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -0400111 */
112struct PulseSequence {
Tom Tsoud3253432016-03-06 03:08:01 -0800113 PulseSequence() : c0(NULL), c1(NULL), c0_inv(NULL), empty(NULL),
114 c0_buffer(NULL), c1_buffer(NULL), c0_inv_buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -0400115 {
116 }
117
118 ~PulseSequence()
119 {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800120 delete c0;
121 delete c1;
Tom Tsoud3253432016-03-06 03:08:01 -0800122 delete c0_inv;
Thomas Tsou83e06892013-08-20 16:10:01 -0400123 delete empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800124 free(c0_buffer);
125 free(c1_buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -0400126 }
127
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800128 signalVector *c0;
129 signalVector *c1;
Tom Tsoud3253432016-03-06 03:08:01 -0800130 signalVector *c0_inv;
Thomas Tsou83e06892013-08-20 16:10:01 -0400131 signalVector *empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800132 void *c0_buffer;
133 void *c1_buffer;
Tom Tsoud3253432016-03-06 03:08:01 -0800134 void *c0_inv_buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -0400135};
136
Tom Tsoud3253432016-03-06 03:08:01 -0800137static CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
138static CorrelationSequence *gEdgeMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
139static CorrelationSequence *gRACHSequence = NULL;
140static PulseSequence *GSMPulse1 = NULL;
141static PulseSequence *GSMPulse4 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000142
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400143void sigProcLibDestroy()
144{
dburgessb3a0ca42011-10-12 07:44:40 +0000145 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400146 delete gMidambles[i];
Tom Tsoud3253432016-03-06 03:08:01 -0800147 delete gEdgeMidambles[i];
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400148 gMidambles[i] = NULL;
Tom Tsoud3253432016-03-06 03:08:01 -0800149 gEdgeMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000150 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400151
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600152 for (int i = 0; i < DELAYFILTS; i++) {
153 delete delayFilters[i];
154 delayFilters[i] = NULL;
155 }
156
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400157 delete GMSKRotation1;
158 delete GMSKReverseRotation1;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800159 delete GMSKRotation4;
160 delete GMSKReverseRotation4;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400161 delete gRACHSequence;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400162 delete GSMPulse1;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800163 delete GSMPulse4;
Tom Tsoud3253432016-03-06 03:08:01 -0800164 delete dnsampler;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400165
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400166 GMSKRotation1 = NULL;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800167 GMSKRotation4 = NULL;
168 GMSKReverseRotation4 = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400169 GMSKReverseRotation1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400170 gRACHSequence = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400171 GSMPulse1 = NULL;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800172 GSMPulse4 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000173}
174
Tom Tsou70134a02017-06-12 14:23:53 -0700175static float vectorNorm2(const signalVector &x)
dburgessb3a0ca42011-10-12 07:44:40 +0000176{
177 signalVector::const_iterator xPtr = x.begin();
178 float Energy = 0.0;
179 for (;xPtr != x.end();xPtr++) {
180 Energy += xPtr->norm2();
181 }
182 return Energy;
183}
184
dburgessb3a0ca42011-10-12 07:44:40 +0000185/** compute e^(-jx) via lookup table. */
Tom Tsou2079a3c2016-03-06 00:58:56 -0800186static complex expjLookup(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000187{
188 float arg = x*M_1_2PI_F;
189 while (arg > 1.0F) arg -= 1.0F;
190 while (arg < 0.0F) arg += 1.0F;
191
192 const float argT = arg*((float)TABLESIZE);
193 const int argI = (int)argT;
194 const float delta = argT-argI;
195 const float iDelta = 1.0F-delta;
196 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
197 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
198}
199
200/** Library setup functions */
Tom Tsou2079a3c2016-03-06 00:58:56 -0800201static void initTrigTables() {
dburgessb3a0ca42011-10-12 07:44:40 +0000202 for (int i = 0; i < TABLESIZE+1; i++) {
203 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
204 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
205 }
206}
207
Tom Tsou2079a3c2016-03-06 00:58:56 -0800208/*
209 * Initialize 4 sps and 1 sps rotation tables
210 */
211static void initGMSKRotationTables()
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400212{
Tom Tsou2079a3c2016-03-06 00:58:56 -0800213 size_t len1 = 157, len4 = 625;
214
215 GMSKRotation4 = new signalVector(len4);
216 GMSKReverseRotation4 = new signalVector(len4);
217 signalVector::iterator rotPtr = GMSKRotation4->begin();
218 signalVector::iterator revPtr = GMSKReverseRotation4->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000219 float phase = 0.0;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800220 while (rotPtr != GMSKRotation4->end()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000221 *rotPtr++ = expjLookup(phase);
222 *revPtr++ = expjLookup(-phase);
Tom Tsou2079a3c2016-03-06 00:58:56 -0800223 phase += M_PI_F / 2.0F / 4.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000224 }
dburgessb3a0ca42011-10-12 07:44:40 +0000225
Tom Tsou2079a3c2016-03-06 00:58:56 -0800226 GMSKRotation1 = new signalVector(len1);
227 GMSKReverseRotation1 = new signalVector(len1);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400228 rotPtr = GMSKRotation1->begin();
229 revPtr = GMSKReverseRotation1->begin();
230 phase = 0.0;
231 while (rotPtr != GMSKRotation1->end()) {
232 *rotPtr++ = expjLookup(phase);
233 *revPtr++ = expjLookup(-phase);
234 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400235 }
dburgessb3a0ca42011-10-12 07:44:40 +0000236}
237
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400238static void GMSKRotate(signalVector &x, int sps)
239{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500240#if HAVE_NEON
241 size_t len;
242 signalVector *a, *b, *out;
243
244 a = &x;
245 out = &x;
246 len = out->size();
247
248 if (len == 157)
249 len--;
250
251 if (sps == 1)
252 b = GMSKRotation1;
253 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800254 b = GMSKRotation4;
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500255
256 mul_complex((float *) out->begin(),
257 (float *) a->begin(),
258 (float *) b->begin(), len);
259#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400260 signalVector::iterator rotPtr, xPtr = x.begin();
261
262 if (sps == 1)
263 rotPtr = GMSKRotation1->begin();
264 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800265 rotPtr = GMSKRotation4->begin();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400266
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500267 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000268 while (xPtr < x.end()) {
269 *xPtr = *rotPtr++ * (xPtr->real());
270 xPtr++;
271 }
272 }
273 else {
274 while (xPtr < x.end()) {
275 *xPtr = *rotPtr++ * (*xPtr);
276 xPtr++;
277 }
278 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500279#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000280}
281
Tom Tsou2079a3c2016-03-06 00:58:56 -0800282static bool GMSKReverseRotate(signalVector &x, int sps)
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400283{
284 signalVector::iterator rotPtr, xPtr= x.begin();
285
286 if (sps == 1)
287 rotPtr = GMSKReverseRotation1->begin();
Tom Tsou2079a3c2016-03-06 00:58:56 -0800288 else if (sps == 4)
289 rotPtr = GMSKReverseRotation4->begin();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400290 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800291 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400292
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500293 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000294 while (xPtr < x.end()) {
295 *xPtr = *rotPtr++ * (xPtr->real());
296 xPtr++;
297 }
298 }
299 else {
300 while (xPtr < x.end()) {
301 *xPtr = *rotPtr++ * (*xPtr);
302 xPtr++;
303 }
304 }
Tom Tsou2079a3c2016-03-06 00:58:56 -0800305
306 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000307}
308
Tom Tsou70134a02017-06-12 14:23:53 -0700309/** Convolution type indicator */
310enum ConvType {
311 START_ONLY,
312 NO_DELAY,
313 CUSTOM,
314 UNDEFINED,
315};
316
317static signalVector *convolve(const signalVector *x, const signalVector *h,
318 signalVector *y, ConvType spanType,
319 size_t start = 0, size_t len = 0,
320 size_t step = 1, int offset = 0)
dburgessb3a0ca42011-10-12 07:44:40 +0000321{
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500322 int rc;
323 size_t head = 0, tail = 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400324 bool alloc = false, append = false;
325 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000326
Thomas Tsou3eaae802013-08-20 19:31:14 -0400327 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000328 return NULL;
329
Thomas Tsou3eaae802013-08-20 19:31:14 -0400330 switch (spanType) {
331 case START_ONLY:
332 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500333 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400334 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500335
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500336 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500337 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000338 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400339 case NO_DELAY:
340 start = h->size() / 2;
341 head = start;
342 tail = start;
343 len = x->size();
344 append = true;
345 break;
346 case CUSTOM:
347 if (start < h->size() - 1) {
348 head = h->size() - start;
349 append = true;
350 }
351 if (start + len > x->size()) {
352 tail = start + len - x->size();
353 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000354 }
355 break;
356 default:
357 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000358 }
dburgessb3a0ca42011-10-12 07:44:40 +0000359
Thomas Tsou3eaae802013-08-20 19:31:14 -0400360 /*
361 * Error if the output vector is too small. Create the output vector
362 * if the pointer is NULL.
363 */
364 if (y && (len > y->size()))
365 return NULL;
366 if (!y) {
367 y = new signalVector(len);
368 alloc = true;
369 }
370
371 /* Prepend or post-pend the input vector if the parameters require it */
372 if (append)
373 _x = new signalVector(*x, head, tail);
374 else
375 _x = x;
376
377 /*
378 * Four convovle types:
379 * 1. Complex-Real (aligned)
380 * 2. Complex-Complex (aligned)
381 * 3. Complex-Real (!aligned)
382 * 4. Complex-Complex (!aligned)
383 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500384 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400385 rc = convolve_real((float *) _x->begin(), _x->size(),
386 (float *) h->begin(), h->size(),
387 (float *) y->begin(), y->size(),
388 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500389 } else if (!h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400390 rc = convolve_complex((float *) _x->begin(), _x->size(),
391 (float *) h->begin(), h->size(),
392 (float *) y->begin(), y->size(),
393 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500394 } else if (h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400395 rc = base_convolve_real((float *) _x->begin(), _x->size(),
396 (float *) h->begin(), h->size(),
397 (float *) y->begin(), y->size(),
398 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500399 } else if (!h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400400 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
401 (float *) h->begin(), h->size(),
402 (float *) y->begin(), y->size(),
403 start, len, step, offset);
404 } else {
405 rc = -1;
406 }
407
408 if (append)
409 delete _x;
410
411 if (rc < 0) {
412 if (alloc)
413 delete y;
414 return NULL;
415 }
416
417 return y;
418}
dburgessb3a0ca42011-10-12 07:44:40 +0000419
Tom Tsoud3253432016-03-06 03:08:01 -0800420/*
421 * Generate static EDGE linear equalizer. This equalizer is not adaptive.
422 * Filter taps are generated from the inverted 1 SPS impulse response of
423 * the EDGE pulse shape captured after the downsampling filter.
424 */
425static bool generateInvertC0Pulse(PulseSequence *pulse)
426{
427 if (!pulse)
428 return false;
429
430 pulse->c0_inv_buffer = convolve_h_alloc(5);
431 pulse->c0_inv = new signalVector((complex *) pulse->c0_inv_buffer, 0, 5);
432 pulse->c0_inv->isReal(true);
433 pulse->c0_inv->setAligned(false);
434
435 signalVector::iterator xP = pulse->c0_inv->begin();
436 *xP++ = 0.15884;
437 *xP++ = -0.43176;
438 *xP++ = 1.00000;
439 *xP++ = -0.42608;
440 *xP++ = 0.14882;
441
442 return true;
443}
444
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400445static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800446{
447 int len;
448
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400449 if (!pulse)
450 return false;
451
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800452 switch (sps) {
453 case 4:
454 len = 8;
455 break;
456 default:
457 return false;
458 }
459
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400460 pulse->c1_buffer = convolve_h_alloc(len);
461 pulse->c1 = new signalVector((complex *)
462 pulse->c1_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500463 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800464
465 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400466 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800467
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400468 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800469
470 switch (sps) {
471 case 4:
472 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400473 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800474 *xP++ = 8.16373112e-03;
475 *xP++ = 2.84385729e-02;
476 *xP++ = 5.64158904e-02;
477 *xP++ = 7.05463553e-02;
478 *xP++ = 5.64158904e-02;
479 *xP++ = 2.84385729e-02;
480 *xP++ = 8.16373112e-03;
481 }
482
483 return true;
484}
485
Tom Tsou2079a3c2016-03-06 00:58:56 -0800486static PulseSequence *generateGSMPulse(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +0000487{
Thomas Tsou83e06892013-08-20 16:10:01 -0400488 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800489 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400490 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400491
Tom Tsoud3253432016-03-06 03:08:01 -0800492 if ((sps != 1) && (sps != 4))
493 return NULL;
494
Thomas Tsou83e06892013-08-20 16:10:01 -0400495 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400496 pulse = new PulseSequence();
497 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500498 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400499 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400500
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400501 /*
502 * For 4 samples-per-symbol use a precomputed single pulse Laurent
503 * approximation. This should yields below 2 degrees of phase error at
504 * the modulator output. Use the existing pulse approximation for all
505 * other oversampling factors.
506 */
507 switch (sps) {
508 case 4:
509 len = 16;
510 break;
Tom Tsoud3253432016-03-06 03:08:01 -0800511 case 1:
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400512 default:
Tom Tsou2079a3c2016-03-06 00:58:56 -0800513 len = 4;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400514 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400515
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400516 pulse->c0_buffer = convolve_h_alloc(len);
517 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500518 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400519
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800520 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400521 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800522
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400523 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400524
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400525 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800526 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400527 *xP++ = 4.46348606e-03;
528 *xP++ = 2.84385729e-02;
529 *xP++ = 1.03184855e-01;
530 *xP++ = 2.56065552e-01;
531 *xP++ = 4.76375085e-01;
532 *xP++ = 7.05961177e-01;
533 *xP++ = 8.71291644e-01;
534 *xP++ = 9.29453645e-01;
535 *xP++ = 8.71291644e-01;
536 *xP++ = 7.05961177e-01;
537 *xP++ = 4.76375085e-01;
538 *xP++ = 2.56065552e-01;
539 *xP++ = 1.03184855e-01;
540 *xP++ = 2.84385729e-02;
541 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400542 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400543 } else {
544 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400545
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400546 /* GSM pulse approximation */
547 for (int i = 0; i < len; i++) {
548 arg = ((float) i - center) / (float) sps;
549 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
550 0.527 * arg * arg * arg * arg);
551 }
dburgessb3a0ca42011-10-12 07:44:40 +0000552
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400553 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
554 xP = pulse->c0->begin();
555 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800556 *xP++ /= avg;
557 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400558
Tom Tsoud3253432016-03-06 03:08:01 -0800559 /*
560 * Current form of the EDGE equalization filter non-realizable at 4 SPS.
561 * Load the onto both 1 SPS and 4 SPS objects for convenience. Note that
562 * the EDGE demodulator downsamples to 1 SPS prior to equalization.
563 */
564 generateInvertC0Pulse(pulse);
565
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400566 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000567}
568
Tom Tsoud3253432016-03-06 03:08:01 -0800569bool vectorSlicer(SoftVector *x)
570{
571 SoftVector::iterator xP = x->begin();
572 SoftVector::iterator xPEnd = x->end();
573 while (xP < xPEnd) {
574 *xP = 0.5 * (*xP + 1.0f);
575 if (*xP > 1.0)
576 *xP = 1.0;
577 if (*xP < 0.0)
578 *xP = 0.0;
579 xP++;
580 }
581 return true;
582}
583
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800584static signalVector *rotateBurst(const BitVector &wBurst,
585 int guardPeriodLength, int sps)
586{
587 int burst_len;
Tom Tsou7278a872017-06-14 14:50:39 -0700588 signalVector *pulse, rotated;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800589 signalVector::iterator itr;
590
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400591 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800592 burst_len = sps * (wBurst.size() + guardPeriodLength);
593 rotated = signalVector(burst_len);
594 itr = rotated.begin();
595
596 for (unsigned i = 0; i < wBurst.size(); i++) {
597 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
598 itr += sps;
599 }
600
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400601 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500602 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800603
604 /* Dummy filter operation */
Tom Tsou7278a872017-06-14 14:50:39 -0700605 return convolve(&rotated, pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800606}
607
Tom Tsoud3253432016-03-06 03:08:01 -0800608static void rotateBurst2(signalVector &burst, double phase)
609{
610 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
611
612 for (size_t i = 0; i < burst.size(); i++)
613 burst[i] = burst[i] * rot;
614}
615
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800616/*
617 * Ignore the guard length argument in the GMSK modulator interface
618 * because it results in 624/628 sized bursts instead of the preferred
619 * burst length of 625. Only 4 SPS is supported.
620 */
621static signalVector *modulateBurstLaurent(const BitVector &bits)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800622{
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800623 int burst_len, sps = 4;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800624 float phase;
Tom Tsou7278a872017-06-14 14:50:39 -0700625 signalVector *c0_pulse, *c1_pulse, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800626 signalVector::iterator c0_itr, c1_itr;
627
Tom Tsou2079a3c2016-03-06 00:58:56 -0800628 c0_pulse = GSMPulse4->c0;
629 c1_pulse = GSMPulse4->c1;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800630
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800631 if (bits.size() > 156)
632 return NULL;
633
634 burst_len = 625;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800635
Tom Tsou7278a872017-06-14 14:50:39 -0700636 signalVector c0_burst(burst_len, c0_pulse->size());
637 c0_burst.isReal(true);
638 c0_itr = c0_burst.begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800639
Tom Tsou7278a872017-06-14 14:50:39 -0700640 signalVector c1_burst(burst_len, c1_pulse->size());
641 c1_itr = c1_burst.begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800642
Tom Tsouaa15d622016-08-11 14:36:23 -0700643 /* Padded differential tail bits */
644 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800645 c0_itr += sps;
646
647 /* Main burst bits */
648 for (unsigned i = 0; i < bits.size(); i++) {
649 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
650 c0_itr += sps;
651 }
652
Tom Tsouaa15d622016-08-11 14:36:23 -0700653 /* Padded differential tail bits */
654 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800655
656 /* Generate C0 phase coefficients */
Tom Tsou7278a872017-06-14 14:50:39 -0700657 GMSKRotate(c0_burst, sps);
658 c0_burst.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800659
Tom Tsou7278a872017-06-14 14:50:39 -0700660 c0_itr = c0_burst.begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800661 c0_itr += sps * 2;
662 c1_itr += sps * 2;
663
664 /* Start magic */
665 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
666 *c1_itr = *c0_itr * Complex<float>(0, phase);
667 c0_itr += sps;
668 c1_itr += sps;
669
670 /* Generate C1 phase coefficients */
671 for (unsigned i = 2; i < bits.size(); i++) {
672 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
673 *c1_itr = *c0_itr * Complex<float>(0, phase);
674
675 c0_itr += sps;
676 c1_itr += sps;
677 }
678
679 /* End magic */
680 int i = bits.size();
681 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
682 *c1_itr = *c0_itr * Complex<float>(0, phase);
683
684 /* Primary (C0) and secondary (C1) pulse shaping */
Tom Tsou7278a872017-06-14 14:50:39 -0700685 c0_shaped = convolve(&c0_burst, c0_pulse, NULL, START_ONLY);
686 c1_shaped = convolve(&c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800687
688 /* Sum shaped outputs into C0 */
689 c0_itr = c0_shaped->begin();
690 c1_itr = c1_shaped->begin();
691 for (unsigned i = 0; i < c0_shaped->size(); i++ )
692 *c0_itr++ += *c1_itr++;
693
694 delete c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800695 return c0_shaped;
696}
697
Tom Tsoud3253432016-03-06 03:08:01 -0800698static signalVector *rotateEdgeBurst(const signalVector &symbols, int sps)
699{
700 signalVector *burst;
701 signalVector::iterator burst_itr;
702
703 burst = new signalVector(symbols.size() * sps);
704 burst_itr = burst->begin();
705
706 for (size_t i = 0; i < symbols.size(); i++) {
707 float phase = i * 3.0f * M_PI / 8.0f;
708 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
709
710 *burst_itr = symbols[i] * rot;
711 burst_itr += sps;
712 }
713
714 return burst;
715}
716
717static signalVector *derotateEdgeBurst(const signalVector &symbols, int sps)
718{
719 signalVector *burst;
720 signalVector::iterator burst_itr;
721
722 if (symbols.size() % sps)
723 return NULL;
724
725 burst = new signalVector(symbols.size() / sps);
726 burst_itr = burst->begin();
727
728 for (size_t i = 0; i < burst->size(); i++) {
729 float phase = (float) (i % 16) * 3.0f * M_PI / 8.0f;
730 Complex<float> rot = Complex<float>(cosf(phase), -sinf(phase));
731
732 *burst_itr = symbols[sps * i] * rot;
733 burst_itr++;
734 }
735
736 return burst;
737}
738
739static signalVector *mapEdgeSymbols(const BitVector &bits)
740{
741 if (bits.size() % 3)
742 return NULL;
743
744 signalVector *symbols = new signalVector(bits.size() / 3);
745
746 for (size_t i = 0; i < symbols->size(); i++) {
747 unsigned index = (((unsigned) bits[3 * i + 0] & 0x01) << 0) |
748 (((unsigned) bits[3 * i + 1] & 0x01) << 1) |
749 (((unsigned) bits[3 * i + 2] & 0x01) << 2);
750
751 (*symbols)[i] = psk8_table[index];
752 }
753
754 return symbols;
755}
756
Tom Tsoud2b07032016-04-26 19:28:59 -0700757/*
758 * EDGE 8-PSK rotate and pulse shape
759 *
760 * Delay the EDGE downlink bursts by one symbol in order to match GMSK pulse
761 * shaping group delay. The difference in group delay arises from the dual
762 * pulse filter combination of the GMSK Laurent represenation whereas 8-PSK
763 * uses a single pulse linear filter.
764 */
Tom Tsoud3253432016-03-06 03:08:01 -0800765static signalVector *shapeEdgeBurst(const signalVector &symbols)
766{
Tom Tsoud2b07032016-04-26 19:28:59 -0700767 size_t nsyms, nsamps = 625, sps = 4;
Tom Tsoud3253432016-03-06 03:08:01 -0800768 signalVector::iterator burst_itr;
769
770 nsyms = symbols.size();
771
Tom Tsoud2b07032016-04-26 19:28:59 -0700772 if (nsyms * sps > nsamps)
Tom Tsoud3253432016-03-06 03:08:01 -0800773 nsyms = 156;
774
Tom Tsou7278a872017-06-14 14:50:39 -0700775 signalVector burst(nsamps, GSMPulse4->c0->size());
Tom Tsoud3253432016-03-06 03:08:01 -0800776
Tom Tsoud2b07032016-04-26 19:28:59 -0700777 /* Delay burst by 1 symbol */
Tom Tsou7278a872017-06-14 14:50:39 -0700778 burst_itr = burst.begin() + sps;
Tom Tsou06676ea2016-07-19 12:50:21 -0700779 for (size_t i = 0; i < nsyms; i++) {
Tom Tsoud3253432016-03-06 03:08:01 -0800780 float phase = i * 3.0f * M_PI / 8.0f;
781 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
782
783 *burst_itr = symbols[i] * rot;
Tom Tsoud2b07032016-04-26 19:28:59 -0700784 burst_itr += sps;
Tom Tsoud3253432016-03-06 03:08:01 -0800785 }
786
787 /* Single Gaussian pulse approximation shaping */
Tom Tsou7278a872017-06-14 14:50:39 -0700788 return convolve(&burst, GSMPulse4->c0, NULL, START_ONLY);
Tom Tsoud3253432016-03-06 03:08:01 -0800789}
790
791/*
Tom Tsou8ee2f382016-03-06 20:57:34 -0800792 * Generate a random GSM normal burst.
793 */
794signalVector *genRandNormalBurst(int tsc, int sps, int tn)
795{
796 if ((tsc < 0) || (tsc > 7) || (tn < 0) || (tn > 7))
797 return NULL;
798 if ((sps != 1) && (sps != 4))
799 return NULL;
800
801 int i = 0;
Tom Tsou7278a872017-06-14 14:50:39 -0700802 BitVector bits(148);
Tom Tsou8ee2f382016-03-06 20:57:34 -0800803
804 /* Tail bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700805 for (; i < 3; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700806 bits[i] = 0;
Tom Tsou8ee2f382016-03-06 20:57:34 -0800807
808 /* Random bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700809 for (; i < 60; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700810 bits[i] = rand() % 2;
Tom Tsou8ee2f382016-03-06 20:57:34 -0800811
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700812 /* Stealing bit */
Tom Tsou7278a872017-06-14 14:50:39 -0700813 bits[i++] = 0;
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700814
Tom Tsou8ee2f382016-03-06 20:57:34 -0800815 /* Training sequence */
816 for (int n = 0; i < 87; i++, n++)
Tom Tsou7278a872017-06-14 14:50:39 -0700817 bits[i] = gTrainingSequence[tsc][n];
Tom Tsou8ee2f382016-03-06 20:57:34 -0800818
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700819 /* Stealing bit */
Tom Tsou7278a872017-06-14 14:50:39 -0700820 bits[i++] = 0;
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700821
Tom Tsou8ee2f382016-03-06 20:57:34 -0800822 /* Random bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700823 for (; i < 145; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700824 bits[i] = rand() % 2;
Tom Tsou8ee2f382016-03-06 20:57:34 -0800825
826 /* Tail bits */
827 for (; i < 148; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700828 bits[i] = 0;
Tom Tsou8ee2f382016-03-06 20:57:34 -0800829
830 int guard = 8 + !(tn % 4);
Tom Tsou7278a872017-06-14 14:50:39 -0700831 return modulateBurst(bits, guard, sps);
Tom Tsou8ee2f382016-03-06 20:57:34 -0800832}
833
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300834/*
835 * Generate a random GSM access burst.
836 */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300837signalVector *genRandAccessBurst(int delay, int sps, int tn)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300838{
839 if ((tn < 0) || (tn > 7))
840 return NULL;
841 if ((sps != 1) && (sps != 4))
842 return NULL;
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300843 if (delay > 68)
844 return NULL;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300845
846 int i = 0;
Tom Tsou7278a872017-06-14 14:50:39 -0700847 BitVector bits(88 + delay);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300848
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300849 /* delay */
850 for (; i < delay; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700851 bits[i] = 0;
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300852
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300853 /* head and synch bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300854 for (int n = 0; i < 49+delay; i++, n++)
Tom Tsou7278a872017-06-14 14:50:39 -0700855 bits[i] = gRACHBurst[n];
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300856
857 /* Random bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300858 for (; i < 85+delay; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700859 bits[i] = rand() % 2;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300860
861 /* Tail bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300862 for (; i < 88+delay; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700863 bits[i] = 0;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300864
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300865 int guard = 68-delay + !(tn % 4);
Tom Tsou7278a872017-06-14 14:50:39 -0700866 return modulateBurst(bits, guard, sps);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300867}
868
Tom Tsou8ee2f382016-03-06 20:57:34 -0800869signalVector *generateEmptyBurst(int sps, int tn)
870{
871 if ((tn < 0) || (tn > 7))
872 return NULL;
873
874 if (sps == 4)
875 return new signalVector(625);
876 else if (sps == 1)
877 return new signalVector(148 + 8 + !(tn % 4));
878 else
879 return NULL;
880}
881
882signalVector *generateDummyBurst(int sps, int tn)
883{
884 if (((sps != 1) && (sps != 4)) || (tn < 0) || (tn > 7))
885 return NULL;
886
887 return modulateBurst(gDummyBurst, 8 + !(tn % 4), sps);
888}
889
890/*
Tom Tsoud3253432016-03-06 03:08:01 -0800891 * Generate a random 8-PSK EDGE burst. Only 4 SPS is supported with
892 * the returned burst being 625 samples in length.
893 */
894signalVector *generateEdgeBurst(int tsc)
895{
896 int tail = 9 / 3;
897 int data = 174 / 3;
898 int train = 78 / 3;
899
900 if ((tsc < 0) || (tsc > 7))
901 return NULL;
902
Tom Tsou7278a872017-06-14 14:50:39 -0700903 signalVector burst(148);
Tom Tsoud3253432016-03-06 03:08:01 -0800904 const BitVector *midamble = &gEdgeTrainingSequence[tsc];
905
906 /* Tail */
907 int n, i = 0;
908 for (; i < tail; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700909 burst[i] = psk8_table[7];
Tom Tsoud3253432016-03-06 03:08:01 -0800910
911 /* Body */
912 for (; i < tail + data; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700913 burst[i] = psk8_table[rand() % 8];
Tom Tsoud3253432016-03-06 03:08:01 -0800914
915 /* TSC */
916 for (n = 0; i < tail + data + train; i++, n++) {
917 unsigned index = (((unsigned) (*midamble)[3 * n + 0] & 0x01) << 0) |
918 (((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
919 (((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
920
Tom Tsou7278a872017-06-14 14:50:39 -0700921 burst[i] = psk8_table[index];
Tom Tsoud3253432016-03-06 03:08:01 -0800922 }
923
924 /* Body */
925 for (; i < tail + data + train + data; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700926 burst[i] = psk8_table[rand() % 8];
Tom Tsoud3253432016-03-06 03:08:01 -0800927
928 /* Tail */
929 for (; i < tail + data + train + data + tail; i++)
Tom Tsou7278a872017-06-14 14:50:39 -0700930 burst[i] = psk8_table[7];
Tom Tsoud3253432016-03-06 03:08:01 -0800931
Tom Tsou7278a872017-06-14 14:50:39 -0700932 return shapeEdgeBurst(burst);
Tom Tsoud3253432016-03-06 03:08:01 -0800933}
934
935/*
936 * Modulate 8-PSK burst. When empty pulse shaping (rotation only)
937 * is enabled, the output vector length will be bit sequence length
938 * times the SPS value. When pulse shaping is enabled, the output
Alexander Chemeris9270a5a2017-03-17 13:03:41 -0700939 * vector length is fixed at 625 samples (156.25 symbols at 4 SPS).
Tom Tsoud3253432016-03-06 03:08:01 -0800940 * Pulse shaped bit sequences that go beyond one burst are truncated.
941 * Pulse shaping at anything but 4 SPS is not supported.
942 */
943signalVector *modulateEdgeBurst(const BitVector &bits,
944 int sps, bool empty)
945{
946 signalVector *shape, *burst;
947
948 if ((sps != 4) && !empty)
949 return NULL;
950
951 burst = mapEdgeSymbols(bits);
952 if (!burst)
953 return NULL;
954
955 if (empty)
956 shape = rotateEdgeBurst(*burst, sps);
957 else
958 shape = shapeEdgeBurst(*burst);
959
960 delete burst;
961 return shape;
962}
963
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800964static signalVector *modulateBurstBasic(const BitVector &bits,
965 int guard_len, int sps)
966{
967 int burst_len;
Tom Tsou7278a872017-06-14 14:50:39 -0700968 signalVector *pulse;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800969 signalVector::iterator burst_itr;
970
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400971 if (sps == 1)
972 pulse = GSMPulse1->c0;
973 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800974 pulse = GSMPulse4->c0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400975
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800976 burst_len = sps * (bits.size() + guard_len);
977
Tom Tsou7278a872017-06-14 14:50:39 -0700978 signalVector burst(burst_len, pulse->size());
979 burst.isReal(true);
980 burst_itr = burst.begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800981
982 /* Raw bits are not differentially encoded */
983 for (unsigned i = 0; i < bits.size(); i++) {
984 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
985 burst_itr += sps;
986 }
987
Tom Tsou7278a872017-06-14 14:50:39 -0700988 GMSKRotate(burst, sps);
989 burst.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800990
991 /* Single Gaussian pulse approximation shaping */
Tom Tsou7278a872017-06-14 14:50:39 -0700992 return convolve(&burst, pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800993}
994
Thomas Tsou3eaae802013-08-20 19:31:14 -0400995/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400996signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
997 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000998{
Thomas Tsou83e06892013-08-20 16:10:01 -0400999 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001000 return rotateBurst(wBurst, guardPeriodLength, sps);
1001 else if (sps == 4)
Tom Tsou4dfd64a2016-03-06 20:31:51 -08001002 return modulateBurstLaurent(wBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -04001003 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001004 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001005}
1006
Tom Tsou2079a3c2016-03-06 00:58:56 -08001007static void generateSincTable()
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001008{
1009 float x;
1010
1011 for (int i = 0; i < TABLESIZE; i++) {
1012 x = (float) i / TABLESIZE * 8 * M_PI;
1013 if (fabs(x) < 0.01) {
1014 sincTable[i] = 1.0f;
1015 continue;
1016 }
1017
1018 sincTable[i] = sinf(x) / x;
1019 }
1020}
1021
Tom Tsou70134a02017-06-12 14:23:53 -07001022static float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +00001023{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001024 if (fabs(x) >= 8 * M_PI)
1025 return 0.0;
1026
1027 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
1028
1029 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +00001030}
1031
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001032/*
1033 * Create fractional delay filterbank with Blackman-harris windowed
1034 * sinc function generator. The number of filters generated is specified
1035 * by the DELAYFILTS value.
1036 */
Tom Tsou70134a02017-06-12 14:23:53 -07001037static void generateDelayFilters()
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001038{
1039 int h_len = 20;
1040 complex *data;
1041 signalVector *h;
1042 signalVector::iterator itr;
1043
1044 float k, sum;
1045 float a0 = 0.35875;
1046 float a1 = 0.48829;
1047 float a2 = 0.14128;
1048 float a3 = 0.01168;
1049
1050 for (int i = 0; i < DELAYFILTS; i++) {
1051 data = (complex *) convolve_h_alloc(h_len);
1052 h = new signalVector(data, 0, h_len);
1053 h->setAligned(true);
1054 h->isReal(true);
1055
1056 sum = 0.0;
1057 itr = h->end();
1058 for (int n = 0; n < h_len; n++) {
1059 k = (float) n;
1060 *--itr = (complex) sinc(M_PI_F *
1061 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
1062 *itr *= a0 -
1063 a1 * cos(2 * M_PI * n / (h_len - 1)) +
1064 a2 * cos(4 * M_PI * n / (h_len - 1)) -
1065 a3 * cos(6 * M_PI * n / (h_len - 1));
1066
1067 sum += itr->real();
1068 }
1069
1070 itr = h->begin();
1071 for (int n = 0; n < h_len; n++)
1072 *itr++ /= sum;
1073
1074 delayFilters[i] = h;
1075 }
1076}
1077
Alexander Chemerise0c12182017-03-18 13:27:48 -07001078signalVector *delayVector(const signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +00001079{
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001080 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001081 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001082 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001083
Thomas Tsou2c282f52013-10-08 21:34:35 -04001084 whole = floor(delay);
1085 frac = delay - whole;
1086
1087 /* Sinc interpolated fractional shift (if allowable) */
1088 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001089 index = floorf(frac * (float) DELAYFILTS);
1090 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -04001091
Thomas Tsou94edaae2013-11-09 22:19:19 -05001092 fshift = convolve(in, h, NULL, NO_DELAY);
1093 if (!fshift)
1094 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001095 }
1096
Thomas Tsou94edaae2013-11-09 22:19:19 -05001097 if (!fshift)
1098 shift = new signalVector(*in);
1099 else
1100 shift = fshift;
1101
Thomas Tsou2c282f52013-10-08 21:34:35 -04001102 /* Integer sample shift */
1103 if (whole < 0) {
1104 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001105 signalVector::iterator wBurstItr = shift->begin();
1106 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001107
Thomas Tsou94edaae2013-11-09 22:19:19 -05001108 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +00001109 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001110
Thomas Tsou94edaae2013-11-09 22:19:19 -05001111 while (wBurstItr < shift->end())
1112 *wBurstItr++ = 0.0;
1113 } else if (whole >= 0) {
1114 signalVector::iterator wBurstItr = shift->end() - 1;
1115 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
1116
1117 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001118 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001119
1120 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001121 *wBurstItr-- = 0.0;
1122 }
Thomas Tsou2c282f52013-10-08 21:34:35 -04001123
Thomas Tsou94edaae2013-11-09 22:19:19 -05001124 if (!out)
1125 return shift;
1126
1127 out->clone(*shift);
1128 delete shift;
1129 return out;
dburgessb3a0ca42011-10-12 07:44:40 +00001130}
Thomas Tsou2c282f52013-10-08 21:34:35 -04001131
Tom Tsou70134a02017-06-12 14:23:53 -07001132static complex interpolatePoint(const signalVector &inSig, float ix)
dburgessb3a0ca42011-10-12 07:44:40 +00001133{
dburgessb3a0ca42011-10-12 07:44:40 +00001134 int start = (int) (floor(ix) - 10);
1135 if (start < 0) start = 0;
1136 int end = (int) (floor(ix) + 11);
1137 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
1138
1139 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001140 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001141 for (int i = start; i < end; i++)
1142 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
1143 }
1144 else {
1145 for (int i = start; i < end; i++)
1146 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
1147 }
1148
1149 return pVal;
1150}
1151
Thomas Tsou8181b012013-08-20 21:17:19 -04001152static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1153{
1154 float val, max = 0.0f;
1155 complex amp;
1156 int _index = -1;
1157
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001158 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001159 val = rxBurst[i].norm2();
1160 if (val > max) {
1161 max = val;
1162 _index = i;
1163 amp = rxBurst[i];
1164 }
1165 }
1166
1167 if (index)
1168 *index = (float) _index;
1169
1170 return amp;
1171}
1172
Tom Tsou70134a02017-06-12 14:23:53 -07001173static complex peakDetect(const signalVector &rxBurst,
1174 float *peakIndex, float *avgPwr)
dburgessb3a0ca42011-10-12 07:44:40 +00001175{
dburgessb3a0ca42011-10-12 07:44:40 +00001176 complex maxVal = 0.0;
1177 float maxIndex = -1;
1178 float sumPower = 0.0;
1179
1180 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1181 float samplePower = rxBurst[i].norm2();
1182 if (samplePower > maxVal.real()) {
1183 maxVal = samplePower;
1184 maxIndex = i;
1185 }
1186 sumPower += samplePower;
1187 }
1188
1189 // interpolate around the peak
1190 // to save computation, we'll use early-late balancing
1191 float earlyIndex = maxIndex-1;
1192 float lateIndex = maxIndex+1;
1193
1194 float incr = 0.5;
1195 while (incr > 1.0/1024.0) {
1196 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1197 complex lateP = interpolatePoint(rxBurst,lateIndex);
1198 if (earlyP < lateP)
1199 earlyIndex += incr;
1200 else if (earlyP > lateP)
1201 earlyIndex -= incr;
1202 else break;
1203 incr /= 2.0;
1204 lateIndex = earlyIndex + 2.0;
1205 }
1206
1207 maxIndex = earlyIndex + 1.0;
1208 maxVal = interpolatePoint(rxBurst,maxIndex);
1209
1210 if (peakIndex!=NULL)
1211 *peakIndex = maxIndex;
1212
1213 if (avgPwr!=NULL)
1214 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1215
1216 return maxVal;
1217
1218}
1219
1220void scaleVector(signalVector &x,
1221 complex scale)
1222{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001223#ifdef HAVE_NEON
1224 int len = x.size();
1225
1226 scale_complex((float *) x.begin(),
1227 (float *) x.begin(),
1228 (float *) &scale, len);
1229#else
dburgessb3a0ca42011-10-12 07:44:40 +00001230 signalVector::iterator xP = x.begin();
1231 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001232 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001233 while (xP < xPEnd) {
1234 *xP = *xP * scale;
1235 xP++;
1236 }
1237 }
1238 else {
1239 while (xP < xPEnd) {
1240 *xP = xP->real() * scale;
1241 xP++;
1242 }
1243 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001244#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001245}
1246
1247/** in-place conjugation */
Tom Tsou70134a02017-06-12 14:23:53 -07001248static void conjugateVector(signalVector &x)
dburgessb3a0ca42011-10-12 07:44:40 +00001249{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001250 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001251 signalVector::iterator xP = x.begin();
1252 signalVector::iterator xPEnd = x.end();
1253 while (xP < xPEnd) {
1254 *xP = xP->conj();
1255 xP++;
1256 }
1257}
1258
Tom Tsou2079a3c2016-03-06 00:58:56 -08001259static bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001260{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001261 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001262 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001263 complex *data = NULL;
1264 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001265 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001266
Thomas Tsou3eaae802013-08-20 19:31:14 -04001267 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001268 return false;
1269
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001270 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001271
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001272 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1273 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1274 if (!midMidamble)
1275 return false;
1276
Thomas Tsou3eaae802013-08-20 19:31:14 -04001277 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001278 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1279 if (!midamble) {
1280 status = false;
1281 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001282 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001283
dburgessb3a0ca42011-10-12 07:44:40 +00001284 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1285 // the ideal TSC has an + 180 degree phase shift,
1286 // due to the pi/2 frequency shift, that
1287 // needs to be accounted for.
1288 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001289 scaleVector(*midMidamble, complex(-1.0, 0.0));
1290 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001291
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001292 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001293
Thomas Tsou3eaae802013-08-20 19:31:14 -04001294 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1295 data = (complex *) convolve_h_alloc(midMidamble->size());
1296 _midMidamble = new signalVector(data, 0, midMidamble->size());
1297 _midMidamble->setAligned(true);
1298 memcpy(_midMidamble->begin(), midMidamble->begin(),
1299 midMidamble->size() * sizeof(complex));
1300
1301 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001302 if (!autocorr) {
1303 status = false;
1304 goto release;
1305 }
dburgessb3a0ca42011-10-12 07:44:40 +00001306
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001307 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001308 gMidambles[tsc]->buffer = data;
1309 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001310 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1311
1312 /* For 1 sps only
1313 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1314 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1315 */
1316 if (sps == 1)
1317 gMidambles[tsc]->toa = toa - 13.5;
1318 else
1319 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001320
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001321release:
dburgessb3a0ca42011-10-12 07:44:40 +00001322 delete autocorr;
1323 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001324 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001325
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001326 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001327 delete _midMidamble;
1328 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001329 gMidambles[tsc] = NULL;
1330 }
1331
1332 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001333}
1334
Tom Tsou70134a02017-06-12 14:23:53 -07001335static CorrelationSequence *generateEdgeMidamble(int tsc)
Tom Tsoud3253432016-03-06 03:08:01 -08001336{
1337 complex *data = NULL;
1338 signalVector *midamble = NULL, *_midamble = NULL;
1339 CorrelationSequence *seq;
1340
1341 if ((tsc < 0) || (tsc > 7))
1342 return NULL;
1343
1344 /* Use middle 48 bits of each TSC. Correlation sequence is not pulse shaped */
1345 const BitVector *bits = &gEdgeTrainingSequence[tsc];
1346 midamble = modulateEdgeBurst(bits->segment(15, 48), 1, true);
1347 if (!midamble)
1348 return NULL;
1349
1350 conjugateVector(*midamble);
1351
1352 data = (complex *) convolve_h_alloc(midamble->size());
1353 _midamble = new signalVector(data, 0, midamble->size());
1354 _midamble->setAligned(true);
1355 memcpy(_midamble->begin(), midamble->begin(),
1356 midamble->size() * sizeof(complex));
1357
1358 /* Channel gain is an empirically measured value */
1359 seq = new CorrelationSequence;
1360 seq->buffer = data;
1361 seq->sequence = _midamble;
1362 seq->gain = Complex<float>(-19.6432, 19.5006) / 1.18;
1363 seq->toa = 0;
1364
1365 delete midamble;
1366
1367 return seq;
1368}
1369
Tom Tsou2079a3c2016-03-06 00:58:56 -08001370static bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001371{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001372 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001373 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001374 complex *data = NULL;
1375 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001376 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001377
1378 delete gRACHSequence;
1379
1380 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1381 if (!seq0)
1382 return false;
1383
1384 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1385 if (!seq1) {
1386 status = false;
1387 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001388 }
1389
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001390 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001391
Thomas Tsou3eaae802013-08-20 19:31:14 -04001392 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1393 data = (complex *) convolve_h_alloc(seq1->size());
1394 _seq1 = new signalVector(data, 0, seq1->size());
1395 _seq1->setAligned(true);
1396 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1397
1398 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1399 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001400 status = false;
1401 goto release;
1402 }
dburgessb3a0ca42011-10-12 07:44:40 +00001403
1404 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001405 gRACHSequence->sequence = _seq1;
1406 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001407 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1408
1409 /* For 1 sps only
1410 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1411 * 20.5 = (40 / 2 - 1) + 1.5
1412 */
1413 if (sps == 1)
1414 gRACHSequence->toa = toa - 20.5;
1415 else
1416 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001417
1418release:
dburgessb3a0ca42011-10-12 07:44:40 +00001419 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001420 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001421 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001422
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001423 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001424 delete _seq1;
1425 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001426 gRACHSequence = NULL;
1427 }
dburgessb3a0ca42011-10-12 07:44:40 +00001428
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001429 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001430}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001431
Tom Tsoua84e1622016-06-29 14:50:25 -07001432/*
1433 * Peak-to-average computation +/- range from peak in symbols
1434 */
1435#define COMPUTE_PEAK_MIN 2
1436#define COMPUTE_PEAK_MAX 5
1437
1438/*
1439 * Minimum number of values needed to compute peak-to-average
1440 */
1441#define COMPUTE_PEAK_CNT 5
1442
Thomas Tsou865bca42013-08-21 20:58:00 -04001443static float computePeakRatio(signalVector *corr,
1444 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001445{
Thomas Tsou865bca42013-08-21 20:58:00 -04001446 int num = 0;
1447 complex *peak;
1448 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001449
Thomas Tsou865bca42013-08-21 20:58:00 -04001450 /* Check for bogus results */
1451 if ((toa < 0.0) || (toa > corr->size()))
1452 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001453
Alexander Chemeris1e9b4d52015-06-04 19:05:28 -04001454 peak = corr->begin() + (int) rint(toa);
1455
Tom Tsoua84e1622016-06-29 14:50:25 -07001456 for (int i = COMPUTE_PEAK_MIN * sps; i <= COMPUTE_PEAK_MAX * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001457 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001458 avg += (peak - i)->norm2();
1459 num++;
1460 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001461 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001462 avg += (peak + i)->norm2();
1463 num++;
1464 }
dburgessb3a0ca42011-10-12 07:44:40 +00001465 }
1466
Tom Tsoua84e1622016-06-29 14:50:25 -07001467 if (num < COMPUTE_PEAK_CNT)
Thomas Tsou865bca42013-08-21 20:58:00 -04001468 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001469
Thomas Tsou3eaae802013-08-20 19:31:14 -04001470 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001471
Thomas Tsou865bca42013-08-21 20:58:00 -04001472 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001473}
1474
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001475float energyDetect(const signalVector &rxBurst, unsigned windowLength)
dburgessb3a0ca42011-10-12 07:44:40 +00001476{
1477
1478 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1479 float energy = 0.0;
Tom Tsou2af14402017-03-23 14:54:00 -07001480 if (windowLength == 0) return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001481 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1482 for (unsigned i = 0; i < windowLength; i++) {
1483 energy += windowItr->norm2();
1484 windowItr+=4;
1485 }
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +03001486 return energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001487}
dburgessb3a0ca42011-10-12 07:44:40 +00001488
Tom Tsou70134a02017-06-12 14:23:53 -07001489static signalVector *downsampleBurst(const signalVector &burst)
1490{
Tom Tsou7278a872017-06-14 14:50:39 -07001491 signalVector in(DOWNSAMPLE_IN_LEN, dnsampler->len());
1492 signalVector *out = new signalVector(DOWNSAMPLE_OUT_LEN);
1493 memcpy(in.begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
Tom Tsou70134a02017-06-12 14:23:53 -07001494
Tom Tsou7278a872017-06-14 14:50:39 -07001495 if (dnsampler->rotate((float *) in.begin(), DOWNSAMPLE_IN_LEN,
Tom Tsou70134a02017-06-12 14:23:53 -07001496 (float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
1497 delete out;
1498 out = NULL;
1499 }
1500
Tom Tsou70134a02017-06-12 14:23:53 -07001501 return out;
1502};
1503
Thomas Tsou865bca42013-08-21 20:58:00 -04001504/*
1505 * Detect a burst based on correlation and peak-to-average ratio
1506 *
1507 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1508 * for initial gating. We do this because energy detection should be disabled.
1509 * For higher oversampling values, we assume the energy detector is in place
1510 * and we run full interpolating peak detection.
1511 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001512static int detectBurst(const signalVector &burst,
Thomas Tsou865bca42013-08-21 20:58:00 -04001513 signalVector &corr, CorrelationSequence *sync,
1514 float thresh, int sps, complex *amp, float *toa,
1515 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001516{
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001517 const signalVector *corr_in;
1518 signalVector *dec = NULL;
Tom Tsoud3253432016-03-06 03:08:01 -08001519
1520 if (sps == 4) {
1521 dec = downsampleBurst(burst);
1522 corr_in = dec;
1523 sps = 1;
1524 } else {
1525 corr_in = &burst;
1526 }
1527
Thomas Tsou865bca42013-08-21 20:58:00 -04001528 /* Correlate */
Tom Tsoud3253432016-03-06 03:08:01 -08001529 if (!convolve(corr_in, sync->sequence, &corr,
1530 CUSTOM, start, len, 1, 0)) {
1531 delete dec;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001532 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001533 }
1534
Tom Tsoud3253432016-03-06 03:08:01 -08001535 delete dec;
1536
1537 /* Running at the downsampled rate at this point */
1538 sps = 1;
1539
Thomas Tsou865bca42013-08-21 20:58:00 -04001540 /* Peak detection - place restrictions at correlation edges */
1541 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001542
Thomas Tsou865bca42013-08-21 20:58:00 -04001543 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1544 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001545
Thomas Tsou865bca42013-08-21 20:58:00 -04001546 /* Peak -to-average ratio */
1547 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1548 return 0;
1549
1550 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1551 *amp = peakDetect(corr, toa, NULL);
1552
1553 /* Normalize our channel gain */
1554 *amp = *amp / sync->gain;
1555
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001556 /* Compensate for residuate time lag */
1557 *toa = *toa - sync->toa;
1558
Thomas Tsou865bca42013-08-21 20:58:00 -04001559 return 1;
1560}
1561
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001562static float maxAmplitude(const signalVector &burst)
Tom Tsou577cd022015-05-18 13:57:54 -07001563{
Alexander Chemeris954b1182015-06-04 15:39:41 -04001564 float max = 0.0;
1565 for (size_t i = 0; i < burst.size(); i++) {
1566 if (fabs(burst[i].real()) > max)
1567 max = fabs(burst[i].real());
1568 if (fabs(burst[i].imag()) > max)
1569 max = fabs(burst[i].imag());
1570 }
Tom Tsou577cd022015-05-18 13:57:54 -07001571
Alexander Chemeris954b1182015-06-04 15:39:41 -04001572 return max;
Tom Tsou577cd022015-05-18 13:57:54 -07001573}
1574
Alexander Chemeris130a8002015-06-09 20:52:11 -04001575/*
1576 * RACH/Normal burst detection with clipping detection
Thomas Tsou865bca42013-08-21 20:58:00 -04001577 *
1578 * Correlation window parameters:
Alexander Chemeris130a8002015-06-09 20:52:11 -04001579 * target: Tail bits + burst length
1580 * head: Search symbols before target
1581 * tail: Search symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001582 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001583static int detectGeneralBurst(const signalVector &rxBurst,
1584 float thresh,
1585 int sps,
1586 complex &amp,
1587 float &toa,
1588 int target, int head, int tail,
1589 CorrelationSequence *sync)
Thomas Tsou865bca42013-08-21 20:58:00 -04001590{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001591 int rc, start, len;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001592 bool clipping = false;
Thomas Tsou865bca42013-08-21 20:58:00 -04001593
1594 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001595 return -SIGERR_UNSUPPORTED;
1596
Alexander Chemeris954b1182015-06-04 15:39:41 -04001597 // Detect potential clipping
1598 // We still may be able to demod the burst, so we'll give it a try
1599 // and only report clipping if we can't demod.
1600 float maxAmpl = maxAmplitude(rxBurst);
1601 if (maxAmpl > CLIP_THRESH) {
1602 LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
1603 clipping = true;
1604 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001605
Tom Tsoud3253432016-03-06 03:08:01 -08001606 start = target - head - 1;
1607 len = head + tail;
Tom Tsou7278a872017-06-14 14:50:39 -07001608 signalVector corr(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001609
Tom Tsou7278a872017-06-14 14:50:39 -07001610 rc = detectBurst(rxBurst, corr, sync,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001611 thresh, sps, &amp, &toa, start, len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001612 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001613 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001614 } else if (!rc) {
Alexander Chemeris130a8002015-06-09 20:52:11 -04001615 amp = 0.0f;
1616 toa = 0.0f;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001617 return clipping?-SIGERR_CLIP:SIGERR_NONE;
dburgessb3a0ca42011-10-12 07:44:40 +00001618 }
1619
Thomas Tsou865bca42013-08-21 20:58:00 -04001620 /* Subtract forward search bits from delay */
Tom Tsoud3253432016-03-06 03:08:01 -08001621 toa -= head;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001622
Thomas Tsou865bca42013-08-21 20:58:00 -04001623 return 1;
1624}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001625
Alexander Chemeris130a8002015-06-09 20:52:11 -04001626
1627/*
1628 * RACH burst detection
1629 *
1630 * Correlation window parameters:
1631 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Tom Tsoue90c24c2016-06-21 16:14:39 -07001632 * head: Search 8 symbols before target
1633 * tail: Search 8 symbols + maximum expected delay
Alexander Chemeris130a8002015-06-09 20:52:11 -04001634 */
Tom Tsou70134a02017-06-12 14:23:53 -07001635static int detectRACHBurst(const signalVector &burst, float threshold, int sps,
1636 complex &amplitude, float &toa, unsigned max_toa)
Alexander Chemeris130a8002015-06-09 20:52:11 -04001637{
1638 int rc, target, head, tail;
1639 CorrelationSequence *sync;
1640
1641 target = 8 + 40;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001642 head = 8;
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001643 tail = 8 + max_toa;
Alexander Chemeris130a8002015-06-09 20:52:11 -04001644 sync = gRACHSequence;
1645
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001646 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001647 target, head, tail, sync);
1648
1649 return rc;
1650}
1651
Thomas Tsou865bca42013-08-21 20:58:00 -04001652/*
1653 * Normal burst detection
1654 *
1655 * Correlation window parameters:
1656 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Tom Tsoue90c24c2016-06-21 16:14:39 -07001657 * head: Search 6 symbols before target
1658 * tail: Search 6 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001659 */
Tom Tsou70134a02017-06-12 14:23:53 -07001660static int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float threshold,
1661 int sps, complex &amplitude, float &toa, unsigned max_toa)
Thomas Tsou865bca42013-08-21 20:58:00 -04001662{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001663 int rc, target, head, tail;
Thomas Tsou865bca42013-08-21 20:58:00 -04001664 CorrelationSequence *sync;
1665
Tom Tsouae91f132017-03-28 14:40:38 -07001666 if (tsc > 7)
Tom Tsou577cd022015-05-18 13:57:54 -07001667 return -SIGERR_UNSUPPORTED;
1668
Thomas Tsou865bca42013-08-21 20:58:00 -04001669 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001670 head = 6;
1671 tail = 6 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001672 sync = gMidambles[tsc];
Thomas Tsou865bca42013-08-21 20:58:00 -04001673
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001674 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001675 target, head, tail, sync);
Alexander Chemeris130a8002015-06-09 20:52:11 -04001676 return rc;
dburgessb3a0ca42011-10-12 07:44:40 +00001677}
1678
Tom Tsou70134a02017-06-12 14:23:53 -07001679static int detectEdgeBurst(const signalVector &burst, unsigned tsc, float threshold,
1680 int sps, complex &amplitude, float &toa, unsigned max_toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001681{
1682 int rc, target, head, tail;
1683 CorrelationSequence *sync;
1684
Tom Tsouae91f132017-03-28 14:40:38 -07001685 if (tsc > 7)
Tom Tsoud3253432016-03-06 03:08:01 -08001686 return -SIGERR_UNSUPPORTED;
1687
1688 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001689 head = 6;
1690 tail = 6 + max_toa;
Tom Tsoud3253432016-03-06 03:08:01 -08001691 sync = gEdgeMidambles[tsc];
1692
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001693 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Tom Tsoud3253432016-03-06 03:08:01 -08001694 target, head, tail, sync);
1695 return rc;
1696}
1697
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001698int detectAnyBurst(const signalVector &burst, unsigned tsc, float threshold,
Alexander Chemeris4e6c9382017-03-17 15:24:18 -07001699 int sps, CorrType type, complex &amp, float &toa,
1700 unsigned max_toa)
1701{
1702 int rc = 0;
1703
1704 switch (type) {
1705 case EDGE:
1706 rc = detectEdgeBurst(burst, tsc, threshold, sps,
1707 amp, toa, max_toa);
1708 if (rc > 0)
1709 break;
1710 else
1711 type = TSC;
1712 case TSC:
1713 rc = analyzeTrafficBurst(burst, tsc, threshold, sps,
1714 amp, toa, max_toa);
1715 break;
1716 case RACH:
1717 rc = detectRACHBurst(burst, threshold, sps, amp, toa,
1718 max_toa);
1719 break;
1720 default:
1721 LOG(ERR) << "Invalid correlation type";
1722 }
1723
1724 if (rc > 0)
1725 return type;
1726
1727 return rc;
1728}
1729
Tom Tsoud3253432016-03-06 03:08:01 -08001730/*
1731 * Soft 8-PSK decoding using Manhattan distance metric
1732 */
1733static SoftVector *softSliceEdgeBurst(signalVector &burst)
1734{
1735 size_t nsyms = 148;
1736
1737 if (burst.size() < nsyms)
1738 return NULL;
1739
1740 signalVector::iterator itr;
1741 SoftVector *bits = new SoftVector(nsyms * 3);
1742
1743 /*
1744 * Bits 0 and 1 - First and second bits of the symbol respectively
1745 */
1746 rotateBurst2(burst, -M_PI / 8.0);
1747 itr = burst.begin();
1748 for (size_t i = 0; i < nsyms; i++) {
1749 (*bits)[3 * i + 0] = -itr->imag();
1750 (*bits)[3 * i + 1] = itr->real();
1751 itr++;
1752 }
1753
1754 /*
1755 * Bit 2 - Collapse symbols into quadrant 0 (positive X and Y).
1756 * Decision area is then simplified to X=Y axis. Rotate again to
1757 * place decision boundary on X-axis.
1758 */
1759 itr = burst.begin();
1760 for (size_t i = 0; i < burst.size(); i++) {
1761 burst[i] = Complex<float>(fabs(itr->real()), fabs(itr->imag()));
1762 itr++;
1763 }
1764
1765 rotateBurst2(burst, -M_PI / 4.0);
1766 itr = burst.begin();
1767 for (size_t i = 0; i < nsyms; i++) {
1768 (*bits)[3 * i + 2] = -itr->imag();
1769 itr++;
1770 }
1771
1772 signalVector soft(bits->size());
1773 for (size_t i = 0; i < bits->size(); i++)
1774 soft[i] = (*bits)[i];
1775
1776 return bits;
1777}
1778
1779/*
Alexander Chemeris132fb242017-03-17 17:22:33 -07001780 * Convert signalVector to SoftVector by taking real part of the signal.
1781 */
1782static SoftVector *signalToSoftVector(signalVector *dec)
1783{
1784 SoftVector *bits = new SoftVector(dec->size());
1785
1786 SoftVector::iterator bit_itr = bits->begin();
1787 signalVector::iterator burst_itr = dec->begin();
1788
1789 for (; burst_itr < dec->end(); burst_itr++)
1790 *bit_itr++ = burst_itr->real();
1791
1792 return bits;
1793}
1794
1795/*
Tom Tsou7fec3032016-03-06 22:33:20 -08001796 * Shared portion of GMSK and EDGE demodulators consisting of timing
1797 * recovery and single tap channel correction. For 4 SPS (if activated),
1798 * the output is downsampled prior to the 1 SPS modulation specific
1799 * stages.
1800 */
Alexander Chemerise0c12182017-03-18 13:27:48 -07001801static signalVector *demodCommon(const signalVector &burst, int sps,
Tom Tsou7fec3032016-03-06 22:33:20 -08001802 complex chan, float toa)
1803{
1804 signalVector *delay, *dec;
1805
1806 if ((sps != 1) && (sps != 4))
1807 return NULL;
1808
Tom Tsou7fec3032016-03-06 22:33:20 -08001809 delay = delayVector(&burst, NULL, -toa * (float) sps);
Alexander Chemerise0c12182017-03-18 13:27:48 -07001810 scaleVector(*delay, (complex) 1.0 / chan);
Tom Tsou7fec3032016-03-06 22:33:20 -08001811
1812 if (sps == 1)
1813 return delay;
1814
1815 dec = downsampleBurst(*delay);
1816
1817 delete delay;
1818 return dec;
1819}
1820
1821/*
Tom Tsoud3253432016-03-06 03:08:01 -08001822 * Demodulate GSMK burst. Prior to symbol rotation, operate at
1823 * 4 SPS (if activated) to minimize distortion through the fractional
1824 * delay filters. Symbol rotation and after always operates at 1 SPS.
1825 */
Tom Tsou70134a02017-06-12 14:23:53 -07001826static SoftVector *demodGmskBurst(const signalVector &rxBurst,
1827 int sps, complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001828{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001829 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08001830 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001831
Tom Tsou7fec3032016-03-06 22:33:20 -08001832 dec = demodCommon(rxBurst, sps, channel, TOA);
1833 if (!dec)
1834 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001835
Tom Tsoud3253432016-03-06 03:08:01 -08001836 /* Shift up by a quarter of a frequency */
1837 GMSKReverseRotate(*dec, 1);
Alexander Chemeris132fb242017-03-17 17:22:33 -07001838 /* Take real part of the signal */
1839 bits = signalToSoftVector(dec);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001840 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001841
Thomas Tsou94edaae2013-11-09 22:19:19 -05001842 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001843}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001844
Tom Tsoud3253432016-03-06 03:08:01 -08001845/*
1846 * Demodulate an 8-PSK burst. Prior to symbol rotation, operate at
1847 * 4 SPS (if activated) to minimize distortion through the fractional
1848 * delay filters. Symbol rotation and after always operates at 1 SPS.
1849 *
1850 * Allow 1 SPS demodulation here, but note that other parts of the
1851 * transceiver restrict EDGE operatoin to 4 SPS - 8-PSK distortion
1852 * through the fractional delay filters at 1 SPS renders signal
1853 * nearly unrecoverable.
1854 */
Tom Tsou70134a02017-06-12 14:23:53 -07001855static SoftVector *demodEdgeBurst(const signalVector &burst,
1856 int sps, complex chan, float toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001857{
1858 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08001859 signalVector *dec, *rot, *eq;
Tom Tsoud3253432016-03-06 03:08:01 -08001860
Tom Tsou7fec3032016-03-06 22:33:20 -08001861 dec = demodCommon(burst, sps, chan, toa);
1862 if (!dec)
Tom Tsoud3253432016-03-06 03:08:01 -08001863 return NULL;
1864
Tom Tsou7fec3032016-03-06 22:33:20 -08001865 /* Equalize and derotate */
Tom Tsoud3253432016-03-06 03:08:01 -08001866 eq = convolve(dec, GSMPulse4->c0_inv, NULL, NO_DELAY);
1867 rot = derotateEdgeBurst(*eq, 1);
1868
Tom Tsou7fec3032016-03-06 22:33:20 -08001869 /* Soft slice and normalize */
Tom Tsou04795622016-04-26 21:17:36 -07001870 bits = softSliceEdgeBurst(*rot);
Tom Tsoud3253432016-03-06 03:08:01 -08001871
1872 delete dec;
1873 delete eq;
1874 delete rot;
1875
1876 return bits;
1877}
1878
Alexander Chemerise0c12182017-03-18 13:27:48 -07001879SoftVector *demodAnyBurst(const signalVector &burst, int sps, complex amp,
Alexander Chemeris6e1dffd2017-03-17 16:13:51 -07001880 float toa, CorrType type)
1881{
1882 if (type == EDGE)
1883 return demodEdgeBurst(burst, sps, amp, toa);
1884 else
1885 return demodGmskBurst(burst, sps, amp, toa);
1886}
1887
Tom Tsou2079a3c2016-03-06 00:58:56 -08001888bool sigProcLibSetup()
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001889{
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001890 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001891 generateSincTable();
Tom Tsou2079a3c2016-03-06 00:58:56 -08001892 initGMSKRotationTables();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001893
Tom Tsou2079a3c2016-03-06 00:58:56 -08001894 GSMPulse1 = generateGSMPulse(1);
1895 GSMPulse4 = generateGSMPulse(4);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001896
Tom Tsou2079a3c2016-03-06 00:58:56 -08001897 generateRACHSequence(1);
Tom Tsoud3253432016-03-06 03:08:01 -08001898 for (int tsc = 0; tsc < 8; tsc++) {
Tom Tsou2079a3c2016-03-06 00:58:56 -08001899 generateMidamble(1, tsc);
Tom Tsoud3253432016-03-06 03:08:01 -08001900 gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);
1901 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001902
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001903 generateDelayFilters();
1904
Tom Tsoud3253432016-03-06 03:08:01 -08001905 dnsampler = new Resampler(1, 4);
1906 if (!dnsampler->init()) {
1907 LOG(ALERT) << "Rx resampler failed to initialize";
1908 goto fail;
1909 }
1910
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001911 return true;
Tom Tsoud3253432016-03-06 03:08:01 -08001912
1913fail:
1914 sigProcLibDestroy();
1915 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001916}