blob: 2ccc714fed09b3091a55a4700b079c342bafe983 [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
dburgessb3a0ca42011-10-12 07:44:40 +000032#define TABLESIZE 1024
33
34/** Lookup tables for trigonometric approximation */
35float cosTable[TABLESIZE+1]; // add 1 element for wrap around
36float sinTable[TABLESIZE+1];
37
38/** Constants */
39static const float M_PI_F = (float)M_PI;
40static const float M_2PI_F = (float)(2.0*M_PI);
41static const float M_1_2PI_F = 1/M_2PI_F;
42
43/** Static vectors that contain a precomputed +/- f_b/4 sinusoid */
44signalVector *GMSKRotation = NULL;
45signalVector *GMSKReverseRotation = NULL;
46
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040047/*
48 * RACH and midamble correlation waveforms
49 */
50struct CorrelationSequence {
51 CorrelationSequence() : sequence(NULL)
52 {
53 }
54
55 ~CorrelationSequence()
56 {
57 delete sequence;
58 }
59
dburgessb3a0ca42011-10-12 07:44:40 +000060 signalVector *sequence;
dburgessb3a0ca42011-10-12 07:44:40 +000061 float TOA;
62 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040063};
dburgessb3a0ca42011-10-12 07:44:40 +000064
Thomas Tsou83e06892013-08-20 16:10:01 -040065/*
66 * Gaussian and empty modulation pulses
67 */
68struct PulseSequence {
69 PulseSequence() : gaussian(NULL), empty(NULL)
70 {
71 }
72
73 ~PulseSequence()
74 {
75 delete gaussian;
76 delete empty;
77 }
78
79 signalVector *gaussian;
80 signalVector *empty;
81};
82
dburgessb3a0ca42011-10-12 07:44:40 +000083CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
84CorrelationSequence *gRACHSequence = NULL;
Thomas Tsou83e06892013-08-20 16:10:01 -040085PulseSequence *GSMPulse = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000086
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040087void sigProcLibDestroy()
88{
dburgessb3a0ca42011-10-12 07:44:40 +000089 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040090 delete gMidambles[i];
91 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000092 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040093
94 delete GMSKRotation;
95 delete GMSKReverseRotation;
96 delete gRACHSequence;
97 delete GSMPulse;
98
99 GMSKRotation = NULL;
100 GMSKReverseRotation = NULL;
101 gRACHSequence = NULL;
102 GSMPulse = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000103}
104
dburgessb3a0ca42011-10-12 07:44:40 +0000105// dB relative to 1.0.
106// if > 1.0, then return 0 dB
107float dB(float x) {
108
109 float arg = 1.0F;
110 float dB = 0.0F;
111
112 if (x >= 1.0F) return 0.0F;
113 if (x <= 0.0F) return -200.0F;
114
115 float prevArg = arg;
116 float prevdB = dB;
117 float stepSize = 16.0F;
118 float dBstepSize = 12.0F;
119 while (stepSize > 1.0F) {
120 do {
121 prevArg = arg;
122 prevdB = dB;
123 arg /= stepSize;
124 dB -= dBstepSize;
125 } while (arg > x);
126 arg = prevArg;
127 dB = prevdB;
128 stepSize *= 0.5F;
129 dBstepSize -= 3.0F;
130 }
131 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
132
133}
134
135// 10^(-dB/10), inverse of dB func.
136float dBinv(float x) {
137
138 float arg = 1.0F;
139 float dB = 0.0F;
140
141 if (x >= 0.0F) return 1.0F;
142 if (x <= -200.0F) return 0.0F;
143
144 float prevArg = arg;
145 float prevdB = dB;
146 float stepSize = 16.0F;
147 float dBstepSize = 12.0F;
148 while (stepSize > 1.0F) {
149 do {
150 prevArg = arg;
151 prevdB = dB;
152 arg /= stepSize;
153 dB -= dBstepSize;
154 } while (dB > x);
155 arg = prevArg;
156 dB = prevdB;
157 stepSize *= 0.5F;
158 dBstepSize -= 3.0F;
159 }
160
161 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
162
163}
164
165float vectorNorm2(const signalVector &x)
166{
167 signalVector::const_iterator xPtr = x.begin();
168 float Energy = 0.0;
169 for (;xPtr != x.end();xPtr++) {
170 Energy += xPtr->norm2();
171 }
172 return Energy;
173}
174
175
176float vectorPower(const signalVector &x)
177{
178 return vectorNorm2(x)/x.size();
179}
180
181/** compute cosine via lookup table */
182float cosLookup(const float x)
183{
184 float arg = x*M_1_2PI_F;
185 while (arg > 1.0F) arg -= 1.0F;
186 while (arg < 0.0F) arg += 1.0F;
187
188 const float argT = arg*((float)TABLESIZE);
189 const int argI = (int)argT;
190 const float delta = argT-argI;
191 const float iDelta = 1.0F-delta;
192 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
193}
194
195/** compute sine via lookup table */
196float sinLookup(const float x)
197{
198 float arg = x*M_1_2PI_F;
199 while (arg > 1.0F) arg -= 1.0F;
200 while (arg < 0.0F) arg += 1.0F;
201
202 const float argT = arg*((float)TABLESIZE);
203 const int argI = (int)argT;
204 const float delta = argT-argI;
205 const float iDelta = 1.0F-delta;
206 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
207}
208
209
210/** compute e^(-jx) via lookup table. */
211complex expjLookup(float x)
212{
213 float arg = x*M_1_2PI_F;
214 while (arg > 1.0F) arg -= 1.0F;
215 while (arg < 0.0F) arg += 1.0F;
216
217 const float argT = arg*((float)TABLESIZE);
218 const int argI = (int)argT;
219 const float delta = argT-argI;
220 const float iDelta = 1.0F-delta;
221 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
222 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
223}
224
225/** Library setup functions */
226void initTrigTables() {
227 for (int i = 0; i < TABLESIZE+1; i++) {
228 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
229 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
230 }
231}
232
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400233void initGMSKRotationTables(int sps)
234{
235 GMSKRotation = new signalVector(157 * sps);
236 GMSKReverseRotation = new signalVector(157 * sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000237 signalVector::iterator rotPtr = GMSKRotation->begin();
238 signalVector::iterator revPtr = GMSKReverseRotation->begin();
239 float phase = 0.0;
240 while (rotPtr != GMSKRotation->end()) {
241 *rotPtr++ = expjLookup(phase);
242 *revPtr++ = expjLookup(-phase);
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400243 phase += M_PI_F / 2.0F / (float) sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000244 }
245}
246
Thomas Tsoue57004d2013-08-20 18:55:33 -0400247bool sigProcLibSetup(int sps)
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400248{
Thomas Tsoue57004d2013-08-20 18:55:33 -0400249 if ((sps != 0) && (sps != 2) && (sps != 4))
250 return false;
251
dburgessb3a0ca42011-10-12 07:44:40 +0000252 initTrigTables();
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400253 initGMSKRotationTables(sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400254 generateGSMPulse(sps, 2);
Thomas Tsoue57004d2013-08-20 18:55:33 -0400255
256 if (!generateRACHSequence(sps)) {
257 sigProcLibDestroy();
258 return false;
259 }
260
261 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000262}
263
264void GMSKRotate(signalVector &x) {
265 signalVector::iterator xPtr = x.begin();
266 signalVector::iterator rotPtr = GMSKRotation->begin();
267 if (x.isRealOnly()) {
268 while (xPtr < x.end()) {
269 *xPtr = *rotPtr++ * (xPtr->real());
270 xPtr++;
271 }
272 }
273 else {
274 while (xPtr < x.end()) {
275 *xPtr = *rotPtr++ * (*xPtr);
276 xPtr++;
277 }
278 }
279}
280
281void GMSKReverseRotate(signalVector &x) {
282 signalVector::iterator xPtr= x.begin();
283 signalVector::iterator rotPtr = GMSKReverseRotation->begin();
284 if (x.isRealOnly()) {
285 while (xPtr < x.end()) {
286 *xPtr = *rotPtr++ * (xPtr->real());
287 xPtr++;
288 }
289 }
290 else {
291 while (xPtr < x.end()) {
292 *xPtr = *rotPtr++ * (*xPtr);
293 xPtr++;
294 }
295 }
296}
297
298
299signalVector* convolve(const signalVector *a,
300 const signalVector *b,
301 signalVector *c,
302 ConvType spanType,
303 unsigned startIx,
304 unsigned len)
305{
306 if ((a==NULL) || (b==NULL)) return NULL;
307 int La = a->size();
308 int Lb = b->size();
309
310 int startIndex;
311 unsigned int outSize;
312 switch (spanType) {
313 case FULL_SPAN:
314 startIndex = 0;
315 outSize = La+Lb-1;
316 break;
317 case OVERLAP_ONLY:
318 startIndex = La;
319 outSize = abs(La-Lb)+1;
320 break;
321 case START_ONLY:
322 startIndex = 0;
323 outSize = La;
324 break;
325 case WITH_TAIL:
326 startIndex = Lb;
327 outSize = La;
328 break;
329 case NO_DELAY:
330 if (Lb % 2)
331 startIndex = Lb/2;
332 else
333 startIndex = Lb/2-1;
334 outSize = La;
335 break;
336 case CUSTOM:
337 startIndex = startIx;
338 outSize = len;
339 break;
340 default:
341 return NULL;
342 }
343
344
345 if (c==NULL)
346 c = new signalVector(outSize);
347 else if (c->size()!=outSize)
348 return NULL;
349
350 signalVector::const_iterator aStart = a->begin();
351 signalVector::const_iterator bStart = b->begin();
352 signalVector::const_iterator aEnd = a->end();
353 signalVector::const_iterator bEnd = b->end();
354 signalVector::iterator cPtr = c->begin();
355 int t = startIndex;
356 int stopIndex = startIndex + outSize;
357 switch (b->getSymmetry()) {
358 case NONE:
359 {
360 while (t < stopIndex) {
361 signalVector::const_iterator aP = aStart+t;
362 signalVector::const_iterator bP = bStart;
363 if (a->isRealOnly() && b->isRealOnly()) {
364 float sum = 0.0;
365 while (bP < bEnd) {
366 if (aP < aStart) break;
367 if (aP < aEnd) sum += (aP->real())*(bP->real());
368 aP--;
369 bP++;
370 }
371 *cPtr++ = sum;
372 }
373 else if (a->isRealOnly()) {
374 complex sum = 0.0;
375 while (bP < bEnd) {
376 if (aP < aStart) break;
377 if (aP < aEnd) sum += (*bP)*(aP->real());
378 aP--;
379 bP++;
380 }
381 *cPtr++ = sum;
382 }
383 else if (b->isRealOnly()) {
384 complex sum = 0.0;
385 while (bP < bEnd) {
386 if (aP < aStart) break;
387 if (aP < aEnd) sum += (*aP)*(bP->real());
388 aP--;
389 bP++;
390 }
391 *cPtr++ = sum;
392 }
393 else {
394 complex sum = 0.0;
395 while (bP < bEnd) {
396 if (aP < aStart) break;
397 if (aP < aEnd) sum += (*aP)*(*bP);
398 aP--;
399 bP++;
400 }
401 *cPtr++ = sum;
402 }
403 t++;
404 }
405 }
406 break;
407 case ABSSYM:
408 {
409 complex sum = 0.0;
410 bool isOdd = (bool) (Lb % 2);
411 if (isOdd)
412 bEnd = bStart + (Lb+1)/2;
413 else
414 bEnd = bStart + Lb/2;
415 while (t < stopIndex) {
416 signalVector::const_iterator aP = aStart+t;
417 signalVector::const_iterator aPsym = aP-Lb+1;
418 signalVector::const_iterator bP = bStart;
419 sum = 0.0;
420 if (!b->isRealOnly()) {
421 while (bP < bEnd) {
422 if (aP < aStart) break;
423 if (aP == aPsym)
424 sum+= (*aP)*(*bP);
425 else if ((aP < aEnd) && (aPsym >= aStart))
426 sum+= ((*aP)+(*aPsym))*(*bP);
427 else if (aP < aEnd)
428 sum += (*aP)*(*bP);
429 else if (aPsym >= aStart)
430 sum += (*aPsym)*(*bP);
431 aP--;
432 aPsym++;
433 bP++;
434 }
435 }
436 else {
437 while (bP < bEnd) {
438 if (aP < aStart) break;
439 if (aP == aPsym)
440 sum+= (*aP)*(bP->real());
441 else if ((aP < aEnd) && (aPsym >= aStart))
442 sum+= ((*aP)+(*aPsym))*(bP->real());
443 else if (aP < aEnd)
444 sum += (*aP)*(bP->real());
445 else if (aPsym >= aStart)
446 sum += (*aPsym)*(bP->real());
447 aP--;
448 aPsym++;
449 bP++;
450 }
451 }
452 *cPtr++ = sum;
453 t++;
454 }
455 }
456 break;
457 default:
458 return NULL;
459 break;
460 }
461
462
463 return c;
464}
465
466
Thomas Tsou83e06892013-08-20 16:10:01 -0400467void generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000468{
Thomas Tsou83e06892013-08-20 16:10:01 -0400469 int len;
470 float arg, center;
dburgessb3a0ca42011-10-12 07:44:40 +0000471
Thomas Tsou83e06892013-08-20 16:10:01 -0400472 delete GSMPulse;
473
474 /* Store a single tap filter used for correlation sequence generation */
475 GSMPulse = new PulseSequence();
476 GSMPulse->empty = new signalVector(1);
477 GSMPulse->empty->isRealOnly(true);
478 *(GSMPulse->empty->begin()) = 1.0f;
479
480 /* GSM pulse approximation */
481 GSMPulse->gaussian = new signalVector(len);
482 GSMPulse->gaussian->isRealOnly(true);
483 signalVector::iterator xP = GSMPulse->gaussian->begin();
484
485 center = (float) (len - 1.0) / 2.0;
486
487 for (int i = 0; i < len; i++) {
488 arg = ((float) i - center) / (float) sps;
489 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
490 0.527 * arg * arg * arg * arg);
dburgessb3a0ca42011-10-12 07:44:40 +0000491 }
492
Thomas Tsou83e06892013-08-20 16:10:01 -0400493 float avgAbsval = sqrtf(vectorNorm2(*GSMPulse->gaussian)/sps);
494 xP = GSMPulse->gaussian->begin();
495 for (int i = 0; i < len; i++)
dburgessb3a0ca42011-10-12 07:44:40 +0000496 *xP++ /= avgAbsval;
dburgessb3a0ca42011-10-12 07:44:40 +0000497}
498
499signalVector* frequencyShift(signalVector *y,
500 signalVector *x,
501 float freq,
502 float startPhase,
503 float *finalPhase)
504{
505
506 if (!x) return NULL;
507
508 if (y==NULL) {
509 y = new signalVector(x->size());
510 y->isRealOnly(x->isRealOnly());
511 if (y==NULL) return NULL;
512 }
513
514 if (y->size() < x->size()) return NULL;
515
516 float phase = startPhase;
517 signalVector::iterator yP = y->begin();
518 signalVector::iterator xPEnd = x->end();
519 signalVector::iterator xP = x->begin();
520
521 if (x->isRealOnly()) {
522 while (xP < xPEnd) {
523 (*yP++) = expjLookup(phase)*( (xP++)->real() );
524 phase += freq;
525 }
526 }
527 else {
528 while (xP < xPEnd) {
529 (*yP++) = (*xP++)*expjLookup(phase);
530 phase += freq;
531 }
532 }
533
534
535 if (finalPhase) *finalPhase = phase;
536
537 return y;
538}
539
540signalVector* reverseConjugate(signalVector *b)
541{
542 signalVector *tmp = new signalVector(b->size());
543 tmp->isRealOnly(b->isRealOnly());
544 signalVector::iterator bP = b->begin();
545 signalVector::iterator bPEnd = b->end();
546 signalVector::iterator tmpP = tmp->end()-1;
547 if (!b->isRealOnly()) {
548 while (bP < bPEnd) {
549 *tmpP-- = bP->conj();
550 bP++;
551 }
552 }
553 else {
554 while (bP < bPEnd) {
555 *tmpP-- = bP->real();
556 bP++;
557 }
558 }
559
560 return tmp;
561}
562
563signalVector* correlate(signalVector *a,
564 signalVector *b,
565 signalVector *c,
566 ConvType spanType,
567 bool bReversedConjugated,
568 unsigned startIx,
569 unsigned len)
570{
571 signalVector *tmp = NULL;
572
573 if (!bReversedConjugated) {
574 tmp = reverseConjugate(b);
575 }
576 else {
577 tmp = b;
578 }
579
580 c = convolve(a,tmp,c,spanType,startIx,len);
581
582 if (!bReversedConjugated) delete tmp;
583
584 return c;
585}
586
587
588/* soft output slicer */
589bool vectorSlicer(signalVector *x)
590{
591
592 signalVector::iterator xP = x->begin();
593 signalVector::iterator xPEnd = x->end();
594 while (xP < xPEnd) {
595 *xP = (complex) (0.5*(xP->real()+1.0F));
596 if (xP->real() > 1.0) *xP = 1.0;
597 if (xP->real() < 0.0) *xP = 0.0;
598 xP++;
599 }
600 return true;
601}
602
Thomas Tsou83e06892013-08-20 16:10:01 -0400603signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
604 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000605{
Thomas Tsou83e06892013-08-20 16:10:01 -0400606 int burstLen;
607 signalVector *pulse, modBurst;
608 signalVector::iterator modBurstItr;
dburgessb3a0ca42011-10-12 07:44:40 +0000609
Thomas Tsou83e06892013-08-20 16:10:01 -0400610 if (emptyPulse)
611 pulse = GSMPulse->empty;
612 else
613 pulse = GSMPulse->gaussian;
dburgessb3a0ca42011-10-12 07:44:40 +0000614
Thomas Tsou83e06892013-08-20 16:10:01 -0400615 burstLen = sps * (wBurst.size() + guardPeriodLength);
616 modBurst = signalVector(burstLen);
617 modBurstItr = modBurst.begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000618
dburgessb3a0ca42011-10-12 07:44:40 +0000619 for (unsigned int i = 0; i < wBurst.size(); i++) {
620 *modBurstItr = 2.0*(wBurst[i] & 0x01)-1.0;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400621 modBurstItr += sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000622 }
623
624 // shift up pi/2
625 // ignore starting phase, since spec allows for discontinuous phase
626 GMSKRotate(modBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -0400627
dburgessb3a0ca42011-10-12 07:44:40 +0000628 modBurst.isRealOnly(false);
629
630 // filter w/ pulse shape
Thomas Tsou83e06892013-08-20 16:10:01 -0400631 signalVector *shapedBurst = convolve(&modBurst, pulse, NULL, NO_DELAY);
dburgessb3a0ca42011-10-12 07:44:40 +0000632
dburgessb3a0ca42011-10-12 07:44:40 +0000633 return shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +0000634}
635
636float sinc(float x)
637{
638 if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
639 return 1.0F;
640}
641
642void delayVector(signalVector &wBurst,
643 float delay)
644{
645
646 int intOffset = (int) floor(delay);
647 float fracOffset = delay - intOffset;
648
649 // do fractional shift first, only do it for reasonable offsets
650 if (fabs(fracOffset) > 1e-2) {
651 // create sinc function
652 signalVector sincVector(21);
653 sincVector.isRealOnly(true);
654 signalVector::iterator sincBurstItr = sincVector.begin();
655 for (int i = 0; i < 21; i++)
656 *sincBurstItr++ = (complex) sinc(M_PI_F*(i-10-fracOffset));
657
658 signalVector shiftedBurst(wBurst.size());
659 convolve(&wBurst,&sincVector,&shiftedBurst,NO_DELAY);
660 wBurst.clone(shiftedBurst);
661 }
662
663 if (intOffset < 0) {
664 intOffset = -intOffset;
665 signalVector::iterator wBurstItr = wBurst.begin();
666 signalVector::iterator shiftedItr = wBurst.begin()+intOffset;
667 while (shiftedItr < wBurst.end())
668 *wBurstItr++ = *shiftedItr++;
669 while (wBurstItr < wBurst.end())
670 *wBurstItr++ = 0.0;
671 }
672 else {
673 signalVector::iterator wBurstItr = wBurst.end()-1;
674 signalVector::iterator shiftedItr = wBurst.end()-1-intOffset;
675 while (shiftedItr >= wBurst.begin())
676 *wBurstItr-- = *shiftedItr--;
677 while (wBurstItr >= wBurst.begin())
678 *wBurstItr-- = 0.0;
679 }
680}
681
682signalVector *gaussianNoise(int length,
683 float variance,
684 complex mean)
685{
686
687 signalVector *noise = new signalVector(length);
688 signalVector::iterator nPtr = noise->begin();
689 float stddev = sqrtf(variance);
690 while (nPtr < noise->end()) {
691 float u1 = (float) rand()/ (float) RAND_MAX;
692 while (u1==0.0)
693 u1 = (float) rand()/ (float) RAND_MAX;
694 float u2 = (float) rand()/ (float) RAND_MAX;
695 float arg = 2.0*M_PI*u2;
696 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
697 nPtr++;
698 }
699
700 return noise;
701}
702
703complex interpolatePoint(const signalVector &inSig,
704 float ix)
705{
706
707 int start = (int) (floor(ix) - 10);
708 if (start < 0) start = 0;
709 int end = (int) (floor(ix) + 11);
710 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
711
712 complex pVal = 0.0;
713 if (!inSig.isRealOnly()) {
714 for (int i = start; i < end; i++)
715 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
716 }
717 else {
718 for (int i = start; i < end; i++)
719 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
720 }
721
722 return pVal;
723}
724
725
726
727complex peakDetect(const signalVector &rxBurst,
728 float *peakIndex,
729 float *avgPwr)
730{
731
732
733 complex maxVal = 0.0;
734 float maxIndex = -1;
735 float sumPower = 0.0;
736
737 for (unsigned int i = 0; i < rxBurst.size(); i++) {
738 float samplePower = rxBurst[i].norm2();
739 if (samplePower > maxVal.real()) {
740 maxVal = samplePower;
741 maxIndex = i;
742 }
743 sumPower += samplePower;
744 }
745
746 // interpolate around the peak
747 // to save computation, we'll use early-late balancing
748 float earlyIndex = maxIndex-1;
749 float lateIndex = maxIndex+1;
750
751 float incr = 0.5;
752 while (incr > 1.0/1024.0) {
753 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
754 complex lateP = interpolatePoint(rxBurst,lateIndex);
755 if (earlyP < lateP)
756 earlyIndex += incr;
757 else if (earlyP > lateP)
758 earlyIndex -= incr;
759 else break;
760 incr /= 2.0;
761 lateIndex = earlyIndex + 2.0;
762 }
763
764 maxIndex = earlyIndex + 1.0;
765 maxVal = interpolatePoint(rxBurst,maxIndex);
766
767 if (peakIndex!=NULL)
768 *peakIndex = maxIndex;
769
770 if (avgPwr!=NULL)
771 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
772
773 return maxVal;
774
775}
776
777void scaleVector(signalVector &x,
778 complex scale)
779{
780 signalVector::iterator xP = x.begin();
781 signalVector::iterator xPEnd = x.end();
782 if (!x.isRealOnly()) {
783 while (xP < xPEnd) {
784 *xP = *xP * scale;
785 xP++;
786 }
787 }
788 else {
789 while (xP < xPEnd) {
790 *xP = xP->real() * scale;
791 xP++;
792 }
793 }
794}
795
796/** in-place conjugation */
797void conjugateVector(signalVector &x)
798{
799 if (x.isRealOnly()) return;
800 signalVector::iterator xP = x.begin();
801 signalVector::iterator xPEnd = x.end();
802 while (xP < xPEnd) {
803 *xP = xP->conj();
804 xP++;
805 }
806}
807
808
809// in-place addition!!
810bool addVector(signalVector &x,
811 signalVector &y)
812{
813 signalVector::iterator xP = x.begin();
814 signalVector::iterator yP = y.begin();
815 signalVector::iterator xPEnd = x.end();
816 signalVector::iterator yPEnd = y.end();
817 while ((xP < xPEnd) && (yP < yPEnd)) {
818 *xP = *xP + *yP;
819 xP++; yP++;
820 }
821 return true;
822}
823
824// in-place multiplication!!
825bool multVector(signalVector &x,
826 signalVector &y)
827{
828 signalVector::iterator xP = x.begin();
829 signalVector::iterator yP = y.begin();
830 signalVector::iterator xPEnd = x.end();
831 signalVector::iterator yPEnd = y.end();
832 while ((xP < xPEnd) && (yP < yPEnd)) {
833 *xP = (*xP) * (*yP);
834 xP++; yP++;
835 }
836 return true;
837}
838
839
840void offsetVector(signalVector &x,
841 complex offset)
842{
843 signalVector::iterator xP = x.begin();
844 signalVector::iterator xPEnd = x.end();
845 if (!x.isRealOnly()) {
846 while (xP < xPEnd) {
847 *xP += offset;
848 xP++;
849 }
850 }
851 else {
852 while (xP < xPEnd) {
853 *xP = xP->real() + offset;
854 xP++;
855 }
856 }
857}
858
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400859bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +0000860{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400861 bool status = true;
862 complex *data = NULL;
863 signalVector *autocorr = NULL, *midamble = NULL;
864 signalVector *midMidamble = NULL;
865
866 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +0000867 return false;
868
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400869 delete gMidambles[tsc];
870
871 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
872 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
873 if (!midMidamble)
874 return false;
875
876 /* Simulated receive sequence is pulse shaped */
877 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
878 if (!midamble) {
879 status = false;
880 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000881 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400882
dburgessb3a0ca42011-10-12 07:44:40 +0000883 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
884 // the ideal TSC has an + 180 degree phase shift,
885 // due to the pi/2 frequency shift, that
886 // needs to be accounted for.
887 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400888 scaleVector(*midMidamble, complex(-1.0, 0.0));
889 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +0000890
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400891 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +0000892
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400893 autocorr = correlate(midamble, midMidamble, NULL, NO_DELAY);
894 if (!autocorr) {
895 status = false;
896 goto release;
897 }
dburgessb3a0ca42011-10-12 07:44:40 +0000898
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400899 gMidambles[tsc] = new CorrelationSequence;
900 gMidambles[tsc]->sequence = midMidamble;
901 gMidambles[tsc]->gain = peakDetect(*autocorr,&gMidambles[tsc]->TOA,NULL);
dburgessb3a0ca42011-10-12 07:44:40 +0000902
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400903release:
dburgessb3a0ca42011-10-12 07:44:40 +0000904 delete autocorr;
905 delete midamble;
906
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400907 if (!status) {
908 delete midMidamble;
909 gMidambles[tsc] = NULL;
910 }
911
912 return status;
dburgessb3a0ca42011-10-12 07:44:40 +0000913}
914
Thomas Tsou83e06892013-08-20 16:10:01 -0400915bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +0000916{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400917 bool status = true;
918 complex *data = NULL;
919 signalVector *autocorr = NULL;
920 signalVector *seq0 = NULL, *seq1 = NULL;
921
922 delete gRACHSequence;
923
924 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
925 if (!seq0)
926 return false;
927
928 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
929 if (!seq1) {
930 status = false;
931 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000932 }
933
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400934 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +0000935
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400936 autocorr = new signalVector(seq0->size());
937 if (!convolve(seq0, seq1, autocorr, NO_DELAY)) {
938 status = false;
939 goto release;
940 }
dburgessb3a0ca42011-10-12 07:44:40 +0000941
942 gRACHSequence = new CorrelationSequence;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400943 gRACHSequence->sequence = seq1;
dburgessb3a0ca42011-10-12 07:44:40 +0000944 gRACHSequence->gain = peakDetect(*autocorr,&gRACHSequence->TOA,NULL);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400945
946release:
dburgessb3a0ca42011-10-12 07:44:40 +0000947 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400948 delete seq0;
dburgessb3a0ca42011-10-12 07:44:40 +0000949
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400950 if (!status) {
951 delete seq1;
952 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}
dburgessb3a0ca42011-10-12 07:44:40 +0000957
958bool detectRACHBurst(signalVector &rxBurst,
959 float detectThreshold,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400960 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +0000961 complex *amplitude,
962 float* TOA)
963{
964
965 //static complex staticData[500];
966
967 //signalVector correlatedRACH(staticData,0,rxBurst.size());
968 signalVector correlatedRACH(rxBurst.size());
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400969 correlate(&rxBurst,gRACHSequence->sequence,&correlatedRACH,NO_DELAY,true);
dburgessb3a0ca42011-10-12 07:44:40 +0000970
971 float meanPower;
972 complex peakAmpl = peakDetect(correlatedRACH,TOA,&meanPower);
973
974 float valleyPower = 0.0;
975
976 // check for bogus results
977 if ((*TOA < 0.0) || (*TOA > correlatedRACH.size())) {
978 *amplitude = 0.0;
979 return false;
980 }
981 complex *peakPtr = correlatedRACH.begin() + (int) rint(*TOA);
982
dburgessb3a0ca42011-10-12 07:44:40 +0000983 float numSamples = 0.0;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400984 for (int i = 57 * sps; i <= 107 * sps; i++) {
dburgessb3a0ca42011-10-12 07:44:40 +0000985 if (peakPtr+i >= correlatedRACH.end())
986 break;
987 valleyPower += (peakPtr+i)->norm2();
988 numSamples++;
989 }
990
991 if (numSamples < 2) {
992 *amplitude = 0.0;
993 return false;
994 }
995
996 float RMS = sqrtf(valleyPower/(float) numSamples)+0.00001;
997 float peakToMean = peakAmpl.abs()/RMS;
998
dburgessb3a0ca42011-10-12 07:44:40 +0000999 *amplitude = peakAmpl/(gRACHSequence->gain);
1000
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001001 *TOA = (*TOA) - gRACHSequence->TOA - 8 * sps;
dburgessb3a0ca42011-10-12 07:44:40 +00001002
dburgessb3a0ca42011-10-12 07:44:40 +00001003 return (peakToMean > detectThreshold);
1004}
1005
1006bool energyDetect(signalVector &rxBurst,
1007 unsigned windowLength,
1008 float detectThreshold,
1009 float *avgPwr)
1010{
1011
1012 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1013 float energy = 0.0;
1014 if (windowLength < 0) windowLength = 20;
1015 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1016 for (unsigned i = 0; i < windowLength; i++) {
1017 energy += windowItr->norm2();
1018 windowItr+=4;
1019 }
1020 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001021 return (energy/windowLength > detectThreshold*detectThreshold);
1022}
1023
1024
1025bool analyzeTrafficBurst(signalVector &rxBurst,
1026 unsigned TSC,
1027 float detectThreshold,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001028 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001029 complex *amplitude,
1030 float *TOA,
1031 unsigned maxTOA,
1032 bool requestChannel,
1033 signalVector **channelResponse,
1034 float *channelResponseOffset)
1035{
1036
1037 assert(TSC<8);
1038 assert(amplitude);
1039 assert(TOA);
1040 assert(gMidambles[TSC]);
1041
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001042 if (maxTOA < 3*sps) maxTOA = 3*sps;
dburgessb3a0ca42011-10-12 07:44:40 +00001043 unsigned spanTOA = maxTOA;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001044 if (spanTOA < 5*sps) spanTOA = 5*sps;
dburgessb3a0ca42011-10-12 07:44:40 +00001045
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001046 unsigned startIx = 66*sps-spanTOA;
1047 unsigned endIx = (66+16)*sps+spanTOA;
dburgessb3a0ca42011-10-12 07:44:40 +00001048 unsigned windowLen = endIx - startIx;
1049 unsigned corrLen = 2*maxTOA+1;
1050
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001051 unsigned expectedTOAPeak = (unsigned) round(gMidambles[TSC]->TOA + (gMidambles[TSC]->sequence->size()-1)/2);
dburgessb3a0ca42011-10-12 07:44:40 +00001052
1053 signalVector burstSegment(rxBurst.begin(),startIx,windowLen);
1054
1055 //static complex staticData[200];
1056 //signalVector correlatedBurst(staticData,0,corrLen);
1057 signalVector correlatedBurst(corrLen);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001058 correlate(&burstSegment, gMidambles[TSC]->sequence,
dburgessb3a0ca42011-10-12 07:44:40 +00001059 &correlatedBurst, CUSTOM,true,
1060 expectedTOAPeak-maxTOA,corrLen);
1061
1062 float meanPower;
1063 *amplitude = peakDetect(correlatedBurst,TOA,&meanPower);
1064 float valleyPower = 0.0; //amplitude->norm2();
1065 complex *peakPtr = correlatedBurst.begin() + (int) rint(*TOA);
1066
1067 // check for bogus results
1068 if ((*TOA < 0.0) || (*TOA > correlatedBurst.size())) {
1069 *amplitude = 0.0;
1070 return false;
1071 }
1072
1073 int numRms = 0;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001074 for (int i = 2*sps; i <= 5*sps;i++) {
dburgessb3a0ca42011-10-12 07:44:40 +00001075 if (peakPtr - i >= correlatedBurst.begin()) {
1076 valleyPower += (peakPtr-i)->norm2();
1077 numRms++;
1078 }
1079 if (peakPtr + i < correlatedBurst.end()) {
1080 valleyPower += (peakPtr+i)->norm2();
1081 numRms++;
1082 }
1083 }
1084
1085 if (numRms < 2) {
1086 // check for bogus results
1087 *amplitude = 0.0;
1088 return false;
1089 }
1090
1091 float RMS = sqrtf(valleyPower/(float)numRms)+0.00001;
1092 float peakToMean = (amplitude->abs())/RMS;
1093
1094 // NOTE: Because ideal TSC is 66 symbols into burst,
1095 // the ideal TSC has an +/- 180 degree phase shift,
1096 // due to the pi/4 frequency shift, that
1097 // needs to be accounted for.
1098
1099 *amplitude = (*amplitude)/gMidambles[TSC]->gain;
1100 *TOA = (*TOA) - (maxTOA);
1101
dburgessb3a0ca42011-10-12 07:44:40 +00001102 if (requestChannel && (peakToMean > detectThreshold)) {
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001103 float TOAoffset = maxTOA;
dburgessb3a0ca42011-10-12 07:44:40 +00001104 delayVector(correlatedBurst,-(*TOA));
1105 // midamble only allows estimation of a 6-tap channel
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001106 signalVector chanVector(6 * sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001107 float maxEnergy = -1.0;
1108 int maxI = -1;
1109 for (int i = 0; i < 7; i++) {
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001110 if (TOAoffset + (i-5) * sps + chanVector.size() > correlatedBurst.size())
1111 continue;
1112 if (TOAoffset + (i-5) * sps < 0)
1113 continue;
1114 correlatedBurst.segmentCopyTo(chanVector,
1115 (int) floor(TOAoffset + (i - 5) * sps),
1116 chanVector.size());
1117 float energy = vectorNorm2(chanVector);
dburgessb3a0ca42011-10-12 07:44:40 +00001118 if (energy > 0.95*maxEnergy) {
1119 maxI = i;
1120 maxEnergy = energy;
1121 }
1122 }
1123
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001124 *channelResponse = new signalVector(chanVector.size());
1125 correlatedBurst.segmentCopyTo(**channelResponse,
1126 (int) floor(TOAoffset + (maxI - 5) * sps),
1127 (*channelResponse)->size());
1128 scaleVector(**channelResponse, complex(1.0, 0.0) / gMidambles[TSC]->gain);
dburgessb3a0ca42011-10-12 07:44:40 +00001129
1130 if (channelResponseOffset)
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001131 *channelResponseOffset = 5 * sps - maxI;
dburgessb3a0ca42011-10-12 07:44:40 +00001132
1133 }
1134
1135 return (peakToMean > detectThreshold);
1136
1137}
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}
1189
1190
1191// 1.0 is sampling frequency
1192// must satisfy cutoffFreq > 1/filterLen
1193signalVector *createLPF(float cutoffFreq,
1194 int filterLen,
1195 float gainDC)
1196{
kurtis.heimerla198d452011-11-26 03:19:28 +00001197#if 0
dburgessb3a0ca42011-10-12 07:44:40 +00001198 signalVector *LPF = new signalVector(filterLen-1);
1199 LPF->isRealOnly(true);
1200 LPF->setSymmetry(ABSSYM);
1201 signalVector::iterator itr = LPF->begin();
1202 double sum = 0.0;
1203 for (int i = 1; i < filterLen; i++) {
1204 float ys = sinc(M_2PI_F*cutoffFreq*((float)i-(float)(filterLen)/2.0F));
1205 float yg = 4.0F * cutoffFreq;
1206 // Blackman -- less brickwall (sloping transition) but larger stopband attenuation
1207 float yw = 0.42 - 0.5*cos(((float)i)*M_2PI_F/(float)(filterLen)) + 0.08*cos(((float)i)*2*M_2PI_F/(float)(filterLen));
1208 // Hamming -- more brickwall with smaller stopband attenuation
1209 //float yw = 0.53836F - 0.46164F * cos(((float)i)*M_2PI_F/(float)(filterLen+1));
1210 *itr++ = (complex) ys*yg*yw;
1211 sum += ys*yg*yw;
1212 }
kurtis.heimerla198d452011-11-26 03:19:28 +00001213#else
1214 double sum = 0.0;
1215 signalVector *LPF;
1216 signalVector::iterator itr;
1217 if (filterLen == 651) { // receive LPF
1218 LPF = new signalVector(651);
1219 LPF->isRealOnly(true);
1220 itr = LPF->begin();
1221 for (int i = 0; i < filterLen; i++) {
1222 *itr++ = complex(rcvLPF_651[i],0.0);
1223 sum += rcvLPF_651[i];
1224 }
1225 }
1226 else {
1227 LPF = new signalVector(961);
1228 LPF->isRealOnly(true);
1229 itr = LPF->begin();
1230 for (int i = 0; i < filterLen; i++) {
1231 *itr++ = complex(sendLPF_961[i],0.0);
1232 sum += sendLPF_961[i];
1233 }
1234 }
1235#endif
1236
dburgessb3a0ca42011-10-12 07:44:40 +00001237 float normFactor = gainDC/sum; //sqrtf(gainDC/vectorNorm2(*LPF));
1238 // normalize power
1239 itr = LPF->begin();
kurtis.heimerla198d452011-11-26 03:19:28 +00001240 for (int i = 0; i < filterLen; i++) {
dburgessb3a0ca42011-10-12 07:44:40 +00001241 *itr = *itr*normFactor;
1242 itr++;
1243 }
1244 return LPF;
1245
1246}
1247
1248
1249
1250#define POLYPHASESPAN 10
1251
1252// assumes filter group delay is 0.5*(length of filter)
1253signalVector *polyphaseResampleVector(signalVector &wVector,
1254 int P, int Q,
1255 signalVector *LPF)
1256
1257{
1258
1259 bool deleteLPF = false;
1260
1261 if (LPF==NULL) {
1262 float cutoffFreq = (P < Q) ? (1.0/(float) Q) : (1.0/(float) P);
1263 LPF = createLPF(cutoffFreq/3.0,100*POLYPHASESPAN+1,Q);
1264 deleteLPF = true;
1265 }
1266
1267 signalVector *resampledVector = new signalVector((int) ceil(wVector.size()*(float) P / (float) Q));
1268 resampledVector->fill(0);
1269 resampledVector->isRealOnly(wVector.isRealOnly());
1270 signalVector::iterator newItr = resampledVector->begin();
1271
1272 //FIXME: need to update for real-only vectors
1273 int outputIx = (LPF->size()+1)/2/Q; //((P > Q) ? P : Q);
1274 while (newItr < resampledVector->end()) {
1275 int outputBranch = (outputIx*Q) % P;
1276 int inputOffset = (outputIx*Q - outputBranch)/P;
1277 signalVector::const_iterator inputItr = wVector.begin() + inputOffset;
1278 signalVector::const_iterator filtItr = LPF->begin() + outputBranch;
1279 while (inputItr >= wVector.end()) {
1280 inputItr--;
1281 filtItr+=P;
1282 }
1283 complex sum = 0.0;
1284 if ((LPF->getSymmetry()!=ABSSYM) || (P>1)) {
1285 if (!LPF->isRealOnly()) {
1286 while ( (inputItr >= wVector.begin()) && (filtItr < LPF->end()) ) {
1287 sum += (*inputItr)*(*filtItr);
1288 inputItr--;
1289 filtItr += P;
1290 }
1291 }
1292 else {
1293 while ( (inputItr >= wVector.begin()) && (filtItr < LPF->end()) ) {
1294 sum += (*inputItr)*(filtItr->real());
1295 inputItr--;
1296 filtItr += P;
1297 }
1298 }
1299 }
1300 else {
1301 signalVector::const_iterator revInputItr = inputItr- LPF->size() + 1;
1302 signalVector::const_iterator filtMidpoint = LPF->begin()+(LPF->size()-1)/2;
1303 if (!LPF->isRealOnly()) {
1304 while (filtItr <= filtMidpoint) {
1305 if (inputItr < revInputItr) break;
1306 if (inputItr == revInputItr)
1307 sum += (*inputItr)*(*filtItr);
1308 else if ( (inputItr < wVector.end()) && (revInputItr >= wVector.begin()) )
1309 sum += (*inputItr + *revInputItr)*(*filtItr);
1310 else if ( inputItr < wVector.end() )
1311 sum += (*inputItr)*(*filtItr);
1312 else if ( revInputItr >= wVector.begin() )
1313 sum += (*revInputItr)*(*filtItr);
1314 inputItr--;
1315 revInputItr++;
1316 filtItr++;
1317 }
1318 }
1319 else {
1320 while (filtItr <= filtMidpoint) {
1321 if (inputItr < revInputItr) break;
1322 if (inputItr == revInputItr)
1323 sum += (*inputItr)*(filtItr->real());
1324 else if ( (inputItr < wVector.end()) && (revInputItr >= wVector.begin()) )
1325 sum += (*inputItr + *revInputItr)*(filtItr->real());
1326 else if ( inputItr < wVector.end() )
1327 sum += (*inputItr)*(filtItr->real());
1328 else if ( revInputItr >= wVector.begin() )
1329 sum += (*revInputItr)*(filtItr->real());
1330 inputItr--;
1331 revInputItr++;
1332 filtItr++;
1333 }
1334 }
1335 }
1336 *newItr = sum;
1337 newItr++;
1338 outputIx++;
1339 }
1340
1341 if (deleteLPF) delete LPF;
1342
1343 return resampledVector;
1344}
1345
1346
1347signalVector *resampleVector(signalVector &wVector,
1348 float expFactor,
1349 complex endPoint)
1350
1351{
1352
1353 if (expFactor < 1.0) return NULL;
1354
1355 signalVector *retVec = new signalVector((int) ceil(wVector.size()*expFactor));
1356
1357 float t = 0.0;
1358
1359 signalVector::iterator retItr = retVec->begin();
1360 while (retItr < retVec->end()) {
1361 unsigned tLow = (unsigned int) floor(t);
1362 unsigned tHigh = tLow + 1;
1363 if (tLow > wVector.size()-1) break;
1364 if (tHigh > wVector.size()) break;
1365 complex lowPoint = wVector[tLow];
1366 complex highPoint = (tHigh == wVector.size()) ? endPoint : wVector[tHigh];
1367 complex a = (tHigh-t);
1368 complex b = (t-tLow);
1369 *retItr = (a*lowPoint + b*highPoint);
1370 t += 1.0/expFactor;
1371 }
1372
1373 return retVec;
1374
1375}
1376
1377
1378// Assumes symbol-spaced sampling!!!
1379// Based upon paper by Al-Dhahir and Cioffi
1380bool designDFE(signalVector &channelResponse,
1381 float SNRestimate,
1382 int Nf,
1383 signalVector **feedForwardFilter,
1384 signalVector **feedbackFilter)
1385{
1386
1387 signalVector G0(Nf);
1388 signalVector G1(Nf);
1389 signalVector::iterator G0ptr = G0.begin();
1390 signalVector::iterator G1ptr = G1.begin();
1391 signalVector::iterator chanPtr = channelResponse.begin();
1392
1393 int nu = channelResponse.size()-1;
1394
1395 *G0ptr = 1.0/sqrtf(SNRestimate);
1396 for(int j = 0; j <= nu; j++) {
1397 *G1ptr = chanPtr->conj();
1398 G1ptr++; chanPtr++;
1399 }
1400
1401 signalVector *L[Nf];
1402 signalVector::iterator Lptr;
1403 float d;
1404 for(int i = 0; i < Nf; i++) {
1405 d = G0.begin()->norm2() + G1.begin()->norm2();
1406 L[i] = new signalVector(Nf+nu);
1407 Lptr = L[i]->begin()+i;
1408 G0ptr = G0.begin(); G1ptr = G1.begin();
1409 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1410 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1411 Lptr++;
1412 G0ptr++;
1413 G1ptr++;
1414 }
1415 complex k = (*G1.begin())/(*G0.begin());
1416
1417 if (i != Nf-1) {
1418 signalVector G0new = G1;
1419 scaleVector(G0new,k.conj());
1420 addVector(G0new,G0);
1421
1422 signalVector G1new = G0;
1423 scaleVector(G1new,k*(-1.0));
1424 addVector(G1new,G1);
1425 delayVector(G1new,-1.0);
1426
1427 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1428 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1429 G0 = G0new;
1430 G1 = G1new;
1431 }
1432 }
1433
1434 *feedbackFilter = new signalVector(nu);
1435 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1436 scaleVector(**feedbackFilter,(complex) -1.0);
1437 conjugateVector(**feedbackFilter);
1438
1439 signalVector v(Nf);
1440 signalVector::iterator vStart = v.begin();
1441 signalVector::iterator vPtr;
1442 *(vStart+Nf-1) = (complex) 1.0;
1443 for(int k = Nf-2; k >= 0; k--) {
1444 Lptr = L[k]->begin()+k+1;
1445 vPtr = vStart + k+1;
1446 complex v_k = 0.0;
1447 for (int j = k+1; j < Nf; j++) {
1448 v_k -= (*vPtr)*(*Lptr);
1449 vPtr++; Lptr++;
1450 }
1451 *(vStart + k) = v_k;
1452 }
1453
1454 *feedForwardFilter = new signalVector(Nf);
1455 signalVector::iterator w = (*feedForwardFilter)->begin();
1456 for (int i = 0; i < Nf; i++) {
1457 delete L[i];
1458 complex w_i = 0.0;
1459 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1460 vPtr = vStart+i;
1461 chanPtr = channelResponse.begin();
1462 for (int k = 0; k < endPt+1; k++) {
1463 w_i += (*vPtr)*(chanPtr->conj());
1464 vPtr++; chanPtr++;
1465 }
1466 *w = w_i/d;
1467 w++;
1468 }
1469
1470
1471 return true;
1472
1473}
1474
1475// Assumes symbol-rate sampling!!!!
1476SoftVector *equalizeBurst(signalVector &rxBurst,
1477 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001478 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001479 signalVector &w, // feedforward filter
1480 signalVector &b) // feedback filter
1481{
1482
1483 delayVector(rxBurst,-TOA);
1484
1485 signalVector* postForwardFull = convolve(&rxBurst,&w,NULL,FULL_SPAN);
1486
1487 signalVector* postForward = new signalVector(rxBurst.size());
1488 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1489 delete postForwardFull;
1490
1491 signalVector::iterator dPtr = postForward->begin();
1492 signalVector::iterator dBackPtr;
1493 signalVector::iterator rotPtr = GMSKRotation->begin();
1494 signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
1495
1496 signalVector *DFEoutput = new signalVector(postForward->size());
1497 signalVector::iterator DFEItr = DFEoutput->begin();
1498
1499 // NOTE: can insert the midamble and/or use midamble to estimate BER
1500 for (; dPtr < postForward->end(); dPtr++) {
1501 dBackPtr = dPtr-1;
1502 signalVector::iterator bPtr = b.begin();
1503 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1504 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1505 bPtr++;
1506 dBackPtr--;
1507 }
1508 *dPtr = *dPtr * (*revRotPtr);
1509 *DFEItr = *dPtr;
1510 // make decision on symbol
1511 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1512 //*DFEItr = *dPtr;
1513 *dPtr = *dPtr * (*rotPtr);
1514 DFEItr++;
1515 rotPtr++;
1516 revRotPtr++;
1517 }
1518
1519 vectorSlicer(DFEoutput);
1520
1521 SoftVector *burstBits = new SoftVector(postForward->size());
1522 SoftVector::iterator burstItr = burstBits->begin();
1523 DFEItr = DFEoutput->begin();
1524 for (; DFEItr < DFEoutput->end(); DFEItr++)
1525 *burstItr++ = DFEItr->real();
1526
1527 delete postForward;
1528
1529 delete DFEoutput;
1530
1531 return burstBits;
1532}