blob: c51d0947ce6aa7057276cc2cb47b2e34acebad51 [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
dburgessb3a0ca42011-10-12 07:44:40 +0000657signalVector* reverseConjugate(signalVector *b)
658{
659 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500660 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000661 signalVector::iterator bP = b->begin();
662 signalVector::iterator bPEnd = b->end();
663 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500664 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000665 while (bP < bPEnd) {
666 *tmpP-- = bP->conj();
667 bP++;
668 }
669 }
670 else {
671 while (bP < bPEnd) {
672 *tmpP-- = bP->real();
673 bP++;
674 }
675 }
676
677 return tmp;
678}
679
Tom Tsoud3253432016-03-06 03:08:01 -0800680bool vectorSlicer(SoftVector *x)
681{
682 SoftVector::iterator xP = x->begin();
683 SoftVector::iterator xPEnd = x->end();
684 while (xP < xPEnd) {
685 *xP = 0.5 * (*xP + 1.0f);
686 if (*xP > 1.0)
687 *xP = 1.0;
688 if (*xP < 0.0)
689 *xP = 0.0;
690 xP++;
691 }
692 return true;
693}
694
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800695static signalVector *rotateBurst(const BitVector &wBurst,
696 int guardPeriodLength, int sps)
697{
698 int burst_len;
699 signalVector *pulse, rotated, *shaped;
700 signalVector::iterator itr;
701
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400702 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800703 burst_len = sps * (wBurst.size() + guardPeriodLength);
704 rotated = signalVector(burst_len);
705 itr = rotated.begin();
706
707 for (unsigned i = 0; i < wBurst.size(); i++) {
708 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
709 itr += sps;
710 }
711
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400712 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500713 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800714
715 /* Dummy filter operation */
716 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
717 if (!shaped)
718 return NULL;
719
720 return shaped;
721}
722
Tom Tsoud3253432016-03-06 03:08:01 -0800723static void rotateBurst2(signalVector &burst, double phase)
724{
725 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
726
727 for (size_t i = 0; i < burst.size(); i++)
728 burst[i] = burst[i] * rot;
729}
730
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800731/*
732 * Ignore the guard length argument in the GMSK modulator interface
733 * because it results in 624/628 sized bursts instead of the preferred
734 * burst length of 625. Only 4 SPS is supported.
735 */
736static signalVector *modulateBurstLaurent(const BitVector &bits)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800737{
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800738 int burst_len, sps = 4;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800739 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500740 signalVector *c0_pulse, *c1_pulse, *c0_burst;
741 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800742 signalVector::iterator c0_itr, c1_itr;
743
Tom Tsou2079a3c2016-03-06 00:58:56 -0800744 c0_pulse = GSMPulse4->c0;
745 c1_pulse = GSMPulse4->c1;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800746
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800747 if (bits.size() > 156)
748 return NULL;
749
750 burst_len = 625;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800751
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500752 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500753 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500754 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800755
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500756 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500757 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500758 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800759
Tom Tsouaa15d622016-08-11 14:36:23 -0700760 /* Padded differential tail bits */
761 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800762 c0_itr += sps;
763
764 /* Main burst bits */
765 for (unsigned i = 0; i < bits.size(); i++) {
766 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
767 c0_itr += sps;
768 }
769
Tom Tsouaa15d622016-08-11 14:36:23 -0700770 /* Padded differential tail bits */
771 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800772
773 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500774 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500775 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800776
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500777 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800778 c0_itr += sps * 2;
779 c1_itr += sps * 2;
780
781 /* Start magic */
782 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
783 *c1_itr = *c0_itr * Complex<float>(0, phase);
784 c0_itr += sps;
785 c1_itr += sps;
786
787 /* Generate C1 phase coefficients */
788 for (unsigned i = 2; i < bits.size(); i++) {
789 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
790 *c1_itr = *c0_itr * Complex<float>(0, phase);
791
792 c0_itr += sps;
793 c1_itr += sps;
794 }
795
796 /* End magic */
797 int i = bits.size();
798 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
799 *c1_itr = *c0_itr * Complex<float>(0, phase);
800
801 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500802 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
803 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800804
805 /* Sum shaped outputs into C0 */
806 c0_itr = c0_shaped->begin();
807 c1_itr = c1_shaped->begin();
808 for (unsigned i = 0; i < c0_shaped->size(); i++ )
809 *c0_itr++ += *c1_itr++;
810
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500811 delete c0_burst;
812 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800813 delete c1_shaped;
814
815 return c0_shaped;
816}
817
Tom Tsoud3253432016-03-06 03:08:01 -0800818static signalVector *rotateEdgeBurst(const signalVector &symbols, int sps)
819{
820 signalVector *burst;
821 signalVector::iterator burst_itr;
822
823 burst = new signalVector(symbols.size() * sps);
824 burst_itr = burst->begin();
825
826 for (size_t i = 0; i < symbols.size(); i++) {
827 float phase = i * 3.0f * M_PI / 8.0f;
828 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
829
830 *burst_itr = symbols[i] * rot;
831 burst_itr += sps;
832 }
833
834 return burst;
835}
836
837static signalVector *derotateEdgeBurst(const signalVector &symbols, int sps)
838{
839 signalVector *burst;
840 signalVector::iterator burst_itr;
841
842 if (symbols.size() % sps)
843 return NULL;
844
845 burst = new signalVector(symbols.size() / sps);
846 burst_itr = burst->begin();
847
848 for (size_t i = 0; i < burst->size(); i++) {
849 float phase = (float) (i % 16) * 3.0f * M_PI / 8.0f;
850 Complex<float> rot = Complex<float>(cosf(phase), -sinf(phase));
851
852 *burst_itr = symbols[sps * i] * rot;
853 burst_itr++;
854 }
855
856 return burst;
857}
858
859static signalVector *mapEdgeSymbols(const BitVector &bits)
860{
861 if (bits.size() % 3)
862 return NULL;
863
864 signalVector *symbols = new signalVector(bits.size() / 3);
865
866 for (size_t i = 0; i < symbols->size(); i++) {
867 unsigned index = (((unsigned) bits[3 * i + 0] & 0x01) << 0) |
868 (((unsigned) bits[3 * i + 1] & 0x01) << 1) |
869 (((unsigned) bits[3 * i + 2] & 0x01) << 2);
870
871 (*symbols)[i] = psk8_table[index];
872 }
873
874 return symbols;
875}
876
Tom Tsoud2b07032016-04-26 19:28:59 -0700877/*
878 * EDGE 8-PSK rotate and pulse shape
879 *
880 * Delay the EDGE downlink bursts by one symbol in order to match GMSK pulse
881 * shaping group delay. The difference in group delay arises from the dual
882 * pulse filter combination of the GMSK Laurent represenation whereas 8-PSK
883 * uses a single pulse linear filter.
884 */
Tom Tsoud3253432016-03-06 03:08:01 -0800885static signalVector *shapeEdgeBurst(const signalVector &symbols)
886{
Tom Tsoud2b07032016-04-26 19:28:59 -0700887 size_t nsyms, nsamps = 625, sps = 4;
Tom Tsoud3253432016-03-06 03:08:01 -0800888 signalVector *burst, *shape;
889 signalVector::iterator burst_itr;
890
891 nsyms = symbols.size();
892
Tom Tsoud2b07032016-04-26 19:28:59 -0700893 if (nsyms * sps > nsamps)
Tom Tsoud3253432016-03-06 03:08:01 -0800894 nsyms = 156;
895
896 burst = new signalVector(nsamps, GSMPulse4->c0->size());
Tom Tsoud3253432016-03-06 03:08:01 -0800897
Tom Tsoud2b07032016-04-26 19:28:59 -0700898 /* Delay burst by 1 symbol */
899 burst_itr = burst->begin() + sps;
Tom Tsou06676ea2016-07-19 12:50:21 -0700900 for (size_t i = 0; i < nsyms; i++) {
Tom Tsoud3253432016-03-06 03:08:01 -0800901 float phase = i * 3.0f * M_PI / 8.0f;
902 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
903
904 *burst_itr = symbols[i] * rot;
Tom Tsoud2b07032016-04-26 19:28:59 -0700905 burst_itr += sps;
Tom Tsoud3253432016-03-06 03:08:01 -0800906 }
907
908 /* Single Gaussian pulse approximation shaping */
909 shape = convolve(burst, GSMPulse4->c0, NULL, START_ONLY);
910 delete burst;
911
912 return shape;
913}
914
915/*
Tom Tsou8ee2f382016-03-06 20:57:34 -0800916 * Generate a random GSM normal burst.
917 */
918signalVector *genRandNormalBurst(int tsc, int sps, int tn)
919{
920 if ((tsc < 0) || (tsc > 7) || (tn < 0) || (tn > 7))
921 return NULL;
922 if ((sps != 1) && (sps != 4))
923 return NULL;
924
925 int i = 0;
926 BitVector *bits = new BitVector(148);
927 signalVector *burst;
928
929 /* Tail bits */
930 for (; i < 4; i++)
931 (*bits)[i] = 0;
932
933 /* Random bits */
934 for (; i < 61; i++)
935 (*bits)[i] = rand() % 2;
936
937 /* Training sequence */
938 for (int n = 0; i < 87; i++, n++)
939 (*bits)[i] = gTrainingSequence[tsc][n];
940
941 /* Random bits */
942 for (; i < 144; i++)
943 (*bits)[i] = rand() % 2;
944
945 /* Tail bits */
946 for (; i < 148; i++)
947 (*bits)[i] = 0;
948
949 int guard = 8 + !(tn % 4);
950 burst = modulateBurst(*bits, guard, sps);
951 delete bits;
952
953 return burst;
954}
955
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300956/*
957 * Generate a random GSM access burst.
958 */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300959signalVector *genRandAccessBurst(int delay, int sps, int tn)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300960{
961 if ((tn < 0) || (tn > 7))
962 return NULL;
963 if ((sps != 1) && (sps != 4))
964 return NULL;
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300965 if (delay > 68)
966 return NULL;
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300967
968 int i = 0;
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300969 BitVector *bits = new BitVector(88+delay);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300970 signalVector *burst;
971
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300972 /* delay */
973 for (; i < delay; i++)
974 (*bits)[i] = 0;
975
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300976 /* head and synch bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300977 for (int n = 0; i < 49+delay; i++, n++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300978 (*bits)[i] = gRACHBurst[n];
979
980 /* Random bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300981 for (; i < 85+delay; i++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300982 (*bits)[i] = rand() % 2;
983
984 /* Tail bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300985 for (; i < 88+delay; i++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300986 (*bits)[i] = 0;
987
Alexander Chemeris37c52c72016-03-25 18:28:34 +0300988 int guard = 68-delay + !(tn % 4);
Alexander Chemeris5efe0502016-03-23 17:06:32 +0300989 burst = modulateBurst(*bits, guard, sps);
990 delete bits;
991
992 return burst;
993}
994
Tom Tsou8ee2f382016-03-06 20:57:34 -0800995signalVector *generateEmptyBurst(int sps, int tn)
996{
997 if ((tn < 0) || (tn > 7))
998 return NULL;
999
1000 if (sps == 4)
1001 return new signalVector(625);
1002 else if (sps == 1)
1003 return new signalVector(148 + 8 + !(tn % 4));
1004 else
1005 return NULL;
1006}
1007
1008signalVector *generateDummyBurst(int sps, int tn)
1009{
1010 if (((sps != 1) && (sps != 4)) || (tn < 0) || (tn > 7))
1011 return NULL;
1012
1013 return modulateBurst(gDummyBurst, 8 + !(tn % 4), sps);
1014}
1015
1016/*
Tom Tsoud3253432016-03-06 03:08:01 -08001017 * Generate a random 8-PSK EDGE burst. Only 4 SPS is supported with
1018 * the returned burst being 625 samples in length.
1019 */
1020signalVector *generateEdgeBurst(int tsc)
1021{
1022 int tail = 9 / 3;
1023 int data = 174 / 3;
1024 int train = 78 / 3;
1025
1026 if ((tsc < 0) || (tsc > 7))
1027 return NULL;
1028
1029 signalVector *shape, *burst = new signalVector(148);
1030 const BitVector *midamble = &gEdgeTrainingSequence[tsc];
1031
1032 /* Tail */
1033 int n, i = 0;
1034 for (; i < tail; i++)
1035 (*burst)[i] = psk8_table[7];
1036
1037 /* Body */
1038 for (; i < tail + data; i++)
1039 (*burst)[i] = psk8_table[rand() % 8];
1040
1041 /* TSC */
1042 for (n = 0; i < tail + data + train; i++, n++) {
1043 unsigned index = (((unsigned) (*midamble)[3 * n + 0] & 0x01) << 0) |
1044 (((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
1045 (((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
1046
1047 (*burst)[i] = psk8_table[index];
1048 }
1049
1050 /* Body */
1051 for (; i < tail + data + train + data; i++)
1052 (*burst)[i] = psk8_table[rand() % 8];
1053
1054 /* Tail */
1055 for (; i < tail + data + train + data + tail; i++)
1056 (*burst)[i] = psk8_table[7];
1057
1058 shape = shapeEdgeBurst(*burst);
1059 delete burst;
1060
1061 return shape;
1062}
1063
1064/*
1065 * Modulate 8-PSK burst. When empty pulse shaping (rotation only)
1066 * is enabled, the output vector length will be bit sequence length
1067 * times the SPS value. When pulse shaping is enabled, the output
Alexander Chemeris9270a5a2017-03-17 13:03:41 -07001068 * vector length is fixed at 625 samples (156.25 symbols at 4 SPS).
Tom Tsoud3253432016-03-06 03:08:01 -08001069 * Pulse shaped bit sequences that go beyond one burst are truncated.
1070 * Pulse shaping at anything but 4 SPS is not supported.
1071 */
1072signalVector *modulateEdgeBurst(const BitVector &bits,
1073 int sps, bool empty)
1074{
1075 signalVector *shape, *burst;
1076
1077 if ((sps != 4) && !empty)
1078 return NULL;
1079
1080 burst = mapEdgeSymbols(bits);
1081 if (!burst)
1082 return NULL;
1083
1084 if (empty)
1085 shape = rotateEdgeBurst(*burst, sps);
1086 else
1087 shape = shapeEdgeBurst(*burst);
1088
1089 delete burst;
1090 return shape;
1091}
1092
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001093static signalVector *modulateBurstBasic(const BitVector &bits,
1094 int guard_len, int sps)
1095{
1096 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001097 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001098 signalVector::iterator burst_itr;
1099
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001100 if (sps == 1)
1101 pulse = GSMPulse1->c0;
1102 else
Tom Tsou2079a3c2016-03-06 00:58:56 -08001103 pulse = GSMPulse4->c0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001104
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001105 burst_len = sps * (bits.size() + guard_len);
1106
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001107 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001108 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001109 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001110
1111 /* Raw bits are not differentially encoded */
1112 for (unsigned i = 0; i < bits.size(); i++) {
1113 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
1114 burst_itr += sps;
1115 }
1116
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001117 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001118 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001119
1120 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001121 shaped = convolve(burst, pulse, NULL, START_ONLY);
1122
1123 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001124
1125 return shaped;
1126}
1127
Thomas Tsou3eaae802013-08-20 19:31:14 -04001128/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -04001129signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
1130 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +00001131{
Thomas Tsou83e06892013-08-20 16:10:01 -04001132 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001133 return rotateBurst(wBurst, guardPeriodLength, sps);
1134 else if (sps == 4)
Tom Tsou4dfd64a2016-03-06 20:31:51 -08001135 return modulateBurstLaurent(wBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -04001136 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001137 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001138}
1139
Tom Tsou2079a3c2016-03-06 00:58:56 -08001140static void generateSincTable()
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001141{
1142 float x;
1143
1144 for (int i = 0; i < TABLESIZE; i++) {
1145 x = (float) i / TABLESIZE * 8 * M_PI;
1146 if (fabs(x) < 0.01) {
1147 sincTable[i] = 1.0f;
1148 continue;
1149 }
1150
1151 sincTable[i] = sinf(x) / x;
1152 }
1153}
1154
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001155float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +00001156{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001157 if (fabs(x) >= 8 * M_PI)
1158 return 0.0;
1159
1160 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
1161
1162 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +00001163}
1164
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001165/*
1166 * Create fractional delay filterbank with Blackman-harris windowed
1167 * sinc function generator. The number of filters generated is specified
1168 * by the DELAYFILTS value.
1169 */
1170void generateDelayFilters()
1171{
1172 int h_len = 20;
1173 complex *data;
1174 signalVector *h;
1175 signalVector::iterator itr;
1176
1177 float k, sum;
1178 float a0 = 0.35875;
1179 float a1 = 0.48829;
1180 float a2 = 0.14128;
1181 float a3 = 0.01168;
1182
1183 for (int i = 0; i < DELAYFILTS; i++) {
1184 data = (complex *) convolve_h_alloc(h_len);
1185 h = new signalVector(data, 0, h_len);
1186 h->setAligned(true);
1187 h->isReal(true);
1188
1189 sum = 0.0;
1190 itr = h->end();
1191 for (int n = 0; n < h_len; n++) {
1192 k = (float) n;
1193 *--itr = (complex) sinc(M_PI_F *
1194 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
1195 *itr *= a0 -
1196 a1 * cos(2 * M_PI * n / (h_len - 1)) +
1197 a2 * cos(4 * M_PI * n / (h_len - 1)) -
1198 a3 * cos(6 * M_PI * n / (h_len - 1));
1199
1200 sum += itr->real();
1201 }
1202
1203 itr = h->begin();
1204 for (int n = 0; n < h_len; n++)
1205 *itr++ /= sum;
1206
1207 delayFilters[i] = h;
1208 }
1209}
1210
Alexander Chemerise0c12182017-03-18 13:27:48 -07001211signalVector *delayVector(const signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +00001212{
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001213 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001214 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001215 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001216
Thomas Tsou2c282f52013-10-08 21:34:35 -04001217 whole = floor(delay);
1218 frac = delay - whole;
1219
1220 /* Sinc interpolated fractional shift (if allowable) */
1221 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001222 index = floorf(frac * (float) DELAYFILTS);
1223 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -04001224
Thomas Tsou94edaae2013-11-09 22:19:19 -05001225 fshift = convolve(in, h, NULL, NO_DELAY);
1226 if (!fshift)
1227 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001228 }
1229
Thomas Tsou94edaae2013-11-09 22:19:19 -05001230 if (!fshift)
1231 shift = new signalVector(*in);
1232 else
1233 shift = fshift;
1234
Thomas Tsou2c282f52013-10-08 21:34:35 -04001235 /* Integer sample shift */
1236 if (whole < 0) {
1237 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001238 signalVector::iterator wBurstItr = shift->begin();
1239 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001240
Thomas Tsou94edaae2013-11-09 22:19:19 -05001241 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +00001242 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001243
Thomas Tsou94edaae2013-11-09 22:19:19 -05001244 while (wBurstItr < shift->end())
1245 *wBurstItr++ = 0.0;
1246 } else if (whole >= 0) {
1247 signalVector::iterator wBurstItr = shift->end() - 1;
1248 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
1249
1250 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001251 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001252
1253 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001254 *wBurstItr-- = 0.0;
1255 }
Thomas Tsou2c282f52013-10-08 21:34:35 -04001256
Thomas Tsou94edaae2013-11-09 22:19:19 -05001257 if (!out)
1258 return shift;
1259
1260 out->clone(*shift);
1261 delete shift;
1262 return out;
dburgessb3a0ca42011-10-12 07:44:40 +00001263}
Thomas Tsou2c282f52013-10-08 21:34:35 -04001264
dburgessb3a0ca42011-10-12 07:44:40 +00001265signalVector *gaussianNoise(int length,
1266 float variance,
1267 complex mean)
1268{
1269
1270 signalVector *noise = new signalVector(length);
1271 signalVector::iterator nPtr = noise->begin();
1272 float stddev = sqrtf(variance);
1273 while (nPtr < noise->end()) {
1274 float u1 = (float) rand()/ (float) RAND_MAX;
1275 while (u1==0.0)
1276 u1 = (float) rand()/ (float) RAND_MAX;
1277 float u2 = (float) rand()/ (float) RAND_MAX;
1278 float arg = 2.0*M_PI*u2;
1279 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
1280 nPtr++;
1281 }
1282
1283 return noise;
1284}
1285
1286complex interpolatePoint(const signalVector &inSig,
1287 float ix)
1288{
1289
1290 int start = (int) (floor(ix) - 10);
1291 if (start < 0) start = 0;
1292 int end = (int) (floor(ix) + 11);
1293 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
1294
1295 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001296 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001297 for (int i = start; i < end; i++)
1298 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
1299 }
1300 else {
1301 for (int i = start; i < end; i++)
1302 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
1303 }
1304
1305 return pVal;
1306}
1307
Thomas Tsou8181b012013-08-20 21:17:19 -04001308static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1309{
1310 float val, max = 0.0f;
1311 complex amp;
1312 int _index = -1;
1313
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001314 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001315 val = rxBurst[i].norm2();
1316 if (val > max) {
1317 max = val;
1318 _index = i;
1319 amp = rxBurst[i];
1320 }
1321 }
1322
1323 if (index)
1324 *index = (float) _index;
1325
1326 return amp;
1327}
1328
dburgessb3a0ca42011-10-12 07:44:40 +00001329complex peakDetect(const signalVector &rxBurst,
1330 float *peakIndex,
1331 float *avgPwr)
1332{
1333
1334
1335 complex maxVal = 0.0;
1336 float maxIndex = -1;
1337 float sumPower = 0.0;
1338
1339 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1340 float samplePower = rxBurst[i].norm2();
1341 if (samplePower > maxVal.real()) {
1342 maxVal = samplePower;
1343 maxIndex = i;
1344 }
1345 sumPower += samplePower;
1346 }
1347
1348 // interpolate around the peak
1349 // to save computation, we'll use early-late balancing
1350 float earlyIndex = maxIndex-1;
1351 float lateIndex = maxIndex+1;
1352
1353 float incr = 0.5;
1354 while (incr > 1.0/1024.0) {
1355 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1356 complex lateP = interpolatePoint(rxBurst,lateIndex);
1357 if (earlyP < lateP)
1358 earlyIndex += incr;
1359 else if (earlyP > lateP)
1360 earlyIndex -= incr;
1361 else break;
1362 incr /= 2.0;
1363 lateIndex = earlyIndex + 2.0;
1364 }
1365
1366 maxIndex = earlyIndex + 1.0;
1367 maxVal = interpolatePoint(rxBurst,maxIndex);
1368
1369 if (peakIndex!=NULL)
1370 *peakIndex = maxIndex;
1371
1372 if (avgPwr!=NULL)
1373 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1374
1375 return maxVal;
1376
1377}
1378
1379void scaleVector(signalVector &x,
1380 complex scale)
1381{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001382#ifdef HAVE_NEON
1383 int len = x.size();
1384
1385 scale_complex((float *) x.begin(),
1386 (float *) x.begin(),
1387 (float *) &scale, len);
1388#else
dburgessb3a0ca42011-10-12 07:44:40 +00001389 signalVector::iterator xP = x.begin();
1390 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001391 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001392 while (xP < xPEnd) {
1393 *xP = *xP * scale;
1394 xP++;
1395 }
1396 }
1397 else {
1398 while (xP < xPEnd) {
1399 *xP = xP->real() * scale;
1400 xP++;
1401 }
1402 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001403#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001404}
1405
1406/** in-place conjugation */
1407void conjugateVector(signalVector &x)
1408{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001409 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001410 signalVector::iterator xP = x.begin();
1411 signalVector::iterator xPEnd = x.end();
1412 while (xP < xPEnd) {
1413 *xP = xP->conj();
1414 xP++;
1415 }
1416}
1417
1418
1419// in-place addition!!
1420bool addVector(signalVector &x,
1421 signalVector &y)
1422{
1423 signalVector::iterator xP = x.begin();
1424 signalVector::iterator yP = y.begin();
1425 signalVector::iterator xPEnd = x.end();
1426 signalVector::iterator yPEnd = y.end();
1427 while ((xP < xPEnd) && (yP < yPEnd)) {
1428 *xP = *xP + *yP;
1429 xP++; yP++;
1430 }
1431 return true;
1432}
1433
1434// in-place multiplication!!
1435bool multVector(signalVector &x,
1436 signalVector &y)
1437{
1438 signalVector::iterator xP = x.begin();
1439 signalVector::iterator yP = y.begin();
1440 signalVector::iterator xPEnd = x.end();
1441 signalVector::iterator yPEnd = y.end();
1442 while ((xP < xPEnd) && (yP < yPEnd)) {
1443 *xP = (*xP) * (*yP);
1444 xP++; yP++;
1445 }
1446 return true;
1447}
1448
Tom Tsou2079a3c2016-03-06 00:58:56 -08001449static bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001450{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001451 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001452 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001453 complex *data = NULL;
1454 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001455 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001456
Thomas Tsou3eaae802013-08-20 19:31:14 -04001457 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001458 return false;
1459
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001460 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001461
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001462 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1463 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1464 if (!midMidamble)
1465 return false;
1466
Thomas Tsou3eaae802013-08-20 19:31:14 -04001467 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001468 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1469 if (!midamble) {
1470 status = false;
1471 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001472 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001473
dburgessb3a0ca42011-10-12 07:44:40 +00001474 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1475 // the ideal TSC has an + 180 degree phase shift,
1476 // due to the pi/2 frequency shift, that
1477 // needs to be accounted for.
1478 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001479 scaleVector(*midMidamble, complex(-1.0, 0.0));
1480 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001481
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001482 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001483
Thomas Tsou3eaae802013-08-20 19:31:14 -04001484 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1485 data = (complex *) convolve_h_alloc(midMidamble->size());
1486 _midMidamble = new signalVector(data, 0, midMidamble->size());
1487 _midMidamble->setAligned(true);
1488 memcpy(_midMidamble->begin(), midMidamble->begin(),
1489 midMidamble->size() * sizeof(complex));
1490
1491 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001492 if (!autocorr) {
1493 status = false;
1494 goto release;
1495 }
dburgessb3a0ca42011-10-12 07:44:40 +00001496
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001497 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001498 gMidambles[tsc]->buffer = data;
1499 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001500 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1501
1502 /* For 1 sps only
1503 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1504 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1505 */
1506 if (sps == 1)
1507 gMidambles[tsc]->toa = toa - 13.5;
1508 else
1509 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001510
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001511release:
dburgessb3a0ca42011-10-12 07:44:40 +00001512 delete autocorr;
1513 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001514 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001515
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001516 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001517 delete _midMidamble;
1518 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001519 gMidambles[tsc] = NULL;
1520 }
1521
1522 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001523}
1524
Tom Tsoud3253432016-03-06 03:08:01 -08001525CorrelationSequence *generateEdgeMidamble(int tsc)
1526{
1527 complex *data = NULL;
1528 signalVector *midamble = NULL, *_midamble = NULL;
1529 CorrelationSequence *seq;
1530
1531 if ((tsc < 0) || (tsc > 7))
1532 return NULL;
1533
1534 /* Use middle 48 bits of each TSC. Correlation sequence is not pulse shaped */
1535 const BitVector *bits = &gEdgeTrainingSequence[tsc];
1536 midamble = modulateEdgeBurst(bits->segment(15, 48), 1, true);
1537 if (!midamble)
1538 return NULL;
1539
1540 conjugateVector(*midamble);
1541
1542 data = (complex *) convolve_h_alloc(midamble->size());
1543 _midamble = new signalVector(data, 0, midamble->size());
1544 _midamble->setAligned(true);
1545 memcpy(_midamble->begin(), midamble->begin(),
1546 midamble->size() * sizeof(complex));
1547
1548 /* Channel gain is an empirically measured value */
1549 seq = new CorrelationSequence;
1550 seq->buffer = data;
1551 seq->sequence = _midamble;
1552 seq->gain = Complex<float>(-19.6432, 19.5006) / 1.18;
1553 seq->toa = 0;
1554
1555 delete midamble;
1556
1557 return seq;
1558}
1559
Tom Tsou2079a3c2016-03-06 00:58:56 -08001560static bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001561{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001562 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001563 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001564 complex *data = NULL;
1565 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001566 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001567
1568 delete gRACHSequence;
1569
1570 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1571 if (!seq0)
1572 return false;
1573
1574 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1575 if (!seq1) {
1576 status = false;
1577 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001578 }
1579
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001580 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001581
Thomas Tsou3eaae802013-08-20 19:31:14 -04001582 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1583 data = (complex *) convolve_h_alloc(seq1->size());
1584 _seq1 = new signalVector(data, 0, seq1->size());
1585 _seq1->setAligned(true);
1586 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1587
1588 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1589 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001590 status = false;
1591 goto release;
1592 }
dburgessb3a0ca42011-10-12 07:44:40 +00001593
1594 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001595 gRACHSequence->sequence = _seq1;
1596 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001597 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1598
1599 /* For 1 sps only
1600 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1601 * 20.5 = (40 / 2 - 1) + 1.5
1602 */
1603 if (sps == 1)
1604 gRACHSequence->toa = toa - 20.5;
1605 else
1606 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001607
1608release:
dburgessb3a0ca42011-10-12 07:44:40 +00001609 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001610 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001611 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001612
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001613 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001614 delete _seq1;
1615 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001616 gRACHSequence = NULL;
1617 }
dburgessb3a0ca42011-10-12 07:44:40 +00001618
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001619 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001620}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001621
Tom Tsoua84e1622016-06-29 14:50:25 -07001622/*
1623 * Peak-to-average computation +/- range from peak in symbols
1624 */
1625#define COMPUTE_PEAK_MIN 2
1626#define COMPUTE_PEAK_MAX 5
1627
1628/*
1629 * Minimum number of values needed to compute peak-to-average
1630 */
1631#define COMPUTE_PEAK_CNT 5
1632
Thomas Tsou865bca42013-08-21 20:58:00 -04001633static float computePeakRatio(signalVector *corr,
1634 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001635{
Thomas Tsou865bca42013-08-21 20:58:00 -04001636 int num = 0;
1637 complex *peak;
1638 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001639
Thomas Tsou865bca42013-08-21 20:58:00 -04001640 /* Check for bogus results */
1641 if ((toa < 0.0) || (toa > corr->size()))
1642 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001643
Alexander Chemeris1e9b4d52015-06-04 19:05:28 -04001644 peak = corr->begin() + (int) rint(toa);
1645
Tom Tsoua84e1622016-06-29 14:50:25 -07001646 for (int i = COMPUTE_PEAK_MIN * sps; i <= COMPUTE_PEAK_MAX * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001647 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001648 avg += (peak - i)->norm2();
1649 num++;
1650 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001651 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001652 avg += (peak + i)->norm2();
1653 num++;
1654 }
dburgessb3a0ca42011-10-12 07:44:40 +00001655 }
1656
Tom Tsoua84e1622016-06-29 14:50:25 -07001657 if (num < COMPUTE_PEAK_CNT)
Thomas Tsou865bca42013-08-21 20:58:00 -04001658 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001659
Thomas Tsou3eaae802013-08-20 19:31:14 -04001660 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001661
Thomas Tsou865bca42013-08-21 20:58:00 -04001662 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001663}
1664
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001665float energyDetect(const signalVector &rxBurst, unsigned windowLength)
dburgessb3a0ca42011-10-12 07:44:40 +00001666{
1667
1668 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1669 float energy = 0.0;
Tom Tsou2af14402017-03-23 14:54:00 -07001670 if (windowLength == 0) return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001671 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1672 for (unsigned i = 0; i < windowLength; i++) {
1673 energy += windowItr->norm2();
1674 windowItr+=4;
1675 }
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +03001676 return energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001677}
dburgessb3a0ca42011-10-12 07:44:40 +00001678
Thomas Tsou865bca42013-08-21 20:58:00 -04001679/*
1680 * Detect a burst based on correlation and peak-to-average ratio
1681 *
1682 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1683 * for initial gating. We do this because energy detection should be disabled.
1684 * For higher oversampling values, we assume the energy detector is in place
1685 * and we run full interpolating peak detection.
1686 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001687static int detectBurst(const signalVector &burst,
Thomas Tsou865bca42013-08-21 20:58:00 -04001688 signalVector &corr, CorrelationSequence *sync,
1689 float thresh, int sps, complex *amp, float *toa,
1690 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001691{
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001692 const signalVector *corr_in;
1693 signalVector *dec = NULL;
Tom Tsoud3253432016-03-06 03:08:01 -08001694
1695 if (sps == 4) {
1696 dec = downsampleBurst(burst);
1697 corr_in = dec;
1698 sps = 1;
1699 } else {
1700 corr_in = &burst;
1701 }
1702
Thomas Tsou865bca42013-08-21 20:58:00 -04001703 /* Correlate */
Tom Tsoud3253432016-03-06 03:08:01 -08001704 if (!convolve(corr_in, sync->sequence, &corr,
1705 CUSTOM, start, len, 1, 0)) {
1706 delete dec;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001707 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001708 }
1709
Tom Tsoud3253432016-03-06 03:08:01 -08001710 delete dec;
1711
1712 /* Running at the downsampled rate at this point */
1713 sps = 1;
1714
Thomas Tsou865bca42013-08-21 20:58:00 -04001715 /* Peak detection - place restrictions at correlation edges */
1716 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001717
Thomas Tsou865bca42013-08-21 20:58:00 -04001718 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1719 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001720
Thomas Tsou865bca42013-08-21 20:58:00 -04001721 /* Peak -to-average ratio */
1722 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1723 return 0;
1724
1725 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1726 *amp = peakDetect(corr, toa, NULL);
1727
1728 /* Normalize our channel gain */
1729 *amp = *amp / sync->gain;
1730
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001731 /* Compensate for residuate time lag */
1732 *toa = *toa - sync->toa;
1733
Thomas Tsou865bca42013-08-21 20:58:00 -04001734 return 1;
1735}
1736
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001737static float maxAmplitude(const signalVector &burst)
Tom Tsou577cd022015-05-18 13:57:54 -07001738{
Alexander Chemeris954b1182015-06-04 15:39:41 -04001739 float max = 0.0;
1740 for (size_t i = 0; i < burst.size(); i++) {
1741 if (fabs(burst[i].real()) > max)
1742 max = fabs(burst[i].real());
1743 if (fabs(burst[i].imag()) > max)
1744 max = fabs(burst[i].imag());
1745 }
Tom Tsou577cd022015-05-18 13:57:54 -07001746
Alexander Chemeris954b1182015-06-04 15:39:41 -04001747 return max;
Tom Tsou577cd022015-05-18 13:57:54 -07001748}
1749
Alexander Chemeris130a8002015-06-09 20:52:11 -04001750/*
1751 * RACH/Normal burst detection with clipping detection
Thomas Tsou865bca42013-08-21 20:58:00 -04001752 *
1753 * Correlation window parameters:
Alexander Chemeris130a8002015-06-09 20:52:11 -04001754 * target: Tail bits + burst length
1755 * head: Search symbols before target
1756 * tail: Search symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001757 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001758static int detectGeneralBurst(const signalVector &rxBurst,
1759 float thresh,
1760 int sps,
1761 complex &amp,
1762 float &toa,
1763 int target, int head, int tail,
1764 CorrelationSequence *sync)
Thomas Tsou865bca42013-08-21 20:58:00 -04001765{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001766 int rc, start, len;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001767 bool clipping = false;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001768 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001769
1770 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001771 return -SIGERR_UNSUPPORTED;
1772
Alexander Chemeris954b1182015-06-04 15:39:41 -04001773 // Detect potential clipping
1774 // We still may be able to demod the burst, so we'll give it a try
1775 // and only report clipping if we can't demod.
1776 float maxAmpl = maxAmplitude(rxBurst);
1777 if (maxAmpl > CLIP_THRESH) {
1778 LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
1779 clipping = true;
1780 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001781
Tom Tsoud3253432016-03-06 03:08:01 -08001782 start = target - head - 1;
1783 len = head + tail;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001784 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001785
Thomas Tsoub075dd22013-11-09 22:25:46 -05001786 rc = detectBurst(rxBurst, *corr, sync,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001787 thresh, sps, &amp, &toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001788 delete corr;
1789
Thomas Tsou865bca42013-08-21 20:58:00 -04001790 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001791 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001792 } else if (!rc) {
Alexander Chemeris130a8002015-06-09 20:52:11 -04001793 amp = 0.0f;
1794 toa = 0.0f;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001795 return clipping?-SIGERR_CLIP:SIGERR_NONE;
dburgessb3a0ca42011-10-12 07:44:40 +00001796 }
1797
Thomas Tsou865bca42013-08-21 20:58:00 -04001798 /* Subtract forward search bits from delay */
Tom Tsoud3253432016-03-06 03:08:01 -08001799 toa -= head;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001800
Thomas Tsou865bca42013-08-21 20:58:00 -04001801 return 1;
1802}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001803
Alexander Chemeris130a8002015-06-09 20:52:11 -04001804
1805/*
1806 * RACH burst detection
1807 *
1808 * Correlation window parameters:
1809 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Tom Tsoue90c24c2016-06-21 16:14:39 -07001810 * head: Search 8 symbols before target
1811 * tail: Search 8 symbols + maximum expected delay
Alexander Chemeris130a8002015-06-09 20:52:11 -04001812 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001813int detectRACHBurst(const signalVector &burst,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001814 float threshold,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001815 int sps,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001816 complex &amplitude,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +03001817 float &toa,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001818 unsigned max_toa)
Alexander Chemeris130a8002015-06-09 20:52:11 -04001819{
1820 int rc, target, head, tail;
1821 CorrelationSequence *sync;
1822
1823 target = 8 + 40;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001824 head = 8;
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001825 tail = 8 + max_toa;
Alexander Chemeris130a8002015-06-09 20:52:11 -04001826 sync = gRACHSequence;
1827
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001828 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001829 target, head, tail, sync);
1830
1831 return rc;
1832}
1833
Thomas Tsou865bca42013-08-21 20:58:00 -04001834/*
1835 * Normal burst detection
1836 *
1837 * Correlation window parameters:
1838 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Tom Tsoue90c24c2016-06-21 16:14:39 -07001839 * head: Search 6 symbols before target
1840 * tail: Search 6 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001841 */
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001842int analyzeTrafficBurst(const signalVector &burst, unsigned tsc, float threshold,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001843 int sps, complex &amplitude, float &toa, unsigned max_toa)
Thomas Tsou865bca42013-08-21 20:58:00 -04001844{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001845 int rc, target, head, tail;
Thomas Tsou865bca42013-08-21 20:58:00 -04001846 CorrelationSequence *sync;
1847
Tom Tsouae91f132017-03-28 14:40:38 -07001848 if (tsc > 7)
Tom Tsou577cd022015-05-18 13:57:54 -07001849 return -SIGERR_UNSUPPORTED;
1850
Thomas Tsou865bca42013-08-21 20:58:00 -04001851 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001852 head = 6;
1853 tail = 6 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001854 sync = gMidambles[tsc];
Thomas Tsou865bca42013-08-21 20:58:00 -04001855
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001856 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001857 target, head, tail, sync);
Alexander Chemeris130a8002015-06-09 20:52:11 -04001858 return rc;
dburgessb3a0ca42011-10-12 07:44:40 +00001859}
1860
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001861int detectEdgeBurst(const signalVector &burst, unsigned tsc, float threshold,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001862 int sps, complex &amplitude, float &toa, unsigned max_toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001863{
1864 int rc, target, head, tail;
1865 CorrelationSequence *sync;
1866
Tom Tsouae91f132017-03-28 14:40:38 -07001867 if (tsc > 7)
Tom Tsoud3253432016-03-06 03:08:01 -08001868 return -SIGERR_UNSUPPORTED;
1869
1870 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001871 head = 6;
1872 tail = 6 + max_toa;
Tom Tsoud3253432016-03-06 03:08:01 -08001873 sync = gEdgeMidambles[tsc];
1874
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001875 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Tom Tsoud3253432016-03-06 03:08:01 -08001876 target, head, tail, sync);
1877 return rc;
1878}
1879
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001880int detectAnyBurst(const signalVector &burst, unsigned tsc, float threshold,
Alexander Chemeris4e6c9382017-03-17 15:24:18 -07001881 int sps, CorrType type, complex &amp, float &toa,
1882 unsigned max_toa)
1883{
1884 int rc = 0;
1885
1886 switch (type) {
1887 case EDGE:
1888 rc = detectEdgeBurst(burst, tsc, threshold, sps,
1889 amp, toa, max_toa);
1890 if (rc > 0)
1891 break;
1892 else
1893 type = TSC;
1894 case TSC:
1895 rc = analyzeTrafficBurst(burst, tsc, threshold, sps,
1896 amp, toa, max_toa);
1897 break;
1898 case RACH:
1899 rc = detectRACHBurst(burst, threshold, sps, amp, toa,
1900 max_toa);
1901 break;
1902 default:
1903 LOG(ERR) << "Invalid correlation type";
1904 }
1905
1906 if (rc > 0)
1907 return type;
1908
1909 return rc;
1910}
1911
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07001912signalVector *downsampleBurst(const signalVector &burst)
Tom Tsoud3253432016-03-06 03:08:01 -08001913{
Tom Tsou76764272016-06-24 14:25:39 -07001914 signalVector *in, *out;
Tom Tsoud3253432016-03-06 03:08:01 -08001915
Tom Tsou76764272016-06-24 14:25:39 -07001916 in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len());
1917 out = new signalVector(DOWNSAMPLE_OUT_LEN);
1918 memcpy(in->begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
Tom Tsoud3253432016-03-06 03:08:01 -08001919
Tom Tsou92bdfb82017-03-28 15:22:01 -07001920 if (dnsampler->rotate((float *) in->begin(), DOWNSAMPLE_IN_LEN,
1921 (float *) out->begin(), DOWNSAMPLE_OUT_LEN) < 0) {
1922 delete out;
1923 out = NULL;
1924 }
1925
Tom Tsou76764272016-06-24 14:25:39 -07001926 delete in;
Tom Tsoud3253432016-03-06 03:08:01 -08001927 return out;
1928};
1929
Thomas Tsou94edaae2013-11-09 22:19:19 -05001930signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001931{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001932 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001933
Thomas Tsou94edaae2013-11-09 22:19:19 -05001934 if (factor <= 1)
1935 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001936
Thomas Tsou94edaae2013-11-09 22:19:19 -05001937 dec = new signalVector(wVector.size() / factor);
1938 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001939
Thomas Tsou94edaae2013-11-09 22:19:19 -05001940 signalVector::iterator itr = dec->begin();
1941 for (size_t i = 0; i < wVector.size(); i += factor)
1942 *itr++ = wVector[i];
1943
1944 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001945}
1946
Tom Tsoud3253432016-03-06 03:08:01 -08001947/*
1948 * Soft 8-PSK decoding using Manhattan distance metric
1949 */
1950static SoftVector *softSliceEdgeBurst(signalVector &burst)
1951{
1952 size_t nsyms = 148;
1953
1954 if (burst.size() < nsyms)
1955 return NULL;
1956
1957 signalVector::iterator itr;
1958 SoftVector *bits = new SoftVector(nsyms * 3);
1959
1960 /*
1961 * Bits 0 and 1 - First and second bits of the symbol respectively
1962 */
1963 rotateBurst2(burst, -M_PI / 8.0);
1964 itr = burst.begin();
1965 for (size_t i = 0; i < nsyms; i++) {
1966 (*bits)[3 * i + 0] = -itr->imag();
1967 (*bits)[3 * i + 1] = itr->real();
1968 itr++;
1969 }
1970
1971 /*
1972 * Bit 2 - Collapse symbols into quadrant 0 (positive X and Y).
1973 * Decision area is then simplified to X=Y axis. Rotate again to
1974 * place decision boundary on X-axis.
1975 */
1976 itr = burst.begin();
1977 for (size_t i = 0; i < burst.size(); i++) {
1978 burst[i] = Complex<float>(fabs(itr->real()), fabs(itr->imag()));
1979 itr++;
1980 }
1981
1982 rotateBurst2(burst, -M_PI / 4.0);
1983 itr = burst.begin();
1984 for (size_t i = 0; i < nsyms; i++) {
1985 (*bits)[3 * i + 2] = -itr->imag();
1986 itr++;
1987 }
1988
1989 signalVector soft(bits->size());
1990 for (size_t i = 0; i < bits->size(); i++)
1991 soft[i] = (*bits)[i];
1992
1993 return bits;
1994}
1995
1996/*
Alexander Chemeris132fb242017-03-17 17:22:33 -07001997 * Convert signalVector to SoftVector by taking real part of the signal.
1998 */
1999static SoftVector *signalToSoftVector(signalVector *dec)
2000{
2001 SoftVector *bits = new SoftVector(dec->size());
2002
2003 SoftVector::iterator bit_itr = bits->begin();
2004 signalVector::iterator burst_itr = dec->begin();
2005
2006 for (; burst_itr < dec->end(); burst_itr++)
2007 *bit_itr++ = burst_itr->real();
2008
2009 return bits;
2010}
2011
2012/*
Tom Tsou7fec3032016-03-06 22:33:20 -08002013 * Shared portion of GMSK and EDGE demodulators consisting of timing
2014 * recovery and single tap channel correction. For 4 SPS (if activated),
2015 * the output is downsampled prior to the 1 SPS modulation specific
2016 * stages.
2017 */
Alexander Chemerise0c12182017-03-18 13:27:48 -07002018static signalVector *demodCommon(const signalVector &burst, int sps,
Tom Tsou7fec3032016-03-06 22:33:20 -08002019 complex chan, float toa)
2020{
2021 signalVector *delay, *dec;
2022
2023 if ((sps != 1) && (sps != 4))
2024 return NULL;
2025
Tom Tsou7fec3032016-03-06 22:33:20 -08002026 delay = delayVector(&burst, NULL, -toa * (float) sps);
Alexander Chemerise0c12182017-03-18 13:27:48 -07002027 scaleVector(*delay, (complex) 1.0 / chan);
Tom Tsou7fec3032016-03-06 22:33:20 -08002028
2029 if (sps == 1)
2030 return delay;
2031
2032 dec = downsampleBurst(*delay);
2033
2034 delete delay;
2035 return dec;
2036}
2037
2038/*
Tom Tsoud3253432016-03-06 03:08:01 -08002039 * Demodulate GSMK burst. Prior to symbol rotation, operate at
2040 * 4 SPS (if activated) to minimize distortion through the fractional
2041 * delay filters. Symbol rotation and after always operates at 1 SPS.
2042 */
Alexander Chemerise0c12182017-03-18 13:27:48 -07002043SoftVector *demodGmskBurst(const signalVector &rxBurst, int sps,
Alexander Chemeris1470fcd2017-03-17 22:35:02 -07002044 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00002045{
Thomas Tsou94edaae2013-11-09 22:19:19 -05002046 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08002047 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00002048
Tom Tsou7fec3032016-03-06 22:33:20 -08002049 dec = demodCommon(rxBurst, sps, channel, TOA);
2050 if (!dec)
2051 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00002052
Tom Tsoud3253432016-03-06 03:08:01 -08002053 /* Shift up by a quarter of a frequency */
2054 GMSKReverseRotate(*dec, 1);
Alexander Chemeris132fb242017-03-17 17:22:33 -07002055 /* Take real part of the signal */
2056 bits = signalToSoftVector(dec);
Thomas Tsou94edaae2013-11-09 22:19:19 -05002057 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00002058
Thomas Tsou94edaae2013-11-09 22:19:19 -05002059 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00002060}
Thomas Tsou94edaae2013-11-09 22:19:19 -05002061
Tom Tsoud3253432016-03-06 03:08:01 -08002062/*
2063 * Demodulate an 8-PSK burst. Prior to symbol rotation, operate at
2064 * 4 SPS (if activated) to minimize distortion through the fractional
2065 * delay filters. Symbol rotation and after always operates at 1 SPS.
2066 *
2067 * Allow 1 SPS demodulation here, but note that other parts of the
2068 * transceiver restrict EDGE operatoin to 4 SPS - 8-PSK distortion
2069 * through the fractional delay filters at 1 SPS renders signal
2070 * nearly unrecoverable.
2071 */
Alexander Chemerise0c12182017-03-18 13:27:48 -07002072SoftVector *demodEdgeBurst(const signalVector &burst, int sps,
Tom Tsoud3253432016-03-06 03:08:01 -08002073 complex chan, float toa)
2074{
2075 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08002076 signalVector *dec, *rot, *eq;
Tom Tsoud3253432016-03-06 03:08:01 -08002077
Tom Tsou7fec3032016-03-06 22:33:20 -08002078 dec = demodCommon(burst, sps, chan, toa);
2079 if (!dec)
Tom Tsoud3253432016-03-06 03:08:01 -08002080 return NULL;
2081
Tom Tsou7fec3032016-03-06 22:33:20 -08002082 /* Equalize and derotate */
Tom Tsoud3253432016-03-06 03:08:01 -08002083 eq = convolve(dec, GSMPulse4->c0_inv, NULL, NO_DELAY);
2084 rot = derotateEdgeBurst(*eq, 1);
2085
Tom Tsou7fec3032016-03-06 22:33:20 -08002086 /* Soft slice and normalize */
Tom Tsou04795622016-04-26 21:17:36 -07002087 bits = softSliceEdgeBurst(*rot);
Tom Tsoud3253432016-03-06 03:08:01 -08002088
2089 delete dec;
2090 delete eq;
2091 delete rot;
2092
2093 return bits;
2094}
2095
Alexander Chemerise0c12182017-03-18 13:27:48 -07002096SoftVector *demodAnyBurst(const signalVector &burst, int sps, complex amp,
Alexander Chemeris6e1dffd2017-03-17 16:13:51 -07002097 float toa, CorrType type)
2098{
2099 if (type == EDGE)
2100 return demodEdgeBurst(burst, sps, amp, toa);
2101 else
2102 return demodGmskBurst(burst, sps, amp, toa);
2103}
2104
Tom Tsou2079a3c2016-03-06 00:58:56 -08002105bool sigProcLibSetup()
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002106{
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002107 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05002108 generateSincTable();
Tom Tsou2079a3c2016-03-06 00:58:56 -08002109 initGMSKRotationTables();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002110
Tom Tsou2079a3c2016-03-06 00:58:56 -08002111 GSMPulse1 = generateGSMPulse(1);
2112 GSMPulse4 = generateGSMPulse(4);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002113
Tom Tsou2079a3c2016-03-06 00:58:56 -08002114 generateRACHSequence(1);
Tom Tsoud3253432016-03-06 03:08:01 -08002115 for (int tsc = 0; tsc < 8; tsc++) {
Tom Tsou2079a3c2016-03-06 00:58:56 -08002116 generateMidamble(1, tsc);
Tom Tsoud3253432016-03-06 03:08:01 -08002117 gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);
2118 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002119
Thomas Tsouf79c4d02013-11-09 15:51:56 -06002120 generateDelayFilters();
2121
Tom Tsoud3253432016-03-06 03:08:01 -08002122 dnsampler = new Resampler(1, 4);
2123 if (!dnsampler->init()) {
2124 LOG(ALERT) << "Rx resampler failed to initialize";
2125 goto fail;
2126 }
2127
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002128 return true;
Tom Tsoud3253432016-03-06 03:08:01 -08002129
2130fail:
2131 sigProcLibDestroy();
2132 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002133}
Alexander Chemerisf7717ac2017-03-17 15:32:26 -07002134
2135std::string corrTypeToString(CorrType corr) {
2136 switch (corr) {
2137 case OFF:
2138 return "OFF";
2139 case TSC:
2140 return "TSC";
2141 case RACH:
2142 return "RACH";
2143 case EDGE:
2144 return "EDGE";
2145 case IDLE:
2146 return "IDLE";
2147 default:
2148 return "unknown";
2149 }
2150}
2151
2152std::ostream& operator<<(std::ostream& os, CorrType corr)
2153{
2154 os << corrTypeToString(corr);
2155 return os;
2156}