blob: ab421b6ea9e1492dc621fbdd155ebfc81a2a0a96 [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"
31
Thomas Tsou3eaae802013-08-20 19:31:14 -040032extern "C" {
33#include "convolve.h"
Thomas Tsou7e4e5362013-10-30 21:18:55 -040034#include "scale.h"
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -050035#include "mult.h"
Thomas Tsou3eaae802013-08-20 19:31:14 -040036}
37
Thomas Tsou7e4e5362013-10-30 21:18:55 -040038using namespace GSM;
39
dburgessb3a0ca42011-10-12 07:44:40 +000040#define TABLESIZE 1024
41
42/** Lookup tables for trigonometric approximation */
43float cosTable[TABLESIZE+1]; // add 1 element for wrap around
44float sinTable[TABLESIZE+1];
45
46/** Constants */
47static const float M_PI_F = (float)M_PI;
48static const float M_2PI_F = (float)(2.0*M_PI);
49static const float M_1_2PI_F = 1/M_2PI_F;
50
Thomas Tsouc1f7c422013-10-11 13:49:55 -040051/* Precomputed rotation vectors */
52static signalVector *GMSKRotationN = NULL;
53static signalVector *GMSKReverseRotationN = NULL;
54static signalVector *GMSKRotation1 = NULL;
55static signalVector *GMSKReverseRotation1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000056
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040057/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040058 * RACH and midamble correlation waveforms. Store the buffer separately
59 * because we need to allocate it explicitly outside of the signal vector
60 * constructor. This is because C++ (prior to C++11) is unable to natively
61 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040062 */
63struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040064 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040065 {
66 }
67
68 ~CorrelationSequence()
69 {
70 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040071 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040072 }
73
dburgessb3a0ca42011-10-12 07:44:40 +000074 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040075 void *buffer;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040076 float toa;
dburgessb3a0ca42011-10-12 07:44:40 +000077 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040078};
dburgessb3a0ca42011-10-12 07:44:40 +000079
Thomas Tsou83e06892013-08-20 16:10:01 -040080/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040081 * Gaussian and empty modulation pulses. Like the correlation sequences,
82 * store the runtime (Gaussian) buffer separately because of needed alignment
83 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -040084 */
85struct PulseSequence {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080086 PulseSequence() : c0(NULL), c1(NULL), empty(NULL),
87 c0_buffer(NULL), c1_buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -040088 {
89 }
90
91 ~PulseSequence()
92 {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080093 delete c0;
94 delete c1;
Thomas Tsou83e06892013-08-20 16:10:01 -040095 delete empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080096 free(c0_buffer);
97 free(c1_buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -040098 }
99
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800100 signalVector *c0;
101 signalVector *c1;
Thomas Tsou83e06892013-08-20 16:10:01 -0400102 signalVector *empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800103 void *c0_buffer;
104 void *c1_buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -0400105};
106
dburgessb3a0ca42011-10-12 07:44:40 +0000107CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
108CorrelationSequence *gRACHSequence = NULL;
Thomas Tsou83e06892013-08-20 16:10:01 -0400109PulseSequence *GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400110PulseSequence *GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000111
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400112void sigProcLibDestroy()
113{
dburgessb3a0ca42011-10-12 07:44:40 +0000114 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400115 delete gMidambles[i];
116 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000117 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400118
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400119 delete GMSKRotationN;
120 delete GMSKReverseRotationN;
121 delete GMSKRotation1;
122 delete GMSKReverseRotation1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400123 delete gRACHSequence;
124 delete GSMPulse;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400125 delete GSMPulse1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400126
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400127 GMSKRotationN = NULL;
128 GMSKRotation1 = NULL;
129 GMSKReverseRotationN = NULL;
130 GMSKReverseRotation1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400131 gRACHSequence = NULL;
132 GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400133 GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000134}
135
dburgessb3a0ca42011-10-12 07:44:40 +0000136// dB relative to 1.0.
137// if > 1.0, then return 0 dB
138float dB(float x) {
139
140 float arg = 1.0F;
141 float dB = 0.0F;
142
143 if (x >= 1.0F) return 0.0F;
144 if (x <= 0.0F) return -200.0F;
145
146 float prevArg = arg;
147 float prevdB = dB;
148 float stepSize = 16.0F;
149 float dBstepSize = 12.0F;
150 while (stepSize > 1.0F) {
151 do {
152 prevArg = arg;
153 prevdB = dB;
154 arg /= stepSize;
155 dB -= dBstepSize;
156 } while (arg > x);
157 arg = prevArg;
158 dB = prevdB;
159 stepSize *= 0.5F;
160 dBstepSize -= 3.0F;
161 }
162 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
163
164}
165
166// 10^(-dB/10), inverse of dB func.
167float dBinv(float x) {
168
169 float arg = 1.0F;
170 float dB = 0.0F;
171
172 if (x >= 0.0F) return 1.0F;
173 if (x <= -200.0F) return 0.0F;
174
175 float prevArg = arg;
176 float prevdB = dB;
177 float stepSize = 16.0F;
178 float dBstepSize = 12.0F;
179 while (stepSize > 1.0F) {
180 do {
181 prevArg = arg;
182 prevdB = dB;
183 arg /= stepSize;
184 dB -= dBstepSize;
185 } while (dB > x);
186 arg = prevArg;
187 dB = prevdB;
188 stepSize *= 0.5F;
189 dBstepSize -= 3.0F;
190 }
191
192 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
193
194}
195
196float vectorNorm2(const signalVector &x)
197{
198 signalVector::const_iterator xPtr = x.begin();
199 float Energy = 0.0;
200 for (;xPtr != x.end();xPtr++) {
201 Energy += xPtr->norm2();
202 }
203 return Energy;
204}
205
206
207float vectorPower(const signalVector &x)
208{
209 return vectorNorm2(x)/x.size();
210}
211
212/** compute cosine via lookup table */
213float cosLookup(const float x)
214{
215 float arg = x*M_1_2PI_F;
216 while (arg > 1.0F) arg -= 1.0F;
217 while (arg < 0.0F) arg += 1.0F;
218
219 const float argT = arg*((float)TABLESIZE);
220 const int argI = (int)argT;
221 const float delta = argT-argI;
222 const float iDelta = 1.0F-delta;
223 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
224}
225
226/** compute sine via lookup table */
227float sinLookup(const float x)
228{
229 float arg = x*M_1_2PI_F;
230 while (arg > 1.0F) arg -= 1.0F;
231 while (arg < 0.0F) arg += 1.0F;
232
233 const float argT = arg*((float)TABLESIZE);
234 const int argI = (int)argT;
235 const float delta = argT-argI;
236 const float iDelta = 1.0F-delta;
237 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
238}
239
240
241/** compute e^(-jx) via lookup table. */
242complex expjLookup(float x)
243{
244 float arg = x*M_1_2PI_F;
245 while (arg > 1.0F) arg -= 1.0F;
246 while (arg < 0.0F) arg += 1.0F;
247
248 const float argT = arg*((float)TABLESIZE);
249 const int argI = (int)argT;
250 const float delta = argT-argI;
251 const float iDelta = 1.0F-delta;
252 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
253 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
254}
255
256/** Library setup functions */
257void initTrigTables() {
258 for (int i = 0; i < TABLESIZE+1; i++) {
259 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
260 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
261 }
262}
263
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400264void initGMSKRotationTables(int sps)
265{
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400266 GMSKRotationN = new signalVector(157 * sps);
267 GMSKReverseRotationN = new signalVector(157 * sps);
268 signalVector::iterator rotPtr = GMSKRotationN->begin();
269 signalVector::iterator revPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000270 float phase = 0.0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400271 while (rotPtr != GMSKRotationN->end()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000272 *rotPtr++ = expjLookup(phase);
273 *revPtr++ = expjLookup(-phase);
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400274 phase += M_PI_F / 2.0F / (float) sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000275 }
dburgessb3a0ca42011-10-12 07:44:40 +0000276
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400277 GMSKRotation1 = new signalVector(157);
278 GMSKReverseRotation1 = new signalVector(157);
279 rotPtr = GMSKRotation1->begin();
280 revPtr = GMSKReverseRotation1->begin();
281 phase = 0.0;
282 while (rotPtr != GMSKRotation1->end()) {
283 *rotPtr++ = expjLookup(phase);
284 *revPtr++ = expjLookup(-phase);
285 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400286 }
dburgessb3a0ca42011-10-12 07:44:40 +0000287}
288
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400289static void GMSKRotate(signalVector &x, int sps)
290{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500291#if HAVE_NEON
292 size_t len;
293 signalVector *a, *b, *out;
294
295 a = &x;
296 out = &x;
297 len = out->size();
298
299 if (len == 157)
300 len--;
301
302 if (sps == 1)
303 b = GMSKRotation1;
304 else
305 b = GMSKRotationN;
306
307 mul_complex((float *) out->begin(),
308 (float *) a->begin(),
309 (float *) b->begin(), len);
310#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400311 signalVector::iterator rotPtr, xPtr = x.begin();
312
313 if (sps == 1)
314 rotPtr = GMSKRotation1->begin();
315 else
316 rotPtr = GMSKRotationN->begin();
317
dburgessb3a0ca42011-10-12 07:44:40 +0000318 if (x.isRealOnly()) {
319 while (xPtr < x.end()) {
320 *xPtr = *rotPtr++ * (xPtr->real());
321 xPtr++;
322 }
323 }
324 else {
325 while (xPtr < x.end()) {
326 *xPtr = *rotPtr++ * (*xPtr);
327 xPtr++;
328 }
329 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500330#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000331}
332
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400333static void GMSKReverseRotate(signalVector &x, int sps)
334{
335 signalVector::iterator rotPtr, xPtr= x.begin();
336
337 if (sps == 1)
338 rotPtr = GMSKReverseRotation1->begin();
339 else
340 rotPtr = GMSKReverseRotationN->begin();
341
dburgessb3a0ca42011-10-12 07:44:40 +0000342 if (x.isRealOnly()) {
343 while (xPtr < x.end()) {
344 *xPtr = *rotPtr++ * (xPtr->real());
345 xPtr++;
346 }
347 }
348 else {
349 while (xPtr < x.end()) {
350 *xPtr = *rotPtr++ * (*xPtr);
351 xPtr++;
352 }
353 }
354}
355
Thomas Tsou3eaae802013-08-20 19:31:14 -0400356signalVector *convolve(const signalVector *x,
357 const signalVector *h,
358 signalVector *y,
359 ConvType spanType, int start,
360 unsigned len, unsigned step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000361{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400362 int rc, head = 0, tail = 0;
363 bool alloc = false, append = false;
364 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000365
Thomas Tsou3eaae802013-08-20 19:31:14 -0400366 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000367 return NULL;
368
Thomas Tsou3eaae802013-08-20 19:31:14 -0400369 switch (spanType) {
370 case START_ONLY:
371 start = 0;
372 head = h->size();
373 len = x->size();
374 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000375 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400376 case NO_DELAY:
377 start = h->size() / 2;
378 head = start;
379 tail = start;
380 len = x->size();
381 append = true;
382 break;
383 case CUSTOM:
384 if (start < h->size() - 1) {
385 head = h->size() - start;
386 append = true;
387 }
388 if (start + len > x->size()) {
389 tail = start + len - x->size();
390 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000391 }
392 break;
393 default:
394 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000395 }
dburgessb3a0ca42011-10-12 07:44:40 +0000396
Thomas Tsou3eaae802013-08-20 19:31:14 -0400397 /*
398 * Error if the output vector is too small. Create the output vector
399 * if the pointer is NULL.
400 */
401 if (y && (len > y->size()))
402 return NULL;
403 if (!y) {
404 y = new signalVector(len);
405 alloc = true;
406 }
407
408 /* Prepend or post-pend the input vector if the parameters require it */
409 if (append)
410 _x = new signalVector(*x, head, tail);
411 else
412 _x = x;
413
414 /*
415 * Four convovle types:
416 * 1. Complex-Real (aligned)
417 * 2. Complex-Complex (aligned)
418 * 3. Complex-Real (!aligned)
419 * 4. Complex-Complex (!aligned)
420 */
421 if (h->isRealOnly() && h->isAligned()) {
422 rc = convolve_real((float *) _x->begin(), _x->size(),
423 (float *) h->begin(), h->size(),
424 (float *) y->begin(), y->size(),
425 start, len, step, offset);
426 } else if (!h->isRealOnly() && h->isAligned()) {
427 rc = convolve_complex((float *) _x->begin(), _x->size(),
428 (float *) h->begin(), h->size(),
429 (float *) y->begin(), y->size(),
430 start, len, step, offset);
431 } else if (h->isRealOnly() && !h->isAligned()) {
432 rc = base_convolve_real((float *) _x->begin(), _x->size(),
433 (float *) h->begin(), h->size(),
434 (float *) y->begin(), y->size(),
435 start, len, step, offset);
436 } else if (!h->isRealOnly() && !h->isAligned()) {
437 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
438 (float *) h->begin(), h->size(),
439 (float *) y->begin(), y->size(),
440 start, len, step, offset);
441 } else {
442 rc = -1;
443 }
444
445 if (append)
446 delete _x;
447
448 if (rc < 0) {
449 if (alloc)
450 delete y;
451 return NULL;
452 }
453
454 return y;
455}
dburgessb3a0ca42011-10-12 07:44:40 +0000456
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400457static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800458{
459 int len;
460
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400461 if (!pulse)
462 return false;
463
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800464 switch (sps) {
465 case 4:
466 len = 8;
467 break;
468 default:
469 return false;
470 }
471
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400472 pulse->c1_buffer = convolve_h_alloc(len);
473 pulse->c1 = new signalVector((complex *)
474 pulse->c1_buffer, 0, len);
475 pulse->c1->isRealOnly(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800476
477 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400478 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800479
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400480 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800481
482 switch (sps) {
483 case 4:
484 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400485 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800486 *xP++ = 8.16373112e-03;
487 *xP++ = 2.84385729e-02;
488 *xP++ = 5.64158904e-02;
489 *xP++ = 7.05463553e-02;
490 *xP++ = 5.64158904e-02;
491 *xP++ = 2.84385729e-02;
492 *xP++ = 8.16373112e-03;
493 }
494
495 return true;
496}
497
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400498static PulseSequence *generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000499{
Thomas Tsou83e06892013-08-20 16:10:01 -0400500 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800501 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400502 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400503
504 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400505 pulse = new PulseSequence();
506 pulse->empty = new signalVector(1);
507 pulse->empty->isRealOnly(true);
508 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400509
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400510 /*
511 * For 4 samples-per-symbol use a precomputed single pulse Laurent
512 * approximation. This should yields below 2 degrees of phase error at
513 * the modulator output. Use the existing pulse approximation for all
514 * other oversampling factors.
515 */
516 switch (sps) {
517 case 4:
518 len = 16;
519 break;
520 default:
521 len = sps * symbolLength;
522 if (len < 4)
523 len = 4;
524 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400525
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400526 pulse->c0_buffer = convolve_h_alloc(len);
527 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
528 pulse->c0->isRealOnly(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400529
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800530 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400531 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800532
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400533 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400534
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400535 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800536 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400537 *xP++ = 4.46348606e-03;
538 *xP++ = 2.84385729e-02;
539 *xP++ = 1.03184855e-01;
540 *xP++ = 2.56065552e-01;
541 *xP++ = 4.76375085e-01;
542 *xP++ = 7.05961177e-01;
543 *xP++ = 8.71291644e-01;
544 *xP++ = 9.29453645e-01;
545 *xP++ = 8.71291644e-01;
546 *xP++ = 7.05961177e-01;
547 *xP++ = 4.76375085e-01;
548 *xP++ = 2.56065552e-01;
549 *xP++ = 1.03184855e-01;
550 *xP++ = 2.84385729e-02;
551 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400552 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400553 } else {
554 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400555
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400556 /* GSM pulse approximation */
557 for (int i = 0; i < len; i++) {
558 arg = ((float) i - center) / (float) sps;
559 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
560 0.527 * arg * arg * arg * arg);
561 }
dburgessb3a0ca42011-10-12 07:44:40 +0000562
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400563 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
564 xP = pulse->c0->begin();
565 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800566 *xP++ /= avg;
567 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400568
569 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000570}
571
572signalVector* frequencyShift(signalVector *y,
573 signalVector *x,
574 float freq,
575 float startPhase,
576 float *finalPhase)
577{
578
579 if (!x) return NULL;
580
581 if (y==NULL) {
582 y = new signalVector(x->size());
583 y->isRealOnly(x->isRealOnly());
584 if (y==NULL) return NULL;
585 }
586
587 if (y->size() < x->size()) return NULL;
588
589 float phase = startPhase;
590 signalVector::iterator yP = y->begin();
591 signalVector::iterator xPEnd = x->end();
592 signalVector::iterator xP = x->begin();
593
594 if (x->isRealOnly()) {
595 while (xP < xPEnd) {
596 (*yP++) = expjLookup(phase)*( (xP++)->real() );
597 phase += freq;
598 }
599 }
600 else {
601 while (xP < xPEnd) {
602 (*yP++) = (*xP++)*expjLookup(phase);
603 phase += freq;
604 }
605 }
606
607
608 if (finalPhase) *finalPhase = phase;
609
610 return y;
611}
612
613signalVector* reverseConjugate(signalVector *b)
614{
615 signalVector *tmp = new signalVector(b->size());
616 tmp->isRealOnly(b->isRealOnly());
617 signalVector::iterator bP = b->begin();
618 signalVector::iterator bPEnd = b->end();
619 signalVector::iterator tmpP = tmp->end()-1;
620 if (!b->isRealOnly()) {
621 while (bP < bPEnd) {
622 *tmpP-- = bP->conj();
623 bP++;
624 }
625 }
626 else {
627 while (bP < bPEnd) {
628 *tmpP-- = bP->real();
629 bP++;
630 }
631 }
632
633 return tmp;
634}
635
dburgessb3a0ca42011-10-12 07:44:40 +0000636/* soft output slicer */
637bool vectorSlicer(signalVector *x)
638{
639
640 signalVector::iterator xP = x->begin();
641 signalVector::iterator xPEnd = x->end();
642 while (xP < xPEnd) {
643 *xP = (complex) (0.5*(xP->real()+1.0F));
644 if (xP->real() > 1.0) *xP = 1.0;
645 if (xP->real() < 0.0) *xP = 0.0;
646 xP++;
647 }
648 return true;
649}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400650
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800651static signalVector *rotateBurst(const BitVector &wBurst,
652 int guardPeriodLength, int sps)
653{
654 int burst_len;
655 signalVector *pulse, rotated, *shaped;
656 signalVector::iterator itr;
657
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400658 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800659 burst_len = sps * (wBurst.size() + guardPeriodLength);
660 rotated = signalVector(burst_len);
661 itr = rotated.begin();
662
663 for (unsigned i = 0; i < wBurst.size(); i++) {
664 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
665 itr += sps;
666 }
667
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400668 GMSKRotate(rotated, sps);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800669 rotated.isRealOnly(false);
670
671 /* Dummy filter operation */
672 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
673 if (!shaped)
674 return NULL;
675
676 return shaped;
677}
678
679static signalVector *modulateBurstLaurent(const BitVector &bits,
680 int guard_len, int sps)
681{
682 int burst_len;
683 float phase;
684 signalVector *c0_pulse, *c1_pulse, c0_burst, c1_burst, *c0_shaped, *c1_shaped;
685 signalVector::iterator c0_itr, c1_itr;
686
687 /*
688 * Apply before and after bits to reduce phase error at burst edges.
689 * Make sure there is enough room in the burst to accomodate all bits.
690 */
691 if (guard_len < 4)
692 guard_len = 4;
693
694 c0_pulse = GSMPulse->c0;
695 c1_pulse = GSMPulse->c1;
696
697 burst_len = sps * (bits.size() + guard_len);
698
699 c0_burst = signalVector(burst_len);
700 c0_burst.isRealOnly(true);
701 c0_itr = c0_burst.begin();
702
703 c1_burst = signalVector(burst_len);
704 c1_burst.isRealOnly(true);
705 c1_itr = c1_burst.begin();
706
707 /* Padded differential start bits */
708 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
709 c0_itr += sps;
710
711 /* Main burst bits */
712 for (unsigned i = 0; i < bits.size(); i++) {
713 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
714 c0_itr += sps;
715 }
716
717 /* Padded differential end bits */
718 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
719
720 /* Generate C0 phase coefficients */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400721 GMSKRotate(c0_burst, sps);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800722 c0_burst.isRealOnly(false);
723
724 c0_itr = c0_burst.begin();
725 c0_itr += sps * 2;
726 c1_itr += sps * 2;
727
728 /* Start magic */
729 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
730 *c1_itr = *c0_itr * Complex<float>(0, phase);
731 c0_itr += sps;
732 c1_itr += sps;
733
734 /* Generate C1 phase coefficients */
735 for (unsigned i = 2; i < bits.size(); i++) {
736 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
737 *c1_itr = *c0_itr * Complex<float>(0, phase);
738
739 c0_itr += sps;
740 c1_itr += sps;
741 }
742
743 /* End magic */
744 int i = bits.size();
745 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
746 *c1_itr = *c0_itr * Complex<float>(0, phase);
747
748 /* Primary (C0) and secondary (C1) pulse shaping */
749 c0_shaped = convolve(&c0_burst, c0_pulse, NULL, START_ONLY);
750 c1_shaped = convolve(&c1_burst, c1_pulse, NULL, START_ONLY);
751
752 /* Sum shaped outputs into C0 */
753 c0_itr = c0_shaped->begin();
754 c1_itr = c1_shaped->begin();
755 for (unsigned i = 0; i < c0_shaped->size(); i++ )
756 *c0_itr++ += *c1_itr++;
757
758 delete c1_shaped;
759
760 return c0_shaped;
761}
762
763static signalVector *modulateBurstBasic(const BitVector &bits,
764 int guard_len, int sps)
765{
766 int burst_len;
767 signalVector *pulse, burst, *shaped;
768 signalVector::iterator burst_itr;
769
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400770 if (sps == 1)
771 pulse = GSMPulse1->c0;
772 else
773 pulse = GSMPulse->c0;
774
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800775 burst_len = sps * (bits.size() + guard_len);
776
777 burst = signalVector(burst_len);
778 burst.isRealOnly(true);
779 burst_itr = burst.begin();
780
781 /* Raw bits are not differentially encoded */
782 for (unsigned i = 0; i < bits.size(); i++) {
783 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
784 burst_itr += sps;
785 }
786
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400787 GMSKRotate(burst, sps);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800788 burst.isRealOnly(false);
789
790 /* Single Gaussian pulse approximation shaping */
791 shaped = convolve(&burst, pulse, NULL, START_ONLY);
792
793 return shaped;
794}
795
Thomas Tsou3eaae802013-08-20 19:31:14 -0400796/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400797signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
798 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000799{
Thomas Tsou83e06892013-08-20 16:10:01 -0400800 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800801 return rotateBurst(wBurst, guardPeriodLength, sps);
802 else if (sps == 4)
803 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400804 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800805 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000806}
807
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800808float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000809{
810 if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
811 return 1.0F;
812}
813
Thomas Tsou3eaae802013-08-20 19:31:14 -0400814bool delayVector(signalVector &wBurst, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000815{
Thomas Tsou2c282f52013-10-08 21:34:35 -0400816 int whole, h_len = 20;
817 float frac;
818 complex *data;
819 signalVector *h, *shift;
820 signalVector::iterator itr;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400821
Thomas Tsou2c282f52013-10-08 21:34:35 -0400822 whole = floor(delay);
823 frac = delay - whole;
824
825 /* Sinc interpolated fractional shift (if allowable) */
826 if (fabs(frac) > 1e-2) {
827 data = (complex *) convolve_h_alloc(h_len);
828 h = new signalVector(data, 0, h_len);
829 h->setAligned(true);
830 h->isRealOnly(true);
831
832 itr = h->end();
833 for (int i = 0; i < h_len; i++)
834 *--itr = (complex) sinc(M_PI_F * (i - h_len / 2 - frac));
835
836 shift = convolve(&wBurst, h, NULL, NO_DELAY);
837
838 delete h;
839 free(data);
840
841 if (!shift)
Thomas Tsou3eaae802013-08-20 19:31:14 -0400842 return false;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400843
844 wBurst.clone(*shift);
845 delete shift;
dburgessb3a0ca42011-10-12 07:44:40 +0000846 }
847
Thomas Tsou2c282f52013-10-08 21:34:35 -0400848 /* Integer sample shift */
849 if (whole < 0) {
850 whole = -whole;
dburgessb3a0ca42011-10-12 07:44:40 +0000851 signalVector::iterator wBurstItr = wBurst.begin();
Thomas Tsou2c282f52013-10-08 21:34:35 -0400852 signalVector::iterator shiftedItr = wBurst.begin() + whole;
853
dburgessb3a0ca42011-10-12 07:44:40 +0000854 while (shiftedItr < wBurst.end())
855 *wBurstItr++ = *shiftedItr++;
856 while (wBurstItr < wBurst.end())
857 *wBurstItr++ = 0.0;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400858 } else {
859 signalVector::iterator wBurstItr = wBurst.end() - 1;
860 signalVector::iterator shiftedItr = wBurst.end() - 1 - whole;
861
dburgessb3a0ca42011-10-12 07:44:40 +0000862 while (shiftedItr >= wBurst.begin())
863 *wBurstItr-- = *shiftedItr--;
864 while (wBurstItr >= wBurst.begin())
865 *wBurstItr-- = 0.0;
866 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400867
868 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000869}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400870
dburgessb3a0ca42011-10-12 07:44:40 +0000871signalVector *gaussianNoise(int length,
872 float variance,
873 complex mean)
874{
875
876 signalVector *noise = new signalVector(length);
877 signalVector::iterator nPtr = noise->begin();
878 float stddev = sqrtf(variance);
879 while (nPtr < noise->end()) {
880 float u1 = (float) rand()/ (float) RAND_MAX;
881 while (u1==0.0)
882 u1 = (float) rand()/ (float) RAND_MAX;
883 float u2 = (float) rand()/ (float) RAND_MAX;
884 float arg = 2.0*M_PI*u2;
885 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
886 nPtr++;
887 }
888
889 return noise;
890}
891
892complex interpolatePoint(const signalVector &inSig,
893 float ix)
894{
895
896 int start = (int) (floor(ix) - 10);
897 if (start < 0) start = 0;
898 int end = (int) (floor(ix) + 11);
899 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
900
901 complex pVal = 0.0;
902 if (!inSig.isRealOnly()) {
903 for (int i = start; i < end; i++)
904 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
905 }
906 else {
907 for (int i = start; i < end; i++)
908 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
909 }
910
911 return pVal;
912}
913
Thomas Tsou8181b012013-08-20 21:17:19 -0400914static complex fastPeakDetect(const signalVector &rxBurst, float *index)
915{
916 float val, max = 0.0f;
917 complex amp;
918 int _index = -1;
919
920 for (int i = 0; i < rxBurst.size(); i++) {
921 val = rxBurst[i].norm2();
922 if (val > max) {
923 max = val;
924 _index = i;
925 amp = rxBurst[i];
926 }
927 }
928
929 if (index)
930 *index = (float) _index;
931
932 return amp;
933}
934
dburgessb3a0ca42011-10-12 07:44:40 +0000935complex peakDetect(const signalVector &rxBurst,
936 float *peakIndex,
937 float *avgPwr)
938{
939
940
941 complex maxVal = 0.0;
942 float maxIndex = -1;
943 float sumPower = 0.0;
944
945 for (unsigned int i = 0; i < rxBurst.size(); i++) {
946 float samplePower = rxBurst[i].norm2();
947 if (samplePower > maxVal.real()) {
948 maxVal = samplePower;
949 maxIndex = i;
950 }
951 sumPower += samplePower;
952 }
953
954 // interpolate around the peak
955 // to save computation, we'll use early-late balancing
956 float earlyIndex = maxIndex-1;
957 float lateIndex = maxIndex+1;
958
959 float incr = 0.5;
960 while (incr > 1.0/1024.0) {
961 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
962 complex lateP = interpolatePoint(rxBurst,lateIndex);
963 if (earlyP < lateP)
964 earlyIndex += incr;
965 else if (earlyP > lateP)
966 earlyIndex -= incr;
967 else break;
968 incr /= 2.0;
969 lateIndex = earlyIndex + 2.0;
970 }
971
972 maxIndex = earlyIndex + 1.0;
973 maxVal = interpolatePoint(rxBurst,maxIndex);
974
975 if (peakIndex!=NULL)
976 *peakIndex = maxIndex;
977
978 if (avgPwr!=NULL)
979 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
980
981 return maxVal;
982
983}
984
985void scaleVector(signalVector &x,
986 complex scale)
987{
Thomas Tsou7e4e5362013-10-30 21:18:55 -0400988#ifdef HAVE_NEON
989 int len = x.size();
990
991 scale_complex((float *) x.begin(),
992 (float *) x.begin(),
993 (float *) &scale, len);
994#else
dburgessb3a0ca42011-10-12 07:44:40 +0000995 signalVector::iterator xP = x.begin();
996 signalVector::iterator xPEnd = x.end();
997 if (!x.isRealOnly()) {
998 while (xP < xPEnd) {
999 *xP = *xP * scale;
1000 xP++;
1001 }
1002 }
1003 else {
1004 while (xP < xPEnd) {
1005 *xP = xP->real() * scale;
1006 xP++;
1007 }
1008 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001009#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001010}
1011
1012/** in-place conjugation */
1013void conjugateVector(signalVector &x)
1014{
1015 if (x.isRealOnly()) return;
1016 signalVector::iterator xP = x.begin();
1017 signalVector::iterator xPEnd = x.end();
1018 while (xP < xPEnd) {
1019 *xP = xP->conj();
1020 xP++;
1021 }
1022}
1023
1024
1025// in-place addition!!
1026bool addVector(signalVector &x,
1027 signalVector &y)
1028{
1029 signalVector::iterator xP = x.begin();
1030 signalVector::iterator yP = y.begin();
1031 signalVector::iterator xPEnd = x.end();
1032 signalVector::iterator yPEnd = y.end();
1033 while ((xP < xPEnd) && (yP < yPEnd)) {
1034 *xP = *xP + *yP;
1035 xP++; yP++;
1036 }
1037 return true;
1038}
1039
1040// in-place multiplication!!
1041bool multVector(signalVector &x,
1042 signalVector &y)
1043{
1044 signalVector::iterator xP = x.begin();
1045 signalVector::iterator yP = y.begin();
1046 signalVector::iterator xPEnd = x.end();
1047 signalVector::iterator yPEnd = y.end();
1048 while ((xP < xPEnd) && (yP < yPEnd)) {
1049 *xP = (*xP) * (*yP);
1050 xP++; yP++;
1051 }
1052 return true;
1053}
1054
1055
1056void offsetVector(signalVector &x,
1057 complex offset)
1058{
1059 signalVector::iterator xP = x.begin();
1060 signalVector::iterator xPEnd = x.end();
1061 if (!x.isRealOnly()) {
1062 while (xP < xPEnd) {
1063 *xP += offset;
1064 xP++;
1065 }
1066 }
1067 else {
1068 while (xP < xPEnd) {
1069 *xP = xP->real() + offset;
1070 xP++;
1071 }
1072 }
1073}
1074
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001075bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001076{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001077 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001078 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001079 complex *data = NULL;
1080 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001081 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001082
Thomas Tsou3eaae802013-08-20 19:31:14 -04001083 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001084 return false;
1085
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001086 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001087
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001088 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1089 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1090 if (!midMidamble)
1091 return false;
1092
Thomas Tsou3eaae802013-08-20 19:31:14 -04001093 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001094 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1095 if (!midamble) {
1096 status = false;
1097 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001098 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001099
dburgessb3a0ca42011-10-12 07:44:40 +00001100 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1101 // the ideal TSC has an + 180 degree phase shift,
1102 // due to the pi/2 frequency shift, that
1103 // needs to be accounted for.
1104 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001105 scaleVector(*midMidamble, complex(-1.0, 0.0));
1106 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001107
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001108 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001109
Thomas Tsou3eaae802013-08-20 19:31:14 -04001110 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1111 data = (complex *) convolve_h_alloc(midMidamble->size());
1112 _midMidamble = new signalVector(data, 0, midMidamble->size());
1113 _midMidamble->setAligned(true);
1114 memcpy(_midMidamble->begin(), midMidamble->begin(),
1115 midMidamble->size() * sizeof(complex));
1116
1117 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001118 if (!autocorr) {
1119 status = false;
1120 goto release;
1121 }
dburgessb3a0ca42011-10-12 07:44:40 +00001122
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001123 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001124 gMidambles[tsc]->buffer = data;
1125 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001126 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1127
1128 /* For 1 sps only
1129 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1130 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1131 */
1132 if (sps == 1)
1133 gMidambles[tsc]->toa = toa - 13.5;
1134 else
1135 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001136
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001137release:
dburgessb3a0ca42011-10-12 07:44:40 +00001138 delete autocorr;
1139 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001140 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001141
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001142 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001143 delete _midMidamble;
1144 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001145 gMidambles[tsc] = NULL;
1146 }
1147
1148 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001149}
1150
Thomas Tsou83e06892013-08-20 16:10:01 -04001151bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001152{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001153 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001154 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001155 complex *data = NULL;
1156 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001157 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001158
1159 delete gRACHSequence;
1160
1161 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1162 if (!seq0)
1163 return false;
1164
1165 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1166 if (!seq1) {
1167 status = false;
1168 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001169 }
1170
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001171 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001172
Thomas Tsou3eaae802013-08-20 19:31:14 -04001173 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1174 data = (complex *) convolve_h_alloc(seq1->size());
1175 _seq1 = new signalVector(data, 0, seq1->size());
1176 _seq1->setAligned(true);
1177 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1178
1179 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1180 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001181 status = false;
1182 goto release;
1183 }
dburgessb3a0ca42011-10-12 07:44:40 +00001184
1185 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001186 gRACHSequence->sequence = _seq1;
1187 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001188 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1189
1190 /* For 1 sps only
1191 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1192 * 20.5 = (40 / 2 - 1) + 1.5
1193 */
1194 if (sps == 1)
1195 gRACHSequence->toa = toa - 20.5;
1196 else
1197 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001198
1199release:
dburgessb3a0ca42011-10-12 07:44:40 +00001200 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001201 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001202 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001203
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001204 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001205 delete _seq1;
1206 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001207 gRACHSequence = NULL;
1208 }
dburgessb3a0ca42011-10-12 07:44:40 +00001209
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001210 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001211}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001212
Thomas Tsou865bca42013-08-21 20:58:00 -04001213static float computePeakRatio(signalVector *corr,
1214 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001215{
Thomas Tsou865bca42013-08-21 20:58:00 -04001216 int num = 0;
1217 complex *peak;
1218 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001219
Thomas Tsou865bca42013-08-21 20:58:00 -04001220 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001221
Thomas Tsou865bca42013-08-21 20:58:00 -04001222 /* Check for bogus results */
1223 if ((toa < 0.0) || (toa > corr->size()))
1224 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001225
Thomas Tsou3eaae802013-08-20 19:31:14 -04001226 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001227 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001228 avg += (peak - i)->norm2();
1229 num++;
1230 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001231 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001232 avg += (peak + i)->norm2();
1233 num++;
1234 }
dburgessb3a0ca42011-10-12 07:44:40 +00001235 }
1236
Thomas Tsou3eaae802013-08-20 19:31:14 -04001237 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001238 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001239
Thomas Tsou3eaae802013-08-20 19:31:14 -04001240 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001241
Thomas Tsou865bca42013-08-21 20:58:00 -04001242 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001243}
1244
1245bool energyDetect(signalVector &rxBurst,
1246 unsigned windowLength,
1247 float detectThreshold,
1248 float *avgPwr)
1249{
1250
1251 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1252 float energy = 0.0;
1253 if (windowLength < 0) windowLength = 20;
1254 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1255 for (unsigned i = 0; i < windowLength; i++) {
1256 energy += windowItr->norm2();
1257 windowItr+=4;
1258 }
1259 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001260 return (energy/windowLength > detectThreshold*detectThreshold);
1261}
dburgessb3a0ca42011-10-12 07:44:40 +00001262
Thomas Tsou865bca42013-08-21 20:58:00 -04001263/*
1264 * Detect a burst based on correlation and peak-to-average ratio
1265 *
1266 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1267 * for initial gating. We do this because energy detection should be disabled.
1268 * For higher oversampling values, we assume the energy detector is in place
1269 * and we run full interpolating peak detection.
1270 */
1271static int detectBurst(signalVector &burst,
1272 signalVector &corr, CorrelationSequence *sync,
1273 float thresh, int sps, complex *amp, float *toa,
1274 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001275{
Thomas Tsou865bca42013-08-21 20:58:00 -04001276 /* Correlate */
1277 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001278 CUSTOM, start, len, sps, 0)) {
1279 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001280 }
1281
Thomas Tsou865bca42013-08-21 20:58:00 -04001282 /* Peak detection - place restrictions at correlation edges */
1283 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001284
Thomas Tsou865bca42013-08-21 20:58:00 -04001285 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1286 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001287
Thomas Tsou865bca42013-08-21 20:58:00 -04001288 /* Peak -to-average ratio */
1289 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1290 return 0;
1291
1292 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1293 *amp = peakDetect(corr, toa, NULL);
1294
1295 /* Normalize our channel gain */
1296 *amp = *amp / sync->gain;
1297
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001298 /* Compenate for residual rotation with dual Laurent pulse */
1299 if (sps == 4)
1300 *amp = *amp * complex(0.0, 1.0);
1301
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001302 /* Compensate for residuate time lag */
1303 *toa = *toa - sync->toa;
1304
Thomas Tsou865bca42013-08-21 20:58:00 -04001305 return 1;
1306}
1307
1308/*
1309 * RACH burst detection
1310 *
1311 * Correlation window parameters:
1312 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001313 * head: Search 4 symbols before target
1314 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001315 */
1316int detectRACHBurst(signalVector &rxBurst,
1317 float thresh,
1318 int sps,
1319 complex *amp,
1320 float *toa)
1321{
1322 int rc, start, target, head, tail, len;
1323 float _toa;
1324 complex _amp;
1325 signalVector corr;
1326 CorrelationSequence *sync;
1327
1328 if ((sps != 1) && (sps != 4))
1329 return -1;
1330
1331 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001332 head = 4;
1333 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001334
1335 start = (target - head) * sps - 1;
1336 len = (head + tail) * sps;
1337 sync = gRACHSequence;
1338 corr = signalVector(len);
1339
1340 rc = detectBurst(rxBurst, corr, sync,
1341 thresh, sps, &_amp, &_toa, start, len);
1342 if (rc < 0) {
1343 return -1;
1344 } else if (!rc) {
1345 if (amp)
1346 *amp = 0.0f;
1347 if (toa)
1348 *toa = 0.0f;
1349 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001350 }
1351
Thomas Tsou865bca42013-08-21 20:58:00 -04001352 /* Subtract forward search bits from delay */
1353 if (toa)
1354 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001355 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001356 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001357
Thomas Tsou865bca42013-08-21 20:58:00 -04001358 return 1;
1359}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001360
Thomas Tsou865bca42013-08-21 20:58:00 -04001361/*
1362 * Normal burst detection
1363 *
1364 * Correlation window parameters:
1365 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001366 * head: Search 4 symbols before target
1367 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001368 */
1369int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1370 int sps, complex *amp, float *toa, unsigned max_toa,
1371 bool chan_req, signalVector **chan, float *chan_offset)
1372{
1373 int rc, start, target, head, tail, len;
1374 complex _amp;
1375 float _toa;
1376 signalVector corr;
1377 CorrelationSequence *sync;
1378
1379 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1380 return -1;
1381
1382 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001383 head = 4;
1384 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001385
1386 start = (target - head) * sps - 1;
1387 len = (head + tail) * sps;
1388 sync = gMidambles[tsc];
1389 corr = signalVector(len);
1390
1391 rc = detectBurst(rxBurst, corr, sync,
1392 thresh, sps, &_amp, &_toa, start, len);
1393 if (rc < 0) {
1394 return -1;
1395 } else if (!rc) {
1396 if (amp)
1397 *amp = 0.0f;
1398 if (toa)
1399 *toa = 0.0f;
1400 return 0;
1401 }
1402
1403 /* Subtract forward search bits from delay */
1404 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001405 if (toa)
1406 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001407 if (amp)
1408 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001409
Thomas Tsou865bca42013-08-21 20:58:00 -04001410 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001411 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001412 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001413
1414 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001415 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001416 }
1417
Thomas Tsou3eaae802013-08-20 19:31:14 -04001418 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001419}
1420
1421signalVector *decimateVector(signalVector &wVector,
1422 int decimationFactor)
1423{
1424
1425 if (decimationFactor <= 1) return NULL;
1426
1427 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
1428 decVector->isRealOnly(wVector.isRealOnly());
1429
1430 signalVector::iterator vecItr = decVector->begin();
1431 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1432 *vecItr++ = wVector[i];
1433
1434 return decVector;
1435}
1436
1437
Thomas Tsou83e06892013-08-20 16:10:01 -04001438SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
1439 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001440{
1441 scaleVector(rxBurst,((complex) 1.0)/channel);
1442 delayVector(rxBurst,-TOA);
1443
1444 signalVector *shapedBurst = &rxBurst;
1445
1446 // shift up by a quarter of a frequency
1447 // ignore starting phase, since spec allows for discontinuous phase
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001448 GMSKReverseRotate(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001449
1450 // run through slicer
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001451 if (sps > 1) {
1452 signalVector *decShapedBurst = decimateVector(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001453 shapedBurst = decShapedBurst;
1454 }
1455
dburgessb3a0ca42011-10-12 07:44:40 +00001456 vectorSlicer(shapedBurst);
1457
1458 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1459
1460 SoftVector::iterator burstItr = burstBits->begin();
1461 signalVector::iterator shapedItr = shapedBurst->begin();
1462 for (; shapedItr < shapedBurst->end(); shapedItr++)
1463 *burstItr++ = shapedItr->real();
1464
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001465 if (sps > 1)
1466 delete shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +00001467
1468 return burstBits;
1469
1470}
dburgessb3a0ca42011-10-12 07:44:40 +00001471
dburgessb3a0ca42011-10-12 07:44:40 +00001472// Assumes symbol-spaced sampling!!!
1473// Based upon paper by Al-Dhahir and Cioffi
1474bool designDFE(signalVector &channelResponse,
1475 float SNRestimate,
1476 int Nf,
1477 signalVector **feedForwardFilter,
1478 signalVector **feedbackFilter)
1479{
1480
1481 signalVector G0(Nf);
1482 signalVector G1(Nf);
1483 signalVector::iterator G0ptr = G0.begin();
1484 signalVector::iterator G1ptr = G1.begin();
1485 signalVector::iterator chanPtr = channelResponse.begin();
1486
1487 int nu = channelResponse.size()-1;
1488
1489 *G0ptr = 1.0/sqrtf(SNRestimate);
1490 for(int j = 0; j <= nu; j++) {
1491 *G1ptr = chanPtr->conj();
1492 G1ptr++; chanPtr++;
1493 }
1494
1495 signalVector *L[Nf];
1496 signalVector::iterator Lptr;
1497 float d;
1498 for(int i = 0; i < Nf; i++) {
1499 d = G0.begin()->norm2() + G1.begin()->norm2();
1500 L[i] = new signalVector(Nf+nu);
1501 Lptr = L[i]->begin()+i;
1502 G0ptr = G0.begin(); G1ptr = G1.begin();
1503 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1504 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1505 Lptr++;
1506 G0ptr++;
1507 G1ptr++;
1508 }
1509 complex k = (*G1.begin())/(*G0.begin());
1510
1511 if (i != Nf-1) {
1512 signalVector G0new = G1;
1513 scaleVector(G0new,k.conj());
1514 addVector(G0new,G0);
1515
1516 signalVector G1new = G0;
1517 scaleVector(G1new,k*(-1.0));
1518 addVector(G1new,G1);
1519 delayVector(G1new,-1.0);
1520
1521 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1522 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1523 G0 = G0new;
1524 G1 = G1new;
1525 }
1526 }
1527
1528 *feedbackFilter = new signalVector(nu);
1529 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1530 scaleVector(**feedbackFilter,(complex) -1.0);
1531 conjugateVector(**feedbackFilter);
1532
1533 signalVector v(Nf);
1534 signalVector::iterator vStart = v.begin();
1535 signalVector::iterator vPtr;
1536 *(vStart+Nf-1) = (complex) 1.0;
1537 for(int k = Nf-2; k >= 0; k--) {
1538 Lptr = L[k]->begin()+k+1;
1539 vPtr = vStart + k+1;
1540 complex v_k = 0.0;
1541 for (int j = k+1; j < Nf; j++) {
1542 v_k -= (*vPtr)*(*Lptr);
1543 vPtr++; Lptr++;
1544 }
1545 *(vStart + k) = v_k;
1546 }
1547
1548 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001549 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001550 for (int i = 0; i < Nf; i++) {
1551 delete L[i];
1552 complex w_i = 0.0;
1553 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1554 vPtr = vStart+i;
1555 chanPtr = channelResponse.begin();
1556 for (int k = 0; k < endPt+1; k++) {
1557 w_i += (*vPtr)*(chanPtr->conj());
1558 vPtr++; chanPtr++;
1559 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001560 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001561 }
1562
1563
1564 return true;
1565
1566}
1567
1568// Assumes symbol-rate sampling!!!!
1569SoftVector *equalizeBurst(signalVector &rxBurst,
1570 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001571 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001572 signalVector &w, // feedforward filter
1573 signalVector &b) // feedback filter
1574{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001575 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001576
Thomas Tsou3eaae802013-08-20 19:31:14 -04001577 if (!delayVector(rxBurst, -TOA))
1578 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001579
Thomas Tsou3eaae802013-08-20 19:31:14 -04001580 postForwardFull = convolve(&rxBurst, &w, NULL,
1581 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1582 if (!postForwardFull)
1583 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001584
1585 signalVector* postForward = new signalVector(rxBurst.size());
1586 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1587 delete postForwardFull;
1588
1589 signalVector::iterator dPtr = postForward->begin();
1590 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001591 signalVector::iterator rotPtr = GMSKRotationN->begin();
1592 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001593
1594 signalVector *DFEoutput = new signalVector(postForward->size());
1595 signalVector::iterator DFEItr = DFEoutput->begin();
1596
1597 // NOTE: can insert the midamble and/or use midamble to estimate BER
1598 for (; dPtr < postForward->end(); dPtr++) {
1599 dBackPtr = dPtr-1;
1600 signalVector::iterator bPtr = b.begin();
1601 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1602 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1603 bPtr++;
1604 dBackPtr--;
1605 }
1606 *dPtr = *dPtr * (*revRotPtr);
1607 *DFEItr = *dPtr;
1608 // make decision on symbol
1609 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1610 //*DFEItr = *dPtr;
1611 *dPtr = *dPtr * (*rotPtr);
1612 DFEItr++;
1613 rotPtr++;
1614 revRotPtr++;
1615 }
1616
1617 vectorSlicer(DFEoutput);
1618
1619 SoftVector *burstBits = new SoftVector(postForward->size());
1620 SoftVector::iterator burstItr = burstBits->begin();
1621 DFEItr = DFEoutput->begin();
1622 for (; DFEItr < DFEoutput->end(); DFEItr++)
1623 *burstItr++ = DFEItr->real();
1624
1625 delete postForward;
1626
1627 delete DFEoutput;
1628
1629 return burstBits;
1630}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001631
1632bool sigProcLibSetup(int sps)
1633{
1634 if ((sps != 1) && (sps != 4))
1635 return false;
1636
1637 initTrigTables();
1638 initGMSKRotationTables(sps);
1639
1640 GSMPulse1 = generateGSMPulse(1, 2);
1641 if (sps > 1)
1642 GSMPulse = generateGSMPulse(sps, 2);
1643
1644 if (!generateRACHSequence(1)) {
1645 sigProcLibDestroy();
1646 return false;
1647 }
1648
1649 return true;
1650}