blob: 41b18cfc53b485f4c7bf8cffe244439687c44e62 [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 */
49float cosTable[TABLESIZE+1]; // add 1 element for wrap around
50float sinTable[TABLESIZE+1];
Thomas Tsou0e0e1f42013-11-09 22:08:51 -050051float 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 Tsoud3253432016-03-06 03:08:01 -080067static Complex<float> psk8_table[8] = {
68 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
dburgessb3a0ca42011-10-12 07:44:40 +0000175// dB relative to 1.0.
176// if > 1.0, then return 0 dB
177float dB(float x) {
178
179 float arg = 1.0F;
180 float dB = 0.0F;
181
182 if (x >= 1.0F) return 0.0F;
183 if (x <= 0.0F) return -200.0F;
184
185 float prevArg = arg;
186 float prevdB = dB;
187 float stepSize = 16.0F;
188 float dBstepSize = 12.0F;
189 while (stepSize > 1.0F) {
190 do {
191 prevArg = arg;
192 prevdB = dB;
193 arg /= stepSize;
194 dB -= dBstepSize;
195 } while (arg > x);
196 arg = prevArg;
197 dB = prevdB;
198 stepSize *= 0.5F;
199 dBstepSize -= 3.0F;
200 }
201 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
202
203}
204
205// 10^(-dB/10), inverse of dB func.
206float dBinv(float x) {
207
208 float arg = 1.0F;
209 float dB = 0.0F;
210
211 if (x >= 0.0F) return 1.0F;
212 if (x <= -200.0F) return 0.0F;
213
214 float prevArg = arg;
215 float prevdB = dB;
216 float stepSize = 16.0F;
217 float dBstepSize = 12.0F;
218 while (stepSize > 1.0F) {
219 do {
220 prevArg = arg;
221 prevdB = dB;
222 arg /= stepSize;
223 dB -= dBstepSize;
224 } while (dB > x);
225 arg = prevArg;
226 dB = prevdB;
227 stepSize *= 0.5F;
228 dBstepSize -= 3.0F;
229 }
230
231 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
232
233}
234
235float vectorNorm2(const signalVector &x)
236{
237 signalVector::const_iterator xPtr = x.begin();
238 float Energy = 0.0;
239 for (;xPtr != x.end();xPtr++) {
240 Energy += xPtr->norm2();
241 }
242 return Energy;
243}
244
245
246float vectorPower(const signalVector &x)
247{
248 return vectorNorm2(x)/x.size();
249}
250
251/** compute cosine via lookup table */
252float cosLookup(const float x)
253{
254 float arg = x*M_1_2PI_F;
255 while (arg > 1.0F) arg -= 1.0F;
256 while (arg < 0.0F) arg += 1.0F;
257
258 const float argT = arg*((float)TABLESIZE);
259 const int argI = (int)argT;
260 const float delta = argT-argI;
261 const float iDelta = 1.0F-delta;
262 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
263}
264
265/** compute sine via lookup table */
266float sinLookup(const float x)
267{
268 float arg = x*M_1_2PI_F;
269 while (arg > 1.0F) arg -= 1.0F;
270 while (arg < 0.0F) arg += 1.0F;
271
272 const float argT = arg*((float)TABLESIZE);
273 const int argI = (int)argT;
274 const float delta = argT-argI;
275 const float iDelta = 1.0F-delta;
276 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
277}
278
279
280/** compute e^(-jx) via lookup table. */
Tom Tsou2079a3c2016-03-06 00:58:56 -0800281static complex expjLookup(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000282{
283 float arg = x*M_1_2PI_F;
284 while (arg > 1.0F) arg -= 1.0F;
285 while (arg < 0.0F) arg += 1.0F;
286
287 const float argT = arg*((float)TABLESIZE);
288 const int argI = (int)argT;
289 const float delta = argT-argI;
290 const float iDelta = 1.0F-delta;
291 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
292 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
293}
294
295/** Library setup functions */
Tom Tsou2079a3c2016-03-06 00:58:56 -0800296static void initTrigTables() {
dburgessb3a0ca42011-10-12 07:44:40 +0000297 for (int i = 0; i < TABLESIZE+1; i++) {
298 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
299 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
300 }
301}
302
Tom Tsou2079a3c2016-03-06 00:58:56 -0800303/*
304 * Initialize 4 sps and 1 sps rotation tables
305 */
306static void initGMSKRotationTables()
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400307{
Tom Tsou2079a3c2016-03-06 00:58:56 -0800308 size_t len1 = 157, len4 = 625;
309
310 GMSKRotation4 = new signalVector(len4);
311 GMSKReverseRotation4 = new signalVector(len4);
312 signalVector::iterator rotPtr = GMSKRotation4->begin();
313 signalVector::iterator revPtr = GMSKReverseRotation4->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000314 float phase = 0.0;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800315 while (rotPtr != GMSKRotation4->end()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000316 *rotPtr++ = expjLookup(phase);
317 *revPtr++ = expjLookup(-phase);
Tom Tsou2079a3c2016-03-06 00:58:56 -0800318 phase += M_PI_F / 2.0F / 4.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000319 }
dburgessb3a0ca42011-10-12 07:44:40 +0000320
Tom Tsou2079a3c2016-03-06 00:58:56 -0800321 GMSKRotation1 = new signalVector(len1);
322 GMSKReverseRotation1 = new signalVector(len1);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400323 rotPtr = GMSKRotation1->begin();
324 revPtr = GMSKReverseRotation1->begin();
325 phase = 0.0;
326 while (rotPtr != GMSKRotation1->end()) {
327 *rotPtr++ = expjLookup(phase);
328 *revPtr++ = expjLookup(-phase);
329 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400330 }
dburgessb3a0ca42011-10-12 07:44:40 +0000331}
332
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400333static void GMSKRotate(signalVector &x, int sps)
334{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500335#if HAVE_NEON
336 size_t len;
337 signalVector *a, *b, *out;
338
339 a = &x;
340 out = &x;
341 len = out->size();
342
343 if (len == 157)
344 len--;
345
346 if (sps == 1)
347 b = GMSKRotation1;
348 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800349 b = GMSKRotation4;
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500350
351 mul_complex((float *) out->begin(),
352 (float *) a->begin(),
353 (float *) b->begin(), len);
354#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400355 signalVector::iterator rotPtr, xPtr = x.begin();
356
357 if (sps == 1)
358 rotPtr = GMSKRotation1->begin();
359 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800360 rotPtr = GMSKRotation4->begin();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400361
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500362 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000363 while (xPtr < x.end()) {
364 *xPtr = *rotPtr++ * (xPtr->real());
365 xPtr++;
366 }
367 }
368 else {
369 while (xPtr < x.end()) {
370 *xPtr = *rotPtr++ * (*xPtr);
371 xPtr++;
372 }
373 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500374#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000375}
376
Tom Tsou2079a3c2016-03-06 00:58:56 -0800377static bool GMSKReverseRotate(signalVector &x, int sps)
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400378{
379 signalVector::iterator rotPtr, xPtr= x.begin();
380
381 if (sps == 1)
382 rotPtr = GMSKReverseRotation1->begin();
Tom Tsou2079a3c2016-03-06 00:58:56 -0800383 else if (sps == 4)
384 rotPtr = GMSKReverseRotation4->begin();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400385 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800386 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400387
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500388 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000389 while (xPtr < x.end()) {
390 *xPtr = *rotPtr++ * (xPtr->real());
391 xPtr++;
392 }
393 }
394 else {
395 while (xPtr < x.end()) {
396 *xPtr = *rotPtr++ * (*xPtr);
397 xPtr++;
398 }
399 }
Tom Tsou2079a3c2016-03-06 00:58:56 -0800400
401 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000402}
403
Thomas Tsou3eaae802013-08-20 19:31:14 -0400404signalVector *convolve(const signalVector *x,
405 const signalVector *h,
406 signalVector *y,
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500407 ConvType spanType, size_t start,
408 size_t len, size_t step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000409{
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500410 int rc;
411 size_t head = 0, tail = 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400412 bool alloc = false, append = false;
413 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000414
Thomas Tsou3eaae802013-08-20 19:31:14 -0400415 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000416 return NULL;
417
Thomas Tsou3eaae802013-08-20 19:31:14 -0400418 switch (spanType) {
419 case START_ONLY:
420 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500421 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400422 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500423
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500424 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500425 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000426 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400427 case NO_DELAY:
428 start = h->size() / 2;
429 head = start;
430 tail = start;
431 len = x->size();
432 append = true;
433 break;
434 case CUSTOM:
435 if (start < h->size() - 1) {
436 head = h->size() - start;
437 append = true;
438 }
439 if (start + len > x->size()) {
440 tail = start + len - x->size();
441 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000442 }
443 break;
444 default:
445 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000446 }
dburgessb3a0ca42011-10-12 07:44:40 +0000447
Thomas Tsou3eaae802013-08-20 19:31:14 -0400448 /*
449 * Error if the output vector is too small. Create the output vector
450 * if the pointer is NULL.
451 */
452 if (y && (len > y->size()))
453 return NULL;
454 if (!y) {
455 y = new signalVector(len);
456 alloc = true;
457 }
458
459 /* Prepend or post-pend the input vector if the parameters require it */
460 if (append)
461 _x = new signalVector(*x, head, tail);
462 else
463 _x = x;
464
465 /*
466 * Four convovle types:
467 * 1. Complex-Real (aligned)
468 * 2. Complex-Complex (aligned)
469 * 3. Complex-Real (!aligned)
470 * 4. Complex-Complex (!aligned)
471 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500472 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400473 rc = convolve_real((float *) _x->begin(), _x->size(),
474 (float *) h->begin(), h->size(),
475 (float *) y->begin(), y->size(),
476 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500477 } else if (!h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400478 rc = convolve_complex((float *) _x->begin(), _x->size(),
479 (float *) h->begin(), h->size(),
480 (float *) y->begin(), y->size(),
481 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500482 } else if (h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400483 rc = base_convolve_real((float *) _x->begin(), _x->size(),
484 (float *) h->begin(), h->size(),
485 (float *) y->begin(), y->size(),
486 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500487 } else if (!h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400488 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
489 (float *) h->begin(), h->size(),
490 (float *) y->begin(), y->size(),
491 start, len, step, offset);
492 } else {
493 rc = -1;
494 }
495
496 if (append)
497 delete _x;
498
499 if (rc < 0) {
500 if (alloc)
501 delete y;
502 return NULL;
503 }
504
505 return y;
506}
dburgessb3a0ca42011-10-12 07:44:40 +0000507
Tom Tsoud3253432016-03-06 03:08:01 -0800508/*
509 * Generate static EDGE linear equalizer. This equalizer is not adaptive.
510 * Filter taps are generated from the inverted 1 SPS impulse response of
511 * the EDGE pulse shape captured after the downsampling filter.
512 */
513static bool generateInvertC0Pulse(PulseSequence *pulse)
514{
515 if (!pulse)
516 return false;
517
518 pulse->c0_inv_buffer = convolve_h_alloc(5);
519 pulse->c0_inv = new signalVector((complex *) pulse->c0_inv_buffer, 0, 5);
520 pulse->c0_inv->isReal(true);
521 pulse->c0_inv->setAligned(false);
522
523 signalVector::iterator xP = pulse->c0_inv->begin();
524 *xP++ = 0.15884;
525 *xP++ = -0.43176;
526 *xP++ = 1.00000;
527 *xP++ = -0.42608;
528 *xP++ = 0.14882;
529
530 return true;
531}
532
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400533static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800534{
535 int len;
536
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400537 if (!pulse)
538 return false;
539
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800540 switch (sps) {
541 case 4:
542 len = 8;
543 break;
544 default:
545 return false;
546 }
547
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400548 pulse->c1_buffer = convolve_h_alloc(len);
549 pulse->c1 = new signalVector((complex *)
550 pulse->c1_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500551 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800552
553 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400554 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800555
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400556 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800557
558 switch (sps) {
559 case 4:
560 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400561 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800562 *xP++ = 8.16373112e-03;
563 *xP++ = 2.84385729e-02;
564 *xP++ = 5.64158904e-02;
565 *xP++ = 7.05463553e-02;
566 *xP++ = 5.64158904e-02;
567 *xP++ = 2.84385729e-02;
568 *xP++ = 8.16373112e-03;
569 }
570
571 return true;
572}
573
Tom Tsou2079a3c2016-03-06 00:58:56 -0800574static PulseSequence *generateGSMPulse(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +0000575{
Thomas Tsou83e06892013-08-20 16:10:01 -0400576 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800577 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400578 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400579
Tom Tsoud3253432016-03-06 03:08:01 -0800580 if ((sps != 1) && (sps != 4))
581 return NULL;
582
Thomas Tsou83e06892013-08-20 16:10:01 -0400583 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400584 pulse = new PulseSequence();
585 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500586 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400587 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400588
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400589 /*
590 * For 4 samples-per-symbol use a precomputed single pulse Laurent
591 * approximation. This should yields below 2 degrees of phase error at
592 * the modulator output. Use the existing pulse approximation for all
593 * other oversampling factors.
594 */
595 switch (sps) {
596 case 4:
597 len = 16;
598 break;
Tom Tsoud3253432016-03-06 03:08:01 -0800599 case 1:
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400600 default:
Tom Tsou2079a3c2016-03-06 00:58:56 -0800601 len = 4;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400602 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400603
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400604 pulse->c0_buffer = convolve_h_alloc(len);
605 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500606 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400607
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800608 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400609 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800610
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400611 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400612
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400613 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800614 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400615 *xP++ = 4.46348606e-03;
616 *xP++ = 2.84385729e-02;
617 *xP++ = 1.03184855e-01;
618 *xP++ = 2.56065552e-01;
619 *xP++ = 4.76375085e-01;
620 *xP++ = 7.05961177e-01;
621 *xP++ = 8.71291644e-01;
622 *xP++ = 9.29453645e-01;
623 *xP++ = 8.71291644e-01;
624 *xP++ = 7.05961177e-01;
625 *xP++ = 4.76375085e-01;
626 *xP++ = 2.56065552e-01;
627 *xP++ = 1.03184855e-01;
628 *xP++ = 2.84385729e-02;
629 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400630 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400631 } else {
632 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400633
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400634 /* GSM pulse approximation */
635 for (int i = 0; i < len; i++) {
636 arg = ((float) i - center) / (float) sps;
637 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
638 0.527 * arg * arg * arg * arg);
639 }
dburgessb3a0ca42011-10-12 07:44:40 +0000640
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400641 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
642 xP = pulse->c0->begin();
643 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800644 *xP++ /= avg;
645 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400646
Tom Tsoud3253432016-03-06 03:08:01 -0800647 /*
648 * Current form of the EDGE equalization filter non-realizable at 4 SPS.
649 * Load the onto both 1 SPS and 4 SPS objects for convenience. Note that
650 * the EDGE demodulator downsamples to 1 SPS prior to equalization.
651 */
652 generateInvertC0Pulse(pulse);
653
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400654 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000655}
656
657signalVector* frequencyShift(signalVector *y,
658 signalVector *x,
659 float freq,
660 float startPhase,
661 float *finalPhase)
662{
663
664 if (!x) return NULL;
665
666 if (y==NULL) {
667 y = new signalVector(x->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500668 y->isReal(x->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000669 if (y==NULL) return NULL;
670 }
671
672 if (y->size() < x->size()) return NULL;
673
674 float phase = startPhase;
675 signalVector::iterator yP = y->begin();
676 signalVector::iterator xPEnd = x->end();
677 signalVector::iterator xP = x->begin();
678
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500679 if (x->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000680 while (xP < xPEnd) {
681 (*yP++) = expjLookup(phase)*( (xP++)->real() );
682 phase += freq;
683 }
684 }
685 else {
686 while (xP < xPEnd) {
687 (*yP++) = (*xP++)*expjLookup(phase);
688 phase += freq;
Thomas Tsou34bbef72013-11-13 22:58:15 -0500689 if (phase > 2 * M_PI)
690 phase -= 2 * M_PI;
691 else if (phase < -2 * M_PI)
692 phase += 2 * M_PI;
dburgessb3a0ca42011-10-12 07:44:40 +0000693 }
694 }
695
696
697 if (finalPhase) *finalPhase = phase;
698
699 return y;
700}
701
702signalVector* reverseConjugate(signalVector *b)
703{
704 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500705 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000706 signalVector::iterator bP = b->begin();
707 signalVector::iterator bPEnd = b->end();
708 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500709 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000710 while (bP < bPEnd) {
711 *tmpP-- = bP->conj();
712 bP++;
713 }
714 }
715 else {
716 while (bP < bPEnd) {
717 *tmpP-- = bP->real();
718 bP++;
719 }
720 }
721
722 return tmp;
723}
724
Tom Tsoud3253432016-03-06 03:08:01 -0800725bool vectorSlicer(SoftVector *x)
726{
727 SoftVector::iterator xP = x->begin();
728 SoftVector::iterator xPEnd = x->end();
729 while (xP < xPEnd) {
730 *xP = 0.5 * (*xP + 1.0f);
731 if (*xP > 1.0)
732 *xP = 1.0;
733 if (*xP < 0.0)
734 *xP = 0.0;
735 xP++;
736 }
737 return true;
738}
739
740bool vectorSlicer(signalVector *x)
dburgessb3a0ca42011-10-12 07:44:40 +0000741{
742
743 signalVector::iterator xP = x->begin();
744 signalVector::iterator xPEnd = x->end();
745 while (xP < xPEnd) {
746 *xP = (complex) (0.5*(xP->real()+1.0F));
747 if (xP->real() > 1.0) *xP = 1.0;
748 if (xP->real() < 0.0) *xP = 0.0;
749 xP++;
750 }
751 return true;
752}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400753
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800754static signalVector *rotateBurst(const BitVector &wBurst,
755 int guardPeriodLength, int sps)
756{
757 int burst_len;
758 signalVector *pulse, rotated, *shaped;
759 signalVector::iterator itr;
760
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400761 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800762 burst_len = sps * (wBurst.size() + guardPeriodLength);
763 rotated = signalVector(burst_len);
764 itr = rotated.begin();
765
766 for (unsigned i = 0; i < wBurst.size(); i++) {
767 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
768 itr += sps;
769 }
770
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400771 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500772 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800773
774 /* Dummy filter operation */
775 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
776 if (!shaped)
777 return NULL;
778
779 return shaped;
780}
781
Tom Tsoud3253432016-03-06 03:08:01 -0800782static void rotateBurst2(signalVector &burst, double phase)
783{
784 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
785
786 for (size_t i = 0; i < burst.size(); i++)
787 burst[i] = burst[i] * rot;
788}
789
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800790/*
791 * Ignore the guard length argument in the GMSK modulator interface
792 * because it results in 624/628 sized bursts instead of the preferred
793 * burst length of 625. Only 4 SPS is supported.
794 */
795static signalVector *modulateBurstLaurent(const BitVector &bits)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800796{
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800797 int burst_len, sps = 4;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800798 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500799 signalVector *c0_pulse, *c1_pulse, *c0_burst;
800 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800801 signalVector::iterator c0_itr, c1_itr;
802
Tom Tsou2079a3c2016-03-06 00:58:56 -0800803 c0_pulse = GSMPulse4->c0;
804 c1_pulse = GSMPulse4->c1;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800805
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800806 if (bits.size() > 156)
807 return NULL;
808
809 burst_len = 625;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800810
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500811 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500812 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500813 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800814
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500815 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500816 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500817 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800818
Tom Tsouaa15d622016-08-11 14:36:23 -0700819 /* Padded differential tail bits */
820 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800821 c0_itr += sps;
822
823 /* Main burst bits */
824 for (unsigned i = 0; i < bits.size(); i++) {
825 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
826 c0_itr += sps;
827 }
828
Tom Tsouaa15d622016-08-11 14:36:23 -0700829 /* Padded differential tail bits */
830 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800831
832 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500833 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500834 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800835
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500836 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800837 c0_itr += sps * 2;
838 c1_itr += sps * 2;
839
840 /* Start magic */
841 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
842 *c1_itr = *c0_itr * Complex<float>(0, phase);
843 c0_itr += sps;
844 c1_itr += sps;
845
846 /* Generate C1 phase coefficients */
847 for (unsigned i = 2; i < bits.size(); i++) {
848 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
849 *c1_itr = *c0_itr * Complex<float>(0, phase);
850
851 c0_itr += sps;
852 c1_itr += sps;
853 }
854
855 /* End magic */
856 int i = bits.size();
857 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
858 *c1_itr = *c0_itr * Complex<float>(0, phase);
859
860 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500861 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
862 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800863
864 /* Sum shaped outputs into C0 */
865 c0_itr = c0_shaped->begin();
866 c1_itr = c1_shaped->begin();
867 for (unsigned i = 0; i < c0_shaped->size(); i++ )
868 *c0_itr++ += *c1_itr++;
869
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500870 delete c0_burst;
871 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800872 delete c1_shaped;
873
874 return c0_shaped;
875}
876
Tom Tsoud3253432016-03-06 03:08:01 -0800877static signalVector *rotateEdgeBurst(const signalVector &symbols, int sps)
878{
879 signalVector *burst;
880 signalVector::iterator burst_itr;
881
882 burst = new signalVector(symbols.size() * sps);
883 burst_itr = burst->begin();
884
885 for (size_t i = 0; i < symbols.size(); i++) {
886 float phase = i * 3.0f * M_PI / 8.0f;
887 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
888
889 *burst_itr = symbols[i] * rot;
890 burst_itr += sps;
891 }
892
893 return burst;
894}
895
896static signalVector *derotateEdgeBurst(const signalVector &symbols, int sps)
897{
898 signalVector *burst;
899 signalVector::iterator burst_itr;
900
901 if (symbols.size() % sps)
902 return NULL;
903
904 burst = new signalVector(symbols.size() / sps);
905 burst_itr = burst->begin();
906
907 for (size_t i = 0; i < burst->size(); i++) {
908 float phase = (float) (i % 16) * 3.0f * M_PI / 8.0f;
909 Complex<float> rot = Complex<float>(cosf(phase), -sinf(phase));
910
911 *burst_itr = symbols[sps * i] * rot;
912 burst_itr++;
913 }
914
915 return burst;
916}
917
918static signalVector *mapEdgeSymbols(const BitVector &bits)
919{
920 if (bits.size() % 3)
921 return NULL;
922
923 signalVector *symbols = new signalVector(bits.size() / 3);
924
925 for (size_t i = 0; i < symbols->size(); i++) {
926 unsigned index = (((unsigned) bits[3 * i + 0] & 0x01) << 0) |
927 (((unsigned) bits[3 * i + 1] & 0x01) << 1) |
928 (((unsigned) bits[3 * i + 2] & 0x01) << 2);
929
930 (*symbols)[i] = psk8_table[index];
931 }
932
933 return symbols;
934}
935
Tom Tsoud2b07032016-04-26 19:28:59 -0700936/*
937 * EDGE 8-PSK rotate and pulse shape
938 *
939 * Delay the EDGE downlink bursts by one symbol in order to match GMSK pulse
940 * shaping group delay. The difference in group delay arises from the dual
941 * pulse filter combination of the GMSK Laurent represenation whereas 8-PSK
942 * uses a single pulse linear filter.
943 */
Tom Tsoud3253432016-03-06 03:08:01 -0800944static signalVector *shapeEdgeBurst(const signalVector &symbols)
945{
Tom Tsoud2b07032016-04-26 19:28:59 -0700946 size_t nsyms, nsamps = 625, sps = 4;
Tom Tsoud3253432016-03-06 03:08:01 -0800947 signalVector *burst, *shape;
948 signalVector::iterator burst_itr;
949
950 nsyms = symbols.size();
951
Tom Tsoud2b07032016-04-26 19:28:59 -0700952 if (nsyms * sps > nsamps)
Tom Tsoud3253432016-03-06 03:08:01 -0800953 nsyms = 156;
954
955 burst = new signalVector(nsamps, GSMPulse4->c0->size());
Tom Tsoud3253432016-03-06 03:08:01 -0800956
Tom Tsoud2b07032016-04-26 19:28:59 -0700957 /* Delay burst by 1 symbol */
958 burst_itr = burst->begin() + sps;
Tom Tsou06676ea2016-07-19 12:50:21 -0700959 for (size_t i = 0; i < nsyms; i++) {
Tom Tsoud3253432016-03-06 03:08:01 -0800960 float phase = i * 3.0f * M_PI / 8.0f;
961 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
962
963 *burst_itr = symbols[i] * rot;
Tom Tsoud2b07032016-04-26 19:28:59 -0700964 burst_itr += sps;
Tom Tsoud3253432016-03-06 03:08:01 -0800965 }
966
967 /* Single Gaussian pulse approximation shaping */
968 shape = convolve(burst, GSMPulse4->c0, NULL, START_ONLY);
969 delete burst;
970
971 return shape;
972}
973
974/*
Tom Tsou8ee2f382016-03-06 20:57:34 -0800975 * Generate a random GSM normal burst.
976 */
977signalVector *genRandNormalBurst(int tsc, int sps, int tn)
978{
979 if ((tsc < 0) || (tsc > 7) || (tn < 0) || (tn > 7))
980 return NULL;
981 if ((sps != 1) && (sps != 4))
982 return NULL;
983
984 int i = 0;
985 BitVector *bits = new BitVector(148);
986 signalVector *burst;
987
988 /* Tail bits */
989 for (; i < 4; i++)
990 (*bits)[i] = 0;
991
992 /* Random bits */
993 for (; i < 61; i++)
994 (*bits)[i] = rand() % 2;
995
996 /* Training sequence */
997 for (int n = 0; i < 87; i++, n++)
998 (*bits)[i] = gTrainingSequence[tsc][n];
999
1000 /* Random bits */
1001 for (; i < 144; i++)
1002 (*bits)[i] = rand() % 2;
1003
1004 /* Tail bits */
1005 for (; i < 148; i++)
1006 (*bits)[i] = 0;
1007
1008 int guard = 8 + !(tn % 4);
1009 burst = modulateBurst(*bits, guard, sps);
1010 delete bits;
1011
1012 return burst;
1013}
1014
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001015/*
1016 * Generate a random GSM access burst.
1017 */
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001018signalVector *genRandAccessBurst(int delay, int sps, int tn)
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001019{
1020 if ((tn < 0) || (tn > 7))
1021 return NULL;
1022 if ((sps != 1) && (sps != 4))
1023 return NULL;
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001024 if (delay > 68)
1025 return NULL;
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001026
1027 int i = 0;
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001028 BitVector *bits = new BitVector(88+delay);
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001029 signalVector *burst;
1030
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001031 /* delay */
1032 for (; i < delay; i++)
1033 (*bits)[i] = 0;
1034
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001035 /* head and synch bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001036 for (int n = 0; i < 49+delay; i++, n++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001037 (*bits)[i] = gRACHBurst[n];
1038
1039 /* Random bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001040 for (; i < 85+delay; i++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001041 (*bits)[i] = rand() % 2;
1042
1043 /* Tail bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001044 for (; i < 88+delay; i++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001045 (*bits)[i] = 0;
1046
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001047 int guard = 68-delay + !(tn % 4);
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001048 burst = modulateBurst(*bits, guard, sps);
1049 delete bits;
1050
1051 return burst;
1052}
1053
Tom Tsou8ee2f382016-03-06 20:57:34 -08001054signalVector *generateEmptyBurst(int sps, int tn)
1055{
1056 if ((tn < 0) || (tn > 7))
1057 return NULL;
1058
1059 if (sps == 4)
1060 return new signalVector(625);
1061 else if (sps == 1)
1062 return new signalVector(148 + 8 + !(tn % 4));
1063 else
1064 return NULL;
1065}
1066
1067signalVector *generateDummyBurst(int sps, int tn)
1068{
1069 if (((sps != 1) && (sps != 4)) || (tn < 0) || (tn > 7))
1070 return NULL;
1071
1072 return modulateBurst(gDummyBurst, 8 + !(tn % 4), sps);
1073}
1074
1075/*
Tom Tsoud3253432016-03-06 03:08:01 -08001076 * Generate a random 8-PSK EDGE burst. Only 4 SPS is supported with
1077 * the returned burst being 625 samples in length.
1078 */
1079signalVector *generateEdgeBurst(int tsc)
1080{
1081 int tail = 9 / 3;
1082 int data = 174 / 3;
1083 int train = 78 / 3;
1084
1085 if ((tsc < 0) || (tsc > 7))
1086 return NULL;
1087
1088 signalVector *shape, *burst = new signalVector(148);
1089 const BitVector *midamble = &gEdgeTrainingSequence[tsc];
1090
1091 /* Tail */
1092 int n, i = 0;
1093 for (; i < tail; i++)
1094 (*burst)[i] = psk8_table[7];
1095
1096 /* Body */
1097 for (; i < tail + data; i++)
1098 (*burst)[i] = psk8_table[rand() % 8];
1099
1100 /* TSC */
1101 for (n = 0; i < tail + data + train; i++, n++) {
1102 unsigned index = (((unsigned) (*midamble)[3 * n + 0] & 0x01) << 0) |
1103 (((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
1104 (((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
1105
1106 (*burst)[i] = psk8_table[index];
1107 }
1108
1109 /* Body */
1110 for (; i < tail + data + train + data; i++)
1111 (*burst)[i] = psk8_table[rand() % 8];
1112
1113 /* Tail */
1114 for (; i < tail + data + train + data + tail; i++)
1115 (*burst)[i] = psk8_table[7];
1116
1117 shape = shapeEdgeBurst(*burst);
1118 delete burst;
1119
1120 return shape;
1121}
1122
1123/*
1124 * Modulate 8-PSK burst. When empty pulse shaping (rotation only)
1125 * is enabled, the output vector length will be bit sequence length
1126 * times the SPS value. When pulse shaping is enabled, the output
Alexander Chemeris9270a5a2017-03-17 13:03:41 -07001127 * vector length is fixed at 625 samples (156.25 symbols at 4 SPS).
Tom Tsoud3253432016-03-06 03:08:01 -08001128 * Pulse shaped bit sequences that go beyond one burst are truncated.
1129 * Pulse shaping at anything but 4 SPS is not supported.
1130 */
1131signalVector *modulateEdgeBurst(const BitVector &bits,
1132 int sps, bool empty)
1133{
1134 signalVector *shape, *burst;
1135
1136 if ((sps != 4) && !empty)
1137 return NULL;
1138
1139 burst = mapEdgeSymbols(bits);
1140 if (!burst)
1141 return NULL;
1142
1143 if (empty)
1144 shape = rotateEdgeBurst(*burst, sps);
1145 else
1146 shape = shapeEdgeBurst(*burst);
1147
1148 delete burst;
1149 return shape;
1150}
1151
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001152static signalVector *modulateBurstBasic(const BitVector &bits,
1153 int guard_len, int sps)
1154{
1155 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001156 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001157 signalVector::iterator burst_itr;
1158
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001159 if (sps == 1)
1160 pulse = GSMPulse1->c0;
1161 else
Tom Tsou2079a3c2016-03-06 00:58:56 -08001162 pulse = GSMPulse4->c0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001163
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001164 burst_len = sps * (bits.size() + guard_len);
1165
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001166 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001167 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001168 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001169
1170 /* Raw bits are not differentially encoded */
1171 for (unsigned i = 0; i < bits.size(); i++) {
1172 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
1173 burst_itr += sps;
1174 }
1175
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001176 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001177 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001178
1179 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001180 shaped = convolve(burst, pulse, NULL, START_ONLY);
1181
1182 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001183
1184 return shaped;
1185}
1186
Thomas Tsou3eaae802013-08-20 19:31:14 -04001187/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -04001188signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
1189 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +00001190{
Thomas Tsou83e06892013-08-20 16:10:01 -04001191 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001192 return rotateBurst(wBurst, guardPeriodLength, sps);
1193 else if (sps == 4)
Tom Tsou4dfd64a2016-03-06 20:31:51 -08001194 return modulateBurstLaurent(wBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -04001195 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001196 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001197}
1198
Tom Tsou2079a3c2016-03-06 00:58:56 -08001199static void generateSincTable()
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001200{
1201 float x;
1202
1203 for (int i = 0; i < TABLESIZE; i++) {
1204 x = (float) i / TABLESIZE * 8 * M_PI;
1205 if (fabs(x) < 0.01) {
1206 sincTable[i] = 1.0f;
1207 continue;
1208 }
1209
1210 sincTable[i] = sinf(x) / x;
1211 }
1212}
1213
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001214float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +00001215{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001216 if (fabs(x) >= 8 * M_PI)
1217 return 0.0;
1218
1219 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
1220
1221 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +00001222}
1223
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001224/*
1225 * Create fractional delay filterbank with Blackman-harris windowed
1226 * sinc function generator. The number of filters generated is specified
1227 * by the DELAYFILTS value.
1228 */
1229void generateDelayFilters()
1230{
1231 int h_len = 20;
1232 complex *data;
1233 signalVector *h;
1234 signalVector::iterator itr;
1235
1236 float k, sum;
1237 float a0 = 0.35875;
1238 float a1 = 0.48829;
1239 float a2 = 0.14128;
1240 float a3 = 0.01168;
1241
1242 for (int i = 0; i < DELAYFILTS; i++) {
1243 data = (complex *) convolve_h_alloc(h_len);
1244 h = new signalVector(data, 0, h_len);
1245 h->setAligned(true);
1246 h->isReal(true);
1247
1248 sum = 0.0;
1249 itr = h->end();
1250 for (int n = 0; n < h_len; n++) {
1251 k = (float) n;
1252 *--itr = (complex) sinc(M_PI_F *
1253 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
1254 *itr *= a0 -
1255 a1 * cos(2 * M_PI * n / (h_len - 1)) +
1256 a2 * cos(4 * M_PI * n / (h_len - 1)) -
1257 a3 * cos(6 * M_PI * n / (h_len - 1));
1258
1259 sum += itr->real();
1260 }
1261
1262 itr = h->begin();
1263 for (int n = 0; n < h_len; n++)
1264 *itr++ /= sum;
1265
1266 delayFilters[i] = h;
1267 }
1268}
1269
Thomas Tsou94edaae2013-11-09 22:19:19 -05001270signalVector *delayVector(signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +00001271{
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001272 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001273 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001274 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001275
Thomas Tsou2c282f52013-10-08 21:34:35 -04001276 whole = floor(delay);
1277 frac = delay - whole;
1278
1279 /* Sinc interpolated fractional shift (if allowable) */
1280 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001281 index = floorf(frac * (float) DELAYFILTS);
1282 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -04001283
Thomas Tsou94edaae2013-11-09 22:19:19 -05001284 fshift = convolve(in, h, NULL, NO_DELAY);
1285 if (!fshift)
1286 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001287 }
1288
Thomas Tsou94edaae2013-11-09 22:19:19 -05001289 if (!fshift)
1290 shift = new signalVector(*in);
1291 else
1292 shift = fshift;
1293
Thomas Tsou2c282f52013-10-08 21:34:35 -04001294 /* Integer sample shift */
1295 if (whole < 0) {
1296 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001297 signalVector::iterator wBurstItr = shift->begin();
1298 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001299
Thomas Tsou94edaae2013-11-09 22:19:19 -05001300 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +00001301 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001302
Thomas Tsou94edaae2013-11-09 22:19:19 -05001303 while (wBurstItr < shift->end())
1304 *wBurstItr++ = 0.0;
1305 } else if (whole >= 0) {
1306 signalVector::iterator wBurstItr = shift->end() - 1;
1307 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
1308
1309 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001310 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001311
1312 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001313 *wBurstItr-- = 0.0;
1314 }
Thomas Tsou2c282f52013-10-08 21:34:35 -04001315
Thomas Tsou94edaae2013-11-09 22:19:19 -05001316 if (!out)
1317 return shift;
1318
1319 out->clone(*shift);
1320 delete shift;
1321 return out;
dburgessb3a0ca42011-10-12 07:44:40 +00001322}
Thomas Tsou2c282f52013-10-08 21:34:35 -04001323
dburgessb3a0ca42011-10-12 07:44:40 +00001324signalVector *gaussianNoise(int length,
1325 float variance,
1326 complex mean)
1327{
1328
1329 signalVector *noise = new signalVector(length);
1330 signalVector::iterator nPtr = noise->begin();
1331 float stddev = sqrtf(variance);
1332 while (nPtr < noise->end()) {
1333 float u1 = (float) rand()/ (float) RAND_MAX;
1334 while (u1==0.0)
1335 u1 = (float) rand()/ (float) RAND_MAX;
1336 float u2 = (float) rand()/ (float) RAND_MAX;
1337 float arg = 2.0*M_PI*u2;
1338 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
1339 nPtr++;
1340 }
1341
1342 return noise;
1343}
1344
1345complex interpolatePoint(const signalVector &inSig,
1346 float ix)
1347{
1348
1349 int start = (int) (floor(ix) - 10);
1350 if (start < 0) start = 0;
1351 int end = (int) (floor(ix) + 11);
1352 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
1353
1354 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001355 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001356 for (int i = start; i < end; i++)
1357 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
1358 }
1359 else {
1360 for (int i = start; i < end; i++)
1361 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
1362 }
1363
1364 return pVal;
1365}
1366
Thomas Tsou8181b012013-08-20 21:17:19 -04001367static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1368{
1369 float val, max = 0.0f;
1370 complex amp;
1371 int _index = -1;
1372
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001373 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001374 val = rxBurst[i].norm2();
1375 if (val > max) {
1376 max = val;
1377 _index = i;
1378 amp = rxBurst[i];
1379 }
1380 }
1381
1382 if (index)
1383 *index = (float) _index;
1384
1385 return amp;
1386}
1387
dburgessb3a0ca42011-10-12 07:44:40 +00001388complex peakDetect(const signalVector &rxBurst,
1389 float *peakIndex,
1390 float *avgPwr)
1391{
1392
1393
1394 complex maxVal = 0.0;
1395 float maxIndex = -1;
1396 float sumPower = 0.0;
1397
1398 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1399 float samplePower = rxBurst[i].norm2();
1400 if (samplePower > maxVal.real()) {
1401 maxVal = samplePower;
1402 maxIndex = i;
1403 }
1404 sumPower += samplePower;
1405 }
1406
1407 // interpolate around the peak
1408 // to save computation, we'll use early-late balancing
1409 float earlyIndex = maxIndex-1;
1410 float lateIndex = maxIndex+1;
1411
1412 float incr = 0.5;
1413 while (incr > 1.0/1024.0) {
1414 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1415 complex lateP = interpolatePoint(rxBurst,lateIndex);
1416 if (earlyP < lateP)
1417 earlyIndex += incr;
1418 else if (earlyP > lateP)
1419 earlyIndex -= incr;
1420 else break;
1421 incr /= 2.0;
1422 lateIndex = earlyIndex + 2.0;
1423 }
1424
1425 maxIndex = earlyIndex + 1.0;
1426 maxVal = interpolatePoint(rxBurst,maxIndex);
1427
1428 if (peakIndex!=NULL)
1429 *peakIndex = maxIndex;
1430
1431 if (avgPwr!=NULL)
1432 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1433
1434 return maxVal;
1435
1436}
1437
1438void scaleVector(signalVector &x,
1439 complex scale)
1440{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001441#ifdef HAVE_NEON
1442 int len = x.size();
1443
1444 scale_complex((float *) x.begin(),
1445 (float *) x.begin(),
1446 (float *) &scale, len);
1447#else
dburgessb3a0ca42011-10-12 07:44:40 +00001448 signalVector::iterator xP = x.begin();
1449 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001450 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001451 while (xP < xPEnd) {
1452 *xP = *xP * scale;
1453 xP++;
1454 }
1455 }
1456 else {
1457 while (xP < xPEnd) {
1458 *xP = xP->real() * scale;
1459 xP++;
1460 }
1461 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001462#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001463}
1464
1465/** in-place conjugation */
1466void conjugateVector(signalVector &x)
1467{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001468 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001469 signalVector::iterator xP = x.begin();
1470 signalVector::iterator xPEnd = x.end();
1471 while (xP < xPEnd) {
1472 *xP = xP->conj();
1473 xP++;
1474 }
1475}
1476
1477
1478// in-place addition!!
1479bool addVector(signalVector &x,
1480 signalVector &y)
1481{
1482 signalVector::iterator xP = x.begin();
1483 signalVector::iterator yP = y.begin();
1484 signalVector::iterator xPEnd = x.end();
1485 signalVector::iterator yPEnd = y.end();
1486 while ((xP < xPEnd) && (yP < yPEnd)) {
1487 *xP = *xP + *yP;
1488 xP++; yP++;
1489 }
1490 return true;
1491}
1492
1493// in-place multiplication!!
1494bool multVector(signalVector &x,
1495 signalVector &y)
1496{
1497 signalVector::iterator xP = x.begin();
1498 signalVector::iterator yP = y.begin();
1499 signalVector::iterator xPEnd = x.end();
1500 signalVector::iterator yPEnd = y.end();
1501 while ((xP < xPEnd) && (yP < yPEnd)) {
1502 *xP = (*xP) * (*yP);
1503 xP++; yP++;
1504 }
1505 return true;
1506}
1507
Tom Tsou2079a3c2016-03-06 00:58:56 -08001508static bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001509{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001510 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001511 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001512 complex *data = NULL;
1513 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001514 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001515
Thomas Tsou3eaae802013-08-20 19:31:14 -04001516 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001517 return false;
1518
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001519 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001520
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001521 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1522 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1523 if (!midMidamble)
1524 return false;
1525
Thomas Tsou3eaae802013-08-20 19:31:14 -04001526 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001527 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1528 if (!midamble) {
1529 status = false;
1530 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001531 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001532
dburgessb3a0ca42011-10-12 07:44:40 +00001533 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1534 // the ideal TSC has an + 180 degree phase shift,
1535 // due to the pi/2 frequency shift, that
1536 // needs to be accounted for.
1537 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001538 scaleVector(*midMidamble, complex(-1.0, 0.0));
1539 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001540
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001541 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001542
Thomas Tsou3eaae802013-08-20 19:31:14 -04001543 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1544 data = (complex *) convolve_h_alloc(midMidamble->size());
1545 _midMidamble = new signalVector(data, 0, midMidamble->size());
1546 _midMidamble->setAligned(true);
1547 memcpy(_midMidamble->begin(), midMidamble->begin(),
1548 midMidamble->size() * sizeof(complex));
1549
1550 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001551 if (!autocorr) {
1552 status = false;
1553 goto release;
1554 }
dburgessb3a0ca42011-10-12 07:44:40 +00001555
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001556 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001557 gMidambles[tsc]->buffer = data;
1558 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001559 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1560
1561 /* For 1 sps only
1562 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1563 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1564 */
1565 if (sps == 1)
1566 gMidambles[tsc]->toa = toa - 13.5;
1567 else
1568 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001569
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001570release:
dburgessb3a0ca42011-10-12 07:44:40 +00001571 delete autocorr;
1572 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001573 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001574
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001575 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001576 delete _midMidamble;
1577 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001578 gMidambles[tsc] = NULL;
1579 }
1580
1581 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001582}
1583
Tom Tsoud3253432016-03-06 03:08:01 -08001584CorrelationSequence *generateEdgeMidamble(int tsc)
1585{
1586 complex *data = NULL;
1587 signalVector *midamble = NULL, *_midamble = NULL;
1588 CorrelationSequence *seq;
1589
1590 if ((tsc < 0) || (tsc > 7))
1591 return NULL;
1592
1593 /* Use middle 48 bits of each TSC. Correlation sequence is not pulse shaped */
1594 const BitVector *bits = &gEdgeTrainingSequence[tsc];
1595 midamble = modulateEdgeBurst(bits->segment(15, 48), 1, true);
1596 if (!midamble)
1597 return NULL;
1598
1599 conjugateVector(*midamble);
1600
1601 data = (complex *) convolve_h_alloc(midamble->size());
1602 _midamble = new signalVector(data, 0, midamble->size());
1603 _midamble->setAligned(true);
1604 memcpy(_midamble->begin(), midamble->begin(),
1605 midamble->size() * sizeof(complex));
1606
1607 /* Channel gain is an empirically measured value */
1608 seq = new CorrelationSequence;
1609 seq->buffer = data;
1610 seq->sequence = _midamble;
1611 seq->gain = Complex<float>(-19.6432, 19.5006) / 1.18;
1612 seq->toa = 0;
1613
1614 delete midamble;
1615
1616 return seq;
1617}
1618
Tom Tsou2079a3c2016-03-06 00:58:56 -08001619static bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001620{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001621 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001622 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001623 complex *data = NULL;
1624 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001625 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001626
1627 delete gRACHSequence;
1628
1629 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1630 if (!seq0)
1631 return false;
1632
1633 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1634 if (!seq1) {
1635 status = false;
1636 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001637 }
1638
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001639 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001640
Thomas Tsou3eaae802013-08-20 19:31:14 -04001641 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1642 data = (complex *) convolve_h_alloc(seq1->size());
1643 _seq1 = new signalVector(data, 0, seq1->size());
1644 _seq1->setAligned(true);
1645 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1646
1647 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1648 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001649 status = false;
1650 goto release;
1651 }
dburgessb3a0ca42011-10-12 07:44:40 +00001652
1653 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001654 gRACHSequence->sequence = _seq1;
1655 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001656 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1657
1658 /* For 1 sps only
1659 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1660 * 20.5 = (40 / 2 - 1) + 1.5
1661 */
1662 if (sps == 1)
1663 gRACHSequence->toa = toa - 20.5;
1664 else
1665 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001666
1667release:
dburgessb3a0ca42011-10-12 07:44:40 +00001668 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001669 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001670 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001671
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001672 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001673 delete _seq1;
1674 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001675 gRACHSequence = NULL;
1676 }
dburgessb3a0ca42011-10-12 07:44:40 +00001677
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001678 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001679}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001680
Tom Tsoua84e1622016-06-29 14:50:25 -07001681/*
1682 * Peak-to-average computation +/- range from peak in symbols
1683 */
1684#define COMPUTE_PEAK_MIN 2
1685#define COMPUTE_PEAK_MAX 5
1686
1687/*
1688 * Minimum number of values needed to compute peak-to-average
1689 */
1690#define COMPUTE_PEAK_CNT 5
1691
Thomas Tsou865bca42013-08-21 20:58:00 -04001692static float computePeakRatio(signalVector *corr,
1693 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001694{
Thomas Tsou865bca42013-08-21 20:58:00 -04001695 int num = 0;
1696 complex *peak;
1697 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001698
Thomas Tsou865bca42013-08-21 20:58:00 -04001699 /* Check for bogus results */
1700 if ((toa < 0.0) || (toa > corr->size()))
1701 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001702
Alexander Chemeris1e9b4d52015-06-04 19:05:28 -04001703 peak = corr->begin() + (int) rint(toa);
1704
Tom Tsoua84e1622016-06-29 14:50:25 -07001705 for (int i = COMPUTE_PEAK_MIN * sps; i <= COMPUTE_PEAK_MAX * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001706 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001707 avg += (peak - i)->norm2();
1708 num++;
1709 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001710 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001711 avg += (peak + i)->norm2();
1712 num++;
1713 }
dburgessb3a0ca42011-10-12 07:44:40 +00001714 }
1715
Tom Tsoua84e1622016-06-29 14:50:25 -07001716 if (num < COMPUTE_PEAK_CNT)
Thomas Tsou865bca42013-08-21 20:58:00 -04001717 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001718
Thomas Tsou3eaae802013-08-20 19:31:14 -04001719 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001720
Thomas Tsou865bca42013-08-21 20:58:00 -04001721 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001722}
1723
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +03001724float energyDetect(signalVector &rxBurst, unsigned windowLength)
dburgessb3a0ca42011-10-12 07:44:40 +00001725{
1726
1727 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1728 float energy = 0.0;
1729 if (windowLength < 0) windowLength = 20;
1730 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1731 for (unsigned i = 0; i < windowLength; i++) {
1732 energy += windowItr->norm2();
1733 windowItr+=4;
1734 }
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +03001735 return energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001736}
dburgessb3a0ca42011-10-12 07:44:40 +00001737
Thomas Tsou865bca42013-08-21 20:58:00 -04001738/*
1739 * Detect a burst based on correlation and peak-to-average ratio
1740 *
1741 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1742 * for initial gating. We do this because energy detection should be disabled.
1743 * For higher oversampling values, we assume the energy detector is in place
1744 * and we run full interpolating peak detection.
1745 */
1746static int detectBurst(signalVector &burst,
1747 signalVector &corr, CorrelationSequence *sync,
1748 float thresh, int sps, complex *amp, float *toa,
1749 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001750{
Tom Tsoud3253432016-03-06 03:08:01 -08001751 signalVector *corr_in, *dec = NULL;
1752
1753 if (sps == 4) {
1754 dec = downsampleBurst(burst);
1755 corr_in = dec;
1756 sps = 1;
1757 } else {
1758 corr_in = &burst;
1759 }
1760
Thomas Tsou865bca42013-08-21 20:58:00 -04001761 /* Correlate */
Tom Tsoud3253432016-03-06 03:08:01 -08001762 if (!convolve(corr_in, sync->sequence, &corr,
1763 CUSTOM, start, len, 1, 0)) {
1764 delete dec;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001765 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001766 }
1767
Tom Tsoud3253432016-03-06 03:08:01 -08001768 delete dec;
1769
1770 /* Running at the downsampled rate at this point */
1771 sps = 1;
1772
Thomas Tsou865bca42013-08-21 20:58:00 -04001773 /* Peak detection - place restrictions at correlation edges */
1774 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001775
Thomas Tsou865bca42013-08-21 20:58:00 -04001776 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1777 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001778
Thomas Tsou865bca42013-08-21 20:58:00 -04001779 /* Peak -to-average ratio */
1780 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1781 return 0;
1782
1783 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1784 *amp = peakDetect(corr, toa, NULL);
1785
1786 /* Normalize our channel gain */
1787 *amp = *amp / sync->gain;
1788
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001789 /* Compenate for residual rotation with dual Laurent pulse */
1790 if (sps == 4)
1791 *amp = *amp * complex(0.0, 1.0);
1792
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001793 /* Compensate for residuate time lag */
1794 *toa = *toa - sync->toa;
1795
Thomas Tsou865bca42013-08-21 20:58:00 -04001796 return 1;
1797}
1798
Alexander Chemeris954b1182015-06-04 15:39:41 -04001799static float maxAmplitude(signalVector &burst)
Tom Tsou577cd022015-05-18 13:57:54 -07001800{
Alexander Chemeris954b1182015-06-04 15:39:41 -04001801 float max = 0.0;
1802 for (size_t i = 0; i < burst.size(); i++) {
1803 if (fabs(burst[i].real()) > max)
1804 max = fabs(burst[i].real());
1805 if (fabs(burst[i].imag()) > max)
1806 max = fabs(burst[i].imag());
1807 }
Tom Tsou577cd022015-05-18 13:57:54 -07001808
Alexander Chemeris954b1182015-06-04 15:39:41 -04001809 return max;
Tom Tsou577cd022015-05-18 13:57:54 -07001810}
1811
Alexander Chemeris130a8002015-06-09 20:52:11 -04001812/*
1813 * RACH/Normal burst detection with clipping detection
Thomas Tsou865bca42013-08-21 20:58:00 -04001814 *
1815 * Correlation window parameters:
Alexander Chemeris130a8002015-06-09 20:52:11 -04001816 * target: Tail bits + burst length
1817 * head: Search symbols before target
1818 * tail: Search symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001819 */
Alexander Chemeris130a8002015-06-09 20:52:11 -04001820int detectGeneralBurst(signalVector &rxBurst,
1821 float thresh,
1822 int sps,
1823 complex &amp,
1824 float &toa,
1825 int target, int head, int tail,
1826 CorrelationSequence *sync)
Thomas Tsou865bca42013-08-21 20:58:00 -04001827{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001828 int rc, start, len;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001829 bool clipping = false;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001830 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001831
1832 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001833 return -SIGERR_UNSUPPORTED;
1834
Alexander Chemeris954b1182015-06-04 15:39:41 -04001835 // Detect potential clipping
1836 // We still may be able to demod the burst, so we'll give it a try
1837 // and only report clipping if we can't demod.
1838 float maxAmpl = maxAmplitude(rxBurst);
1839 if (maxAmpl > CLIP_THRESH) {
1840 LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
1841 clipping = true;
1842 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001843
Tom Tsoud3253432016-03-06 03:08:01 -08001844 start = target - head - 1;
1845 len = head + tail;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001846 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001847
Thomas Tsoub075dd22013-11-09 22:25:46 -05001848 rc = detectBurst(rxBurst, *corr, sync,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001849 thresh, sps, &amp, &toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001850 delete corr;
1851
Thomas Tsou865bca42013-08-21 20:58:00 -04001852 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001853 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001854 } else if (!rc) {
Alexander Chemeris130a8002015-06-09 20:52:11 -04001855 amp = 0.0f;
1856 toa = 0.0f;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001857 return clipping?-SIGERR_CLIP:SIGERR_NONE;
dburgessb3a0ca42011-10-12 07:44:40 +00001858 }
1859
Thomas Tsou865bca42013-08-21 20:58:00 -04001860 /* Subtract forward search bits from delay */
Tom Tsoud3253432016-03-06 03:08:01 -08001861 toa -= head;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001862
Thomas Tsou865bca42013-08-21 20:58:00 -04001863 return 1;
1864}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001865
Alexander Chemeris130a8002015-06-09 20:52:11 -04001866
1867/*
1868 * RACH burst detection
1869 *
1870 * Correlation window parameters:
1871 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Tom Tsoue90c24c2016-06-21 16:14:39 -07001872 * head: Search 8 symbols before target
1873 * tail: Search 8 symbols + maximum expected delay
Alexander Chemeris130a8002015-06-09 20:52:11 -04001874 */
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001875int detectRACHBurst(signalVector &burst,
1876 float threshold,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001877 int sps,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001878 complex &amplitude,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +03001879 float &toa,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001880 unsigned max_toa)
Alexander Chemeris130a8002015-06-09 20:52:11 -04001881{
1882 int rc, target, head, tail;
1883 CorrelationSequence *sync;
1884
1885 target = 8 + 40;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001886 head = 8;
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001887 tail = 8 + max_toa;
Alexander Chemeris130a8002015-06-09 20:52:11 -04001888 sync = gRACHSequence;
1889
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001890 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001891 target, head, tail, sync);
1892
1893 return rc;
1894}
1895
Thomas Tsou865bca42013-08-21 20:58:00 -04001896/*
1897 * Normal burst detection
1898 *
1899 * Correlation window parameters:
1900 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Tom Tsoue90c24c2016-06-21 16:14:39 -07001901 * head: Search 6 symbols before target
1902 * tail: Search 6 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001903 */
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001904int analyzeTrafficBurst(signalVector &burst, unsigned tsc, float threshold,
1905 int sps, complex &amplitude, float &toa, unsigned max_toa)
Thomas Tsou865bca42013-08-21 20:58:00 -04001906{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001907 int rc, target, head, tail;
Thomas Tsou865bca42013-08-21 20:58:00 -04001908 CorrelationSequence *sync;
1909
Alexander Chemeris130a8002015-06-09 20:52:11 -04001910 if ((tsc < 0) || (tsc > 7))
Tom Tsou577cd022015-05-18 13:57:54 -07001911 return -SIGERR_UNSUPPORTED;
1912
Thomas Tsou865bca42013-08-21 20:58:00 -04001913 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001914 head = 6;
1915 tail = 6 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001916 sync = gMidambles[tsc];
Thomas Tsou865bca42013-08-21 20:58:00 -04001917
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001918 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001919 target, head, tail, sync);
Alexander Chemeris130a8002015-06-09 20:52:11 -04001920 return rc;
dburgessb3a0ca42011-10-12 07:44:40 +00001921}
1922
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001923int detectEdgeBurst(signalVector &burst, unsigned tsc, float threshold,
1924 int sps, complex &amplitude, float &toa, unsigned max_toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001925{
1926 int rc, target, head, tail;
1927 CorrelationSequence *sync;
1928
1929 if ((tsc < 0) || (tsc > 7))
1930 return -SIGERR_UNSUPPORTED;
1931
1932 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001933 head = 6;
1934 tail = 6 + max_toa;
Tom Tsoud3253432016-03-06 03:08:01 -08001935 sync = gEdgeMidambles[tsc];
1936
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001937 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Tom Tsoud3253432016-03-06 03:08:01 -08001938 target, head, tail, sync);
1939 return rc;
1940}
1941
1942signalVector *downsampleBurst(signalVector &burst)
1943{
Tom Tsou76764272016-06-24 14:25:39 -07001944 signalVector *in, *out;
Tom Tsoud3253432016-03-06 03:08:01 -08001945
Tom Tsou76764272016-06-24 14:25:39 -07001946 in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len());
1947 out = new signalVector(DOWNSAMPLE_OUT_LEN);
1948 memcpy(in->begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
Tom Tsoud3253432016-03-06 03:08:01 -08001949
Tom Tsou76764272016-06-24 14:25:39 -07001950 dnsampler->rotate((float *) in->begin(), DOWNSAMPLE_IN_LEN,
1951 (float *) out->begin(), DOWNSAMPLE_OUT_LEN);
1952 delete in;
Tom Tsoud3253432016-03-06 03:08:01 -08001953 return out;
1954};
1955
Thomas Tsou94edaae2013-11-09 22:19:19 -05001956signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001957{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001958 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001959
Thomas Tsou94edaae2013-11-09 22:19:19 -05001960 if (factor <= 1)
1961 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001962
Thomas Tsou94edaae2013-11-09 22:19:19 -05001963 dec = new signalVector(wVector.size() / factor);
1964 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001965
Thomas Tsou94edaae2013-11-09 22:19:19 -05001966 signalVector::iterator itr = dec->begin();
1967 for (size_t i = 0; i < wVector.size(); i += factor)
1968 *itr++ = wVector[i];
1969
1970 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001971}
1972
Tom Tsoud3253432016-03-06 03:08:01 -08001973/*
1974 * Soft 8-PSK decoding using Manhattan distance metric
1975 */
1976static SoftVector *softSliceEdgeBurst(signalVector &burst)
1977{
1978 size_t nsyms = 148;
1979
1980 if (burst.size() < nsyms)
1981 return NULL;
1982
1983 signalVector::iterator itr;
1984 SoftVector *bits = new SoftVector(nsyms * 3);
1985
1986 /*
1987 * Bits 0 and 1 - First and second bits of the symbol respectively
1988 */
1989 rotateBurst2(burst, -M_PI / 8.0);
1990 itr = burst.begin();
1991 for (size_t i = 0; i < nsyms; i++) {
1992 (*bits)[3 * i + 0] = -itr->imag();
1993 (*bits)[3 * i + 1] = itr->real();
1994 itr++;
1995 }
1996
1997 /*
1998 * Bit 2 - Collapse symbols into quadrant 0 (positive X and Y).
1999 * Decision area is then simplified to X=Y axis. Rotate again to
2000 * place decision boundary on X-axis.
2001 */
2002 itr = burst.begin();
2003 for (size_t i = 0; i < burst.size(); i++) {
2004 burst[i] = Complex<float>(fabs(itr->real()), fabs(itr->imag()));
2005 itr++;
2006 }
2007
2008 rotateBurst2(burst, -M_PI / 4.0);
2009 itr = burst.begin();
2010 for (size_t i = 0; i < nsyms; i++) {
2011 (*bits)[3 * i + 2] = -itr->imag();
2012 itr++;
2013 }
2014
2015 signalVector soft(bits->size());
2016 for (size_t i = 0; i < bits->size(); i++)
2017 soft[i] = (*bits)[i];
2018
2019 return bits;
2020}
2021
2022/*
Tom Tsou7fec3032016-03-06 22:33:20 -08002023 * Shared portion of GMSK and EDGE demodulators consisting of timing
2024 * recovery and single tap channel correction. For 4 SPS (if activated),
2025 * the output is downsampled prior to the 1 SPS modulation specific
2026 * stages.
2027 */
2028static signalVector *demodCommon(signalVector &burst, int sps,
2029 complex chan, float toa)
2030{
2031 signalVector *delay, *dec;
2032
2033 if ((sps != 1) && (sps != 4))
2034 return NULL;
2035
2036 scaleVector(burst, (complex) 1.0 / chan);
2037 delay = delayVector(&burst, NULL, -toa * (float) sps);
2038
2039 if (sps == 1)
2040 return delay;
2041
2042 dec = downsampleBurst(*delay);
2043
2044 delete delay;
2045 return dec;
2046}
2047
2048/*
Tom Tsoud3253432016-03-06 03:08:01 -08002049 * Demodulate GSMK burst. Prior to symbol rotation, operate at
2050 * 4 SPS (if activated) to minimize distortion through the fractional
2051 * delay filters. Symbol rotation and after always operates at 1 SPS.
2052 */
Thomas Tsou83e06892013-08-20 16:10:01 -04002053SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05002054 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00002055{
Thomas Tsou94edaae2013-11-09 22:19:19 -05002056 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08002057 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00002058
Tom Tsou7fec3032016-03-06 22:33:20 -08002059 dec = demodCommon(rxBurst, sps, channel, TOA);
2060 if (!dec)
2061 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00002062
Tom Tsoud3253432016-03-06 03:08:01 -08002063 /* Shift up by a quarter of a frequency */
2064 GMSKReverseRotate(*dec, 1);
Thomas Tsou94edaae2013-11-09 22:19:19 -05002065 vectorSlicer(dec);
dburgessb3a0ca42011-10-12 07:44:40 +00002066
Thomas Tsou94edaae2013-11-09 22:19:19 -05002067 bits = new SoftVector(dec->size());
dburgessb3a0ca42011-10-12 07:44:40 +00002068
Thomas Tsou94edaae2013-11-09 22:19:19 -05002069 SoftVector::iterator bit_itr = bits->begin();
2070 signalVector::iterator burst_itr = dec->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00002071
Thomas Tsou94edaae2013-11-09 22:19:19 -05002072 for (; burst_itr < dec->end(); burst_itr++)
2073 *bit_itr++ = burst_itr->real();
dburgessb3a0ca42011-10-12 07:44:40 +00002074
Thomas Tsou94edaae2013-11-09 22:19:19 -05002075 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00002076
Thomas Tsou94edaae2013-11-09 22:19:19 -05002077 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00002078}
Thomas Tsou94edaae2013-11-09 22:19:19 -05002079
Tom Tsoud3253432016-03-06 03:08:01 -08002080/*
2081 * Demodulate an 8-PSK burst. Prior to symbol rotation, operate at
2082 * 4 SPS (if activated) to minimize distortion through the fractional
2083 * delay filters. Symbol rotation and after always operates at 1 SPS.
2084 *
2085 * Allow 1 SPS demodulation here, but note that other parts of the
2086 * transceiver restrict EDGE operatoin to 4 SPS - 8-PSK distortion
2087 * through the fractional delay filters at 1 SPS renders signal
2088 * nearly unrecoverable.
2089 */
2090SoftVector *demodEdgeBurst(signalVector &burst, int sps,
2091 complex chan, float toa)
2092{
2093 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08002094 signalVector *dec, *rot, *eq;
Tom Tsoud3253432016-03-06 03:08:01 -08002095
Tom Tsou7fec3032016-03-06 22:33:20 -08002096 dec = demodCommon(burst, sps, chan, toa);
2097 if (!dec)
Tom Tsoud3253432016-03-06 03:08:01 -08002098 return NULL;
2099
Tom Tsou7fec3032016-03-06 22:33:20 -08002100 /* Equalize and derotate */
Tom Tsoud3253432016-03-06 03:08:01 -08002101 eq = convolve(dec, GSMPulse4->c0_inv, NULL, NO_DELAY);
2102 rot = derotateEdgeBurst(*eq, 1);
2103
Tom Tsou7fec3032016-03-06 22:33:20 -08002104 /* Soft slice and normalize */
Tom Tsou04795622016-04-26 21:17:36 -07002105 bits = softSliceEdgeBurst(*rot);
Tom Tsoud3253432016-03-06 03:08:01 -08002106 vectorSlicer(bits);
2107
2108 delete dec;
2109 delete eq;
2110 delete rot;
2111
2112 return bits;
2113}
2114
Tom Tsou2079a3c2016-03-06 00:58:56 -08002115bool sigProcLibSetup()
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002116{
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002117 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05002118 generateSincTable();
Tom Tsou2079a3c2016-03-06 00:58:56 -08002119 initGMSKRotationTables();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002120
Tom Tsou2079a3c2016-03-06 00:58:56 -08002121 GSMPulse1 = generateGSMPulse(1);
2122 GSMPulse4 = generateGSMPulse(4);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002123
Tom Tsou2079a3c2016-03-06 00:58:56 -08002124 generateRACHSequence(1);
Tom Tsoud3253432016-03-06 03:08:01 -08002125 for (int tsc = 0; tsc < 8; tsc++) {
Tom Tsou2079a3c2016-03-06 00:58:56 -08002126 generateMidamble(1, tsc);
Tom Tsoud3253432016-03-06 03:08:01 -08002127 gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);
2128 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002129
Thomas Tsouf79c4d02013-11-09 15:51:56 -06002130 generateDelayFilters();
2131
Tom Tsoud3253432016-03-06 03:08:01 -08002132 dnsampler = new Resampler(1, 4);
2133 if (!dnsampler->init()) {
2134 LOG(ALERT) << "Rx resampler failed to initialize";
2135 goto fail;
2136 }
2137
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002138 return true;
Tom Tsoud3253432016-03-06 03:08:01 -08002139
2140fail:
2141 sigProcLibDestroy();
2142 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002143}