blob: 3a9a529d41ba217a2db3aad4594780da928c5da8 [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;
588 signalVector *pulse, rotated, *shaped;
589 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 */
605 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
606 if (!shaped)
607 return NULL;
608
609 return shaped;
610}
611
Tom Tsoud3253432016-03-06 03:08:01 -0800612static void rotateBurst2(signalVector &burst, double phase)
613{
614 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
615
616 for (size_t i = 0; i < burst.size(); i++)
617 burst[i] = burst[i] * rot;
618}
619
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800620/*
621 * Ignore the guard length argument in the GMSK modulator interface
622 * because it results in 624/628 sized bursts instead of the preferred
623 * burst length of 625. Only 4 SPS is supported.
624 */
625static signalVector *modulateBurstLaurent(const BitVector &bits)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800626{
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800627 int burst_len, sps = 4;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800628 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500629 signalVector *c0_pulse, *c1_pulse, *c0_burst;
630 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800631 signalVector::iterator c0_itr, c1_itr;
632
Tom Tsou2079a3c2016-03-06 00:58:56 -0800633 c0_pulse = GSMPulse4->c0;
634 c1_pulse = GSMPulse4->c1;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800635
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800636 if (bits.size() > 156)
637 return NULL;
638
639 burst_len = 625;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800640
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500641 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500642 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500643 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800644
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500645 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500646 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500647 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800648
Tom Tsouaa15d622016-08-11 14:36:23 -0700649 /* Padded differential tail bits */
650 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800651 c0_itr += sps;
652
653 /* Main burst bits */
654 for (unsigned i = 0; i < bits.size(); i++) {
655 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
656 c0_itr += sps;
657 }
658
Tom Tsouaa15d622016-08-11 14:36:23 -0700659 /* Padded differential tail bits */
660 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800661
662 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500663 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500664 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800665
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500666 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800667 c0_itr += sps * 2;
668 c1_itr += sps * 2;
669
670 /* Start magic */
671 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
672 *c1_itr = *c0_itr * Complex<float>(0, phase);
673 c0_itr += sps;
674 c1_itr += sps;
675
676 /* Generate C1 phase coefficients */
677 for (unsigned i = 2; i < bits.size(); i++) {
678 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
679 *c1_itr = *c0_itr * Complex<float>(0, phase);
680
681 c0_itr += sps;
682 c1_itr += sps;
683 }
684
685 /* End magic */
686 int i = bits.size();
687 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
688 *c1_itr = *c0_itr * Complex<float>(0, phase);
689
690 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500691 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
692 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800693
694 /* Sum shaped outputs into C0 */
695 c0_itr = c0_shaped->begin();
696 c1_itr = c1_shaped->begin();
697 for (unsigned i = 0; i < c0_shaped->size(); i++ )
698 *c0_itr++ += *c1_itr++;
699
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500700 delete c0_burst;
701 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800702 delete c1_shaped;
703
704 return c0_shaped;
705}
706
Tom Tsoud3253432016-03-06 03:08:01 -0800707static signalVector *rotateEdgeBurst(const signalVector &symbols, int sps)
708{
709 signalVector *burst;
710 signalVector::iterator burst_itr;
711
712 burst = new signalVector(symbols.size() * sps);
713 burst_itr = burst->begin();
714
715 for (size_t i = 0; i < symbols.size(); i++) {
716 float phase = i * 3.0f * M_PI / 8.0f;
717 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
718
719 *burst_itr = symbols[i] * rot;
720 burst_itr += sps;
721 }
722
723 return burst;
724}
725
726static signalVector *derotateEdgeBurst(const signalVector &symbols, int sps)
727{
728 signalVector *burst;
729 signalVector::iterator burst_itr;
730
731 if (symbols.size() % sps)
732 return NULL;
733
734 burst = new signalVector(symbols.size() / sps);
735 burst_itr = burst->begin();
736
737 for (size_t i = 0; i < burst->size(); i++) {
738 float phase = (float) (i % 16) * 3.0f * M_PI / 8.0f;
739 Complex<float> rot = Complex<float>(cosf(phase), -sinf(phase));
740
741 *burst_itr = symbols[sps * i] * rot;
742 burst_itr++;
743 }
744
745 return burst;
746}
747
748static signalVector *mapEdgeSymbols(const BitVector &bits)
749{
750 if (bits.size() % 3)
751 return NULL;
752
753 signalVector *symbols = new signalVector(bits.size() / 3);
754
755 for (size_t i = 0; i < symbols->size(); i++) {
756 unsigned index = (((unsigned) bits[3 * i + 0] & 0x01) << 0) |
757 (((unsigned) bits[3 * i + 1] & 0x01) << 1) |
758 (((unsigned) bits[3 * i + 2] & 0x01) << 2);
759
760 (*symbols)[i] = psk8_table[index];
761 }
762
763 return symbols;
764}
765
Tom Tsoud2b07032016-04-26 19:28:59 -0700766/*
767 * EDGE 8-PSK rotate and pulse shape
768 *
769 * Delay the EDGE downlink bursts by one symbol in order to match GMSK pulse
770 * shaping group delay. The difference in group delay arises from the dual
771 * pulse filter combination of the GMSK Laurent represenation whereas 8-PSK
772 * uses a single pulse linear filter.
773 */
Tom Tsoud3253432016-03-06 03:08:01 -0800774static signalVector *shapeEdgeBurst(const signalVector &symbols)
775{
Tom Tsoud2b07032016-04-26 19:28:59 -0700776 size_t nsyms, nsamps = 625, sps = 4;
Tom Tsoud3253432016-03-06 03:08:01 -0800777 signalVector *burst, *shape;
778 signalVector::iterator burst_itr;
779
780 nsyms = symbols.size();
781
Tom Tsoud2b07032016-04-26 19:28:59 -0700782 if (nsyms * sps > nsamps)
Tom Tsoud3253432016-03-06 03:08:01 -0800783 nsyms = 156;
784
785 burst = new signalVector(nsamps, GSMPulse4->c0->size());
Tom Tsoud3253432016-03-06 03:08:01 -0800786
Tom Tsoud2b07032016-04-26 19:28:59 -0700787 /* Delay burst by 1 symbol */
788 burst_itr = burst->begin() + sps;
Tom Tsou06676ea2016-07-19 12:50:21 -0700789 for (size_t i = 0; i < nsyms; i++) {
Tom Tsoud3253432016-03-06 03:08:01 -0800790 float phase = i * 3.0f * M_PI / 8.0f;
791 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
792
793 *burst_itr = symbols[i] * rot;
Tom Tsoud2b07032016-04-26 19:28:59 -0700794 burst_itr += sps;
Tom Tsoud3253432016-03-06 03:08:01 -0800795 }
796
797 /* Single Gaussian pulse approximation shaping */
798 shape = convolve(burst, GSMPulse4->c0, NULL, START_ONLY);
799 delete burst;
800
801 return shape;
802}
803
804/*
Tom Tsou8ee2f382016-03-06 20:57:34 -0800805 * Generate a random GSM normal burst.
806 */
807signalVector *genRandNormalBurst(int tsc, int sps, int tn)
808{
809 if ((tsc < 0) || (tsc > 7) || (tn < 0) || (tn > 7))
810 return NULL;
811 if ((sps != 1) && (sps != 4))
812 return NULL;
813
814 int i = 0;
815 BitVector *bits = new BitVector(148);
816 signalVector *burst;
817
818 /* Tail bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700819 for (; i < 3; i++)
Tom Tsou8ee2f382016-03-06 20:57:34 -0800820 (*bits)[i] = 0;
821
822 /* Random bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700823 for (; i < 60; i++)
Tom Tsou8ee2f382016-03-06 20:57:34 -0800824 (*bits)[i] = rand() % 2;
825
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700826 /* Stealing bit */
827 (*bits)[i++] = 0;
828
Tom Tsou8ee2f382016-03-06 20:57:34 -0800829 /* Training sequence */
830 for (int n = 0; i < 87; i++, n++)
831 (*bits)[i] = gTrainingSequence[tsc][n];
832
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700833 /* Stealing bit */
834 (*bits)[i++] = 0;
835
Tom Tsou8ee2f382016-03-06 20:57:34 -0800836 /* Random bits */
Alexander Chemeris5e65b532017-03-24 23:24:22 -0700837 for (; i < 145; i++)
Tom Tsou8ee2f382016-03-06 20:57:34 -0800838 (*bits)[i] = rand() % 2;
839
840 /* Tail bits */
841 for (; i < 148; i++)
842 (*bits)[i] = 0;
843
844 int guard = 8 + !(tn % 4);
845 burst = modulateBurst(*bits, guard, sps);
846 delete bits;
847
848 return burst;
849}
850
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300851/*
852 * Generate a random GSM access burst.
853 */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300854signalVector *genRandAccessBurst(int delay, int sps, int tn)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300855{
856 if ((tn < 0) || (tn > 7))
857 return NULL;
858 if ((sps != 1) && (sps != 4))
859 return NULL;
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300860 if (delay > 68)
861 return NULL;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300862
863 int i = 0;
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300864 BitVector *bits = new BitVector(88+delay);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300865 signalVector *burst;
866
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300867 /* delay */
868 for (; i < delay; i++)
869 (*bits)[i] = 0;
870
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300871 /* head and synch bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300872 for (int n = 0; i < 49+delay; i++, n++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300873 (*bits)[i] = gRACHBurst[n];
874
875 /* Random bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300876 for (; i < 85+delay; i++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300877 (*bits)[i] = rand() % 2;
878
879 /* Tail bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300880 for (; i < 88+delay; i++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300881 (*bits)[i] = 0;
882
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300883 int guard = 68-delay + !(tn % 4);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300884 burst = modulateBurst(*bits, guard, sps);
885 delete bits;
886
887 return burst;
888}
889
Tom Tsou8ee2f382016-03-06 20:57:34 -0800890signalVector *generateEmptyBurst(int sps, int tn)
891{
892 if ((tn < 0) || (tn > 7))
893 return NULL;
894
895 if (sps == 4)
896 return new signalVector(625);
897 else if (sps == 1)
898 return new signalVector(148 + 8 + !(tn % 4));
899 else
900 return NULL;
901}
902
903signalVector *generateDummyBurst(int sps, int tn)
904{
905 if (((sps != 1) && (sps != 4)) || (tn < 0) || (tn > 7))
906 return NULL;
907
908 return modulateBurst(gDummyBurst, 8 + !(tn % 4), sps);
909}
910
911/*
Tom Tsoud3253432016-03-06 03:08:01 -0800912 * Generate a random 8-PSK EDGE burst. Only 4 SPS is supported with
913 * the returned burst being 625 samples in length.
914 */
915signalVector *generateEdgeBurst(int tsc)
916{
917 int tail = 9 / 3;
918 int data = 174 / 3;
919 int train = 78 / 3;
920
921 if ((tsc < 0) || (tsc > 7))
922 return NULL;
923
924 signalVector *shape, *burst = new signalVector(148);
925 const BitVector *midamble = &gEdgeTrainingSequence[tsc];
926
927 /* Tail */
928 int n, i = 0;
929 for (; i < tail; i++)
930 (*burst)[i] = psk8_table[7];
931
932 /* Body */
933 for (; i < tail + data; i++)
934 (*burst)[i] = psk8_table[rand() % 8];
935
936 /* TSC */
937 for (n = 0; i < tail + data + train; i++, n++) {
938 unsigned index = (((unsigned) (*midamble)[3 * n + 0] & 0x01) << 0) |
939 (((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
940 (((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
941
942 (*burst)[i] = psk8_table[index];
943 }
944
945 /* Body */
946 for (; i < tail + data + train + data; i++)
947 (*burst)[i] = psk8_table[rand() % 8];
948
949 /* Tail */
950 for (; i < tail + data + train + data + tail; i++)
951 (*burst)[i] = psk8_table[7];
952
953 shape = shapeEdgeBurst(*burst);
954 delete burst;
955
956 return shape;
957}
958
959/*
960 * Modulate 8-PSK burst. When empty pulse shaping (rotation only)
961 * is enabled, the output vector length will be bit sequence length
962 * times the SPS value. When pulse shaping is enabled, the output
Alexander Chemeris9270a5a2017-03-17 13:03:41 -0700963 * vector length is fixed at 625 samples (156.25 symbols at 4 SPS).
Tom Tsoud3253432016-03-06 03:08:01 -0800964 * Pulse shaped bit sequences that go beyond one burst are truncated.
965 * Pulse shaping at anything but 4 SPS is not supported.
966 */
967signalVector *modulateEdgeBurst(const BitVector &bits,
968 int sps, bool empty)
969{
970 signalVector *shape, *burst;
971
972 if ((sps != 4) && !empty)
973 return NULL;
974
975 burst = mapEdgeSymbols(bits);
976 if (!burst)
977 return NULL;
978
979 if (empty)
980 shape = rotateEdgeBurst(*burst, sps);
981 else
982 shape = shapeEdgeBurst(*burst);
983
984 delete burst;
985 return shape;
986}
987
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800988static signalVector *modulateBurstBasic(const BitVector &bits,
989 int guard_len, int sps)
990{
991 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500992 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800993 signalVector::iterator burst_itr;
994
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400995 if (sps == 1)
996 pulse = GSMPulse1->c0;
997 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800998 pulse = GSMPulse4->c0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400999
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001000 burst_len = sps * (bits.size() + guard_len);
1001
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001002 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001003 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001004 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001005
1006 /* Raw bits are not differentially encoded */
1007 for (unsigned i = 0; i < bits.size(); i++) {
1008 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
1009 burst_itr += sps;
1010 }
1011
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001012 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001013 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001014
1015 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001016 shaped = convolve(burst, pulse, NULL, START_ONLY);
1017
1018 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001019
1020 return shaped;
1021}
1022
Thomas Tsou3eaae802013-08-20 19:31:14 -04001023/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -04001024signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
1025 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +00001026{
Thomas Tsou83e06892013-08-20 16:10:01 -04001027 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001028 return rotateBurst(wBurst, guardPeriodLength, sps);
1029 else if (sps == 4)
Tom Tsou4dfd64a2016-03-06 20:31:51 -08001030 return modulateBurstLaurent(wBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -04001031 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001032 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001033}
1034
Tom Tsou2079a3c2016-03-06 00:58:56 -08001035static void generateSincTable()
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001036{
1037 float x;
1038
1039 for (int i = 0; i < TABLESIZE; i++) {
1040 x = (float) i / TABLESIZE * 8 * M_PI;
1041 if (fabs(x) < 0.01) {
1042 sincTable[i] = 1.0f;
1043 continue;
1044 }
1045
1046 sincTable[i] = sinf(x) / x;
1047 }
1048}
1049
Tom Tsou70134a02017-06-12 14:23:53 -07001050static float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +00001051{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001052 if (fabs(x) >= 8 * M_PI)
1053 return 0.0;
1054
1055 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
1056
1057 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +00001058}
1059
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001060/*
1061 * Create fractional delay filterbank with Blackman-harris windowed
1062 * sinc function generator. The number of filters generated is specified
1063 * by the DELAYFILTS value.
1064 */
Tom Tsou70134a02017-06-12 14:23:53 -07001065static void generateDelayFilters()
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001066{
1067 int h_len = 20;
1068 complex *data;
1069 signalVector *h;
1070 signalVector::iterator itr;
1071
1072 float k, sum;
1073 float a0 = 0.35875;
1074 float a1 = 0.48829;
1075 float a2 = 0.14128;
1076 float a3 = 0.01168;
1077
1078 for (int i = 0; i < DELAYFILTS; i++) {
1079 data = (complex *) convolve_h_alloc(h_len);
1080 h = new signalVector(data, 0, h_len);
1081 h->setAligned(true);
1082 h->isReal(true);
1083
1084 sum = 0.0;
1085 itr = h->end();
1086 for (int n = 0; n < h_len; n++) {
1087 k = (float) n;
1088 *--itr = (complex) sinc(M_PI_F *
1089 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
1090 *itr *= a0 -
1091 a1 * cos(2 * M_PI * n / (h_len - 1)) +
1092 a2 * cos(4 * M_PI * n / (h_len - 1)) -
1093 a3 * cos(6 * M_PI * n / (h_len - 1));
1094
1095 sum += itr->real();
1096 }
1097
1098 itr = h->begin();
1099 for (int n = 0; n < h_len; n++)
1100 *itr++ /= sum;
1101
1102 delayFilters[i] = h;
1103 }
1104}
1105
Alexander Chemerise0c12182017-03-18 13:27:48 -07001106signalVector *delayVector(const signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +00001107{
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001108 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001109 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001110 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001111
Thomas Tsou2c282f52013-10-08 21:34:35 -04001112 whole = floor(delay);
1113 frac = delay - whole;
1114
1115 /* Sinc interpolated fractional shift (if allowable) */
1116 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001117 index = floorf(frac * (float) DELAYFILTS);
1118 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -04001119
Thomas Tsou94edaae2013-11-09 22:19:19 -05001120 fshift = convolve(in, h, NULL, NO_DELAY);
1121 if (!fshift)
1122 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001123 }
1124
Thomas Tsou94edaae2013-11-09 22:19:19 -05001125 if (!fshift)
1126 shift = new signalVector(*in);
1127 else
1128 shift = fshift;
1129
Thomas Tsou2c282f52013-10-08 21:34:35 -04001130 /* Integer sample shift */
1131 if (whole < 0) {
1132 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001133 signalVector::iterator wBurstItr = shift->begin();
1134 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001135
Thomas Tsou94edaae2013-11-09 22:19:19 -05001136 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +00001137 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001138
Thomas Tsou94edaae2013-11-09 22:19:19 -05001139 while (wBurstItr < shift->end())
1140 *wBurstItr++ = 0.0;
1141 } else if (whole >= 0) {
1142 signalVector::iterator wBurstItr = shift->end() - 1;
1143 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
1144
1145 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001146 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001147
1148 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001149 *wBurstItr-- = 0.0;
1150 }
Thomas Tsou2c282f52013-10-08 21:34:35 -04001151
Thomas Tsou94edaae2013-11-09 22:19:19 -05001152 if (!out)
1153 return shift;
1154
1155 out->clone(*shift);
1156 delete shift;
1157 return out;
dburgessb3a0ca42011-10-12 07:44:40 +00001158}
Thomas Tsou2c282f52013-10-08 21:34:35 -04001159
Tom Tsou70134a02017-06-12 14:23:53 -07001160static complex interpolatePoint(const signalVector &inSig, float ix)
dburgessb3a0ca42011-10-12 07:44:40 +00001161{
dburgessb3a0ca42011-10-12 07:44:40 +00001162 int start = (int) (floor(ix) - 10);
1163 if (start < 0) start = 0;
1164 int end = (int) (floor(ix) + 11);
1165 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
1166
1167 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001168 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001169 for (int i = start; i < end; i++)
1170 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
1171 }
1172 else {
1173 for (int i = start; i < end; i++)
1174 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
1175 }
1176
1177 return pVal;
1178}
1179
Thomas Tsou8181b012013-08-20 21:17:19 -04001180static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1181{
1182 float val, max = 0.0f;
1183 complex amp;
1184 int _index = -1;
1185
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001186 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001187 val = rxBurst[i].norm2();
1188 if (val > max) {
1189 max = val;
1190 _index = i;
1191 amp = rxBurst[i];
1192 }
1193 }
1194
1195 if (index)
1196 *index = (float) _index;
1197
1198 return amp;
1199}
1200
Tom Tsou70134a02017-06-12 14:23:53 -07001201static complex peakDetect(const signalVector &rxBurst,
1202 float *peakIndex, float *avgPwr)
dburgessb3a0ca42011-10-12 07:44:40 +00001203{
dburgessb3a0ca42011-10-12 07:44:40 +00001204 complex maxVal = 0.0;
1205 float maxIndex = -1;
1206 float sumPower = 0.0;
1207
1208 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1209 float samplePower = rxBurst[i].norm2();
1210 if (samplePower > maxVal.real()) {
1211 maxVal = samplePower;
1212 maxIndex = i;
1213 }
1214 sumPower += samplePower;
1215 }
1216
1217 // interpolate around the peak
1218 // to save computation, we'll use early-late balancing
1219 float earlyIndex = maxIndex-1;
1220 float lateIndex = maxIndex+1;
1221
1222 float incr = 0.5;
1223 while (incr > 1.0/1024.0) {
1224 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1225 complex lateP = interpolatePoint(rxBurst,lateIndex);
1226 if (earlyP < lateP)
1227 earlyIndex += incr;
1228 else if (earlyP > lateP)
1229 earlyIndex -= incr;
1230 else break;
1231 incr /= 2.0;
1232 lateIndex = earlyIndex + 2.0;
1233 }
1234
1235 maxIndex = earlyIndex + 1.0;
1236 maxVal = interpolatePoint(rxBurst,maxIndex);
1237
1238 if (peakIndex!=NULL)
1239 *peakIndex = maxIndex;
1240
1241 if (avgPwr!=NULL)
1242 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1243
1244 return maxVal;
1245
1246}
1247
1248void scaleVector(signalVector &x,
1249 complex scale)
1250{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001251#ifdef HAVE_NEON
1252 int len = x.size();
1253
1254 scale_complex((float *) x.begin(),
1255 (float *) x.begin(),
1256 (float *) &scale, len);
1257#else
dburgessb3a0ca42011-10-12 07:44:40 +00001258 signalVector::iterator xP = x.begin();
1259 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001260 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001261 while (xP < xPEnd) {
1262 *xP = *xP * scale;
1263 xP++;
1264 }
1265 }
1266 else {
1267 while (xP < xPEnd) {
1268 *xP = xP->real() * scale;
1269 xP++;
1270 }
1271 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001272#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001273}
1274
1275/** in-place conjugation */
Tom Tsou70134a02017-06-12 14:23:53 -07001276static void conjugateVector(signalVector &x)
dburgessb3a0ca42011-10-12 07:44:40 +00001277{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001278 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001279 signalVector::iterator xP = x.begin();
1280 signalVector::iterator xPEnd = x.end();
1281 while (xP < xPEnd) {
1282 *xP = xP->conj();
1283 xP++;
1284 }
1285}
1286
Tom Tsou2079a3c2016-03-06 00:58:56 -08001287static bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001288{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001289 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001290 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001291 complex *data = NULL;
1292 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001293 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001294
Thomas Tsou3eaae802013-08-20 19:31:14 -04001295 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001296 return false;
1297
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001298 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001299
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001300 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1301 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1302 if (!midMidamble)
1303 return false;
1304
Thomas Tsou3eaae802013-08-20 19:31:14 -04001305 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001306 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1307 if (!midamble) {
1308 status = false;
1309 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001310 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001311
dburgessb3a0ca42011-10-12 07:44:40 +00001312 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1313 // the ideal TSC has an + 180 degree phase shift,
1314 // due to the pi/2 frequency shift, that
1315 // needs to be accounted for.
1316 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001317 scaleVector(*midMidamble, complex(-1.0, 0.0));
1318 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001319
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001320 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001321
Thomas Tsou3eaae802013-08-20 19:31:14 -04001322 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1323 data = (complex *) convolve_h_alloc(midMidamble->size());
1324 _midMidamble = new signalVector(data, 0, midMidamble->size());
1325 _midMidamble->setAligned(true);
1326 memcpy(_midMidamble->begin(), midMidamble->begin(),
1327 midMidamble->size() * sizeof(complex));
1328
1329 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001330 if (!autocorr) {
1331 status = false;
1332 goto release;
1333 }
dburgessb3a0ca42011-10-12 07:44:40 +00001334
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001335 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001336 gMidambles[tsc]->buffer = data;
1337 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001338 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1339
1340 /* For 1 sps only
1341 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1342 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1343 */
1344 if (sps == 1)
1345 gMidambles[tsc]->toa = toa - 13.5;
1346 else
1347 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001348
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001349release:
dburgessb3a0ca42011-10-12 07:44:40 +00001350 delete autocorr;
1351 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001352 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001353
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001354 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001355 delete _midMidamble;
1356 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001357 gMidambles[tsc] = NULL;
1358 }
1359
1360 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001361}
1362
Tom Tsou70134a02017-06-12 14:23:53 -07001363static CorrelationSequence *generateEdgeMidamble(int tsc)
Tom Tsoud3253432016-03-06 03:08:01 -08001364{
1365 complex *data = NULL;
1366 signalVector *midamble = NULL, *_midamble = NULL;
1367 CorrelationSequence *seq;
1368
1369 if ((tsc < 0) || (tsc > 7))
1370 return NULL;
1371
1372 /* Use middle 48 bits of each TSC. Correlation sequence is not pulse shaped */
1373 const BitVector *bits = &gEdgeTrainingSequence[tsc];
1374 midamble = modulateEdgeBurst(bits->segment(15, 48), 1, true);
1375 if (!midamble)
1376 return NULL;
1377
1378 conjugateVector(*midamble);
1379
1380 data = (complex *) convolve_h_alloc(midamble->size());
1381 _midamble = new signalVector(data, 0, midamble->size());
1382 _midamble->setAligned(true);
1383 memcpy(_midamble->begin(), midamble->begin(),
1384 midamble->size() * sizeof(complex));
1385
1386 /* Channel gain is an empirically measured value */
1387 seq = new CorrelationSequence;
1388 seq->buffer = data;
1389 seq->sequence = _midamble;
1390 seq->gain = Complex<float>(-19.6432, 19.5006) / 1.18;
1391 seq->toa = 0;
1392
1393 delete midamble;
1394
1395 return seq;
1396}
1397
Tom Tsou2079a3c2016-03-06 00:58:56 -08001398static bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001399{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001400 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001401 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001402 complex *data = NULL;
1403 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001404 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001405
1406 delete gRACHSequence;
1407
1408 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1409 if (!seq0)
1410 return false;
1411
1412 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1413 if (!seq1) {
1414 status = false;
1415 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001416 }
1417
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001418 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001419
Thomas Tsou3eaae802013-08-20 19:31:14 -04001420 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1421 data = (complex *) convolve_h_alloc(seq1->size());
1422 _seq1 = new signalVector(data, 0, seq1->size());
1423 _seq1->setAligned(true);
1424 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1425
1426 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1427 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001428 status = false;
1429 goto release;
1430 }
dburgessb3a0ca42011-10-12 07:44:40 +00001431
1432 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001433 gRACHSequence->sequence = _seq1;
1434 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001435 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1436
1437 /* For 1 sps only
1438 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1439 * 20.5 = (40 / 2 - 1) + 1.5
1440 */
1441 if (sps == 1)
1442 gRACHSequence->toa = toa - 20.5;
1443 else
1444 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001445
1446release:
dburgessb3a0ca42011-10-12 07:44:40 +00001447 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001448 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001449 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001450
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001451 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001452 delete _seq1;
1453 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001454 gRACHSequence = NULL;
1455 }
dburgessb3a0ca42011-10-12 07:44:40 +00001456
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001457 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001458}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001459
Tom Tsoua84e1622016-06-29 14:50:25 -07001460/*
1461 * Peak-to-average computation +/- range from peak in symbols
1462 */
1463#define COMPUTE_PEAK_MIN 2
1464#define COMPUTE_PEAK_MAX 5
1465
1466/*
1467 * Minimum number of values needed to compute peak-to-average
1468 */
1469#define COMPUTE_PEAK_CNT 5
1470
Thomas Tsou865bca42013-08-21 20:58:00 -04001471static float computePeakRatio(signalVector *corr,
1472 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001473{
Thomas Tsou865bca42013-08-21 20:58:00 -04001474 int num = 0;
1475 complex *peak;
1476 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001477
Thomas Tsou865bca42013-08-21 20:58:00 -04001478 /* Check for bogus results */
1479 if ((toa < 0.0) || (toa > corr->size()))
1480 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001481
Alexander Chemeris1e9b4d52015-06-04 19:05:28 -04001482 peak = corr->begin() + (int) rint(toa);
1483
Tom Tsoua84e1622016-06-29 14:50:25 -07001484 for (int i = COMPUTE_PEAK_MIN * sps; i <= COMPUTE_PEAK_MAX * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001485 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001486 avg += (peak - i)->norm2();
1487 num++;
1488 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001489 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001490 avg += (peak + i)->norm2();
1491 num++;
1492 }
dburgessb3a0ca42011-10-12 07:44:40 +00001493 }
1494
Tom Tsoua84e1622016-06-29 14:50:25 -07001495 if (num < COMPUTE_PEAK_CNT)
Thomas Tsou865bca42013-08-21 20:58:00 -04001496 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001497
Thomas Tsou3eaae802013-08-20 19:31:14 -04001498 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001499
Thomas Tsou865bca42013-08-21 20:58:00 -04001500 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001501}
1502
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001503float energyDetect(const signalVector &rxBurst, unsigned windowLength)
dburgessb3a0ca42011-10-12 07:44:40 +00001504{
1505
1506 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1507 float energy = 0.0;
Tom Tsou2af14402017-03-23 14:54:00 -07001508 if (windowLength == 0) return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001509 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1510 for (unsigned i = 0; i < windowLength; i++) {
1511 energy += windowItr->norm2();
1512 windowItr+=4;
1513 }
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +03001514 return energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001515}
dburgessb3a0ca42011-10-12 07:44:40 +00001516
Tom Tsou70134a02017-06-12 14:23:53 -07001517static signalVector *downsampleBurst(const signalVector &burst)
1518{
1519 signalVector *in, *out;
1520
1521 in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len());
1522 out = new signalVector(DOWNSAMPLE_OUT_LEN);
1523 memcpy(in->begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
1524
1525 if (dnsampler->rotate((float *) in->begin(), DOWNSAMPLE_IN_LEN,
1526 (float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
1527 delete out;
1528 out = NULL;
1529 }
1530
1531 delete in;
1532 return out;
1533};
1534
Thomas Tsou865bca42013-08-21 20:58:00 -04001535/*
1536 * Detect a burst based on correlation and peak-to-average ratio
1537 *
1538 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1539 * for initial gating. We do this because energy detection should be disabled.
1540 * For higher oversampling values, we assume the energy detector is in place
1541 * and we run full interpolating peak detection.
1542 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001543static int detectBurst(const signalVector &burst,
Thomas Tsou865bca42013-08-21 20:58:00 -04001544 signalVector &corr, CorrelationSequence *sync,
1545 float thresh, int sps, complex *amp, float *toa,
1546 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001547{
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001548 const signalVector *corr_in;
1549 signalVector *dec = NULL;
Tom Tsoud3253432016-03-06 03:08:01 -08001550
1551 if (sps == 4) {
1552 dec = downsampleBurst(burst);
1553 corr_in = dec;
1554 sps = 1;
1555 } else {
1556 corr_in = &burst;
1557 }
1558
Thomas Tsou865bca42013-08-21 20:58:00 -04001559 /* Correlate */
Tom Tsoud3253432016-03-06 03:08:01 -08001560 if (!convolve(corr_in, sync->sequence, &corr,
1561 CUSTOM, start, len, 1, 0)) {
1562 delete dec;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001563 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001564 }
1565
Tom Tsoud3253432016-03-06 03:08:01 -08001566 delete dec;
1567
1568 /* Running at the downsampled rate at this point */
1569 sps = 1;
1570
Thomas Tsou865bca42013-08-21 20:58:00 -04001571 /* Peak detection - place restrictions at correlation edges */
1572 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001573
Thomas Tsou865bca42013-08-21 20:58:00 -04001574 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1575 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001576
Thomas Tsou865bca42013-08-21 20:58:00 -04001577 /* Peak -to-average ratio */
1578 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1579 return 0;
1580
1581 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1582 *amp = peakDetect(corr, toa, NULL);
1583
1584 /* Normalize our channel gain */
1585 *amp = *amp / sync->gain;
1586
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001587 /* Compensate for residuate time lag */
1588 *toa = *toa - sync->toa;
1589
Thomas Tsou865bca42013-08-21 20:58:00 -04001590 return 1;
1591}
1592
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001593static float maxAmplitude(const signalVector &burst)
Tom Tsou577cd022015-05-18 13:57:54 -07001594{
Alexander Chemeris954b1182015-06-04 15:39:41 -04001595 float max = 0.0;
1596 for (size_t i = 0; i < burst.size(); i++) {
1597 if (fabs(burst[i].real()) > max)
1598 max = fabs(burst[i].real());
1599 if (fabs(burst[i].imag()) > max)
1600 max = fabs(burst[i].imag());
1601 }
Tom Tsou577cd022015-05-18 13:57:54 -07001602
Alexander Chemeris954b1182015-06-04 15:39:41 -04001603 return max;
Tom Tsou577cd022015-05-18 13:57:54 -07001604}
1605
Alexander Chemeris130a8002015-06-09 20:52:11 -04001606/*
1607 * RACH/Normal burst detection with clipping detection
Thomas Tsou865bca42013-08-21 20:58:00 -04001608 *
1609 * Correlation window parameters:
Alexander Chemeris130a8002015-06-09 20:52:11 -04001610 * target: Tail bits + burst length
1611 * head: Search symbols before target
1612 * tail: Search symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001613 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001614static int detectGeneralBurst(const signalVector &rxBurst,
1615 float thresh,
1616 int sps,
1617 complex &amp,
1618 float &toa,
1619 int target, int head, int tail,
1620 CorrelationSequence *sync)
Thomas Tsou865bca42013-08-21 20:58:00 -04001621{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001622 int rc, start, len;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001623 bool clipping = false;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001624 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001625
1626 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001627 return -SIGERR_UNSUPPORTED;
1628
Alexander Chemeris954b1182015-06-04 15:39:41 -04001629 // Detect potential clipping
1630 // We still may be able to demod the burst, so we'll give it a try
1631 // and only report clipping if we can't demod.
1632 float maxAmpl = maxAmplitude(rxBurst);
1633 if (maxAmpl > CLIP_THRESH) {
1634 LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
1635 clipping = true;
1636 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001637
Tom Tsoud3253432016-03-06 03:08:01 -08001638 start = target - head - 1;
1639 len = head + tail;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001640 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001641
Thomas Tsoub075dd22013-11-09 22:25:46 -05001642 rc = detectBurst(rxBurst, *corr, sync,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001643 thresh, sps, &amp, &toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001644 delete corr;
1645
Thomas Tsou865bca42013-08-21 20:58:00 -04001646 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001647 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001648 } else if (!rc) {
Alexander Chemeris130a8002015-06-09 20:52:11 -04001649 amp = 0.0f;
1650 toa = 0.0f;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001651 return clipping?-SIGERR_CLIP:SIGERR_NONE;
dburgessb3a0ca42011-10-12 07:44:40 +00001652 }
1653
Thomas Tsou865bca42013-08-21 20:58:00 -04001654 /* Subtract forward search bits from delay */
Tom Tsoud3253432016-03-06 03:08:01 -08001655 toa -= head;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001656
Thomas Tsou865bca42013-08-21 20:58:00 -04001657 return 1;
1658}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001659
Alexander Chemeris130a8002015-06-09 20:52:11 -04001660
1661/*
1662 * RACH burst detection
1663 *
1664 * Correlation window parameters:
1665 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Tom Tsoue90c24c2016-06-21 16:14:39 -07001666 * head: Search 8 symbols before target
1667 * tail: Search 8 symbols + maximum expected delay
Alexander Chemeris130a8002015-06-09 20:52:11 -04001668 */
Tom Tsou70134a02017-06-12 14:23:53 -07001669static int detectRACHBurst(const signalVector &burst, float threshold, int sps,
1670 complex &amplitude, float &toa, unsigned max_toa)
Alexander Chemeris130a8002015-06-09 20:52:11 -04001671{
1672 int rc, target, head, tail;
1673 CorrelationSequence *sync;
1674
1675 target = 8 + 40;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001676 head = 8;
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001677 tail = 8 + max_toa;
Alexander Chemeris130a8002015-06-09 20:52:11 -04001678 sync = gRACHSequence;
1679
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001680 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001681 target, head, tail, sync);
1682
1683 return rc;
1684}
1685
Thomas Tsou865bca42013-08-21 20:58:00 -04001686/*
1687 * Normal burst detection
1688 *
1689 * Correlation window parameters:
1690 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Tom Tsoue90c24c2016-06-21 16:14:39 -07001691 * head: Search 6 symbols before target
1692 * tail: Search 6 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001693 */
Tom Tsou70134a02017-06-12 14:23:53 -07001694static int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float threshold,
1695 int sps, complex &amplitude, float &toa, unsigned max_toa)
Thomas Tsou865bca42013-08-21 20:58:00 -04001696{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001697 int rc, target, head, tail;
Thomas Tsou865bca42013-08-21 20:58:00 -04001698 CorrelationSequence *sync;
1699
Tom Tsouae91f132017-03-28 14:40:38 -07001700 if (tsc > 7)
Tom Tsou577cd022015-05-18 13:57:54 -07001701 return -SIGERR_UNSUPPORTED;
1702
Thomas Tsou865bca42013-08-21 20:58:00 -04001703 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001704 head = 6;
1705 tail = 6 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001706 sync = gMidambles[tsc];
Thomas Tsou865bca42013-08-21 20:58:00 -04001707
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001708 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001709 target, head, tail, sync);
Alexander Chemeris130a8002015-06-09 20:52:11 -04001710 return rc;
dburgessb3a0ca42011-10-12 07:44:40 +00001711}
1712
Tom Tsou70134a02017-06-12 14:23:53 -07001713static int detectEdgeBurst(const signalVector &burst, unsigned tsc, float threshold,
1714 int sps, complex &amplitude, float &toa, unsigned max_toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001715{
1716 int rc, target, head, tail;
1717 CorrelationSequence *sync;
1718
Tom Tsouae91f132017-03-28 14:40:38 -07001719 if (tsc > 7)
Tom Tsoud3253432016-03-06 03:08:01 -08001720 return -SIGERR_UNSUPPORTED;
1721
1722 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001723 head = 6;
1724 tail = 6 + max_toa;
Tom Tsoud3253432016-03-06 03:08:01 -08001725 sync = gEdgeMidambles[tsc];
1726
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001727 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Tom Tsoud3253432016-03-06 03:08:01 -08001728 target, head, tail, sync);
1729 return rc;
1730}
1731
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001732int detectAnyBurst(const signalVector &burst, unsigned tsc, float threshold,
Alexander Chemeris4e6c9382017-03-17 15:24:18 -07001733 int sps, CorrType type, complex &amp, float &toa,
1734 unsigned max_toa)
1735{
1736 int rc = 0;
1737
1738 switch (type) {
1739 case EDGE:
1740 rc = detectEdgeBurst(burst, tsc, threshold, sps,
1741 amp, toa, max_toa);
1742 if (rc > 0)
1743 break;
1744 else
1745 type = TSC;
1746 case TSC:
1747 rc = analyzeTrafficBurst(burst, tsc, threshold, sps,
1748 amp, toa, max_toa);
1749 break;
1750 case RACH:
1751 rc = detectRACHBurst(burst, threshold, sps, amp, toa,
1752 max_toa);
1753 break;
1754 default:
1755 LOG(ERR) << "Invalid correlation type";
1756 }
1757
1758 if (rc > 0)
1759 return type;
1760
1761 return rc;
1762}
1763
Tom Tsoud3253432016-03-06 03:08:01 -08001764/*
1765 * Soft 8-PSK decoding using Manhattan distance metric
1766 */
1767static SoftVector *softSliceEdgeBurst(signalVector &burst)
1768{
1769 size_t nsyms = 148;
1770
1771 if (burst.size() < nsyms)
1772 return NULL;
1773
1774 signalVector::iterator itr;
1775 SoftVector *bits = new SoftVector(nsyms * 3);
1776
1777 /*
1778 * Bits 0 and 1 - First and second bits of the symbol respectively
1779 */
1780 rotateBurst2(burst, -M_PI / 8.0);
1781 itr = burst.begin();
1782 for (size_t i = 0; i < nsyms; i++) {
1783 (*bits)[3 * i + 0] = -itr->imag();
1784 (*bits)[3 * i + 1] = itr->real();
1785 itr++;
1786 }
1787
1788 /*
1789 * Bit 2 - Collapse symbols into quadrant 0 (positive X and Y).
1790 * Decision area is then simplified to X=Y axis. Rotate again to
1791 * place decision boundary on X-axis.
1792 */
1793 itr = burst.begin();
1794 for (size_t i = 0; i < burst.size(); i++) {
1795 burst[i] = Complex<float>(fabs(itr->real()), fabs(itr->imag()));
1796 itr++;
1797 }
1798
1799 rotateBurst2(burst, -M_PI / 4.0);
1800 itr = burst.begin();
1801 for (size_t i = 0; i < nsyms; i++) {
1802 (*bits)[3 * i + 2] = -itr->imag();
1803 itr++;
1804 }
1805
1806 signalVector soft(bits->size());
1807 for (size_t i = 0; i < bits->size(); i++)
1808 soft[i] = (*bits)[i];
1809
1810 return bits;
1811}
1812
1813/*
Alexander Chemeris132fb242017-03-17 17:22:33 -07001814 * Convert signalVector to SoftVector by taking real part of the signal.
1815 */
1816static SoftVector *signalToSoftVector(signalVector *dec)
1817{
1818 SoftVector *bits = new SoftVector(dec->size());
1819
1820 SoftVector::iterator bit_itr = bits->begin();
1821 signalVector::iterator burst_itr = dec->begin();
1822
1823 for (; burst_itr < dec->end(); burst_itr++)
1824 *bit_itr++ = burst_itr->real();
1825
1826 return bits;
1827}
1828
1829/*
Tom Tsou7fec3032016-03-06 22:33:20 -08001830 * Shared portion of GMSK and EDGE demodulators consisting of timing
1831 * recovery and single tap channel correction. For 4 SPS (if activated),
1832 * the output is downsampled prior to the 1 SPS modulation specific
1833 * stages.
1834 */
Alexander Chemerise0c12182017-03-18 13:27:48 -07001835static signalVector *demodCommon(const signalVector &burst, int sps,
Tom Tsou7fec3032016-03-06 22:33:20 -08001836 complex chan, float toa)
1837{
1838 signalVector *delay, *dec;
1839
1840 if ((sps != 1) && (sps != 4))
1841 return NULL;
1842
Tom Tsou7fec3032016-03-06 22:33:20 -08001843 delay = delayVector(&burst, NULL, -toa * (float) sps);
Alexander Chemerise0c12182017-03-18 13:27:48 -07001844 scaleVector(*delay, (complex) 1.0 / chan);
Tom Tsou7fec3032016-03-06 22:33:20 -08001845
1846 if (sps == 1)
1847 return delay;
1848
1849 dec = downsampleBurst(*delay);
1850
1851 delete delay;
1852 return dec;
1853}
1854
1855/*
Tom Tsoud3253432016-03-06 03:08:01 -08001856 * Demodulate GSMK burst. Prior to symbol rotation, operate at
1857 * 4 SPS (if activated) to minimize distortion through the fractional
1858 * delay filters. Symbol rotation and after always operates at 1 SPS.
1859 */
Tom Tsou70134a02017-06-12 14:23:53 -07001860static SoftVector *demodGmskBurst(const signalVector &rxBurst,
1861 int sps, complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001862{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001863 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08001864 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001865
Tom Tsou7fec3032016-03-06 22:33:20 -08001866 dec = demodCommon(rxBurst, sps, channel, TOA);
1867 if (!dec)
1868 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001869
Tom Tsoud3253432016-03-06 03:08:01 -08001870 /* Shift up by a quarter of a frequency */
1871 GMSKReverseRotate(*dec, 1);
Alexander Chemeris132fb242017-03-17 17:22:33 -07001872 /* Take real part of the signal */
1873 bits = signalToSoftVector(dec);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001874 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001875
Thomas Tsou94edaae2013-11-09 22:19:19 -05001876 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001877}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001878
Tom Tsoud3253432016-03-06 03:08:01 -08001879/*
1880 * Demodulate an 8-PSK burst. Prior to symbol rotation, operate at
1881 * 4 SPS (if activated) to minimize distortion through the fractional
1882 * delay filters. Symbol rotation and after always operates at 1 SPS.
1883 *
1884 * Allow 1 SPS demodulation here, but note that other parts of the
1885 * transceiver restrict EDGE operatoin to 4 SPS - 8-PSK distortion
1886 * through the fractional delay filters at 1 SPS renders signal
1887 * nearly unrecoverable.
1888 */
Tom Tsou70134a02017-06-12 14:23:53 -07001889static SoftVector *demodEdgeBurst(const signalVector &burst,
1890 int sps, complex chan, float toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001891{
1892 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08001893 signalVector *dec, *rot, *eq;
Tom Tsoud3253432016-03-06 03:08:01 -08001894
Tom Tsou7fec3032016-03-06 22:33:20 -08001895 dec = demodCommon(burst, sps, chan, toa);
1896 if (!dec)
Tom Tsoud3253432016-03-06 03:08:01 -08001897 return NULL;
1898
Tom Tsou7fec3032016-03-06 22:33:20 -08001899 /* Equalize and derotate */
Tom Tsoud3253432016-03-06 03:08:01 -08001900 eq = convolve(dec, GSMPulse4->c0_inv, NULL, NO_DELAY);
1901 rot = derotateEdgeBurst(*eq, 1);
1902
Tom Tsou7fec3032016-03-06 22:33:20 -08001903 /* Soft slice and normalize */
Tom Tsou04795622016-04-26 21:17:36 -07001904 bits = softSliceEdgeBurst(*rot);
Tom Tsoud3253432016-03-06 03:08:01 -08001905
1906 delete dec;
1907 delete eq;
1908 delete rot;
1909
1910 return bits;
1911}
1912
Alexander Chemerise0c12182017-03-18 13:27:48 -07001913SoftVector *demodAnyBurst(const signalVector &burst, int sps, complex amp,
Alexander Chemeris6e1dffd2017-03-17 16:13:51 -07001914 float toa, CorrType type)
1915{
1916 if (type == EDGE)
1917 return demodEdgeBurst(burst, sps, amp, toa);
1918 else
1919 return demodGmskBurst(burst, sps, amp, toa);
1920}
1921
Tom Tsou2079a3c2016-03-06 00:58:56 -08001922bool sigProcLibSetup()
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001923{
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001924 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001925 generateSincTable();
Tom Tsou2079a3c2016-03-06 00:58:56 -08001926 initGMSKRotationTables();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001927
Tom Tsou2079a3c2016-03-06 00:58:56 -08001928 GSMPulse1 = generateGSMPulse(1);
1929 GSMPulse4 = generateGSMPulse(4);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001930
Tom Tsou2079a3c2016-03-06 00:58:56 -08001931 generateRACHSequence(1);
Tom Tsoud3253432016-03-06 03:08:01 -08001932 for (int tsc = 0; tsc < 8; tsc++) {
Tom Tsou2079a3c2016-03-06 00:58:56 -08001933 generateMidamble(1, tsc);
Tom Tsoud3253432016-03-06 03:08:01 -08001934 gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);
1935 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001936
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001937 generateDelayFilters();
1938
Tom Tsoud3253432016-03-06 03:08:01 -08001939 dnsampler = new Resampler(1, 4);
1940 if (!dnsampler->init()) {
1941 LOG(ALERT) << "Rx resampler failed to initialize";
1942 goto fail;
1943 }
1944
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001945 return true;
Tom Tsoud3253432016-03-06 03:08:01 -08001946
1947fail:
1948 sigProcLibDestroy();
1949 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001950}