blob: 56a1a58a225e6277b4350d04f5484c2521787002 [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
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800740static signalVector *rotateBurst(const BitVector &wBurst,
741 int guardPeriodLength, int sps)
742{
743 int burst_len;
744 signalVector *pulse, rotated, *shaped;
745 signalVector::iterator itr;
746
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400747 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800748 burst_len = sps * (wBurst.size() + guardPeriodLength);
749 rotated = signalVector(burst_len);
750 itr = rotated.begin();
751
752 for (unsigned i = 0; i < wBurst.size(); i++) {
753 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
754 itr += sps;
755 }
756
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400757 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500758 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800759
760 /* Dummy filter operation */
761 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
762 if (!shaped)
763 return NULL;
764
765 return shaped;
766}
767
Tom Tsoud3253432016-03-06 03:08:01 -0800768static void rotateBurst2(signalVector &burst, double phase)
769{
770 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
771
772 for (size_t i = 0; i < burst.size(); i++)
773 burst[i] = burst[i] * rot;
774}
775
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800776/*
777 * Ignore the guard length argument in the GMSK modulator interface
778 * because it results in 624/628 sized bursts instead of the preferred
779 * burst length of 625. Only 4 SPS is supported.
780 */
781static signalVector *modulateBurstLaurent(const BitVector &bits)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800782{
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800783 int burst_len, sps = 4;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800784 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500785 signalVector *c0_pulse, *c1_pulse, *c0_burst;
786 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800787 signalVector::iterator c0_itr, c1_itr;
788
Tom Tsou2079a3c2016-03-06 00:58:56 -0800789 c0_pulse = GSMPulse4->c0;
790 c1_pulse = GSMPulse4->c1;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800791
Tom Tsou4dfd64a2016-03-06 20:31:51 -0800792 if (bits.size() > 156)
793 return NULL;
794
795 burst_len = 625;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800796
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500797 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500798 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500799 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800800
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500801 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500802 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500803 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800804
Tom Tsouaa15d622016-08-11 14:36:23 -0700805 /* Padded differential tail bits */
806 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800807 c0_itr += sps;
808
809 /* Main burst bits */
810 for (unsigned i = 0; i < bits.size(); i++) {
811 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
812 c0_itr += sps;
813 }
814
Tom Tsouaa15d622016-08-11 14:36:23 -0700815 /* Padded differential tail bits */
816 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800817
818 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500819 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500820 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800821
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500822 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800823 c0_itr += sps * 2;
824 c1_itr += sps * 2;
825
826 /* Start magic */
827 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
828 *c1_itr = *c0_itr * Complex<float>(0, phase);
829 c0_itr += sps;
830 c1_itr += sps;
831
832 /* Generate C1 phase coefficients */
833 for (unsigned i = 2; i < bits.size(); i++) {
834 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
835 *c1_itr = *c0_itr * Complex<float>(0, phase);
836
837 c0_itr += sps;
838 c1_itr += sps;
839 }
840
841 /* End magic */
842 int i = bits.size();
843 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
844 *c1_itr = *c0_itr * Complex<float>(0, phase);
845
846 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500847 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
848 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800849
850 /* Sum shaped outputs into C0 */
851 c0_itr = c0_shaped->begin();
852 c1_itr = c1_shaped->begin();
853 for (unsigned i = 0; i < c0_shaped->size(); i++ )
854 *c0_itr++ += *c1_itr++;
855
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500856 delete c0_burst;
857 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800858 delete c1_shaped;
859
860 return c0_shaped;
861}
862
Tom Tsoud3253432016-03-06 03:08:01 -0800863static signalVector *rotateEdgeBurst(const signalVector &symbols, int sps)
864{
865 signalVector *burst;
866 signalVector::iterator burst_itr;
867
868 burst = new signalVector(symbols.size() * sps);
869 burst_itr = burst->begin();
870
871 for (size_t i = 0; i < symbols.size(); i++) {
872 float phase = i * 3.0f * M_PI / 8.0f;
873 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
874
875 *burst_itr = symbols[i] * rot;
876 burst_itr += sps;
877 }
878
879 return burst;
880}
881
882static signalVector *derotateEdgeBurst(const signalVector &symbols, int sps)
883{
884 signalVector *burst;
885 signalVector::iterator burst_itr;
886
887 if (symbols.size() % sps)
888 return NULL;
889
890 burst = new signalVector(symbols.size() / sps);
891 burst_itr = burst->begin();
892
893 for (size_t i = 0; i < burst->size(); i++) {
894 float phase = (float) (i % 16) * 3.0f * M_PI / 8.0f;
895 Complex<float> rot = Complex<float>(cosf(phase), -sinf(phase));
896
897 *burst_itr = symbols[sps * i] * rot;
898 burst_itr++;
899 }
900
901 return burst;
902}
903
904static signalVector *mapEdgeSymbols(const BitVector &bits)
905{
906 if (bits.size() % 3)
907 return NULL;
908
909 signalVector *symbols = new signalVector(bits.size() / 3);
910
911 for (size_t i = 0; i < symbols->size(); i++) {
912 unsigned index = (((unsigned) bits[3 * i + 0] & 0x01) << 0) |
913 (((unsigned) bits[3 * i + 1] & 0x01) << 1) |
914 (((unsigned) bits[3 * i + 2] & 0x01) << 2);
915
916 (*symbols)[i] = psk8_table[index];
917 }
918
919 return symbols;
920}
921
Tom Tsoud2b07032016-04-26 19:28:59 -0700922/*
923 * EDGE 8-PSK rotate and pulse shape
924 *
925 * Delay the EDGE downlink bursts by one symbol in order to match GMSK pulse
926 * shaping group delay. The difference in group delay arises from the dual
927 * pulse filter combination of the GMSK Laurent represenation whereas 8-PSK
928 * uses a single pulse linear filter.
929 */
Tom Tsoud3253432016-03-06 03:08:01 -0800930static signalVector *shapeEdgeBurst(const signalVector &symbols)
931{
Tom Tsoud2b07032016-04-26 19:28:59 -0700932 size_t nsyms, nsamps = 625, sps = 4;
Tom Tsoud3253432016-03-06 03:08:01 -0800933 signalVector *burst, *shape;
934 signalVector::iterator burst_itr;
935
936 nsyms = symbols.size();
937
Tom Tsoud2b07032016-04-26 19:28:59 -0700938 if (nsyms * sps > nsamps)
Tom Tsoud3253432016-03-06 03:08:01 -0800939 nsyms = 156;
940
941 burst = new signalVector(nsamps, GSMPulse4->c0->size());
Tom Tsoud3253432016-03-06 03:08:01 -0800942
Tom Tsoud2b07032016-04-26 19:28:59 -0700943 /* Delay burst by 1 symbol */
944 burst_itr = burst->begin() + sps;
Tom Tsou06676ea2016-07-19 12:50:21 -0700945 for (size_t i = 0; i < nsyms; i++) {
Tom Tsoud3253432016-03-06 03:08:01 -0800946 float phase = i * 3.0f * M_PI / 8.0f;
947 Complex<float> rot = Complex<float>(cos(phase), sin(phase));
948
949 *burst_itr = symbols[i] * rot;
Tom Tsoud2b07032016-04-26 19:28:59 -0700950 burst_itr += sps;
Tom Tsoud3253432016-03-06 03:08:01 -0800951 }
952
953 /* Single Gaussian pulse approximation shaping */
954 shape = convolve(burst, GSMPulse4->c0, NULL, START_ONLY);
955 delete burst;
956
957 return shape;
958}
959
960/*
Tom Tsou8ee2f382016-03-06 20:57:34 -0800961 * Generate a random GSM normal burst.
962 */
963signalVector *genRandNormalBurst(int tsc, int sps, int tn)
964{
965 if ((tsc < 0) || (tsc > 7) || (tn < 0) || (tn > 7))
966 return NULL;
967 if ((sps != 1) && (sps != 4))
968 return NULL;
969
970 int i = 0;
971 BitVector *bits = new BitVector(148);
972 signalVector *burst;
973
974 /* Tail bits */
975 for (; i < 4; i++)
976 (*bits)[i] = 0;
977
978 /* Random bits */
979 for (; i < 61; i++)
980 (*bits)[i] = rand() % 2;
981
982 /* Training sequence */
983 for (int n = 0; i < 87; i++, n++)
984 (*bits)[i] = gTrainingSequence[tsc][n];
985
986 /* Random bits */
987 for (; i < 144; i++)
988 (*bits)[i] = rand() % 2;
989
990 /* Tail bits */
991 for (; i < 148; i++)
992 (*bits)[i] = 0;
993
994 int guard = 8 + !(tn % 4);
995 burst = modulateBurst(*bits, guard, sps);
996 delete bits;
997
998 return burst;
999}
1000
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001001/*
1002 * Generate a random GSM access burst.
1003 */
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001004signalVector *genRandAccessBurst(int delay, int sps, int tn)
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001005{
1006 if ((tn < 0) || (tn > 7))
1007 return NULL;
1008 if ((sps != 1) && (sps != 4))
1009 return NULL;
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001010 if (delay > 68)
1011 return NULL;
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001012
1013 int i = 0;
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001014 BitVector *bits = new BitVector(88+delay);
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001015 signalVector *burst;
1016
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001017 /* delay */
1018 for (; i < delay; i++)
1019 (*bits)[i] = 0;
1020
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001021 /* head and synch bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001022 for (int n = 0; i < 49+delay; i++, n++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001023 (*bits)[i] = gRACHBurst[n];
1024
1025 /* Random bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001026 for (; i < 85+delay; i++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001027 (*bits)[i] = rand() % 2;
1028
1029 /* Tail bits */
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001030 for (; i < 88+delay; i++)
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001031 (*bits)[i] = 0;
1032
Alexander Chemeris37c52c72016-03-25 18:28:34 +03001033 int guard = 68-delay + !(tn % 4);
Alexander Chemeris5efe0502016-03-23 17:06:32 +03001034 burst = modulateBurst(*bits, guard, sps);
1035 delete bits;
1036
1037 return burst;
1038}
1039
Tom Tsou8ee2f382016-03-06 20:57:34 -08001040signalVector *generateEmptyBurst(int sps, int tn)
1041{
1042 if ((tn < 0) || (tn > 7))
1043 return NULL;
1044
1045 if (sps == 4)
1046 return new signalVector(625);
1047 else if (sps == 1)
1048 return new signalVector(148 + 8 + !(tn % 4));
1049 else
1050 return NULL;
1051}
1052
1053signalVector *generateDummyBurst(int sps, int tn)
1054{
1055 if (((sps != 1) && (sps != 4)) || (tn < 0) || (tn > 7))
1056 return NULL;
1057
1058 return modulateBurst(gDummyBurst, 8 + !(tn % 4), sps);
1059}
1060
1061/*
Tom Tsoud3253432016-03-06 03:08:01 -08001062 * Generate a random 8-PSK EDGE burst. Only 4 SPS is supported with
1063 * the returned burst being 625 samples in length.
1064 */
1065signalVector *generateEdgeBurst(int tsc)
1066{
1067 int tail = 9 / 3;
1068 int data = 174 / 3;
1069 int train = 78 / 3;
1070
1071 if ((tsc < 0) || (tsc > 7))
1072 return NULL;
1073
1074 signalVector *shape, *burst = new signalVector(148);
1075 const BitVector *midamble = &gEdgeTrainingSequence[tsc];
1076
1077 /* Tail */
1078 int n, i = 0;
1079 for (; i < tail; i++)
1080 (*burst)[i] = psk8_table[7];
1081
1082 /* Body */
1083 for (; i < tail + data; i++)
1084 (*burst)[i] = psk8_table[rand() % 8];
1085
1086 /* TSC */
1087 for (n = 0; i < tail + data + train; i++, n++) {
1088 unsigned index = (((unsigned) (*midamble)[3 * n + 0] & 0x01) << 0) |
1089 (((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) |
1090 (((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2);
1091
1092 (*burst)[i] = psk8_table[index];
1093 }
1094
1095 /* Body */
1096 for (; i < tail + data + train + data; i++)
1097 (*burst)[i] = psk8_table[rand() % 8];
1098
1099 /* Tail */
1100 for (; i < tail + data + train + data + tail; i++)
1101 (*burst)[i] = psk8_table[7];
1102
1103 shape = shapeEdgeBurst(*burst);
1104 delete burst;
1105
1106 return shape;
1107}
1108
1109/*
1110 * Modulate 8-PSK burst. When empty pulse shaping (rotation only)
1111 * is enabled, the output vector length will be bit sequence length
1112 * times the SPS value. When pulse shaping is enabled, the output
Alexander Chemeris9270a5a2017-03-17 13:03:41 -07001113 * vector length is fixed at 625 samples (156.25 symbols at 4 SPS).
Tom Tsoud3253432016-03-06 03:08:01 -08001114 * Pulse shaped bit sequences that go beyond one burst are truncated.
1115 * Pulse shaping at anything but 4 SPS is not supported.
1116 */
1117signalVector *modulateEdgeBurst(const BitVector &bits,
1118 int sps, bool empty)
1119{
1120 signalVector *shape, *burst;
1121
1122 if ((sps != 4) && !empty)
1123 return NULL;
1124
1125 burst = mapEdgeSymbols(bits);
1126 if (!burst)
1127 return NULL;
1128
1129 if (empty)
1130 shape = rotateEdgeBurst(*burst, sps);
1131 else
1132 shape = shapeEdgeBurst(*burst);
1133
1134 delete burst;
1135 return shape;
1136}
1137
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001138static signalVector *modulateBurstBasic(const BitVector &bits,
1139 int guard_len, int sps)
1140{
1141 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001142 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001143 signalVector::iterator burst_itr;
1144
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001145 if (sps == 1)
1146 pulse = GSMPulse1->c0;
1147 else
Tom Tsou2079a3c2016-03-06 00:58:56 -08001148 pulse = GSMPulse4->c0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001149
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001150 burst_len = sps * (bits.size() + guard_len);
1151
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001152 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001153 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001154 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001155
1156 /* Raw bits are not differentially encoded */
1157 for (unsigned i = 0; i < bits.size(); i++) {
1158 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
1159 burst_itr += sps;
1160 }
1161
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001162 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001163 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001164
1165 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -05001166 shaped = convolve(burst, pulse, NULL, START_ONLY);
1167
1168 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001169
1170 return shaped;
1171}
1172
Thomas Tsou3eaae802013-08-20 19:31:14 -04001173/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -04001174signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
1175 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +00001176{
Thomas Tsou83e06892013-08-20 16:10:01 -04001177 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001178 return rotateBurst(wBurst, guardPeriodLength, sps);
1179 else if (sps == 4)
Tom Tsou4dfd64a2016-03-06 20:31:51 -08001180 return modulateBurstLaurent(wBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -04001181 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001182 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001183}
1184
Tom Tsou2079a3c2016-03-06 00:58:56 -08001185static void generateSincTable()
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001186{
1187 float x;
1188
1189 for (int i = 0; i < TABLESIZE; i++) {
1190 x = (float) i / TABLESIZE * 8 * M_PI;
1191 if (fabs(x) < 0.01) {
1192 sincTable[i] = 1.0f;
1193 continue;
1194 }
1195
1196 sincTable[i] = sinf(x) / x;
1197 }
1198}
1199
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001200float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +00001201{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001202 if (fabs(x) >= 8 * M_PI)
1203 return 0.0;
1204
1205 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
1206
1207 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +00001208}
1209
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001210/*
1211 * Create fractional delay filterbank with Blackman-harris windowed
1212 * sinc function generator. The number of filters generated is specified
1213 * by the DELAYFILTS value.
1214 */
1215void generateDelayFilters()
1216{
1217 int h_len = 20;
1218 complex *data;
1219 signalVector *h;
1220 signalVector::iterator itr;
1221
1222 float k, sum;
1223 float a0 = 0.35875;
1224 float a1 = 0.48829;
1225 float a2 = 0.14128;
1226 float a3 = 0.01168;
1227
1228 for (int i = 0; i < DELAYFILTS; i++) {
1229 data = (complex *) convolve_h_alloc(h_len);
1230 h = new signalVector(data, 0, h_len);
1231 h->setAligned(true);
1232 h->isReal(true);
1233
1234 sum = 0.0;
1235 itr = h->end();
1236 for (int n = 0; n < h_len; n++) {
1237 k = (float) n;
1238 *--itr = (complex) sinc(M_PI_F *
1239 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
1240 *itr *= a0 -
1241 a1 * cos(2 * M_PI * n / (h_len - 1)) +
1242 a2 * cos(4 * M_PI * n / (h_len - 1)) -
1243 a3 * cos(6 * M_PI * n / (h_len - 1));
1244
1245 sum += itr->real();
1246 }
1247
1248 itr = h->begin();
1249 for (int n = 0; n < h_len; n++)
1250 *itr++ /= sum;
1251
1252 delayFilters[i] = h;
1253 }
1254}
1255
Thomas Tsou94edaae2013-11-09 22:19:19 -05001256signalVector *delayVector(signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +00001257{
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001258 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001259 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001260 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001261
Thomas Tsou2c282f52013-10-08 21:34:35 -04001262 whole = floor(delay);
1263 frac = delay - whole;
1264
1265 /* Sinc interpolated fractional shift (if allowable) */
1266 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001267 index = floorf(frac * (float) DELAYFILTS);
1268 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -04001269
Thomas Tsou94edaae2013-11-09 22:19:19 -05001270 fshift = convolve(in, h, NULL, NO_DELAY);
1271 if (!fshift)
1272 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001273 }
1274
Thomas Tsou94edaae2013-11-09 22:19:19 -05001275 if (!fshift)
1276 shift = new signalVector(*in);
1277 else
1278 shift = fshift;
1279
Thomas Tsou2c282f52013-10-08 21:34:35 -04001280 /* Integer sample shift */
1281 if (whole < 0) {
1282 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001283 signalVector::iterator wBurstItr = shift->begin();
1284 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001285
Thomas Tsou94edaae2013-11-09 22:19:19 -05001286 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +00001287 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -04001288
Thomas Tsou94edaae2013-11-09 22:19:19 -05001289 while (wBurstItr < shift->end())
1290 *wBurstItr++ = 0.0;
1291 } else if (whole >= 0) {
1292 signalVector::iterator wBurstItr = shift->end() - 1;
1293 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
1294
1295 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001296 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -05001297
1298 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001299 *wBurstItr-- = 0.0;
1300 }
Thomas Tsou2c282f52013-10-08 21:34:35 -04001301
Thomas Tsou94edaae2013-11-09 22:19:19 -05001302 if (!out)
1303 return shift;
1304
1305 out->clone(*shift);
1306 delete shift;
1307 return out;
dburgessb3a0ca42011-10-12 07:44:40 +00001308}
Thomas Tsou2c282f52013-10-08 21:34:35 -04001309
dburgessb3a0ca42011-10-12 07:44:40 +00001310signalVector *gaussianNoise(int length,
1311 float variance,
1312 complex mean)
1313{
1314
1315 signalVector *noise = new signalVector(length);
1316 signalVector::iterator nPtr = noise->begin();
1317 float stddev = sqrtf(variance);
1318 while (nPtr < noise->end()) {
1319 float u1 = (float) rand()/ (float) RAND_MAX;
1320 while (u1==0.0)
1321 u1 = (float) rand()/ (float) RAND_MAX;
1322 float u2 = (float) rand()/ (float) RAND_MAX;
1323 float arg = 2.0*M_PI*u2;
1324 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
1325 nPtr++;
1326 }
1327
1328 return noise;
1329}
1330
1331complex interpolatePoint(const signalVector &inSig,
1332 float ix)
1333{
1334
1335 int start = (int) (floor(ix) - 10);
1336 if (start < 0) start = 0;
1337 int end = (int) (floor(ix) + 11);
1338 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
1339
1340 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001341 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001342 for (int i = start; i < end; i++)
1343 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
1344 }
1345 else {
1346 for (int i = start; i < end; i++)
1347 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
1348 }
1349
1350 return pVal;
1351}
1352
Thomas Tsou8181b012013-08-20 21:17:19 -04001353static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1354{
1355 float val, max = 0.0f;
1356 complex amp;
1357 int _index = -1;
1358
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001359 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001360 val = rxBurst[i].norm2();
1361 if (val > max) {
1362 max = val;
1363 _index = i;
1364 amp = rxBurst[i];
1365 }
1366 }
1367
1368 if (index)
1369 *index = (float) _index;
1370
1371 return amp;
1372}
1373
dburgessb3a0ca42011-10-12 07:44:40 +00001374complex peakDetect(const signalVector &rxBurst,
1375 float *peakIndex,
1376 float *avgPwr)
1377{
1378
1379
1380 complex maxVal = 0.0;
1381 float maxIndex = -1;
1382 float sumPower = 0.0;
1383
1384 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1385 float samplePower = rxBurst[i].norm2();
1386 if (samplePower > maxVal.real()) {
1387 maxVal = samplePower;
1388 maxIndex = i;
1389 }
1390 sumPower += samplePower;
1391 }
1392
1393 // interpolate around the peak
1394 // to save computation, we'll use early-late balancing
1395 float earlyIndex = maxIndex-1;
1396 float lateIndex = maxIndex+1;
1397
1398 float incr = 0.5;
1399 while (incr > 1.0/1024.0) {
1400 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1401 complex lateP = interpolatePoint(rxBurst,lateIndex);
1402 if (earlyP < lateP)
1403 earlyIndex += incr;
1404 else if (earlyP > lateP)
1405 earlyIndex -= incr;
1406 else break;
1407 incr /= 2.0;
1408 lateIndex = earlyIndex + 2.0;
1409 }
1410
1411 maxIndex = earlyIndex + 1.0;
1412 maxVal = interpolatePoint(rxBurst,maxIndex);
1413
1414 if (peakIndex!=NULL)
1415 *peakIndex = maxIndex;
1416
1417 if (avgPwr!=NULL)
1418 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1419
1420 return maxVal;
1421
1422}
1423
1424void scaleVector(signalVector &x,
1425 complex scale)
1426{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001427#ifdef HAVE_NEON
1428 int len = x.size();
1429
1430 scale_complex((float *) x.begin(),
1431 (float *) x.begin(),
1432 (float *) &scale, len);
1433#else
dburgessb3a0ca42011-10-12 07:44:40 +00001434 signalVector::iterator xP = x.begin();
1435 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001436 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001437 while (xP < xPEnd) {
1438 *xP = *xP * scale;
1439 xP++;
1440 }
1441 }
1442 else {
1443 while (xP < xPEnd) {
1444 *xP = xP->real() * scale;
1445 xP++;
1446 }
1447 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001448#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001449}
1450
1451/** in-place conjugation */
1452void conjugateVector(signalVector &x)
1453{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001454 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001455 signalVector::iterator xP = x.begin();
1456 signalVector::iterator xPEnd = x.end();
1457 while (xP < xPEnd) {
1458 *xP = xP->conj();
1459 xP++;
1460 }
1461}
1462
1463
1464// in-place addition!!
1465bool addVector(signalVector &x,
1466 signalVector &y)
1467{
1468 signalVector::iterator xP = x.begin();
1469 signalVector::iterator yP = y.begin();
1470 signalVector::iterator xPEnd = x.end();
1471 signalVector::iterator yPEnd = y.end();
1472 while ((xP < xPEnd) && (yP < yPEnd)) {
1473 *xP = *xP + *yP;
1474 xP++; yP++;
1475 }
1476 return true;
1477}
1478
1479// in-place multiplication!!
1480bool multVector(signalVector &x,
1481 signalVector &y)
1482{
1483 signalVector::iterator xP = x.begin();
1484 signalVector::iterator yP = y.begin();
1485 signalVector::iterator xPEnd = x.end();
1486 signalVector::iterator yPEnd = y.end();
1487 while ((xP < xPEnd) && (yP < yPEnd)) {
1488 *xP = (*xP) * (*yP);
1489 xP++; yP++;
1490 }
1491 return true;
1492}
1493
Tom Tsou2079a3c2016-03-06 00:58:56 -08001494static bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001495{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001496 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001497 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001498 complex *data = NULL;
1499 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001500 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001501
Thomas Tsou3eaae802013-08-20 19:31:14 -04001502 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001503 return false;
1504
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001505 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001506
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001507 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1508 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1509 if (!midMidamble)
1510 return false;
1511
Thomas Tsou3eaae802013-08-20 19:31:14 -04001512 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001513 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1514 if (!midamble) {
1515 status = false;
1516 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001517 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001518
dburgessb3a0ca42011-10-12 07:44:40 +00001519 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1520 // the ideal TSC has an + 180 degree phase shift,
1521 // due to the pi/2 frequency shift, that
1522 // needs to be accounted for.
1523 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001524 scaleVector(*midMidamble, complex(-1.0, 0.0));
1525 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001526
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001527 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001528
Thomas Tsou3eaae802013-08-20 19:31:14 -04001529 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1530 data = (complex *) convolve_h_alloc(midMidamble->size());
1531 _midMidamble = new signalVector(data, 0, midMidamble->size());
1532 _midMidamble->setAligned(true);
1533 memcpy(_midMidamble->begin(), midMidamble->begin(),
1534 midMidamble->size() * sizeof(complex));
1535
1536 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001537 if (!autocorr) {
1538 status = false;
1539 goto release;
1540 }
dburgessb3a0ca42011-10-12 07:44:40 +00001541
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001542 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001543 gMidambles[tsc]->buffer = data;
1544 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001545 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1546
1547 /* For 1 sps only
1548 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1549 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1550 */
1551 if (sps == 1)
1552 gMidambles[tsc]->toa = toa - 13.5;
1553 else
1554 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001555
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001556release:
dburgessb3a0ca42011-10-12 07:44:40 +00001557 delete autocorr;
1558 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001559 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001560
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001561 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001562 delete _midMidamble;
1563 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001564 gMidambles[tsc] = NULL;
1565 }
1566
1567 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001568}
1569
Tom Tsoud3253432016-03-06 03:08:01 -08001570CorrelationSequence *generateEdgeMidamble(int tsc)
1571{
1572 complex *data = NULL;
1573 signalVector *midamble = NULL, *_midamble = NULL;
1574 CorrelationSequence *seq;
1575
1576 if ((tsc < 0) || (tsc > 7))
1577 return NULL;
1578
1579 /* Use middle 48 bits of each TSC. Correlation sequence is not pulse shaped */
1580 const BitVector *bits = &gEdgeTrainingSequence[tsc];
1581 midamble = modulateEdgeBurst(bits->segment(15, 48), 1, true);
1582 if (!midamble)
1583 return NULL;
1584
1585 conjugateVector(*midamble);
1586
1587 data = (complex *) convolve_h_alloc(midamble->size());
1588 _midamble = new signalVector(data, 0, midamble->size());
1589 _midamble->setAligned(true);
1590 memcpy(_midamble->begin(), midamble->begin(),
1591 midamble->size() * sizeof(complex));
1592
1593 /* Channel gain is an empirically measured value */
1594 seq = new CorrelationSequence;
1595 seq->buffer = data;
1596 seq->sequence = _midamble;
1597 seq->gain = Complex<float>(-19.6432, 19.5006) / 1.18;
1598 seq->toa = 0;
1599
1600 delete midamble;
1601
1602 return seq;
1603}
1604
Tom Tsou2079a3c2016-03-06 00:58:56 -08001605static bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001606{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001607 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001608 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001609 complex *data = NULL;
1610 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001611 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001612
1613 delete gRACHSequence;
1614
1615 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1616 if (!seq0)
1617 return false;
1618
1619 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1620 if (!seq1) {
1621 status = false;
1622 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001623 }
1624
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001625 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001626
Thomas Tsou3eaae802013-08-20 19:31:14 -04001627 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1628 data = (complex *) convolve_h_alloc(seq1->size());
1629 _seq1 = new signalVector(data, 0, seq1->size());
1630 _seq1->setAligned(true);
1631 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1632
1633 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1634 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001635 status = false;
1636 goto release;
1637 }
dburgessb3a0ca42011-10-12 07:44:40 +00001638
1639 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001640 gRACHSequence->sequence = _seq1;
1641 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001642 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1643
1644 /* For 1 sps only
1645 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1646 * 20.5 = (40 / 2 - 1) + 1.5
1647 */
1648 if (sps == 1)
1649 gRACHSequence->toa = toa - 20.5;
1650 else
1651 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001652
1653release:
dburgessb3a0ca42011-10-12 07:44:40 +00001654 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001655 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001656 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001657
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001658 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001659 delete _seq1;
1660 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001661 gRACHSequence = NULL;
1662 }
dburgessb3a0ca42011-10-12 07:44:40 +00001663
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001664 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001665}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001666
Tom Tsoua84e1622016-06-29 14:50:25 -07001667/*
1668 * Peak-to-average computation +/- range from peak in symbols
1669 */
1670#define COMPUTE_PEAK_MIN 2
1671#define COMPUTE_PEAK_MAX 5
1672
1673/*
1674 * Minimum number of values needed to compute peak-to-average
1675 */
1676#define COMPUTE_PEAK_CNT 5
1677
Thomas Tsou865bca42013-08-21 20:58:00 -04001678static float computePeakRatio(signalVector *corr,
1679 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001680{
Thomas Tsou865bca42013-08-21 20:58:00 -04001681 int num = 0;
1682 complex *peak;
1683 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001684
Thomas Tsou865bca42013-08-21 20:58:00 -04001685 /* Check for bogus results */
1686 if ((toa < 0.0) || (toa > corr->size()))
1687 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001688
Alexander Chemeris1e9b4d52015-06-04 19:05:28 -04001689 peak = corr->begin() + (int) rint(toa);
1690
Tom Tsoua84e1622016-06-29 14:50:25 -07001691 for (int i = COMPUTE_PEAK_MIN * sps; i <= COMPUTE_PEAK_MAX * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001692 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001693 avg += (peak - i)->norm2();
1694 num++;
1695 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001696 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001697 avg += (peak + i)->norm2();
1698 num++;
1699 }
dburgessb3a0ca42011-10-12 07:44:40 +00001700 }
1701
Tom Tsoua84e1622016-06-29 14:50:25 -07001702 if (num < COMPUTE_PEAK_CNT)
Thomas Tsou865bca42013-08-21 20:58:00 -04001703 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001704
Thomas Tsou3eaae802013-08-20 19:31:14 -04001705 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001706
Thomas Tsou865bca42013-08-21 20:58:00 -04001707 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001708}
1709
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +03001710float energyDetect(signalVector &rxBurst, unsigned windowLength)
dburgessb3a0ca42011-10-12 07:44:40 +00001711{
1712
1713 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1714 float energy = 0.0;
1715 if (windowLength < 0) windowLength = 20;
1716 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1717 for (unsigned i = 0; i < windowLength; i++) {
1718 energy += windowItr->norm2();
1719 windowItr+=4;
1720 }
Alexander Chemeris1dd05cf2017-03-15 23:23:36 +03001721 return energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001722}
dburgessb3a0ca42011-10-12 07:44:40 +00001723
Thomas Tsou865bca42013-08-21 20:58:00 -04001724/*
1725 * Detect a burst based on correlation and peak-to-average ratio
1726 *
1727 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1728 * for initial gating. We do this because energy detection should be disabled.
1729 * For higher oversampling values, we assume the energy detector is in place
1730 * and we run full interpolating peak detection.
1731 */
1732static int detectBurst(signalVector &burst,
1733 signalVector &corr, CorrelationSequence *sync,
1734 float thresh, int sps, complex *amp, float *toa,
1735 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001736{
Tom Tsoud3253432016-03-06 03:08:01 -08001737 signalVector *corr_in, *dec = NULL;
1738
1739 if (sps == 4) {
1740 dec = downsampleBurst(burst);
1741 corr_in = dec;
1742 sps = 1;
1743 } else {
1744 corr_in = &burst;
1745 }
1746
Thomas Tsou865bca42013-08-21 20:58:00 -04001747 /* Correlate */
Tom Tsoud3253432016-03-06 03:08:01 -08001748 if (!convolve(corr_in, sync->sequence, &corr,
1749 CUSTOM, start, len, 1, 0)) {
1750 delete dec;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001751 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001752 }
1753
Tom Tsoud3253432016-03-06 03:08:01 -08001754 delete dec;
1755
1756 /* Running at the downsampled rate at this point */
1757 sps = 1;
1758
Thomas Tsou865bca42013-08-21 20:58:00 -04001759 /* Peak detection - place restrictions at correlation edges */
1760 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001761
Thomas Tsou865bca42013-08-21 20:58:00 -04001762 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1763 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001764
Thomas Tsou865bca42013-08-21 20:58:00 -04001765 /* Peak -to-average ratio */
1766 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1767 return 0;
1768
1769 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1770 *amp = peakDetect(corr, toa, NULL);
1771
1772 /* Normalize our channel gain */
1773 *amp = *amp / sync->gain;
1774
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001775 /* Compenate for residual rotation with dual Laurent pulse */
1776 if (sps == 4)
1777 *amp = *amp * complex(0.0, 1.0);
1778
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001779 /* Compensate for residuate time lag */
1780 *toa = *toa - sync->toa;
1781
Thomas Tsou865bca42013-08-21 20:58:00 -04001782 return 1;
1783}
1784
Alexander Chemeris954b1182015-06-04 15:39:41 -04001785static float maxAmplitude(signalVector &burst)
Tom Tsou577cd022015-05-18 13:57:54 -07001786{
Alexander Chemeris954b1182015-06-04 15:39:41 -04001787 float max = 0.0;
1788 for (size_t i = 0; i < burst.size(); i++) {
1789 if (fabs(burst[i].real()) > max)
1790 max = fabs(burst[i].real());
1791 if (fabs(burst[i].imag()) > max)
1792 max = fabs(burst[i].imag());
1793 }
Tom Tsou577cd022015-05-18 13:57:54 -07001794
Alexander Chemeris954b1182015-06-04 15:39:41 -04001795 return max;
Tom Tsou577cd022015-05-18 13:57:54 -07001796}
1797
Alexander Chemeris130a8002015-06-09 20:52:11 -04001798/*
1799 * RACH/Normal burst detection with clipping detection
Thomas Tsou865bca42013-08-21 20:58:00 -04001800 *
1801 * Correlation window parameters:
Alexander Chemeris130a8002015-06-09 20:52:11 -04001802 * target: Tail bits + burst length
1803 * head: Search symbols before target
1804 * tail: Search symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001805 */
Alexander Chemeris130a8002015-06-09 20:52:11 -04001806int detectGeneralBurst(signalVector &rxBurst,
1807 float thresh,
1808 int sps,
1809 complex &amp,
1810 float &toa,
1811 int target, int head, int tail,
1812 CorrelationSequence *sync)
Thomas Tsou865bca42013-08-21 20:58:00 -04001813{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001814 int rc, start, len;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001815 bool clipping = false;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001816 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001817
1818 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001819 return -SIGERR_UNSUPPORTED;
1820
Alexander Chemeris954b1182015-06-04 15:39:41 -04001821 // Detect potential clipping
1822 // We still may be able to demod the burst, so we'll give it a try
1823 // and only report clipping if we can't demod.
1824 float maxAmpl = maxAmplitude(rxBurst);
1825 if (maxAmpl > CLIP_THRESH) {
1826 LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
1827 clipping = true;
1828 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001829
Tom Tsoud3253432016-03-06 03:08:01 -08001830 start = target - head - 1;
1831 len = head + tail;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001832 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001833
Thomas Tsoub075dd22013-11-09 22:25:46 -05001834 rc = detectBurst(rxBurst, *corr, sync,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001835 thresh, sps, &amp, &toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001836 delete corr;
1837
Thomas Tsou865bca42013-08-21 20:58:00 -04001838 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001839 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001840 } else if (!rc) {
Alexander Chemeris130a8002015-06-09 20:52:11 -04001841 amp = 0.0f;
1842 toa = 0.0f;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001843 return clipping?-SIGERR_CLIP:SIGERR_NONE;
dburgessb3a0ca42011-10-12 07:44:40 +00001844 }
1845
Thomas Tsou865bca42013-08-21 20:58:00 -04001846 /* Subtract forward search bits from delay */
Tom Tsoud3253432016-03-06 03:08:01 -08001847 toa -= head;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001848
Thomas Tsou865bca42013-08-21 20:58:00 -04001849 return 1;
1850}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001851
Alexander Chemeris130a8002015-06-09 20:52:11 -04001852
1853/*
1854 * RACH burst detection
1855 *
1856 * Correlation window parameters:
1857 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Tom Tsoue90c24c2016-06-21 16:14:39 -07001858 * head: Search 8 symbols before target
1859 * tail: Search 8 symbols + maximum expected delay
Alexander Chemeris130a8002015-06-09 20:52:11 -04001860 */
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001861int detectRACHBurst(signalVector &burst,
1862 float threshold,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001863 int sps,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001864 complex &amplitude,
Alexander Chemeris78d1fc92016-03-19 21:16:22 +03001865 float &toa,
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001866 unsigned max_toa)
Alexander Chemeris130a8002015-06-09 20:52:11 -04001867{
1868 int rc, target, head, tail;
1869 CorrelationSequence *sync;
1870
1871 target = 8 + 40;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001872 head = 8;
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001873 tail = 8 + max_toa;
Alexander Chemeris130a8002015-06-09 20:52:11 -04001874 sync = gRACHSequence;
1875
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001876 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001877 target, head, tail, sync);
1878
1879 return rc;
1880}
1881
Thomas Tsou865bca42013-08-21 20:58:00 -04001882/*
1883 * Normal burst detection
1884 *
1885 * Correlation window parameters:
1886 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Tom Tsoue90c24c2016-06-21 16:14:39 -07001887 * head: Search 6 symbols before target
1888 * tail: Search 6 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001889 */
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001890int analyzeTrafficBurst(signalVector &burst, unsigned tsc, float threshold,
1891 int sps, complex &amplitude, float &toa, unsigned max_toa)
Thomas Tsou865bca42013-08-21 20:58:00 -04001892{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001893 int rc, target, head, tail;
Thomas Tsou865bca42013-08-21 20:58:00 -04001894 CorrelationSequence *sync;
1895
Alexander Chemeris130a8002015-06-09 20:52:11 -04001896 if ((tsc < 0) || (tsc > 7))
Tom Tsou577cd022015-05-18 13:57:54 -07001897 return -SIGERR_UNSUPPORTED;
1898
Thomas Tsou865bca42013-08-21 20:58:00 -04001899 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001900 head = 6;
1901 tail = 6 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001902 sync = gMidambles[tsc];
Thomas Tsou865bca42013-08-21 20:58:00 -04001903
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001904 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001905 target, head, tail, sync);
Alexander Chemeris130a8002015-06-09 20:52:11 -04001906 return rc;
dburgessb3a0ca42011-10-12 07:44:40 +00001907}
1908
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001909int detectEdgeBurst(signalVector &burst, unsigned tsc, float threshold,
1910 int sps, complex &amplitude, float &toa, unsigned max_toa)
Tom Tsoud3253432016-03-06 03:08:01 -08001911{
1912 int rc, target, head, tail;
1913 CorrelationSequence *sync;
1914
1915 if ((tsc < 0) || (tsc > 7))
1916 return -SIGERR_UNSUPPORTED;
1917
1918 target = 3 + 58 + 16 + 5;
Tom Tsoue90c24c2016-06-21 16:14:39 -07001919 head = 6;
1920 tail = 6 + max_toa;
Tom Tsoud3253432016-03-06 03:08:01 -08001921 sync = gEdgeMidambles[tsc];
1922
Alexander Chemeris14d13b62017-03-17 15:12:17 -07001923 rc = detectGeneralBurst(burst, threshold, sps, amplitude, toa,
Tom Tsoud3253432016-03-06 03:08:01 -08001924 target, head, tail, sync);
1925 return rc;
1926}
1927
1928signalVector *downsampleBurst(signalVector &burst)
1929{
Tom Tsou76764272016-06-24 14:25:39 -07001930 signalVector *in, *out;
Tom Tsoud3253432016-03-06 03:08:01 -08001931
Tom Tsou76764272016-06-24 14:25:39 -07001932 in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len());
1933 out = new signalVector(DOWNSAMPLE_OUT_LEN);
1934 memcpy(in->begin(), burst.begin(), DOWNSAMPLE_IN_LEN * 2 * sizeof(float));
Tom Tsoud3253432016-03-06 03:08:01 -08001935
Tom Tsou76764272016-06-24 14:25:39 -07001936 dnsampler->rotate((float *) in->begin(), DOWNSAMPLE_IN_LEN,
1937 (float *) out->begin(), DOWNSAMPLE_OUT_LEN);
1938 delete in;
Tom Tsoud3253432016-03-06 03:08:01 -08001939 return out;
1940};
1941
Thomas Tsou94edaae2013-11-09 22:19:19 -05001942signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001943{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001944 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001945
Thomas Tsou94edaae2013-11-09 22:19:19 -05001946 if (factor <= 1)
1947 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001948
Thomas Tsou94edaae2013-11-09 22:19:19 -05001949 dec = new signalVector(wVector.size() / factor);
1950 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001951
Thomas Tsou94edaae2013-11-09 22:19:19 -05001952 signalVector::iterator itr = dec->begin();
1953 for (size_t i = 0; i < wVector.size(); i += factor)
1954 *itr++ = wVector[i];
1955
1956 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001957}
1958
Tom Tsoud3253432016-03-06 03:08:01 -08001959/*
1960 * Soft 8-PSK decoding using Manhattan distance metric
1961 */
1962static SoftVector *softSliceEdgeBurst(signalVector &burst)
1963{
1964 size_t nsyms = 148;
1965
1966 if (burst.size() < nsyms)
1967 return NULL;
1968
1969 signalVector::iterator itr;
1970 SoftVector *bits = new SoftVector(nsyms * 3);
1971
1972 /*
1973 * Bits 0 and 1 - First and second bits of the symbol respectively
1974 */
1975 rotateBurst2(burst, -M_PI / 8.0);
1976 itr = burst.begin();
1977 for (size_t i = 0; i < nsyms; i++) {
1978 (*bits)[3 * i + 0] = -itr->imag();
1979 (*bits)[3 * i + 1] = itr->real();
1980 itr++;
1981 }
1982
1983 /*
1984 * Bit 2 - Collapse symbols into quadrant 0 (positive X and Y).
1985 * Decision area is then simplified to X=Y axis. Rotate again to
1986 * place decision boundary on X-axis.
1987 */
1988 itr = burst.begin();
1989 for (size_t i = 0; i < burst.size(); i++) {
1990 burst[i] = Complex<float>(fabs(itr->real()), fabs(itr->imag()));
1991 itr++;
1992 }
1993
1994 rotateBurst2(burst, -M_PI / 4.0);
1995 itr = burst.begin();
1996 for (size_t i = 0; i < nsyms; i++) {
1997 (*bits)[3 * i + 2] = -itr->imag();
1998 itr++;
1999 }
2000
2001 signalVector soft(bits->size());
2002 for (size_t i = 0; i < bits->size(); i++)
2003 soft[i] = (*bits)[i];
2004
2005 return bits;
2006}
2007
2008/*
Alexander Chemeris132fb242017-03-17 17:22:33 -07002009 * Convert signalVector to SoftVector by taking real part of the signal.
2010 */
2011static SoftVector *signalToSoftVector(signalVector *dec)
2012{
2013 SoftVector *bits = new SoftVector(dec->size());
2014
2015 SoftVector::iterator bit_itr = bits->begin();
2016 signalVector::iterator burst_itr = dec->begin();
2017
2018 for (; burst_itr < dec->end(); burst_itr++)
2019 *bit_itr++ = burst_itr->real();
2020
2021 return bits;
2022}
2023
2024/*
Tom Tsou7fec3032016-03-06 22:33:20 -08002025 * Shared portion of GMSK and EDGE demodulators consisting of timing
2026 * recovery and single tap channel correction. For 4 SPS (if activated),
2027 * the output is downsampled prior to the 1 SPS modulation specific
2028 * stages.
2029 */
2030static signalVector *demodCommon(signalVector &burst, int sps,
2031 complex chan, float toa)
2032{
2033 signalVector *delay, *dec;
2034
2035 if ((sps != 1) && (sps != 4))
2036 return NULL;
2037
2038 scaleVector(burst, (complex) 1.0 / chan);
2039 delay = delayVector(&burst, NULL, -toa * (float) sps);
2040
2041 if (sps == 1)
2042 return delay;
2043
2044 dec = downsampleBurst(*delay);
2045
2046 delete delay;
2047 return dec;
2048}
2049
2050/*
Tom Tsoud3253432016-03-06 03:08:01 -08002051 * Demodulate GSMK burst. Prior to symbol rotation, operate at
2052 * 4 SPS (if activated) to minimize distortion through the fractional
2053 * delay filters. Symbol rotation and after always operates at 1 SPS.
2054 */
Alexander Chemeris1c0b8b32017-03-17 16:12:47 -07002055SoftVector *demodGmskBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05002056 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00002057{
Thomas Tsou94edaae2013-11-09 22:19:19 -05002058 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08002059 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00002060
Tom Tsou7fec3032016-03-06 22:33:20 -08002061 dec = demodCommon(rxBurst, sps, channel, TOA);
2062 if (!dec)
2063 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00002064
Tom Tsoud3253432016-03-06 03:08:01 -08002065 /* Shift up by a quarter of a frequency */
2066 GMSKReverseRotate(*dec, 1);
Alexander Chemeris132fb242017-03-17 17:22:33 -07002067 /* Take real part of the signal */
2068 bits = signalToSoftVector(dec);
Thomas Tsou94edaae2013-11-09 22:19:19 -05002069 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00002070
Alexander Chemeris132fb242017-03-17 17:22:33 -07002071 vectorSlicer(bits);
2072
Thomas Tsou94edaae2013-11-09 22:19:19 -05002073 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00002074}
Thomas Tsou94edaae2013-11-09 22:19:19 -05002075
Tom Tsoud3253432016-03-06 03:08:01 -08002076/*
2077 * Demodulate an 8-PSK burst. Prior to symbol rotation, operate at
2078 * 4 SPS (if activated) to minimize distortion through the fractional
2079 * delay filters. Symbol rotation and after always operates at 1 SPS.
2080 *
2081 * Allow 1 SPS demodulation here, but note that other parts of the
2082 * transceiver restrict EDGE operatoin to 4 SPS - 8-PSK distortion
2083 * through the fractional delay filters at 1 SPS renders signal
2084 * nearly unrecoverable.
2085 */
2086SoftVector *demodEdgeBurst(signalVector &burst, int sps,
2087 complex chan, float toa)
2088{
2089 SoftVector *bits;
Tom Tsou7fec3032016-03-06 22:33:20 -08002090 signalVector *dec, *rot, *eq;
Tom Tsoud3253432016-03-06 03:08:01 -08002091
Tom Tsou7fec3032016-03-06 22:33:20 -08002092 dec = demodCommon(burst, sps, chan, toa);
2093 if (!dec)
Tom Tsoud3253432016-03-06 03:08:01 -08002094 return NULL;
2095
Tom Tsou7fec3032016-03-06 22:33:20 -08002096 /* Equalize and derotate */
Tom Tsoud3253432016-03-06 03:08:01 -08002097 eq = convolve(dec, GSMPulse4->c0_inv, NULL, NO_DELAY);
2098 rot = derotateEdgeBurst(*eq, 1);
2099
Tom Tsou7fec3032016-03-06 22:33:20 -08002100 /* Soft slice and normalize */
Tom Tsou04795622016-04-26 21:17:36 -07002101 bits = softSliceEdgeBurst(*rot);
Tom Tsoud3253432016-03-06 03:08:01 -08002102 vectorSlicer(bits);
2103
2104 delete dec;
2105 delete eq;
2106 delete rot;
2107
2108 return bits;
2109}
2110
Tom Tsou2079a3c2016-03-06 00:58:56 -08002111bool sigProcLibSetup()
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002112{
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002113 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05002114 generateSincTable();
Tom Tsou2079a3c2016-03-06 00:58:56 -08002115 initGMSKRotationTables();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002116
Tom Tsou2079a3c2016-03-06 00:58:56 -08002117 GSMPulse1 = generateGSMPulse(1);
2118 GSMPulse4 = generateGSMPulse(4);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002119
Tom Tsou2079a3c2016-03-06 00:58:56 -08002120 generateRACHSequence(1);
Tom Tsoud3253432016-03-06 03:08:01 -08002121 for (int tsc = 0; tsc < 8; tsc++) {
Tom Tsou2079a3c2016-03-06 00:58:56 -08002122 generateMidamble(1, tsc);
Tom Tsoud3253432016-03-06 03:08:01 -08002123 gEdgeMidambles[tsc] = generateEdgeMidamble(tsc);
2124 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002125
Thomas Tsouf79c4d02013-11-09 15:51:56 -06002126 generateDelayFilters();
2127
Tom Tsoud3253432016-03-06 03:08:01 -08002128 dnsampler = new Resampler(1, 4);
2129 if (!dnsampler->init()) {
2130 LOG(ALERT) << "Rx resampler failed to initialize";
2131 goto fail;
2132 }
2133
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002134 return true;
Tom Tsoud3253432016-03-06 03:08:01 -08002135
2136fail:
2137 sigProcLibDestroy();
2138 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04002139}