blob: 6650948dc2ea2ef70920cde7b226c4ccc0a5e11c [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 Tsou865bca42013-08-21 20:58:00 -0400262 if ((sps != 1) && (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
Thomas Tsou865bca42013-08-21 20:58:00 -0400958static float computePeakRatio(signalVector *corr,
959 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +0000960{
Thomas Tsou865bca42013-08-21 20:58:00 -0400961 int num = 0;
962 complex *peak;
963 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000964
Thomas Tsou865bca42013-08-21 20:58:00 -0400965 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +0000966
Thomas Tsou865bca42013-08-21 20:58:00 -0400967 /* Check for bogus results */
968 if ((toa < 0.0) || (toa > corr->size()))
969 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000970
Thomas Tsou3eaae802013-08-20 19:31:14 -0400971 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -0400972 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400973 avg += (peak - i)->norm2();
974 num++;
975 }
Thomas Tsou865bca42013-08-21 20:58:00 -0400976 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400977 avg += (peak + i)->norm2();
978 num++;
979 }
dburgessb3a0ca42011-10-12 07:44:40 +0000980 }
981
Thomas Tsou3eaae802013-08-20 19:31:14 -0400982 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -0400983 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000984
Thomas Tsou3eaae802013-08-20 19:31:14 -0400985 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +0000986
Thomas Tsou865bca42013-08-21 20:58:00 -0400987 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +0000988}
989
990bool energyDetect(signalVector &rxBurst,
991 unsigned windowLength,
992 float detectThreshold,
993 float *avgPwr)
994{
995
996 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
997 float energy = 0.0;
998 if (windowLength < 0) windowLength = 20;
999 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1000 for (unsigned i = 0; i < windowLength; i++) {
1001 energy += windowItr->norm2();
1002 windowItr+=4;
1003 }
1004 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001005 return (energy/windowLength > detectThreshold*detectThreshold);
1006}
dburgessb3a0ca42011-10-12 07:44:40 +00001007
Thomas Tsou865bca42013-08-21 20:58:00 -04001008/*
1009 * Detect a burst based on correlation and peak-to-average ratio
1010 *
1011 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1012 * for initial gating. We do this because energy detection should be disabled.
1013 * For higher oversampling values, we assume the energy detector is in place
1014 * and we run full interpolating peak detection.
1015 */
1016static int detectBurst(signalVector &burst,
1017 signalVector &corr, CorrelationSequence *sync,
1018 float thresh, int sps, complex *amp, float *toa,
1019 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001020{
Thomas Tsou865bca42013-08-21 20:58:00 -04001021 /* Correlate */
1022 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001023 CUSTOM, start, len, sps, 0)) {
1024 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001025 }
1026
Thomas Tsou865bca42013-08-21 20:58:00 -04001027 /* Peak detection - place restrictions at correlation edges */
1028 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001029
Thomas Tsou865bca42013-08-21 20:58:00 -04001030 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1031 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001032
Thomas Tsou865bca42013-08-21 20:58:00 -04001033 /* Peak -to-average ratio */
1034 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1035 return 0;
1036
1037 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1038 *amp = peakDetect(corr, toa, NULL);
1039
1040 /* Normalize our channel gain */
1041 *amp = *amp / sync->gain;
1042
1043 return 1;
1044}
1045
1046/*
1047 * RACH burst detection
1048 *
1049 * Correlation window parameters:
1050 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
1051 * head: Search 8 symbols before target
1052 * tail: Search 8 symbols after target
1053 */
1054int detectRACHBurst(signalVector &rxBurst,
1055 float thresh,
1056 int sps,
1057 complex *amp,
1058 float *toa)
1059{
1060 int rc, start, target, head, tail, len;
1061 float _toa;
1062 complex _amp;
1063 signalVector corr;
1064 CorrelationSequence *sync;
1065
1066 if ((sps != 1) && (sps != 4))
1067 return -1;
1068
1069 target = 8 + 40;
1070 head = 8;
1071 tail = head;
1072
1073 start = (target - head) * sps - 1;
1074 len = (head + tail) * sps;
1075 sync = gRACHSequence;
1076 corr = signalVector(len);
1077
1078 rc = detectBurst(rxBurst, corr, sync,
1079 thresh, sps, &_amp, &_toa, start, len);
1080 if (rc < 0) {
1081 return -1;
1082 } else if (!rc) {
1083 if (amp)
1084 *amp = 0.0f;
1085 if (toa)
1086 *toa = 0.0f;
1087 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001088 }
1089
Thomas Tsou865bca42013-08-21 20:58:00 -04001090 /* Subtract forward search bits from delay */
1091 if (toa)
1092 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001093 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001094 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001095
Thomas Tsou865bca42013-08-21 20:58:00 -04001096 return 1;
1097}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001098
Thomas Tsou865bca42013-08-21 20:58:00 -04001099/*
1100 * Normal burst detection
1101 *
1102 * Correlation window parameters:
1103 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
1104 * head: Search 8 symbols before target
1105 * tail: Search 8 symbols + maximum expected delay
1106 */
1107int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1108 int sps, complex *amp, float *toa, unsigned max_toa,
1109 bool chan_req, signalVector **chan, float *chan_offset)
1110{
1111 int rc, start, target, head, tail, len;
1112 complex _amp;
1113 float _toa;
1114 signalVector corr;
1115 CorrelationSequence *sync;
1116
1117 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1118 return -1;
1119
1120 target = 3 + 58 + 16 + 5;
1121 head = 8;
1122 tail = head + max_toa;
1123
1124 start = (target - head) * sps - 1;
1125 len = (head + tail) * sps;
1126 sync = gMidambles[tsc];
1127 corr = signalVector(len);
1128
1129 rc = detectBurst(rxBurst, corr, sync,
1130 thresh, sps, &_amp, &_toa, start, len);
1131 if (rc < 0) {
1132 return -1;
1133 } else if (!rc) {
1134 if (amp)
1135 *amp = 0.0f;
1136 if (toa)
1137 *toa = 0.0f;
1138 return 0;
1139 }
1140
1141 /* Subtract forward search bits from delay */
1142 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001143 if (toa)
1144 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001145 if (amp)
1146 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001147
Thomas Tsou865bca42013-08-21 20:58:00 -04001148 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001149 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001150 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001151
1152 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001153 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001154 }
1155
Thomas Tsou3eaae802013-08-20 19:31:14 -04001156 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001157}
1158
1159signalVector *decimateVector(signalVector &wVector,
1160 int decimationFactor)
1161{
1162
1163 if (decimationFactor <= 1) return NULL;
1164
1165 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
1166 decVector->isRealOnly(wVector.isRealOnly());
1167
1168 signalVector::iterator vecItr = decVector->begin();
1169 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1170 *vecItr++ = wVector[i];
1171
1172 return decVector;
1173}
1174
1175
Thomas Tsou83e06892013-08-20 16:10:01 -04001176SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
1177 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001178{
1179 scaleVector(rxBurst,((complex) 1.0)/channel);
1180 delayVector(rxBurst,-TOA);
1181
1182 signalVector *shapedBurst = &rxBurst;
1183
1184 // shift up by a quarter of a frequency
1185 // ignore starting phase, since spec allows for discontinuous phase
1186 GMSKReverseRotate(*shapedBurst);
1187
1188 // run through slicer
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001189 if (sps > 1) {
1190 signalVector *decShapedBurst = decimateVector(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001191 shapedBurst = decShapedBurst;
1192 }
1193
dburgessb3a0ca42011-10-12 07:44:40 +00001194 vectorSlicer(shapedBurst);
1195
1196 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1197
1198 SoftVector::iterator burstItr = burstBits->begin();
1199 signalVector::iterator shapedItr = shapedBurst->begin();
1200 for (; shapedItr < shapedBurst->end(); shapedItr++)
1201 *burstItr++ = shapedItr->real();
1202
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001203 if (sps > 1)
1204 delete shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +00001205
1206 return burstBits;
1207
1208}
dburgessb3a0ca42011-10-12 07:44:40 +00001209
dburgessb3a0ca42011-10-12 07:44:40 +00001210// Assumes symbol-spaced sampling!!!
1211// Based upon paper by Al-Dhahir and Cioffi
1212bool designDFE(signalVector &channelResponse,
1213 float SNRestimate,
1214 int Nf,
1215 signalVector **feedForwardFilter,
1216 signalVector **feedbackFilter)
1217{
1218
1219 signalVector G0(Nf);
1220 signalVector G1(Nf);
1221 signalVector::iterator G0ptr = G0.begin();
1222 signalVector::iterator G1ptr = G1.begin();
1223 signalVector::iterator chanPtr = channelResponse.begin();
1224
1225 int nu = channelResponse.size()-1;
1226
1227 *G0ptr = 1.0/sqrtf(SNRestimate);
1228 for(int j = 0; j <= nu; j++) {
1229 *G1ptr = chanPtr->conj();
1230 G1ptr++; chanPtr++;
1231 }
1232
1233 signalVector *L[Nf];
1234 signalVector::iterator Lptr;
1235 float d;
1236 for(int i = 0; i < Nf; i++) {
1237 d = G0.begin()->norm2() + G1.begin()->norm2();
1238 L[i] = new signalVector(Nf+nu);
1239 Lptr = L[i]->begin()+i;
1240 G0ptr = G0.begin(); G1ptr = G1.begin();
1241 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1242 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1243 Lptr++;
1244 G0ptr++;
1245 G1ptr++;
1246 }
1247 complex k = (*G1.begin())/(*G0.begin());
1248
1249 if (i != Nf-1) {
1250 signalVector G0new = G1;
1251 scaleVector(G0new,k.conj());
1252 addVector(G0new,G0);
1253
1254 signalVector G1new = G0;
1255 scaleVector(G1new,k*(-1.0));
1256 addVector(G1new,G1);
1257 delayVector(G1new,-1.0);
1258
1259 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1260 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1261 G0 = G0new;
1262 G1 = G1new;
1263 }
1264 }
1265
1266 *feedbackFilter = new signalVector(nu);
1267 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1268 scaleVector(**feedbackFilter,(complex) -1.0);
1269 conjugateVector(**feedbackFilter);
1270
1271 signalVector v(Nf);
1272 signalVector::iterator vStart = v.begin();
1273 signalVector::iterator vPtr;
1274 *(vStart+Nf-1) = (complex) 1.0;
1275 for(int k = Nf-2; k >= 0; k--) {
1276 Lptr = L[k]->begin()+k+1;
1277 vPtr = vStart + k+1;
1278 complex v_k = 0.0;
1279 for (int j = k+1; j < Nf; j++) {
1280 v_k -= (*vPtr)*(*Lptr);
1281 vPtr++; Lptr++;
1282 }
1283 *(vStart + k) = v_k;
1284 }
1285
1286 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001287 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001288 for (int i = 0; i < Nf; i++) {
1289 delete L[i];
1290 complex w_i = 0.0;
1291 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1292 vPtr = vStart+i;
1293 chanPtr = channelResponse.begin();
1294 for (int k = 0; k < endPt+1; k++) {
1295 w_i += (*vPtr)*(chanPtr->conj());
1296 vPtr++; chanPtr++;
1297 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001298 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001299 }
1300
1301
1302 return true;
1303
1304}
1305
1306// Assumes symbol-rate sampling!!!!
1307SoftVector *equalizeBurst(signalVector &rxBurst,
1308 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001309 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001310 signalVector &w, // feedforward filter
1311 signalVector &b) // feedback filter
1312{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001313 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001314
Thomas Tsou3eaae802013-08-20 19:31:14 -04001315 if (!delayVector(rxBurst, -TOA))
1316 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001317
Thomas Tsou3eaae802013-08-20 19:31:14 -04001318 postForwardFull = convolve(&rxBurst, &w, NULL,
1319 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1320 if (!postForwardFull)
1321 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001322
1323 signalVector* postForward = new signalVector(rxBurst.size());
1324 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1325 delete postForwardFull;
1326
1327 signalVector::iterator dPtr = postForward->begin();
1328 signalVector::iterator dBackPtr;
1329 signalVector::iterator rotPtr = GMSKRotation->begin();
1330 signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
1331
1332 signalVector *DFEoutput = new signalVector(postForward->size());
1333 signalVector::iterator DFEItr = DFEoutput->begin();
1334
1335 // NOTE: can insert the midamble and/or use midamble to estimate BER
1336 for (; dPtr < postForward->end(); dPtr++) {
1337 dBackPtr = dPtr-1;
1338 signalVector::iterator bPtr = b.begin();
1339 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1340 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1341 bPtr++;
1342 dBackPtr--;
1343 }
1344 *dPtr = *dPtr * (*revRotPtr);
1345 *DFEItr = *dPtr;
1346 // make decision on symbol
1347 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1348 //*DFEItr = *dPtr;
1349 *dPtr = *dPtr * (*rotPtr);
1350 DFEItr++;
1351 rotPtr++;
1352 revRotPtr++;
1353 }
1354
1355 vectorSlicer(DFEoutput);
1356
1357 SoftVector *burstBits = new SoftVector(postForward->size());
1358 SoftVector::iterator burstItr = burstBits->begin();
1359 DFEItr = DFEoutput->begin();
1360 for (; DFEItr < DFEoutput->end(); DFEItr++)
1361 *burstItr++ = DFEItr->real();
1362
1363 delete postForward;
1364
1365 delete DFEoutput;
1366
1367 return burstBits;
1368}