blob: 51584b7534ed6f08f026cfdb8609442d65c95e5f [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
dburgessb3a0ca42011-10-12 07:44:40 +000025#include "sigProcLib.h"
26#include "GSMCommon.h"
kurtis.heimerla198d452011-11-26 03:19:28 +000027#include "sendLPF_961.h"
28#include "rcvLPF_651.h"
dburgessb3a0ca42011-10-12 07:44:40 +000029
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040030using namespace GSM;
31
Thomas Tsou3eaae802013-08-20 19:31:14 -040032extern "C" {
33#include "convolve.h"
34}
35
dburgessb3a0ca42011-10-12 07:44:40 +000036#define TABLESIZE 1024
37
38/** Lookup tables for trigonometric approximation */
39float cosTable[TABLESIZE+1]; // add 1 element for wrap around
40float sinTable[TABLESIZE+1];
41
42/** Constants */
43static const float M_PI_F = (float)M_PI;
44static const float M_2PI_F = (float)(2.0*M_PI);
45static const float M_1_2PI_F = 1/M_2PI_F;
46
47/** Static vectors that contain a precomputed +/- f_b/4 sinusoid */
48signalVector *GMSKRotation = NULL;
49signalVector *GMSKReverseRotation = NULL;
50
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040051/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040052 * RACH and midamble correlation waveforms. Store the buffer separately
53 * because we need to allocate it explicitly outside of the signal vector
54 * constructor. This is because C++ (prior to C++11) is unable to natively
55 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040056 */
57struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040058 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040059 {
60 }
61
62 ~CorrelationSequence()
63 {
64 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040065 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040066 }
67
dburgessb3a0ca42011-10-12 07:44:40 +000068 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040069 void *buffer;
dburgessb3a0ca42011-10-12 07:44:40 +000070 float TOA;
71 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040072};
dburgessb3a0ca42011-10-12 07:44:40 +000073
Thomas Tsou83e06892013-08-20 16:10:01 -040074/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040075 * Gaussian and empty modulation pulses. Like the correlation sequences,
76 * store the runtime (Gaussian) buffer separately because of needed alignment
77 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -040078 */
79struct PulseSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040080 PulseSequence() : gaussian(NULL), empty(NULL), buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -040081 {
82 }
83
84 ~PulseSequence()
85 {
86 delete gaussian;
87 delete empty;
Thomas Tsou3eaae802013-08-20 19:31:14 -040088 free(buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -040089 }
90
91 signalVector *gaussian;
92 signalVector *empty;
Thomas Tsou3eaae802013-08-20 19:31:14 -040093 void *buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -040094};
95
dburgessb3a0ca42011-10-12 07:44:40 +000096CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
97CorrelationSequence *gRACHSequence = NULL;
Thomas Tsou83e06892013-08-20 16:10:01 -040098PulseSequence *GSMPulse = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000099
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400100void sigProcLibDestroy()
101{
dburgessb3a0ca42011-10-12 07:44:40 +0000102 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400103 delete gMidambles[i];
104 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000105 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400106
107 delete GMSKRotation;
108 delete GMSKReverseRotation;
109 delete gRACHSequence;
110 delete GSMPulse;
111
112 GMSKRotation = NULL;
113 GMSKReverseRotation = NULL;
114 gRACHSequence = NULL;
115 GSMPulse = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000116}
117
dburgessb3a0ca42011-10-12 07:44:40 +0000118// dB relative to 1.0.
119// if > 1.0, then return 0 dB
120float dB(float x) {
121
122 float arg = 1.0F;
123 float dB = 0.0F;
124
125 if (x >= 1.0F) return 0.0F;
126 if (x <= 0.0F) return -200.0F;
127
128 float prevArg = arg;
129 float prevdB = dB;
130 float stepSize = 16.0F;
131 float dBstepSize = 12.0F;
132 while (stepSize > 1.0F) {
133 do {
134 prevArg = arg;
135 prevdB = dB;
136 arg /= stepSize;
137 dB -= dBstepSize;
138 } while (arg > x);
139 arg = prevArg;
140 dB = prevdB;
141 stepSize *= 0.5F;
142 dBstepSize -= 3.0F;
143 }
144 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
145
146}
147
148// 10^(-dB/10), inverse of dB func.
149float dBinv(float x) {
150
151 float arg = 1.0F;
152 float dB = 0.0F;
153
154 if (x >= 0.0F) return 1.0F;
155 if (x <= -200.0F) return 0.0F;
156
157 float prevArg = arg;
158 float prevdB = dB;
159 float stepSize = 16.0F;
160 float dBstepSize = 12.0F;
161 while (stepSize > 1.0F) {
162 do {
163 prevArg = arg;
164 prevdB = dB;
165 arg /= stepSize;
166 dB -= dBstepSize;
167 } while (dB > x);
168 arg = prevArg;
169 dB = prevdB;
170 stepSize *= 0.5F;
171 dBstepSize -= 3.0F;
172 }
173
174 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
175
176}
177
178float vectorNorm2(const signalVector &x)
179{
180 signalVector::const_iterator xPtr = x.begin();
181 float Energy = 0.0;
182 for (;xPtr != x.end();xPtr++) {
183 Energy += xPtr->norm2();
184 }
185 return Energy;
186}
187
188
189float vectorPower(const signalVector &x)
190{
191 return vectorNorm2(x)/x.size();
192}
193
194/** compute cosine via lookup table */
195float cosLookup(const float x)
196{
197 float arg = x*M_1_2PI_F;
198 while (arg > 1.0F) arg -= 1.0F;
199 while (arg < 0.0F) arg += 1.0F;
200
201 const float argT = arg*((float)TABLESIZE);
202 const int argI = (int)argT;
203 const float delta = argT-argI;
204 const float iDelta = 1.0F-delta;
205 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
206}
207
208/** compute sine via lookup table */
209float sinLookup(const float x)
210{
211 float arg = x*M_1_2PI_F;
212 while (arg > 1.0F) arg -= 1.0F;
213 while (arg < 0.0F) arg += 1.0F;
214
215 const float argT = arg*((float)TABLESIZE);
216 const int argI = (int)argT;
217 const float delta = argT-argI;
218 const float iDelta = 1.0F-delta;
219 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
220}
221
222
223/** compute e^(-jx) via lookup table. */
224complex expjLookup(float x)
225{
226 float arg = x*M_1_2PI_F;
227 while (arg > 1.0F) arg -= 1.0F;
228 while (arg < 0.0F) arg += 1.0F;
229
230 const float argT = arg*((float)TABLESIZE);
231 const int argI = (int)argT;
232 const float delta = argT-argI;
233 const float iDelta = 1.0F-delta;
234 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
235 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
236}
237
238/** Library setup functions */
239void initTrigTables() {
240 for (int i = 0; i < TABLESIZE+1; i++) {
241 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
242 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
243 }
244}
245
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400246void initGMSKRotationTables(int sps)
247{
248 GMSKRotation = new signalVector(157 * sps);
249 GMSKReverseRotation = new signalVector(157 * sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000250 signalVector::iterator rotPtr = GMSKRotation->begin();
251 signalVector::iterator revPtr = GMSKReverseRotation->begin();
252 float phase = 0.0;
253 while (rotPtr != GMSKRotation->end()) {
254 *rotPtr++ = expjLookup(phase);
255 *revPtr++ = expjLookup(-phase);
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400256 phase += M_PI_F / 2.0F / (float) sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000257 }
258}
259
Thomas Tsoue57004d2013-08-20 18:55:33 -0400260bool sigProcLibSetup(int sps)
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400261{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400262 if ((sps != 1) && (sps != 2) && (sps != 4))
Thomas Tsoue57004d2013-08-20 18:55:33 -0400263 return false;
264
dburgessb3a0ca42011-10-12 07:44:40 +0000265 initTrigTables();
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400266 initGMSKRotationTables(sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400267 generateGSMPulse(sps, 2);
Thomas Tsoue57004d2013-08-20 18:55:33 -0400268
269 if (!generateRACHSequence(sps)) {
270 sigProcLibDestroy();
271 return false;
272 }
273
274 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000275}
276
277void GMSKRotate(signalVector &x) {
278 signalVector::iterator xPtr = x.begin();
279 signalVector::iterator rotPtr = GMSKRotation->begin();
280 if (x.isRealOnly()) {
281 while (xPtr < x.end()) {
282 *xPtr = *rotPtr++ * (xPtr->real());
283 xPtr++;
284 }
285 }
286 else {
287 while (xPtr < x.end()) {
288 *xPtr = *rotPtr++ * (*xPtr);
289 xPtr++;
290 }
291 }
292}
293
294void GMSKReverseRotate(signalVector &x) {
295 signalVector::iterator xPtr= x.begin();
296 signalVector::iterator rotPtr = GMSKReverseRotation->begin();
297 if (x.isRealOnly()) {
298 while (xPtr < x.end()) {
299 *xPtr = *rotPtr++ * (xPtr->real());
300 xPtr++;
301 }
302 }
303 else {
304 while (xPtr < x.end()) {
305 *xPtr = *rotPtr++ * (*xPtr);
306 xPtr++;
307 }
308 }
309}
310
Thomas Tsou3eaae802013-08-20 19:31:14 -0400311signalVector *convolve(const signalVector *x,
312 const signalVector *h,
313 signalVector *y,
314 ConvType spanType, int start,
315 unsigned len, unsigned step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000316{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400317 int rc, head = 0, tail = 0;
318 bool alloc = false, append = false;
319 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000320
Thomas Tsou3eaae802013-08-20 19:31:14 -0400321 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000322 return NULL;
323
Thomas Tsou3eaae802013-08-20 19:31:14 -0400324 switch (spanType) {
325 case START_ONLY:
326 start = 0;
327 head = h->size();
328 len = x->size();
329 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000330 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400331 case NO_DELAY:
332 start = h->size() / 2;
333 head = start;
334 tail = start;
335 len = x->size();
336 append = true;
337 break;
338 case CUSTOM:
339 if (start < h->size() - 1) {
340 head = h->size() - start;
341 append = true;
342 }
343 if (start + len > x->size()) {
344 tail = start + len - x->size();
345 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000346 }
347 break;
348 default:
349 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000350 }
dburgessb3a0ca42011-10-12 07:44:40 +0000351
Thomas Tsou3eaae802013-08-20 19:31:14 -0400352 /*
353 * Error if the output vector is too small. Create the output vector
354 * if the pointer is NULL.
355 */
356 if (y && (len > y->size()))
357 return NULL;
358 if (!y) {
359 y = new signalVector(len);
360 alloc = true;
361 }
362
363 /* Prepend or post-pend the input vector if the parameters require it */
364 if (append)
365 _x = new signalVector(*x, head, tail);
366 else
367 _x = x;
368
369 /*
370 * Four convovle types:
371 * 1. Complex-Real (aligned)
372 * 2. Complex-Complex (aligned)
373 * 3. Complex-Real (!aligned)
374 * 4. Complex-Complex (!aligned)
375 */
376 if (h->isRealOnly() && h->isAligned()) {
377 rc = convolve_real((float *) _x->begin(), _x->size(),
378 (float *) h->begin(), h->size(),
379 (float *) y->begin(), y->size(),
380 start, len, step, offset);
381 } else if (!h->isRealOnly() && h->isAligned()) {
382 rc = convolve_complex((float *) _x->begin(), _x->size(),
383 (float *) h->begin(), h->size(),
384 (float *) y->begin(), y->size(),
385 start, len, step, offset);
386 } else if (h->isRealOnly() && !h->isAligned()) {
387 rc = base_convolve_real((float *) _x->begin(), _x->size(),
388 (float *) h->begin(), h->size(),
389 (float *) y->begin(), y->size(),
390 start, len, step, offset);
391 } else if (!h->isRealOnly() && !h->isAligned()) {
392 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
393 (float *) h->begin(), h->size(),
394 (float *) y->begin(), y->size(),
395 start, len, step, offset);
396 } else {
397 rc = -1;
398 }
399
400 if (append)
401 delete _x;
402
403 if (rc < 0) {
404 if (alloc)
405 delete y;
406 return NULL;
407 }
408
409 return y;
410}
dburgessb3a0ca42011-10-12 07:44:40 +0000411
Thomas Tsou83e06892013-08-20 16:10:01 -0400412void generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000413{
Thomas Tsou83e06892013-08-20 16:10:01 -0400414 int len;
415 float arg, center;
dburgessb3a0ca42011-10-12 07:44:40 +0000416
Thomas Tsou83e06892013-08-20 16:10:01 -0400417 delete GSMPulse;
418
419 /* Store a single tap filter used for correlation sequence generation */
420 GSMPulse = new PulseSequence();
421 GSMPulse->empty = new signalVector(1);
422 GSMPulse->empty->isRealOnly(true);
423 *(GSMPulse->empty->begin()) = 1.0f;
424
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400425 /*
426 * For 4 samples-per-symbol use a precomputed single pulse Laurent
427 * approximation. This should yields below 2 degrees of phase error at
428 * the modulator output. Use the existing pulse approximation for all
429 * other oversampling factors.
430 */
431 switch (sps) {
432 case 4:
433 len = 16;
434 break;
435 default:
436 len = sps * symbolLength;
437 if (len < 4)
438 len = 4;
439 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400440
Thomas Tsou3eaae802013-08-20 19:31:14 -0400441 GSMPulse->buffer = convolve_h_alloc(len);
442 GSMPulse->gaussian = new signalVector((complex *)
443 GSMPulse->buffer, 0, len);
444 GSMPulse->gaussian->setAligned(true);
Thomas Tsou83e06892013-08-20 16:10:01 -0400445 GSMPulse->gaussian->isRealOnly(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400446
Thomas Tsou83e06892013-08-20 16:10:01 -0400447 signalVector::iterator xP = GSMPulse->gaussian->begin();
448
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400449 if (sps == 4) {
450 *xP++ = 4.46348606e-03;
451 *xP++ = 2.84385729e-02;
452 *xP++ = 1.03184855e-01;
453 *xP++ = 2.56065552e-01;
454 *xP++ = 4.76375085e-01;
455 *xP++ = 7.05961177e-01;
456 *xP++ = 8.71291644e-01;
457 *xP++ = 9.29453645e-01;
458 *xP++ = 8.71291644e-01;
459 *xP++ = 7.05961177e-01;
460 *xP++ = 4.76375085e-01;
461 *xP++ = 2.56065552e-01;
462 *xP++ = 1.03184855e-01;
463 *xP++ = 2.84385729e-02;
464 *xP++ = 4.46348606e-03;
465 *xP++ = 0.0;
466 } else {
467 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400468
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400469 /* GSM pulse approximation */
470 for (int i = 0; i < len; i++) {
471 arg = ((float) i - center) / (float) sps;
472 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
473 0.527 * arg * arg * arg * arg);
474 }
dburgessb3a0ca42011-10-12 07:44:40 +0000475 }
476
Thomas Tsou83e06892013-08-20 16:10:01 -0400477 float avgAbsval = sqrtf(vectorNorm2(*GSMPulse->gaussian)/sps);
478 xP = GSMPulse->gaussian->begin();
479 for (int i = 0; i < len; i++)
dburgessb3a0ca42011-10-12 07:44:40 +0000480 *xP++ /= avgAbsval;
dburgessb3a0ca42011-10-12 07:44:40 +0000481}
482
483signalVector* frequencyShift(signalVector *y,
484 signalVector *x,
485 float freq,
486 float startPhase,
487 float *finalPhase)
488{
489
490 if (!x) return NULL;
491
492 if (y==NULL) {
493 y = new signalVector(x->size());
494 y->isRealOnly(x->isRealOnly());
495 if (y==NULL) return NULL;
496 }
497
498 if (y->size() < x->size()) return NULL;
499
500 float phase = startPhase;
501 signalVector::iterator yP = y->begin();
502 signalVector::iterator xPEnd = x->end();
503 signalVector::iterator xP = x->begin();
504
505 if (x->isRealOnly()) {
506 while (xP < xPEnd) {
507 (*yP++) = expjLookup(phase)*( (xP++)->real() );
508 phase += freq;
509 }
510 }
511 else {
512 while (xP < xPEnd) {
513 (*yP++) = (*xP++)*expjLookup(phase);
514 phase += freq;
515 }
516 }
517
518
519 if (finalPhase) *finalPhase = phase;
520
521 return y;
522}
523
524signalVector* reverseConjugate(signalVector *b)
525{
526 signalVector *tmp = new signalVector(b->size());
527 tmp->isRealOnly(b->isRealOnly());
528 signalVector::iterator bP = b->begin();
529 signalVector::iterator bPEnd = b->end();
530 signalVector::iterator tmpP = tmp->end()-1;
531 if (!b->isRealOnly()) {
532 while (bP < bPEnd) {
533 *tmpP-- = bP->conj();
534 bP++;
535 }
536 }
537 else {
538 while (bP < bPEnd) {
539 *tmpP-- = bP->real();
540 bP++;
541 }
542 }
543
544 return tmp;
545}
546
dburgessb3a0ca42011-10-12 07:44:40 +0000547/* soft output slicer */
548bool vectorSlicer(signalVector *x)
549{
550
551 signalVector::iterator xP = x->begin();
552 signalVector::iterator xPEnd = x->end();
553 while (xP < xPEnd) {
554 *xP = (complex) (0.5*(xP->real()+1.0F));
555 if (xP->real() > 1.0) *xP = 1.0;
556 if (xP->real() < 0.0) *xP = 0.0;
557 xP++;
558 }
559 return true;
560}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400561
562/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400563signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
564 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000565{
Thomas Tsou83e06892013-08-20 16:10:01 -0400566 int burstLen;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400567 signalVector *pulse, *shapedBurst, modBurst;
Thomas Tsou83e06892013-08-20 16:10:01 -0400568 signalVector::iterator modBurstItr;
dburgessb3a0ca42011-10-12 07:44:40 +0000569
Thomas Tsou83e06892013-08-20 16:10:01 -0400570 if (emptyPulse)
571 pulse = GSMPulse->empty;
572 else
573 pulse = GSMPulse->gaussian;
dburgessb3a0ca42011-10-12 07:44:40 +0000574
Thomas Tsou83e06892013-08-20 16:10:01 -0400575 burstLen = sps * (wBurst.size() + guardPeriodLength);
576 modBurst = signalVector(burstLen);
577 modBurstItr = modBurst.begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000578
dburgessb3a0ca42011-10-12 07:44:40 +0000579 for (unsigned int i = 0; i < wBurst.size(); i++) {
580 *modBurstItr = 2.0*(wBurst[i] & 0x01)-1.0;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400581 modBurstItr += sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000582 }
583
584 // shift up pi/2
585 // ignore starting phase, since spec allows for discontinuous phase
586 GMSKRotate(modBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -0400587
dburgessb3a0ca42011-10-12 07:44:40 +0000588 modBurst.isRealOnly(false);
589
590 // filter w/ pulse shape
Thomas Tsou3eaae802013-08-20 19:31:14 -0400591 shapedBurst = convolve(&modBurst, pulse, NULL, START_ONLY);
592 if (!shapedBurst)
593 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000594
dburgessb3a0ca42011-10-12 07:44:40 +0000595 return shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +0000596}
597
598float sinc(float x)
599{
600 if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
601 return 1.0F;
602}
603
Thomas Tsou3eaae802013-08-20 19:31:14 -0400604bool delayVector(signalVector &wBurst, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000605{
606
607 int intOffset = (int) floor(delay);
608 float fracOffset = delay - intOffset;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400609
dburgessb3a0ca42011-10-12 07:44:40 +0000610 // do fractional shift first, only do it for reasonable offsets
611 if (fabs(fracOffset) > 1e-2) {
612 // create sinc function
613 signalVector sincVector(21);
614 sincVector.isRealOnly(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400615 signalVector::iterator sincBurstItr = sincVector.end();
dburgessb3a0ca42011-10-12 07:44:40 +0000616 for (int i = 0; i < 21; i++)
Thomas Tsou3eaae802013-08-20 19:31:14 -0400617 *--sincBurstItr = (complex) sinc(M_PI_F*(i-10-fracOffset));
dburgessb3a0ca42011-10-12 07:44:40 +0000618
619 signalVector shiftedBurst(wBurst.size());
Thomas Tsou3eaae802013-08-20 19:31:14 -0400620 if (!convolve(&wBurst, &sincVector, &shiftedBurst, NO_DELAY))
621 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000622 wBurst.clone(shiftedBurst);
623 }
624
625 if (intOffset < 0) {
626 intOffset = -intOffset;
627 signalVector::iterator wBurstItr = wBurst.begin();
628 signalVector::iterator shiftedItr = wBurst.begin()+intOffset;
629 while (shiftedItr < wBurst.end())
630 *wBurstItr++ = *shiftedItr++;
631 while (wBurstItr < wBurst.end())
632 *wBurstItr++ = 0.0;
633 }
634 else {
635 signalVector::iterator wBurstItr = wBurst.end()-1;
636 signalVector::iterator shiftedItr = wBurst.end()-1-intOffset;
637 while (shiftedItr >= wBurst.begin())
638 *wBurstItr-- = *shiftedItr--;
639 while (wBurstItr >= wBurst.begin())
640 *wBurstItr-- = 0.0;
641 }
642}
643
644signalVector *gaussianNoise(int length,
645 float variance,
646 complex mean)
647{
648
649 signalVector *noise = new signalVector(length);
650 signalVector::iterator nPtr = noise->begin();
651 float stddev = sqrtf(variance);
652 while (nPtr < noise->end()) {
653 float u1 = (float) rand()/ (float) RAND_MAX;
654 while (u1==0.0)
655 u1 = (float) rand()/ (float) RAND_MAX;
656 float u2 = (float) rand()/ (float) RAND_MAX;
657 float arg = 2.0*M_PI*u2;
658 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
659 nPtr++;
660 }
661
662 return noise;
663}
664
665complex interpolatePoint(const signalVector &inSig,
666 float ix)
667{
668
669 int start = (int) (floor(ix) - 10);
670 if (start < 0) start = 0;
671 int end = (int) (floor(ix) + 11);
672 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
673
674 complex pVal = 0.0;
675 if (!inSig.isRealOnly()) {
676 for (int i = start; i < end; i++)
677 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
678 }
679 else {
680 for (int i = start; i < end; i++)
681 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
682 }
683
684 return pVal;
685}
686
Thomas Tsou8181b012013-08-20 21:17:19 -0400687static complex fastPeakDetect(const signalVector &rxBurst, float *index)
688{
689 float val, max = 0.0f;
690 complex amp;
691 int _index = -1;
692
693 for (int i = 0; i < rxBurst.size(); i++) {
694 val = rxBurst[i].norm2();
695 if (val > max) {
696 max = val;
697 _index = i;
698 amp = rxBurst[i];
699 }
700 }
701
702 if (index)
703 *index = (float) _index;
704
705 return amp;
706}
707
dburgessb3a0ca42011-10-12 07:44:40 +0000708complex peakDetect(const signalVector &rxBurst,
709 float *peakIndex,
710 float *avgPwr)
711{
712
713
714 complex maxVal = 0.0;
715 float maxIndex = -1;
716 float sumPower = 0.0;
717
718 for (unsigned int i = 0; i < rxBurst.size(); i++) {
719 float samplePower = rxBurst[i].norm2();
720 if (samplePower > maxVal.real()) {
721 maxVal = samplePower;
722 maxIndex = i;
723 }
724 sumPower += samplePower;
725 }
726
727 // interpolate around the peak
728 // to save computation, we'll use early-late balancing
729 float earlyIndex = maxIndex-1;
730 float lateIndex = maxIndex+1;
731
732 float incr = 0.5;
733 while (incr > 1.0/1024.0) {
734 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
735 complex lateP = interpolatePoint(rxBurst,lateIndex);
736 if (earlyP < lateP)
737 earlyIndex += incr;
738 else if (earlyP > lateP)
739 earlyIndex -= incr;
740 else break;
741 incr /= 2.0;
742 lateIndex = earlyIndex + 2.0;
743 }
744
745 maxIndex = earlyIndex + 1.0;
746 maxVal = interpolatePoint(rxBurst,maxIndex);
747
748 if (peakIndex!=NULL)
749 *peakIndex = maxIndex;
750
751 if (avgPwr!=NULL)
752 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
753
754 return maxVal;
755
756}
757
758void scaleVector(signalVector &x,
759 complex scale)
760{
761 signalVector::iterator xP = x.begin();
762 signalVector::iterator xPEnd = x.end();
763 if (!x.isRealOnly()) {
764 while (xP < xPEnd) {
765 *xP = *xP * scale;
766 xP++;
767 }
768 }
769 else {
770 while (xP < xPEnd) {
771 *xP = xP->real() * scale;
772 xP++;
773 }
774 }
775}
776
777/** in-place conjugation */
778void conjugateVector(signalVector &x)
779{
780 if (x.isRealOnly()) return;
781 signalVector::iterator xP = x.begin();
782 signalVector::iterator xPEnd = x.end();
783 while (xP < xPEnd) {
784 *xP = xP->conj();
785 xP++;
786 }
787}
788
789
790// in-place addition!!
791bool addVector(signalVector &x,
792 signalVector &y)
793{
794 signalVector::iterator xP = x.begin();
795 signalVector::iterator yP = y.begin();
796 signalVector::iterator xPEnd = x.end();
797 signalVector::iterator yPEnd = y.end();
798 while ((xP < xPEnd) && (yP < yPEnd)) {
799 *xP = *xP + *yP;
800 xP++; yP++;
801 }
802 return true;
803}
804
805// in-place multiplication!!
806bool multVector(signalVector &x,
807 signalVector &y)
808{
809 signalVector::iterator xP = x.begin();
810 signalVector::iterator yP = y.begin();
811 signalVector::iterator xPEnd = x.end();
812 signalVector::iterator yPEnd = y.end();
813 while ((xP < xPEnd) && (yP < yPEnd)) {
814 *xP = (*xP) * (*yP);
815 xP++; yP++;
816 }
817 return true;
818}
819
820
821void offsetVector(signalVector &x,
822 complex offset)
823{
824 signalVector::iterator xP = x.begin();
825 signalVector::iterator xPEnd = x.end();
826 if (!x.isRealOnly()) {
827 while (xP < xPEnd) {
828 *xP += offset;
829 xP++;
830 }
831 }
832 else {
833 while (xP < xPEnd) {
834 *xP = xP->real() + offset;
835 xP++;
836 }
837 }
838}
839
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400840bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +0000841{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400842 bool status = true;
843 complex *data = NULL;
844 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400845 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400846
Thomas Tsou3eaae802013-08-20 19:31:14 -0400847 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +0000848 return false;
849
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400850 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -0400851
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400852 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
853 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
854 if (!midMidamble)
855 return false;
856
Thomas Tsou3eaae802013-08-20 19:31:14 -0400857 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400858 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
859 if (!midamble) {
860 status = false;
861 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000862 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400863
dburgessb3a0ca42011-10-12 07:44:40 +0000864 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
865 // the ideal TSC has an + 180 degree phase shift,
866 // due to the pi/2 frequency shift, that
867 // needs to be accounted for.
868 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400869 scaleVector(*midMidamble, complex(-1.0, 0.0));
870 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +0000871
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400872 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +0000873
Thomas Tsou3eaae802013-08-20 19:31:14 -0400874 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
875 data = (complex *) convolve_h_alloc(midMidamble->size());
876 _midMidamble = new signalVector(data, 0, midMidamble->size());
877 _midMidamble->setAligned(true);
878 memcpy(_midMidamble->begin(), midMidamble->begin(),
879 midMidamble->size() * sizeof(complex));
880
881 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400882 if (!autocorr) {
883 status = false;
884 goto release;
885 }
dburgessb3a0ca42011-10-12 07:44:40 +0000886
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400887 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400888 gMidambles[tsc]->buffer = data;
889 gMidambles[tsc]->sequence = _midMidamble;
890 gMidambles[tsc]->gain = peakDetect(*autocorr,&gMidambles[tsc]->TOA, NULL);
dburgessb3a0ca42011-10-12 07:44:40 +0000891
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400892release:
dburgessb3a0ca42011-10-12 07:44:40 +0000893 delete autocorr;
894 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400895 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +0000896
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400897 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400898 delete _midMidamble;
899 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400900 gMidambles[tsc] = NULL;
901 }
902
903 return status;
dburgessb3a0ca42011-10-12 07:44:40 +0000904}
905
Thomas Tsou83e06892013-08-20 16:10:01 -0400906bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +0000907{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400908 bool status = true;
909 complex *data = NULL;
910 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400911 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400912
913 delete gRACHSequence;
914
915 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
916 if (!seq0)
917 return false;
918
919 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
920 if (!seq1) {
921 status = false;
922 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000923 }
924
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400925 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +0000926
Thomas Tsou3eaae802013-08-20 19:31:14 -0400927 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
928 data = (complex *) convolve_h_alloc(seq1->size());
929 _seq1 = new signalVector(data, 0, seq1->size());
930 _seq1->setAligned(true);
931 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
932
933 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
934 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400935 status = false;
936 goto release;
937 }
dburgessb3a0ca42011-10-12 07:44:40 +0000938
939 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400940 gRACHSequence->sequence = _seq1;
941 gRACHSequence->buffer = data;
942 gRACHSequence->gain = peakDetect(*autocorr,&gRACHSequence->TOA, NULL);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400943
944release:
dburgessb3a0ca42011-10-12 07:44:40 +0000945 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400946 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400947 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +0000948
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400949 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400950 delete _seq1;
951 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400952 gRACHSequence = NULL;
953 }
dburgessb3a0ca42011-10-12 07:44:40 +0000954
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400955 return status;
dburgessb3a0ca42011-10-12 07:44:40 +0000956}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400957
958int detectRACHBurst(signalVector &rxBurst,
959 float thresh,
960 int sps,
961 complex *amp,
962 float *toa)
dburgessb3a0ca42011-10-12 07:44:40 +0000963{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400964 int start, len, num = 0;
965 float _toa, rms, par, avg = 0.0f;
966 complex _amp, *peak;
967 signalVector corr, *sync = gRACHSequence->sequence;
dburgessb3a0ca42011-10-12 07:44:40 +0000968
Thomas Tsou3eaae802013-08-20 19:31:14 -0400969 if ((sps != 1) && (sps != 2) && (sps != 4))
970 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000971
Thomas Tsou3eaae802013-08-20 19:31:14 -0400972 start = 40 * sps;
973 len = 24 * sps;
974 corr = signalVector(len);
dburgessb3a0ca42011-10-12 07:44:40 +0000975
Thomas Tsou3eaae802013-08-20 19:31:14 -0400976 if (!convolve(&rxBurst, sync, &corr,
977 CUSTOM, start, len, sps, 0)) {
978 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000979 }
980
Thomas Tsou8181b012013-08-20 21:17:19 -0400981 _amp = fastPeakDetect(corr, &_toa);
982
983 /* Restrict peak-to-average calculations at the edges */
Thomas Tsou3eaae802013-08-20 19:31:14 -0400984 if ((_toa < 3) || (_toa > len - 3))
985 goto notfound;
986
987 peak = corr.begin() + (int) rint(_toa);
988
Thomas Tsou8181b012013-08-20 21:17:19 -0400989 /* Compute peak-to-average ratio. Reject if we don't have enough values */
Thomas Tsou3eaae802013-08-20 19:31:14 -0400990 for (int i = 2 * sps; i <= 5 * sps; i++) {
991 if (peak - i >= corr.begin()) {
992 avg += (peak - i)->norm2();
993 num++;
994 }
995 if (peak + i < corr.end()) {
996 avg += (peak + i)->norm2();
997 num++;
998 }
dburgessb3a0ca42011-10-12 07:44:40 +0000999 }
1000
Thomas Tsou3eaae802013-08-20 19:31:14 -04001001 if (num < 2)
1002 goto notfound;
dburgessb3a0ca42011-10-12 07:44:40 +00001003
Thomas Tsou3eaae802013-08-20 19:31:14 -04001004 rms = sqrtf(avg / (float) num) + 0.00001;
1005 par = _amp.abs() / rms;
1006 if (par < thresh)
1007 goto notfound;
dburgessb3a0ca42011-10-12 07:44:40 +00001008
Thomas Tsou8181b012013-08-20 21:17:19 -04001009 /* Run the full peak detection to obtain interpolated values */
1010 _amp = peakDetect(corr, &_toa, NULL);
1011
Thomas Tsou3eaae802013-08-20 19:31:14 -04001012 /* Subtract forward tail bits from delay */
1013 if (toa)
1014 *toa = _toa - 8 * sps;
Thomas Tsou8181b012013-08-20 21:17:19 -04001015
1016 /* Normalize our channel gain */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001017 if (amp)
1018 *amp = _amp / gRACHSequence->gain;
dburgessb3a0ca42011-10-12 07:44:40 +00001019
Thomas Tsou3eaae802013-08-20 19:31:14 -04001020 return 1;
1021
1022notfound:
1023 if (amp)
1024 *amp = 0.0f;
1025 if (toa)
1026 *toa = 0.0f;
1027
1028 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001029}
1030
1031bool energyDetect(signalVector &rxBurst,
1032 unsigned windowLength,
1033 float detectThreshold,
1034 float *avgPwr)
1035{
1036
1037 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1038 float energy = 0.0;
1039 if (windowLength < 0) windowLength = 20;
1040 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1041 for (unsigned i = 0; i < windowLength; i++) {
1042 energy += windowItr->norm2();
1043 windowItr+=4;
1044 }
1045 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001046 return (energy/windowLength > detectThreshold*detectThreshold);
1047}
dburgessb3a0ca42011-10-12 07:44:40 +00001048
Thomas Tsou3eaae802013-08-20 19:31:14 -04001049int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1050 int sps, complex *amp, float *toa, unsigned max_toa,
1051 bool chan_req, signalVector **chan, float *chan_offset)
dburgessb3a0ca42011-10-12 07:44:40 +00001052{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001053 int start, target, len, num = 0;
1054 complex _amp, *peak;
1055 float _toa, rms, par, avg = 0.0f;
1056 signalVector corr, *sync, *_chan;
dburgessb3a0ca42011-10-12 07:44:40 +00001057
Thomas Tsou3eaae802013-08-20 19:31:14 -04001058 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 2) && (sps != 4)))
1059 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001060
Thomas Tsou3eaae802013-08-20 19:31:14 -04001061 target = 3 + 58 + 5 + 16;
1062 start = (target - 8) * sps;
1063 len = (8 + 8 + max_toa) * sps;
dburgessb3a0ca42011-10-12 07:44:40 +00001064
Thomas Tsou3eaae802013-08-20 19:31:14 -04001065 sync = gMidambles[tsc]->sequence;
1066 sync = gMidambles[tsc]->sequence;
1067 corr = signalVector(len);
dburgessb3a0ca42011-10-12 07:44:40 +00001068
Thomas Tsou3eaae802013-08-20 19:31:14 -04001069 if (!convolve(&rxBurst, sync, &corr,
1070 CUSTOM, start, len, sps, 0)) {
1071 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001072 }
1073
Thomas Tsou3eaae802013-08-20 19:31:14 -04001074 _amp = peakDetect(corr, &_toa, NULL);
1075 peak = corr.begin() + (int) rint(_toa);
1076
1077 /* Check for bogus results */
1078 if ((_toa < 0.0) || (_toa > corr.size()))
1079 goto notfound;
1080
1081 for (int i = 2 * sps; i <= 5 * sps; i++) {
1082 if (peak - i >= corr.begin()) {
1083 avg += (peak - i)->norm2();
1084 num++;
dburgessb3a0ca42011-10-12 07:44:40 +00001085 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001086 if (peak + i < corr.end()) {
1087 avg += (peak + i)->norm2();
1088 num++;
dburgessb3a0ca42011-10-12 07:44:40 +00001089 }
1090 }
1091
Thomas Tsou3eaae802013-08-20 19:31:14 -04001092 if (num < 2)
1093 goto notfound;
1094
1095 rms = sqrtf(avg / (float) num) + 0.00001;
1096 par = (_amp.abs()) / rms;
1097 if (par < thresh)
1098 goto notfound;
1099
1100 /*
1101 * NOTE: Because ideal TSC is 66 symbols into burst,
1102 * the ideal TSC has an +/- 180 degree phase shift,
1103 * due to the pi/4 frequency shift, that
1104 * needs to be accounted for.
1105 */
1106 if (amp)
1107 *amp = _amp / gMidambles[tsc]->gain;
1108
1109 /* Delay one half of peak-centred correlation length */
1110 _toa -= sps * 8;
1111
1112 if (toa)
1113 *toa = _toa;
1114
1115 if (chan_req) {
1116 _chan = new signalVector(6 * sps);
1117
1118 delayVector(corr, -_toa);
1119 corr.segmentCopyTo(*_chan, target - 3, _chan->size());
1120 scaleVector(*_chan, complex(1.0, 0.0) / gMidambles[tsc]->gain);
1121
1122 *chan = _chan;
1123
1124 if (chan_offset)
1125 *chan_offset = 3.0 * sps;;
dburgessb3a0ca42011-10-12 07:44:40 +00001126 }
1127
Thomas Tsou3eaae802013-08-20 19:31:14 -04001128 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001129
Thomas Tsou3eaae802013-08-20 19:31:14 -04001130notfound:
1131 if (amp)
1132 *amp = 0.0f;
1133 if (toa)
1134 *toa = 0.0f;
dburgessb3a0ca42011-10-12 07:44:40 +00001135
Thomas Tsou3eaae802013-08-20 19:31:14 -04001136 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001137}
1138
1139signalVector *decimateVector(signalVector &wVector,
1140 int decimationFactor)
1141{
1142
1143 if (decimationFactor <= 1) return NULL;
1144
1145 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
1146 decVector->isRealOnly(wVector.isRealOnly());
1147
1148 signalVector::iterator vecItr = decVector->begin();
1149 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1150 *vecItr++ = wVector[i];
1151
1152 return decVector;
1153}
1154
1155
Thomas Tsou83e06892013-08-20 16:10:01 -04001156SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
1157 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001158{
1159 scaleVector(rxBurst,((complex) 1.0)/channel);
1160 delayVector(rxBurst,-TOA);
1161
1162 signalVector *shapedBurst = &rxBurst;
1163
1164 // shift up by a quarter of a frequency
1165 // ignore starting phase, since spec allows for discontinuous phase
1166 GMSKReverseRotate(*shapedBurst);
1167
1168 // run through slicer
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001169 if (sps > 1) {
1170 signalVector *decShapedBurst = decimateVector(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001171 shapedBurst = decShapedBurst;
1172 }
1173
dburgessb3a0ca42011-10-12 07:44:40 +00001174 vectorSlicer(shapedBurst);
1175
1176 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1177
1178 SoftVector::iterator burstItr = burstBits->begin();
1179 signalVector::iterator shapedItr = shapedBurst->begin();
1180 for (; shapedItr < shapedBurst->end(); shapedItr++)
1181 *burstItr++ = shapedItr->real();
1182
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001183 if (sps > 1)
1184 delete shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +00001185
1186 return burstBits;
1187
1188}
dburgessb3a0ca42011-10-12 07:44:40 +00001189
dburgessb3a0ca42011-10-12 07:44:40 +00001190// Assumes symbol-spaced sampling!!!
1191// Based upon paper by Al-Dhahir and Cioffi
1192bool designDFE(signalVector &channelResponse,
1193 float SNRestimate,
1194 int Nf,
1195 signalVector **feedForwardFilter,
1196 signalVector **feedbackFilter)
1197{
1198
1199 signalVector G0(Nf);
1200 signalVector G1(Nf);
1201 signalVector::iterator G0ptr = G0.begin();
1202 signalVector::iterator G1ptr = G1.begin();
1203 signalVector::iterator chanPtr = channelResponse.begin();
1204
1205 int nu = channelResponse.size()-1;
1206
1207 *G0ptr = 1.0/sqrtf(SNRestimate);
1208 for(int j = 0; j <= nu; j++) {
1209 *G1ptr = chanPtr->conj();
1210 G1ptr++; chanPtr++;
1211 }
1212
1213 signalVector *L[Nf];
1214 signalVector::iterator Lptr;
1215 float d;
1216 for(int i = 0; i < Nf; i++) {
1217 d = G0.begin()->norm2() + G1.begin()->norm2();
1218 L[i] = new signalVector(Nf+nu);
1219 Lptr = L[i]->begin()+i;
1220 G0ptr = G0.begin(); G1ptr = G1.begin();
1221 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1222 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1223 Lptr++;
1224 G0ptr++;
1225 G1ptr++;
1226 }
1227 complex k = (*G1.begin())/(*G0.begin());
1228
1229 if (i != Nf-1) {
1230 signalVector G0new = G1;
1231 scaleVector(G0new,k.conj());
1232 addVector(G0new,G0);
1233
1234 signalVector G1new = G0;
1235 scaleVector(G1new,k*(-1.0));
1236 addVector(G1new,G1);
1237 delayVector(G1new,-1.0);
1238
1239 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1240 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1241 G0 = G0new;
1242 G1 = G1new;
1243 }
1244 }
1245
1246 *feedbackFilter = new signalVector(nu);
1247 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1248 scaleVector(**feedbackFilter,(complex) -1.0);
1249 conjugateVector(**feedbackFilter);
1250
1251 signalVector v(Nf);
1252 signalVector::iterator vStart = v.begin();
1253 signalVector::iterator vPtr;
1254 *(vStart+Nf-1) = (complex) 1.0;
1255 for(int k = Nf-2; k >= 0; k--) {
1256 Lptr = L[k]->begin()+k+1;
1257 vPtr = vStart + k+1;
1258 complex v_k = 0.0;
1259 for (int j = k+1; j < Nf; j++) {
1260 v_k -= (*vPtr)*(*Lptr);
1261 vPtr++; Lptr++;
1262 }
1263 *(vStart + k) = v_k;
1264 }
1265
1266 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001267 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001268 for (int i = 0; i < Nf; i++) {
1269 delete L[i];
1270 complex w_i = 0.0;
1271 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1272 vPtr = vStart+i;
1273 chanPtr = channelResponse.begin();
1274 for (int k = 0; k < endPt+1; k++) {
1275 w_i += (*vPtr)*(chanPtr->conj());
1276 vPtr++; chanPtr++;
1277 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001278 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001279 }
1280
1281
1282 return true;
1283
1284}
1285
1286// Assumes symbol-rate sampling!!!!
1287SoftVector *equalizeBurst(signalVector &rxBurst,
1288 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001289 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001290 signalVector &w, // feedforward filter
1291 signalVector &b) // feedback filter
1292{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001293 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001294
Thomas Tsou3eaae802013-08-20 19:31:14 -04001295 if (!delayVector(rxBurst, -TOA))
1296 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001297
Thomas Tsou3eaae802013-08-20 19:31:14 -04001298 postForwardFull = convolve(&rxBurst, &w, NULL,
1299 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1300 if (!postForwardFull)
1301 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001302
1303 signalVector* postForward = new signalVector(rxBurst.size());
1304 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1305 delete postForwardFull;
1306
1307 signalVector::iterator dPtr = postForward->begin();
1308 signalVector::iterator dBackPtr;
1309 signalVector::iterator rotPtr = GMSKRotation->begin();
1310 signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
1311
1312 signalVector *DFEoutput = new signalVector(postForward->size());
1313 signalVector::iterator DFEItr = DFEoutput->begin();
1314
1315 // NOTE: can insert the midamble and/or use midamble to estimate BER
1316 for (; dPtr < postForward->end(); dPtr++) {
1317 dBackPtr = dPtr-1;
1318 signalVector::iterator bPtr = b.begin();
1319 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1320 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1321 bPtr++;
1322 dBackPtr--;
1323 }
1324 *dPtr = *dPtr * (*revRotPtr);
1325 *DFEItr = *dPtr;
1326 // make decision on symbol
1327 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1328 //*DFEItr = *dPtr;
1329 *dPtr = *dPtr * (*rotPtr);
1330 DFEItr++;
1331 rotPtr++;
1332 revRotPtr++;
1333 }
1334
1335 vectorSlicer(DFEoutput);
1336
1337 SoftVector *burstBits = new SoftVector(postForward->size());
1338 SoftVector::iterator burstItr = burstBits->begin();
1339 DFEItr = DFEoutput->begin();
1340 for (; DFEItr < DFEoutput->end(); DFEItr++)
1341 *burstItr++ = DFEItr->real();
1342
1343 delete postForward;
1344
1345 delete DFEoutput;
1346
1347 return burstBits;
1348}