blob: 23538f37745cf0c4f9be9fff3b1996de07bdac0f [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;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500372 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400373 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500374
375 if (x->getStartIndex() < head)
376 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000377 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400378 case NO_DELAY:
379 start = h->size() / 2;
380 head = start;
381 tail = start;
382 len = x->size();
383 append = true;
384 break;
385 case CUSTOM:
386 if (start < h->size() - 1) {
387 head = h->size() - start;
388 append = true;
389 }
390 if (start + len > x->size()) {
391 tail = start + len - x->size();
392 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000393 }
394 break;
395 default:
396 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000397 }
dburgessb3a0ca42011-10-12 07:44:40 +0000398
Thomas Tsou3eaae802013-08-20 19:31:14 -0400399 /*
400 * Error if the output vector is too small. Create the output vector
401 * if the pointer is NULL.
402 */
403 if (y && (len > y->size()))
404 return NULL;
405 if (!y) {
406 y = new signalVector(len);
407 alloc = true;
408 }
409
410 /* Prepend or post-pend the input vector if the parameters require it */
411 if (append)
412 _x = new signalVector(*x, head, tail);
413 else
414 _x = x;
415
416 /*
417 * Four convovle types:
418 * 1. Complex-Real (aligned)
419 * 2. Complex-Complex (aligned)
420 * 3. Complex-Real (!aligned)
421 * 4. Complex-Complex (!aligned)
422 */
423 if (h->isRealOnly() && h->isAligned()) {
424 rc = convolve_real((float *) _x->begin(), _x->size(),
425 (float *) h->begin(), h->size(),
426 (float *) y->begin(), y->size(),
427 start, len, step, offset);
428 } else if (!h->isRealOnly() && h->isAligned()) {
429 rc = convolve_complex((float *) _x->begin(), _x->size(),
430 (float *) h->begin(), h->size(),
431 (float *) y->begin(), y->size(),
432 start, len, step, offset);
433 } else if (h->isRealOnly() && !h->isAligned()) {
434 rc = base_convolve_real((float *) _x->begin(), _x->size(),
435 (float *) h->begin(), h->size(),
436 (float *) y->begin(), y->size(),
437 start, len, step, offset);
438 } else if (!h->isRealOnly() && !h->isAligned()) {
439 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
440 (float *) h->begin(), h->size(),
441 (float *) y->begin(), y->size(),
442 start, len, step, offset);
443 } else {
444 rc = -1;
445 }
446
447 if (append)
448 delete _x;
449
450 if (rc < 0) {
451 if (alloc)
452 delete y;
453 return NULL;
454 }
455
456 return y;
457}
dburgessb3a0ca42011-10-12 07:44:40 +0000458
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400459static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800460{
461 int len;
462
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400463 if (!pulse)
464 return false;
465
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800466 switch (sps) {
467 case 4:
468 len = 8;
469 break;
470 default:
471 return false;
472 }
473
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400474 pulse->c1_buffer = convolve_h_alloc(len);
475 pulse->c1 = new signalVector((complex *)
476 pulse->c1_buffer, 0, len);
477 pulse->c1->isRealOnly(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800478
479 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400480 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800481
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400482 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800483
484 switch (sps) {
485 case 4:
486 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400487 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800488 *xP++ = 8.16373112e-03;
489 *xP++ = 2.84385729e-02;
490 *xP++ = 5.64158904e-02;
491 *xP++ = 7.05463553e-02;
492 *xP++ = 5.64158904e-02;
493 *xP++ = 2.84385729e-02;
494 *xP++ = 8.16373112e-03;
495 }
496
497 return true;
498}
499
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400500static PulseSequence *generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000501{
Thomas Tsou83e06892013-08-20 16:10:01 -0400502 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800503 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400504 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400505
506 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400507 pulse = new PulseSequence();
508 pulse->empty = new signalVector(1);
509 pulse->empty->isRealOnly(true);
510 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400511
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400512 /*
513 * For 4 samples-per-symbol use a precomputed single pulse Laurent
514 * approximation. This should yields below 2 degrees of phase error at
515 * the modulator output. Use the existing pulse approximation for all
516 * other oversampling factors.
517 */
518 switch (sps) {
519 case 4:
520 len = 16;
521 break;
522 default:
523 len = sps * symbolLength;
524 if (len < 4)
525 len = 4;
526 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400527
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400528 pulse->c0_buffer = convolve_h_alloc(len);
529 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
530 pulse->c0->isRealOnly(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400531
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800532 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400533 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800534
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400535 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400536
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400537 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800538 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400539 *xP++ = 4.46348606e-03;
540 *xP++ = 2.84385729e-02;
541 *xP++ = 1.03184855e-01;
542 *xP++ = 2.56065552e-01;
543 *xP++ = 4.76375085e-01;
544 *xP++ = 7.05961177e-01;
545 *xP++ = 8.71291644e-01;
546 *xP++ = 9.29453645e-01;
547 *xP++ = 8.71291644e-01;
548 *xP++ = 7.05961177e-01;
549 *xP++ = 4.76375085e-01;
550 *xP++ = 2.56065552e-01;
551 *xP++ = 1.03184855e-01;
552 *xP++ = 2.84385729e-02;
553 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400554 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400555 } else {
556 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400557
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400558 /* GSM pulse approximation */
559 for (int i = 0; i < len; i++) {
560 arg = ((float) i - center) / (float) sps;
561 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
562 0.527 * arg * arg * arg * arg);
563 }
dburgessb3a0ca42011-10-12 07:44:40 +0000564
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400565 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
566 xP = pulse->c0->begin();
567 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800568 *xP++ /= avg;
569 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400570
571 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000572}
573
574signalVector* frequencyShift(signalVector *y,
575 signalVector *x,
576 float freq,
577 float startPhase,
578 float *finalPhase)
579{
580
581 if (!x) return NULL;
582
583 if (y==NULL) {
584 y = new signalVector(x->size());
585 y->isRealOnly(x->isRealOnly());
586 if (y==NULL) return NULL;
587 }
588
589 if (y->size() < x->size()) return NULL;
590
591 float phase = startPhase;
592 signalVector::iterator yP = y->begin();
593 signalVector::iterator xPEnd = x->end();
594 signalVector::iterator xP = x->begin();
595
596 if (x->isRealOnly()) {
597 while (xP < xPEnd) {
598 (*yP++) = expjLookup(phase)*( (xP++)->real() );
599 phase += freq;
600 }
601 }
602 else {
603 while (xP < xPEnd) {
604 (*yP++) = (*xP++)*expjLookup(phase);
605 phase += freq;
606 }
607 }
608
609
610 if (finalPhase) *finalPhase = phase;
611
612 return y;
613}
614
615signalVector* reverseConjugate(signalVector *b)
616{
617 signalVector *tmp = new signalVector(b->size());
618 tmp->isRealOnly(b->isRealOnly());
619 signalVector::iterator bP = b->begin();
620 signalVector::iterator bPEnd = b->end();
621 signalVector::iterator tmpP = tmp->end()-1;
622 if (!b->isRealOnly()) {
623 while (bP < bPEnd) {
624 *tmpP-- = bP->conj();
625 bP++;
626 }
627 }
628 else {
629 while (bP < bPEnd) {
630 *tmpP-- = bP->real();
631 bP++;
632 }
633 }
634
635 return tmp;
636}
637
dburgessb3a0ca42011-10-12 07:44:40 +0000638/* soft output slicer */
639bool vectorSlicer(signalVector *x)
640{
641
642 signalVector::iterator xP = x->begin();
643 signalVector::iterator xPEnd = x->end();
644 while (xP < xPEnd) {
645 *xP = (complex) (0.5*(xP->real()+1.0F));
646 if (xP->real() > 1.0) *xP = 1.0;
647 if (xP->real() < 0.0) *xP = 0.0;
648 xP++;
649 }
650 return true;
651}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400652
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800653static signalVector *rotateBurst(const BitVector &wBurst,
654 int guardPeriodLength, int sps)
655{
656 int burst_len;
657 signalVector *pulse, rotated, *shaped;
658 signalVector::iterator itr;
659
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400660 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800661 burst_len = sps * (wBurst.size() + guardPeriodLength);
662 rotated = signalVector(burst_len);
663 itr = rotated.begin();
664
665 for (unsigned i = 0; i < wBurst.size(); i++) {
666 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
667 itr += sps;
668 }
669
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400670 GMSKRotate(rotated, sps);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800671 rotated.isRealOnly(false);
672
673 /* Dummy filter operation */
674 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
675 if (!shaped)
676 return NULL;
677
678 return shaped;
679}
680
681static signalVector *modulateBurstLaurent(const BitVector &bits,
682 int guard_len, int sps)
683{
684 int burst_len;
685 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500686 signalVector *c0_pulse, *c1_pulse, *c0_burst;
687 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800688 signalVector::iterator c0_itr, c1_itr;
689
690 /*
691 * Apply before and after bits to reduce phase error at burst edges.
692 * Make sure there is enough room in the burst to accomodate all bits.
693 */
694 if (guard_len < 4)
695 guard_len = 4;
696
697 c0_pulse = GSMPulse->c0;
698 c1_pulse = GSMPulse->c1;
699
700 burst_len = sps * (bits.size() + guard_len);
701
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500702 c0_burst = new signalVector(burst_len, c0_pulse->size());
703 c0_burst->isRealOnly(true);
704 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800705
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500706 c1_burst = new signalVector(burst_len, c1_pulse->size());
707 c1_burst->isRealOnly(true);
708 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800709
710 /* Padded differential start bits */
711 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
712 c0_itr += sps;
713
714 /* Main burst bits */
715 for (unsigned i = 0; i < bits.size(); i++) {
716 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
717 c0_itr += sps;
718 }
719
720 /* Padded differential end bits */
721 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
722
723 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500724 GMSKRotate(*c0_burst, sps);
725 c0_burst->isRealOnly(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800726
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500727 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800728 c0_itr += sps * 2;
729 c1_itr += sps * 2;
730
731 /* Start magic */
732 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
733 *c1_itr = *c0_itr * Complex<float>(0, phase);
734 c0_itr += sps;
735 c1_itr += sps;
736
737 /* Generate C1 phase coefficients */
738 for (unsigned i = 2; i < bits.size(); i++) {
739 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
740 *c1_itr = *c0_itr * Complex<float>(0, phase);
741
742 c0_itr += sps;
743 c1_itr += sps;
744 }
745
746 /* End magic */
747 int i = bits.size();
748 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
749 *c1_itr = *c0_itr * Complex<float>(0, phase);
750
751 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500752 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
753 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800754
755 /* Sum shaped outputs into C0 */
756 c0_itr = c0_shaped->begin();
757 c1_itr = c1_shaped->begin();
758 for (unsigned i = 0; i < c0_shaped->size(); i++ )
759 *c0_itr++ += *c1_itr++;
760
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500761 delete c0_burst;
762 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800763 delete c1_shaped;
764
765 return c0_shaped;
766}
767
768static signalVector *modulateBurstBasic(const BitVector &bits,
769 int guard_len, int sps)
770{
771 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500772 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800773 signalVector::iterator burst_itr;
774
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400775 if (sps == 1)
776 pulse = GSMPulse1->c0;
777 else
778 pulse = GSMPulse->c0;
779
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800780 burst_len = sps * (bits.size() + guard_len);
781
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500782 burst = new signalVector(burst_len, pulse->size());
783 burst->isRealOnly(true);
784 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800785
786 /* Raw bits are not differentially encoded */
787 for (unsigned i = 0; i < bits.size(); i++) {
788 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
789 burst_itr += sps;
790 }
791
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500792 GMSKRotate(*burst, sps);
793 burst->isRealOnly(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800794
795 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500796 shaped = convolve(burst, pulse, NULL, START_ONLY);
797
798 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800799
800 return shaped;
801}
802
Thomas Tsou3eaae802013-08-20 19:31:14 -0400803/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400804signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
805 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000806{
Thomas Tsou83e06892013-08-20 16:10:01 -0400807 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800808 return rotateBurst(wBurst, guardPeriodLength, sps);
809 else if (sps == 4)
810 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400811 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800812 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000813}
814
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800815float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000816{
817 if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
818 return 1.0F;
819}
820
Thomas Tsou3eaae802013-08-20 19:31:14 -0400821bool delayVector(signalVector &wBurst, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000822{
Thomas Tsou2c282f52013-10-08 21:34:35 -0400823 int whole, h_len = 20;
824 float frac;
825 complex *data;
826 signalVector *h, *shift;
827 signalVector::iterator itr;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400828
Thomas Tsou2c282f52013-10-08 21:34:35 -0400829 whole = floor(delay);
830 frac = delay - whole;
831
832 /* Sinc interpolated fractional shift (if allowable) */
833 if (fabs(frac) > 1e-2) {
834 data = (complex *) convolve_h_alloc(h_len);
835 h = new signalVector(data, 0, h_len);
836 h->setAligned(true);
837 h->isRealOnly(true);
838
839 itr = h->end();
840 for (int i = 0; i < h_len; i++)
841 *--itr = (complex) sinc(M_PI_F * (i - h_len / 2 - frac));
842
843 shift = convolve(&wBurst, h, NULL, NO_DELAY);
844
845 delete h;
846 free(data);
847
848 if (!shift)
Thomas Tsou3eaae802013-08-20 19:31:14 -0400849 return false;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400850
851 wBurst.clone(*shift);
852 delete shift;
dburgessb3a0ca42011-10-12 07:44:40 +0000853 }
854
Thomas Tsou2c282f52013-10-08 21:34:35 -0400855 /* Integer sample shift */
856 if (whole < 0) {
857 whole = -whole;
dburgessb3a0ca42011-10-12 07:44:40 +0000858 signalVector::iterator wBurstItr = wBurst.begin();
Thomas Tsou2c282f52013-10-08 21:34:35 -0400859 signalVector::iterator shiftedItr = wBurst.begin() + whole;
860
dburgessb3a0ca42011-10-12 07:44:40 +0000861 while (shiftedItr < wBurst.end())
862 *wBurstItr++ = *shiftedItr++;
863 while (wBurstItr < wBurst.end())
864 *wBurstItr++ = 0.0;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400865 } else {
866 signalVector::iterator wBurstItr = wBurst.end() - 1;
867 signalVector::iterator shiftedItr = wBurst.end() - 1 - whole;
868
dburgessb3a0ca42011-10-12 07:44:40 +0000869 while (shiftedItr >= wBurst.begin())
870 *wBurstItr-- = *shiftedItr--;
871 while (wBurstItr >= wBurst.begin())
872 *wBurstItr-- = 0.0;
873 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400874
875 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000876}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400877
dburgessb3a0ca42011-10-12 07:44:40 +0000878signalVector *gaussianNoise(int length,
879 float variance,
880 complex mean)
881{
882
883 signalVector *noise = new signalVector(length);
884 signalVector::iterator nPtr = noise->begin();
885 float stddev = sqrtf(variance);
886 while (nPtr < noise->end()) {
887 float u1 = (float) rand()/ (float) RAND_MAX;
888 while (u1==0.0)
889 u1 = (float) rand()/ (float) RAND_MAX;
890 float u2 = (float) rand()/ (float) RAND_MAX;
891 float arg = 2.0*M_PI*u2;
892 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
893 nPtr++;
894 }
895
896 return noise;
897}
898
899complex interpolatePoint(const signalVector &inSig,
900 float ix)
901{
902
903 int start = (int) (floor(ix) - 10);
904 if (start < 0) start = 0;
905 int end = (int) (floor(ix) + 11);
906 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
907
908 complex pVal = 0.0;
909 if (!inSig.isRealOnly()) {
910 for (int i = start; i < end; i++)
911 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
912 }
913 else {
914 for (int i = start; i < end; i++)
915 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
916 }
917
918 return pVal;
919}
920
Thomas Tsou8181b012013-08-20 21:17:19 -0400921static complex fastPeakDetect(const signalVector &rxBurst, float *index)
922{
923 float val, max = 0.0f;
924 complex amp;
925 int _index = -1;
926
927 for (int i = 0; i < rxBurst.size(); i++) {
928 val = rxBurst[i].norm2();
929 if (val > max) {
930 max = val;
931 _index = i;
932 amp = rxBurst[i];
933 }
934 }
935
936 if (index)
937 *index = (float) _index;
938
939 return amp;
940}
941
dburgessb3a0ca42011-10-12 07:44:40 +0000942complex peakDetect(const signalVector &rxBurst,
943 float *peakIndex,
944 float *avgPwr)
945{
946
947
948 complex maxVal = 0.0;
949 float maxIndex = -1;
950 float sumPower = 0.0;
951
952 for (unsigned int i = 0; i < rxBurst.size(); i++) {
953 float samplePower = rxBurst[i].norm2();
954 if (samplePower > maxVal.real()) {
955 maxVal = samplePower;
956 maxIndex = i;
957 }
958 sumPower += samplePower;
959 }
960
961 // interpolate around the peak
962 // to save computation, we'll use early-late balancing
963 float earlyIndex = maxIndex-1;
964 float lateIndex = maxIndex+1;
965
966 float incr = 0.5;
967 while (incr > 1.0/1024.0) {
968 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
969 complex lateP = interpolatePoint(rxBurst,lateIndex);
970 if (earlyP < lateP)
971 earlyIndex += incr;
972 else if (earlyP > lateP)
973 earlyIndex -= incr;
974 else break;
975 incr /= 2.0;
976 lateIndex = earlyIndex + 2.0;
977 }
978
979 maxIndex = earlyIndex + 1.0;
980 maxVal = interpolatePoint(rxBurst,maxIndex);
981
982 if (peakIndex!=NULL)
983 *peakIndex = maxIndex;
984
985 if (avgPwr!=NULL)
986 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
987
988 return maxVal;
989
990}
991
992void scaleVector(signalVector &x,
993 complex scale)
994{
Thomas Tsou7e4e5362013-10-30 21:18:55 -0400995#ifdef HAVE_NEON
996 int len = x.size();
997
998 scale_complex((float *) x.begin(),
999 (float *) x.begin(),
1000 (float *) &scale, len);
1001#else
dburgessb3a0ca42011-10-12 07:44:40 +00001002 signalVector::iterator xP = x.begin();
1003 signalVector::iterator xPEnd = x.end();
1004 if (!x.isRealOnly()) {
1005 while (xP < xPEnd) {
1006 *xP = *xP * scale;
1007 xP++;
1008 }
1009 }
1010 else {
1011 while (xP < xPEnd) {
1012 *xP = xP->real() * scale;
1013 xP++;
1014 }
1015 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001016#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001017}
1018
1019/** in-place conjugation */
1020void conjugateVector(signalVector &x)
1021{
1022 if (x.isRealOnly()) return;
1023 signalVector::iterator xP = x.begin();
1024 signalVector::iterator xPEnd = x.end();
1025 while (xP < xPEnd) {
1026 *xP = xP->conj();
1027 xP++;
1028 }
1029}
1030
1031
1032// in-place addition!!
1033bool addVector(signalVector &x,
1034 signalVector &y)
1035{
1036 signalVector::iterator xP = x.begin();
1037 signalVector::iterator yP = y.begin();
1038 signalVector::iterator xPEnd = x.end();
1039 signalVector::iterator yPEnd = y.end();
1040 while ((xP < xPEnd) && (yP < yPEnd)) {
1041 *xP = *xP + *yP;
1042 xP++; yP++;
1043 }
1044 return true;
1045}
1046
1047// in-place multiplication!!
1048bool multVector(signalVector &x,
1049 signalVector &y)
1050{
1051 signalVector::iterator xP = x.begin();
1052 signalVector::iterator yP = y.begin();
1053 signalVector::iterator xPEnd = x.end();
1054 signalVector::iterator yPEnd = y.end();
1055 while ((xP < xPEnd) && (yP < yPEnd)) {
1056 *xP = (*xP) * (*yP);
1057 xP++; yP++;
1058 }
1059 return true;
1060}
1061
1062
1063void offsetVector(signalVector &x,
1064 complex offset)
1065{
1066 signalVector::iterator xP = x.begin();
1067 signalVector::iterator xPEnd = x.end();
1068 if (!x.isRealOnly()) {
1069 while (xP < xPEnd) {
1070 *xP += offset;
1071 xP++;
1072 }
1073 }
1074 else {
1075 while (xP < xPEnd) {
1076 *xP = xP->real() + offset;
1077 xP++;
1078 }
1079 }
1080}
1081
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001082bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001083{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001084 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001085 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001086 complex *data = NULL;
1087 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001088 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001089
Thomas Tsou3eaae802013-08-20 19:31:14 -04001090 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001091 return false;
1092
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001093 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001094
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001095 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1096 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1097 if (!midMidamble)
1098 return false;
1099
Thomas Tsou3eaae802013-08-20 19:31:14 -04001100 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001101 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1102 if (!midamble) {
1103 status = false;
1104 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001105 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001106
dburgessb3a0ca42011-10-12 07:44:40 +00001107 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1108 // the ideal TSC has an + 180 degree phase shift,
1109 // due to the pi/2 frequency shift, that
1110 // needs to be accounted for.
1111 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001112 scaleVector(*midMidamble, complex(-1.0, 0.0));
1113 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001114
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001115 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001116
Thomas Tsou3eaae802013-08-20 19:31:14 -04001117 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1118 data = (complex *) convolve_h_alloc(midMidamble->size());
1119 _midMidamble = new signalVector(data, 0, midMidamble->size());
1120 _midMidamble->setAligned(true);
1121 memcpy(_midMidamble->begin(), midMidamble->begin(),
1122 midMidamble->size() * sizeof(complex));
1123
1124 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001125 if (!autocorr) {
1126 status = false;
1127 goto release;
1128 }
dburgessb3a0ca42011-10-12 07:44:40 +00001129
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001130 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001131 gMidambles[tsc]->buffer = data;
1132 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001133 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1134
1135 /* For 1 sps only
1136 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1137 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1138 */
1139 if (sps == 1)
1140 gMidambles[tsc]->toa = toa - 13.5;
1141 else
1142 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001143
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001144release:
dburgessb3a0ca42011-10-12 07:44:40 +00001145 delete autocorr;
1146 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001147 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001148
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001149 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001150 delete _midMidamble;
1151 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001152 gMidambles[tsc] = NULL;
1153 }
1154
1155 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001156}
1157
Thomas Tsou83e06892013-08-20 16:10:01 -04001158bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001159{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001160 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001161 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001162 complex *data = NULL;
1163 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001164 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001165
1166 delete gRACHSequence;
1167
1168 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1169 if (!seq0)
1170 return false;
1171
1172 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1173 if (!seq1) {
1174 status = false;
1175 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001176 }
1177
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001178 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001179
Thomas Tsou3eaae802013-08-20 19:31:14 -04001180 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1181 data = (complex *) convolve_h_alloc(seq1->size());
1182 _seq1 = new signalVector(data, 0, seq1->size());
1183 _seq1->setAligned(true);
1184 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1185
1186 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1187 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001188 status = false;
1189 goto release;
1190 }
dburgessb3a0ca42011-10-12 07:44:40 +00001191
1192 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001193 gRACHSequence->sequence = _seq1;
1194 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001195 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1196
1197 /* For 1 sps only
1198 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1199 * 20.5 = (40 / 2 - 1) + 1.5
1200 */
1201 if (sps == 1)
1202 gRACHSequence->toa = toa - 20.5;
1203 else
1204 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001205
1206release:
dburgessb3a0ca42011-10-12 07:44:40 +00001207 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001208 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001209 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001210
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001211 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001212 delete _seq1;
1213 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001214 gRACHSequence = NULL;
1215 }
dburgessb3a0ca42011-10-12 07:44:40 +00001216
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001217 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001218}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001219
Thomas Tsou865bca42013-08-21 20:58:00 -04001220static float computePeakRatio(signalVector *corr,
1221 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001222{
Thomas Tsou865bca42013-08-21 20:58:00 -04001223 int num = 0;
1224 complex *peak;
1225 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001226
Thomas Tsou865bca42013-08-21 20:58:00 -04001227 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001228
Thomas Tsou865bca42013-08-21 20:58:00 -04001229 /* Check for bogus results */
1230 if ((toa < 0.0) || (toa > corr->size()))
1231 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001232
Thomas Tsou3eaae802013-08-20 19:31:14 -04001233 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001234 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001235 avg += (peak - i)->norm2();
1236 num++;
1237 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001238 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001239 avg += (peak + i)->norm2();
1240 num++;
1241 }
dburgessb3a0ca42011-10-12 07:44:40 +00001242 }
1243
Thomas Tsou3eaae802013-08-20 19:31:14 -04001244 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001245 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001246
Thomas Tsou3eaae802013-08-20 19:31:14 -04001247 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001248
Thomas Tsou865bca42013-08-21 20:58:00 -04001249 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001250}
1251
1252bool energyDetect(signalVector &rxBurst,
1253 unsigned windowLength,
1254 float detectThreshold,
1255 float *avgPwr)
1256{
1257
1258 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1259 float energy = 0.0;
1260 if (windowLength < 0) windowLength = 20;
1261 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1262 for (unsigned i = 0; i < windowLength; i++) {
1263 energy += windowItr->norm2();
1264 windowItr+=4;
1265 }
1266 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001267 return (energy/windowLength > detectThreshold*detectThreshold);
1268}
dburgessb3a0ca42011-10-12 07:44:40 +00001269
Thomas Tsou865bca42013-08-21 20:58:00 -04001270/*
1271 * Detect a burst based on correlation and peak-to-average ratio
1272 *
1273 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1274 * for initial gating. We do this because energy detection should be disabled.
1275 * For higher oversampling values, we assume the energy detector is in place
1276 * and we run full interpolating peak detection.
1277 */
1278static int detectBurst(signalVector &burst,
1279 signalVector &corr, CorrelationSequence *sync,
1280 float thresh, int sps, complex *amp, float *toa,
1281 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001282{
Thomas Tsou865bca42013-08-21 20:58:00 -04001283 /* Correlate */
1284 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001285 CUSTOM, start, len, sps, 0)) {
1286 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001287 }
1288
Thomas Tsou865bca42013-08-21 20:58:00 -04001289 /* Peak detection - place restrictions at correlation edges */
1290 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001291
Thomas Tsou865bca42013-08-21 20:58:00 -04001292 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1293 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001294
Thomas Tsou865bca42013-08-21 20:58:00 -04001295 /* Peak -to-average ratio */
1296 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1297 return 0;
1298
1299 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1300 *amp = peakDetect(corr, toa, NULL);
1301
1302 /* Normalize our channel gain */
1303 *amp = *amp / sync->gain;
1304
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001305 /* Compenate for residual rotation with dual Laurent pulse */
1306 if (sps == 4)
1307 *amp = *amp * complex(0.0, 1.0);
1308
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001309 /* Compensate for residuate time lag */
1310 *toa = *toa - sync->toa;
1311
Thomas Tsou865bca42013-08-21 20:58:00 -04001312 return 1;
1313}
1314
1315/*
1316 * RACH burst detection
1317 *
1318 * Correlation window parameters:
1319 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001320 * head: Search 4 symbols before target
1321 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001322 */
1323int detectRACHBurst(signalVector &rxBurst,
1324 float thresh,
1325 int sps,
1326 complex *amp,
1327 float *toa)
1328{
1329 int rc, start, target, head, tail, len;
1330 float _toa;
1331 complex _amp;
1332 signalVector corr;
1333 CorrelationSequence *sync;
1334
1335 if ((sps != 1) && (sps != 4))
1336 return -1;
1337
1338 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001339 head = 4;
1340 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001341
1342 start = (target - head) * sps - 1;
1343 len = (head + tail) * sps;
1344 sync = gRACHSequence;
1345 corr = signalVector(len);
1346
1347 rc = detectBurst(rxBurst, corr, sync,
1348 thresh, sps, &_amp, &_toa, start, len);
1349 if (rc < 0) {
1350 return -1;
1351 } else if (!rc) {
1352 if (amp)
1353 *amp = 0.0f;
1354 if (toa)
1355 *toa = 0.0f;
1356 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001357 }
1358
Thomas Tsou865bca42013-08-21 20:58:00 -04001359 /* Subtract forward search bits from delay */
1360 if (toa)
1361 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001362 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001363 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001364
Thomas Tsou865bca42013-08-21 20:58:00 -04001365 return 1;
1366}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001367
Thomas Tsou865bca42013-08-21 20:58:00 -04001368/*
1369 * Normal burst detection
1370 *
1371 * Correlation window parameters:
1372 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001373 * head: Search 4 symbols before target
1374 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001375 */
1376int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1377 int sps, complex *amp, float *toa, unsigned max_toa,
1378 bool chan_req, signalVector **chan, float *chan_offset)
1379{
1380 int rc, start, target, head, tail, len;
1381 complex _amp;
1382 float _toa;
1383 signalVector corr;
1384 CorrelationSequence *sync;
1385
1386 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1387 return -1;
1388
1389 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001390 head = 4;
1391 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001392
1393 start = (target - head) * sps - 1;
1394 len = (head + tail) * sps;
1395 sync = gMidambles[tsc];
1396 corr = signalVector(len);
1397
1398 rc = detectBurst(rxBurst, corr, sync,
1399 thresh, sps, &_amp, &_toa, start, len);
1400 if (rc < 0) {
1401 return -1;
1402 } else if (!rc) {
1403 if (amp)
1404 *amp = 0.0f;
1405 if (toa)
1406 *toa = 0.0f;
1407 return 0;
1408 }
1409
1410 /* Subtract forward search bits from delay */
1411 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001412 if (toa)
1413 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001414 if (amp)
1415 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001416
Thomas Tsou865bca42013-08-21 20:58:00 -04001417 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001418 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001419 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001420
1421 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001422 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001423 }
1424
Thomas Tsou3eaae802013-08-20 19:31:14 -04001425 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001426}
1427
1428signalVector *decimateVector(signalVector &wVector,
1429 int decimationFactor)
1430{
1431
1432 if (decimationFactor <= 1) return NULL;
1433
1434 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
1435 decVector->isRealOnly(wVector.isRealOnly());
1436
1437 signalVector::iterator vecItr = decVector->begin();
1438 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1439 *vecItr++ = wVector[i];
1440
1441 return decVector;
1442}
1443
1444
Thomas Tsou83e06892013-08-20 16:10:01 -04001445SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
1446 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001447{
1448 scaleVector(rxBurst,((complex) 1.0)/channel);
1449 delayVector(rxBurst,-TOA);
1450
1451 signalVector *shapedBurst = &rxBurst;
1452
1453 // shift up by a quarter of a frequency
1454 // ignore starting phase, since spec allows for discontinuous phase
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001455 GMSKReverseRotate(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001456
1457 // run through slicer
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001458 if (sps > 1) {
1459 signalVector *decShapedBurst = decimateVector(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001460 shapedBurst = decShapedBurst;
1461 }
1462
dburgessb3a0ca42011-10-12 07:44:40 +00001463 vectorSlicer(shapedBurst);
1464
1465 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1466
1467 SoftVector::iterator burstItr = burstBits->begin();
1468 signalVector::iterator shapedItr = shapedBurst->begin();
1469 for (; shapedItr < shapedBurst->end(); shapedItr++)
1470 *burstItr++ = shapedItr->real();
1471
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001472 if (sps > 1)
1473 delete shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +00001474
1475 return burstBits;
1476
1477}
dburgessb3a0ca42011-10-12 07:44:40 +00001478
dburgessb3a0ca42011-10-12 07:44:40 +00001479// Assumes symbol-spaced sampling!!!
1480// Based upon paper by Al-Dhahir and Cioffi
1481bool designDFE(signalVector &channelResponse,
1482 float SNRestimate,
1483 int Nf,
1484 signalVector **feedForwardFilter,
1485 signalVector **feedbackFilter)
1486{
1487
1488 signalVector G0(Nf);
1489 signalVector G1(Nf);
1490 signalVector::iterator G0ptr = G0.begin();
1491 signalVector::iterator G1ptr = G1.begin();
1492 signalVector::iterator chanPtr = channelResponse.begin();
1493
1494 int nu = channelResponse.size()-1;
1495
1496 *G0ptr = 1.0/sqrtf(SNRestimate);
1497 for(int j = 0; j <= nu; j++) {
1498 *G1ptr = chanPtr->conj();
1499 G1ptr++; chanPtr++;
1500 }
1501
1502 signalVector *L[Nf];
1503 signalVector::iterator Lptr;
1504 float d;
1505 for(int i = 0; i < Nf; i++) {
1506 d = G0.begin()->norm2() + G1.begin()->norm2();
1507 L[i] = new signalVector(Nf+nu);
1508 Lptr = L[i]->begin()+i;
1509 G0ptr = G0.begin(); G1ptr = G1.begin();
1510 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1511 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1512 Lptr++;
1513 G0ptr++;
1514 G1ptr++;
1515 }
1516 complex k = (*G1.begin())/(*G0.begin());
1517
1518 if (i != Nf-1) {
1519 signalVector G0new = G1;
1520 scaleVector(G0new,k.conj());
1521 addVector(G0new,G0);
1522
1523 signalVector G1new = G0;
1524 scaleVector(G1new,k*(-1.0));
1525 addVector(G1new,G1);
1526 delayVector(G1new,-1.0);
1527
1528 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1529 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1530 G0 = G0new;
1531 G1 = G1new;
1532 }
1533 }
1534
1535 *feedbackFilter = new signalVector(nu);
1536 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1537 scaleVector(**feedbackFilter,(complex) -1.0);
1538 conjugateVector(**feedbackFilter);
1539
1540 signalVector v(Nf);
1541 signalVector::iterator vStart = v.begin();
1542 signalVector::iterator vPtr;
1543 *(vStart+Nf-1) = (complex) 1.0;
1544 for(int k = Nf-2; k >= 0; k--) {
1545 Lptr = L[k]->begin()+k+1;
1546 vPtr = vStart + k+1;
1547 complex v_k = 0.0;
1548 for (int j = k+1; j < Nf; j++) {
1549 v_k -= (*vPtr)*(*Lptr);
1550 vPtr++; Lptr++;
1551 }
1552 *(vStart + k) = v_k;
1553 }
1554
1555 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001556 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001557 for (int i = 0; i < Nf; i++) {
1558 delete L[i];
1559 complex w_i = 0.0;
1560 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1561 vPtr = vStart+i;
1562 chanPtr = channelResponse.begin();
1563 for (int k = 0; k < endPt+1; k++) {
1564 w_i += (*vPtr)*(chanPtr->conj());
1565 vPtr++; chanPtr++;
1566 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001567 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001568 }
1569
1570
1571 return true;
1572
1573}
1574
1575// Assumes symbol-rate sampling!!!!
1576SoftVector *equalizeBurst(signalVector &rxBurst,
1577 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001578 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001579 signalVector &w, // feedforward filter
1580 signalVector &b) // feedback filter
1581{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001582 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001583
Thomas Tsou3eaae802013-08-20 19:31:14 -04001584 if (!delayVector(rxBurst, -TOA))
1585 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001586
Thomas Tsou3eaae802013-08-20 19:31:14 -04001587 postForwardFull = convolve(&rxBurst, &w, NULL,
1588 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1589 if (!postForwardFull)
1590 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001591
1592 signalVector* postForward = new signalVector(rxBurst.size());
1593 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1594 delete postForwardFull;
1595
1596 signalVector::iterator dPtr = postForward->begin();
1597 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001598 signalVector::iterator rotPtr = GMSKRotationN->begin();
1599 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001600
1601 signalVector *DFEoutput = new signalVector(postForward->size());
1602 signalVector::iterator DFEItr = DFEoutput->begin();
1603
1604 // NOTE: can insert the midamble and/or use midamble to estimate BER
1605 for (; dPtr < postForward->end(); dPtr++) {
1606 dBackPtr = dPtr-1;
1607 signalVector::iterator bPtr = b.begin();
1608 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1609 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1610 bPtr++;
1611 dBackPtr--;
1612 }
1613 *dPtr = *dPtr * (*revRotPtr);
1614 *DFEItr = *dPtr;
1615 // make decision on symbol
1616 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1617 //*DFEItr = *dPtr;
1618 *dPtr = *dPtr * (*rotPtr);
1619 DFEItr++;
1620 rotPtr++;
1621 revRotPtr++;
1622 }
1623
1624 vectorSlicer(DFEoutput);
1625
1626 SoftVector *burstBits = new SoftVector(postForward->size());
1627 SoftVector::iterator burstItr = burstBits->begin();
1628 DFEItr = DFEoutput->begin();
1629 for (; DFEItr < DFEoutput->end(); DFEItr++)
1630 *burstItr++ = DFEItr->real();
1631
1632 delete postForward;
1633
1634 delete DFEoutput;
1635
1636 return burstBits;
1637}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001638
1639bool sigProcLibSetup(int sps)
1640{
1641 if ((sps != 1) && (sps != 4))
1642 return false;
1643
1644 initTrigTables();
1645 initGMSKRotationTables(sps);
1646
1647 GSMPulse1 = generateGSMPulse(1, 2);
1648 if (sps > 1)
1649 GSMPulse = generateGSMPulse(sps, 2);
1650
1651 if (!generateRACHSequence(1)) {
1652 sigProcLibDestroy();
1653 return false;
1654 }
1655
1656 return true;
1657}