blob: fe09c16685c2774421f958aba462512da48cbb53 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
2* Copyright 2008 Free Software Foundation, Inc.
3*
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
25
26
27#define NDEBUG
28
29#include "sigProcLib.h"
30#include "GSMCommon.h"
31
32#include <Logger.h>
33
34#define TABLESIZE 1024
35
36/** Lookup tables for trigonometric approximation */
37float cosTable[TABLESIZE+1]; // add 1 element for wrap around
38float sinTable[TABLESIZE+1];
39
40/** Constants */
41static const float M_PI_F = (float)M_PI;
42static const float M_2PI_F = (float)(2.0*M_PI);
43static const float M_1_2PI_F = 1/M_2PI_F;
44
45/** Static vectors that contain a precomputed +/- f_b/4 sinusoid */
46signalVector *GMSKRotation = NULL;
47signalVector *GMSKReverseRotation = NULL;
48
49/** Static ideal RACH and midamble correlation waveforms */
50typedef struct {
51 signalVector *sequence;
52 signalVector *sequenceReversedConjugated;
53 float TOA;
54 complex gain;
55} CorrelationSequence;
56
57CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
58CorrelationSequence *gRACHSequence = NULL;
59
60void sigProcLibDestroy(void) {
61 if (GMSKRotation) {
62 delete GMSKRotation;
63 GMSKRotation = NULL;
64 }
65 if (GMSKReverseRotation) {
66 delete GMSKReverseRotation;
67 GMSKReverseRotation = NULL;
68 }
69 for (int i = 0; i < 8; i++) {
70 if (gMidambles[i]!=NULL) {
71 if (gMidambles[i]->sequence) delete gMidambles[i]->sequence;
72 if (gMidambles[i]->sequenceReversedConjugated) delete gMidambles[i]->sequenceReversedConjugated;
73 delete gMidambles[i];
74 gMidambles[i] = NULL;
75 }
76 }
77 if (gRACHSequence) {
78 if (gRACHSequence->sequence) delete gRACHSequence->sequence;
79 if (gRACHSequence->sequenceReversedConjugated) delete gRACHSequence->sequenceReversedConjugated;
80 delete gRACHSequence;
81 gRACHSequence = NULL;
82 }
83}
84
85
86
87// dB relative to 1.0.
88// if > 1.0, then return 0 dB
89float dB(float x) {
90
91 float arg = 1.0F;
92 float dB = 0.0F;
93
94 if (x >= 1.0F) return 0.0F;
95 if (x <= 0.0F) return -200.0F;
96
97 float prevArg = arg;
98 float prevdB = dB;
99 float stepSize = 16.0F;
100 float dBstepSize = 12.0F;
101 while (stepSize > 1.0F) {
102 do {
103 prevArg = arg;
104 prevdB = dB;
105 arg /= stepSize;
106 dB -= dBstepSize;
107 } while (arg > x);
108 arg = prevArg;
109 dB = prevdB;
110 stepSize *= 0.5F;
111 dBstepSize -= 3.0F;
112 }
113 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
114
115}
116
117// 10^(-dB/10), inverse of dB func.
118float dBinv(float x) {
119
120 float arg = 1.0F;
121 float dB = 0.0F;
122
123 if (x >= 0.0F) return 1.0F;
124 if (x <= -200.0F) return 0.0F;
125
126 float prevArg = arg;
127 float prevdB = dB;
128 float stepSize = 16.0F;
129 float dBstepSize = 12.0F;
130 while (stepSize > 1.0F) {
131 do {
132 prevArg = arg;
133 prevdB = dB;
134 arg /= stepSize;
135 dB -= dBstepSize;
136 } while (dB > x);
137 arg = prevArg;
138 dB = prevdB;
139 stepSize *= 0.5F;
140 dBstepSize -= 3.0F;
141 }
142
143 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
144
145}
146
147float vectorNorm2(const signalVector &x)
148{
149 signalVector::const_iterator xPtr = x.begin();
150 float Energy = 0.0;
151 for (;xPtr != x.end();xPtr++) {
152 Energy += xPtr->norm2();
153 }
154 return Energy;
155}
156
157
158float vectorPower(const signalVector &x)
159{
160 return vectorNorm2(x)/x.size();
161}
162
163/** compute cosine via lookup table */
164float cosLookup(const float x)
165{
166 float arg = x*M_1_2PI_F;
167 while (arg > 1.0F) arg -= 1.0F;
168 while (arg < 0.0F) arg += 1.0F;
169
170 const float argT = arg*((float)TABLESIZE);
171 const int argI = (int)argT;
172 const float delta = argT-argI;
173 const float iDelta = 1.0F-delta;
174 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
175}
176
177/** compute sine via lookup table */
178float sinLookup(const float x)
179{
180 float arg = x*M_1_2PI_F;
181 while (arg > 1.0F) arg -= 1.0F;
182 while (arg < 0.0F) arg += 1.0F;
183
184 const float argT = arg*((float)TABLESIZE);
185 const int argI = (int)argT;
186 const float delta = argT-argI;
187 const float iDelta = 1.0F-delta;
188 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
189}
190
191
192/** compute e^(-jx) via lookup table. */
193complex expjLookup(float x)
194{
195 float arg = x*M_1_2PI_F;
196 while (arg > 1.0F) arg -= 1.0F;
197 while (arg < 0.0F) arg += 1.0F;
198
199 const float argT = arg*((float)TABLESIZE);
200 const int argI = (int)argT;
201 const float delta = argT-argI;
202 const float iDelta = 1.0F-delta;
203 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
204 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
205}
206
207/** Library setup functions */
208void initTrigTables() {
209 for (int i = 0; i < TABLESIZE+1; i++) {
210 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
211 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
212 }
213}
214
215void initGMSKRotationTables(int samplesPerSymbol) {
216 GMSKRotation = new signalVector(157*samplesPerSymbol);
217 GMSKReverseRotation = new signalVector(157*samplesPerSymbol);
218 signalVector::iterator rotPtr = GMSKRotation->begin();
219 signalVector::iterator revPtr = GMSKReverseRotation->begin();
220 float phase = 0.0;
221 while (rotPtr != GMSKRotation->end()) {
222 *rotPtr++ = expjLookup(phase);
223 *revPtr++ = expjLookup(-phase);
224 phase += M_PI_F/2.0F/(float) samplesPerSymbol;
225 }
226}
227
228void sigProcLibSetup(int samplesPerSymbol) {
229 initTrigTables();
230 initGMSKRotationTables(samplesPerSymbol);
231}
232
233void GMSKRotate(signalVector &x) {
234 signalVector::iterator xPtr = x.begin();
235 signalVector::iterator rotPtr = GMSKRotation->begin();
236 if (x.isRealOnly()) {
237 while (xPtr < x.end()) {
238 *xPtr = *rotPtr++ * (xPtr->real());
239 xPtr++;
240 }
241 }
242 else {
243 while (xPtr < x.end()) {
244 *xPtr = *rotPtr++ * (*xPtr);
245 xPtr++;
246 }
247 }
248}
249
250void GMSKReverseRotate(signalVector &x) {
251 signalVector::iterator xPtr= x.begin();
252 signalVector::iterator rotPtr = GMSKReverseRotation->begin();
253 if (x.isRealOnly()) {
254 while (xPtr < x.end()) {
255 *xPtr = *rotPtr++ * (xPtr->real());
256 xPtr++;
257 }
258 }
259 else {
260 while (xPtr < x.end()) {
261 *xPtr = *rotPtr++ * (*xPtr);
262 xPtr++;
263 }
264 }
265}
266
267
268signalVector* convolve(const signalVector *a,
269 const signalVector *b,
270 signalVector *c,
271 ConvType spanType,
272 unsigned startIx,
273 unsigned len)
274{
275 if ((a==NULL) || (b==NULL)) return NULL;
276 int La = a->size();
277 int Lb = b->size();
278
279 int startIndex;
280 unsigned int outSize;
281 switch (spanType) {
282 case FULL_SPAN:
283 startIndex = 0;
284 outSize = La+Lb-1;
285 break;
286 case OVERLAP_ONLY:
287 startIndex = La;
288 outSize = abs(La-Lb)+1;
289 break;
290 case START_ONLY:
291 startIndex = 0;
292 outSize = La;
293 break;
294 case WITH_TAIL:
295 startIndex = Lb;
296 outSize = La;
297 break;
298 case NO_DELAY:
299 if (Lb % 2)
300 startIndex = Lb/2;
301 else
302 startIndex = Lb/2-1;
303 outSize = La;
304 break;
305 case CUSTOM:
306 startIndex = startIx;
307 outSize = len;
308 break;
309 default:
310 return NULL;
311 }
312
313
314 if (c==NULL)
315 c = new signalVector(outSize);
316 else if (c->size()!=outSize)
317 return NULL;
318
319 signalVector::const_iterator aStart = a->begin();
320 signalVector::const_iterator bStart = b->begin();
321 signalVector::const_iterator aEnd = a->end();
322 signalVector::const_iterator bEnd = b->end();
323 signalVector::iterator cPtr = c->begin();
324 int t = startIndex;
325 int stopIndex = startIndex + outSize;
326 switch (b->getSymmetry()) {
327 case NONE:
328 {
329 while (t < stopIndex) {
330 signalVector::const_iterator aP = aStart+t;
331 signalVector::const_iterator bP = bStart;
332 if (a->isRealOnly() && b->isRealOnly()) {
333 float sum = 0.0;
334 while (bP < bEnd) {
335 if (aP < aStart) break;
336 if (aP < aEnd) sum += (aP->real())*(bP->real());
337 aP--;
338 bP++;
339 }
340 *cPtr++ = sum;
341 }
342 else if (a->isRealOnly()) {
343 complex sum = 0.0;
344 while (bP < bEnd) {
345 if (aP < aStart) break;
346 if (aP < aEnd) sum += (*bP)*(aP->real());
347 aP--;
348 bP++;
349 }
350 *cPtr++ = sum;
351 }
352 else if (b->isRealOnly()) {
353 complex sum = 0.0;
354 while (bP < bEnd) {
355 if (aP < aStart) break;
356 if (aP < aEnd) sum += (*aP)*(bP->real());
357 aP--;
358 bP++;
359 }
360 *cPtr++ = sum;
361 }
362 else {
363 complex sum = 0.0;
364 while (bP < bEnd) {
365 if (aP < aStart) break;
366 if (aP < aEnd) sum += (*aP)*(*bP);
367 aP--;
368 bP++;
369 }
370 *cPtr++ = sum;
371 }
372 t++;
373 }
374 }
375 break;
376 case ABSSYM:
377 {
378 complex sum = 0.0;
379 bool isOdd = (bool) (Lb % 2);
380 if (isOdd)
381 bEnd = bStart + (Lb+1)/2;
382 else
383 bEnd = bStart + Lb/2;
384 while (t < stopIndex) {
385 signalVector::const_iterator aP = aStart+t;
386 signalVector::const_iterator aPsym = aP-Lb+1;
387 signalVector::const_iterator bP = bStart;
388 sum = 0.0;
389 if (!b->isRealOnly()) {
390 while (bP < bEnd) {
391 if (aP < aStart) break;
392 if (aP == aPsym)
393 sum+= (*aP)*(*bP);
394 else if ((aP < aEnd) && (aPsym >= aStart))
395 sum+= ((*aP)+(*aPsym))*(*bP);
396 else if (aP < aEnd)
397 sum += (*aP)*(*bP);
398 else if (aPsym >= aStart)
399 sum += (*aPsym)*(*bP);
400 aP--;
401 aPsym++;
402 bP++;
403 }
404 }
405 else {
406 while (bP < bEnd) {
407 if (aP < aStart) break;
408 if (aP == aPsym)
409 sum+= (*aP)*(bP->real());
410 else if ((aP < aEnd) && (aPsym >= aStart))
411 sum+= ((*aP)+(*aPsym))*(bP->real());
412 else if (aP < aEnd)
413 sum += (*aP)*(bP->real());
414 else if (aPsym >= aStart)
415 sum += (*aPsym)*(bP->real());
416 aP--;
417 aPsym++;
418 bP++;
419 }
420 }
421 *cPtr++ = sum;
422 t++;
423 }
424 }
425 break;
426 default:
427 return NULL;
428 break;
429 }
430
431
432 return c;
433}
434
435
436signalVector* generateGSMPulse(int symbolLength,
437 int samplesPerSymbol)
438{
439
440 int numSamples = samplesPerSymbol*symbolLength + 1;
441 signalVector *x = new signalVector(numSamples);
442 signalVector::iterator xP = x->begin();
443 int centerPoint = (numSamples-1)/2;
444 for (int i = 0; i < numSamples; i++) {
445 float arg = (float) (i-centerPoint)/(float) samplesPerSymbol;
446 *xP++ = 0.96*exp(-1.1380*arg*arg-0.527*arg*arg*arg*arg); // GSM pulse approx.
447 }
448
449 float avgAbsval = sqrtf(vectorNorm2(*x)/samplesPerSymbol);
450 xP = x->begin();
451 for (int i = 0; i < numSamples; i++)
452 *xP++ /= avgAbsval;
453 x->isRealOnly(true);
454 x->setSymmetry(ABSSYM);
455 return x;
456}
457
458signalVector* frequencyShift(signalVector *y,
459 signalVector *x,
460 float freq,
461 float startPhase,
462 float *finalPhase)
463{
464
465 if (!x) return NULL;
466
467 if (y==NULL) {
468 y = new signalVector(x->size());
469 y->isRealOnly(x->isRealOnly());
470 if (y==NULL) return NULL;
471 }
472
473 if (y->size() < x->size()) return NULL;
474
475 float phase = startPhase;
476 signalVector::iterator yP = y->begin();
477 signalVector::iterator xPEnd = x->end();
478 signalVector::iterator xP = x->begin();
479
480 if (x->isRealOnly()) {
481 while (xP < xPEnd) {
482 (*yP++) = expjLookup(phase)*( (xP++)->real() );
483 phase += freq;
484 }
485 }
486 else {
487 while (xP < xPEnd) {
488 (*yP++) = (*xP++)*expjLookup(phase);
489 phase += freq;
490 }
491 }
492
493
494 if (finalPhase) *finalPhase = phase;
495
496 return y;
497}
498
499signalVector* reverseConjugate(signalVector *b)
500{
501 signalVector *tmp = new signalVector(b->size());
502 tmp->isRealOnly(b->isRealOnly());
503 signalVector::iterator bP = b->begin();
504 signalVector::iterator bPEnd = b->end();
505 signalVector::iterator tmpP = tmp->end()-1;
506 if (!b->isRealOnly()) {
507 while (bP < bPEnd) {
508 *tmpP-- = bP->conj();
509 bP++;
510 }
511 }
512 else {
513 while (bP < bPEnd) {
514 *tmpP-- = bP->real();
515 bP++;
516 }
517 }
518
519 return tmp;
520}
521
522signalVector* correlate(signalVector *a,
523 signalVector *b,
524 signalVector *c,
525 ConvType spanType,
526 bool bReversedConjugated,
527 unsigned startIx,
528 unsigned len)
529{
530 signalVector *tmp = NULL;
531
532 if (!bReversedConjugated) {
533 tmp = reverseConjugate(b);
534 }
535 else {
536 tmp = b;
537 }
538
539 c = convolve(a,tmp,c,spanType,startIx,len);
540
541 if (!bReversedConjugated) delete tmp;
542
543 return c;
544}
545
546
547/* 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}
561
562signalVector *modulateBurst(const BitVector &wBurst,
563 const signalVector &gsmPulse,
564 int guardPeriodLength,
565 int samplesPerSymbol)
566{
567
568 //static complex staticBurst[157];
569
570 int burstSize = samplesPerSymbol*(wBurst.size()+guardPeriodLength);
571 //signalVector modBurst((complex *) staticBurst,0,burstSize);
572 signalVector modBurst(burstSize);// = new signalVector(burstSize);
573 modBurst.isRealOnly(true);
574 //memset(staticBurst,0,sizeof(complex)*burstSize);
575 modBurst.fill(0.0);
576 signalVector::iterator modBurstItr = modBurst.begin();
577
578#if 0
579 // if wBurst is already differentially decoded
580 *modBurstItr = 2.0*(wBurst[0] & 0x01)-1.0;
581 signalVector::iterator prevVal = modBurstItr;
582 for (unsigned int i = 1; i < wBurst.size(); i++) {
583 modBurstItr += samplesPerSymbol;
584 if (wBurst[i] & 0x01)
585 *modBurstItr = *prevVal * complex(0.0,1.0);
586 else
587 *modBurstItr = *prevVal * complex(0.0,-1.0);
588 prevVal = modBurstItr;
589 }
590#else
591 // if wBurst are the raw bits
592 for (unsigned int i = 0; i < wBurst.size(); i++) {
593 *modBurstItr = 2.0*(wBurst[i] & 0x01)-1.0;
594 modBurstItr += samplesPerSymbol;
595 }
596
597 // shift up pi/2
598 // ignore starting phase, since spec allows for discontinuous phase
599 GMSKRotate(modBurst);
600#endif
601 modBurst.isRealOnly(false);
602
603 // filter w/ pulse shape
604 signalVector *shapedBurst = convolve(&modBurst,&gsmPulse,NULL,NO_DELAY);
605
606 //delete modBurst;
607
608 return shapedBurst;
609
610}
611
612float sinc(float x)
613{
614 if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
615 return 1.0F;
616}
617
618void delayVector(signalVector &wBurst,
619 float delay)
620{
621
622 int intOffset = (int) floor(delay);
623 float fracOffset = delay - intOffset;
624
625 // do fractional shift first, only do it for reasonable offsets
626 if (fabs(fracOffset) > 1e-2) {
627 // create sinc function
628 signalVector sincVector(21);
629 sincVector.isRealOnly(true);
630 signalVector::iterator sincBurstItr = sincVector.begin();
631 for (int i = 0; i < 21; i++)
632 *sincBurstItr++ = (complex) sinc(M_PI_F*(i-10-fracOffset));
633
634 signalVector shiftedBurst(wBurst.size());
635 convolve(&wBurst,&sincVector,&shiftedBurst,NO_DELAY);
636 wBurst.clone(shiftedBurst);
637 }
638
639 if (intOffset < 0) {
640 intOffset = -intOffset;
641 signalVector::iterator wBurstItr = wBurst.begin();
642 signalVector::iterator shiftedItr = wBurst.begin()+intOffset;
643 while (shiftedItr < wBurst.end())
644 *wBurstItr++ = *shiftedItr++;
645 while (wBurstItr < wBurst.end())
646 *wBurstItr++ = 0.0;
647 }
648 else {
649 signalVector::iterator wBurstItr = wBurst.end()-1;
650 signalVector::iterator shiftedItr = wBurst.end()-1-intOffset;
651 while (shiftedItr >= wBurst.begin())
652 *wBurstItr-- = *shiftedItr--;
653 while (wBurstItr >= wBurst.begin())
654 *wBurstItr-- = 0.0;
655 }
656}
657
658signalVector *gaussianNoise(int length,
659 float variance,
660 complex mean)
661{
662
663 signalVector *noise = new signalVector(length);
664 signalVector::iterator nPtr = noise->begin();
665 float stddev = sqrtf(variance);
666 while (nPtr < noise->end()) {
667 float u1 = (float) rand()/ (float) RAND_MAX;
668 while (u1==0.0)
669 u1 = (float) rand()/ (float) RAND_MAX;
670 float u2 = (float) rand()/ (float) RAND_MAX;
671 float arg = 2.0*M_PI*u2;
672 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
673 nPtr++;
674 }
675
676 return noise;
677}
678
679complex interpolatePoint(const signalVector &inSig,
680 float ix)
681{
682
683 int start = (int) (floor(ix) - 10);
684 if (start < 0) start = 0;
685 int end = (int) (floor(ix) + 11);
686 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
687
688 complex pVal = 0.0;
689 if (!inSig.isRealOnly()) {
690 for (int i = start; i < end; i++)
691 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
692 }
693 else {
694 for (int i = start; i < end; i++)
695 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
696 }
697
698 return pVal;
699}
700
701
702
703complex peakDetect(const signalVector &rxBurst,
704 float *peakIndex,
705 float *avgPwr)
706{
707
708
709 complex maxVal = 0.0;
710 float maxIndex = -1;
711 float sumPower = 0.0;
712
713 for (unsigned int i = 0; i < rxBurst.size(); i++) {
714 float samplePower = rxBurst[i].norm2();
715 if (samplePower > maxVal.real()) {
716 maxVal = samplePower;
717 maxIndex = i;
718 }
719 sumPower += samplePower;
720 }
721
722 // interpolate around the peak
723 // to save computation, we'll use early-late balancing
724 float earlyIndex = maxIndex-1;
725 float lateIndex = maxIndex+1;
726
727 float incr = 0.5;
728 while (incr > 1.0/1024.0) {
729 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
730 complex lateP = interpolatePoint(rxBurst,lateIndex);
731 if (earlyP < lateP)
732 earlyIndex += incr;
733 else if (earlyP > lateP)
734 earlyIndex -= incr;
735 else break;
736 incr /= 2.0;
737 lateIndex = earlyIndex + 2.0;
738 }
739
740 maxIndex = earlyIndex + 1.0;
741 maxVal = interpolatePoint(rxBurst,maxIndex);
742
743 if (peakIndex!=NULL)
744 *peakIndex = maxIndex;
745
746 if (avgPwr!=NULL)
747 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
748
749 return maxVal;
750
751}
752
753void scaleVector(signalVector &x,
754 complex scale)
755{
756 signalVector::iterator xP = x.begin();
757 signalVector::iterator xPEnd = x.end();
758 if (!x.isRealOnly()) {
759 while (xP < xPEnd) {
760 *xP = *xP * scale;
761 xP++;
762 }
763 }
764 else {
765 while (xP < xPEnd) {
766 *xP = xP->real() * scale;
767 xP++;
768 }
769 }
770}
771
772/** in-place conjugation */
773void conjugateVector(signalVector &x)
774{
775 if (x.isRealOnly()) return;
776 signalVector::iterator xP = x.begin();
777 signalVector::iterator xPEnd = x.end();
778 while (xP < xPEnd) {
779 *xP = xP->conj();
780 xP++;
781 }
782}
783
784
785// in-place addition!!
786bool addVector(signalVector &x,
787 signalVector &y)
788{
789 signalVector::iterator xP = x.begin();
790 signalVector::iterator yP = y.begin();
791 signalVector::iterator xPEnd = x.end();
792 signalVector::iterator yPEnd = y.end();
793 while ((xP < xPEnd) && (yP < yPEnd)) {
794 *xP = *xP + *yP;
795 xP++; yP++;
796 }
797 return true;
798}
799
800// in-place multiplication!!
801bool multVector(signalVector &x,
802 signalVector &y)
803{
804 signalVector::iterator xP = x.begin();
805 signalVector::iterator yP = y.begin();
806 signalVector::iterator xPEnd = x.end();
807 signalVector::iterator yPEnd = y.end();
808 while ((xP < xPEnd) && (yP < yPEnd)) {
809 *xP = (*xP) * (*yP);
810 xP++; yP++;
811 }
812 return true;
813}
814
815
816void offsetVector(signalVector &x,
817 complex offset)
818{
819 signalVector::iterator xP = x.begin();
820 signalVector::iterator xPEnd = x.end();
821 if (!x.isRealOnly()) {
822 while (xP < xPEnd) {
823 *xP += offset;
824 xP++;
825 }
826 }
827 else {
828 while (xP < xPEnd) {
829 *xP = xP->real() + offset;
830 xP++;
831 }
832 }
833}
834
835bool generateMidamble(signalVector &gsmPulse,
836 int samplesPerSymbol,
837 int TSC)
838{
839
840 if ((TSC < 0) || (TSC > 7))
841 return false;
842
843 if (gMidambles[TSC]) {
844 if (gMidambles[TSC]->sequence!=NULL) delete gMidambles[TSC]->sequence;
845 if (gMidambles[TSC]->sequenceReversedConjugated!=NULL) delete gMidambles[TSC]->sequenceReversedConjugated;
846 }
847
848 signalVector emptyPulse(1);
849 *(emptyPulse.begin()) = 1.0;
850
851 // only use middle 16 bits of each TSC
852 signalVector *middleMidamble = modulateBurst(gTrainingSequence[TSC].segment(5,16),
853 emptyPulse,
854 0,
855 samplesPerSymbol);
856 signalVector *midamble = modulateBurst(gTrainingSequence[TSC],
857 gsmPulse,
858 0,
859 samplesPerSymbol);
860
861 if (midamble == NULL) return false;
862 if (middleMidamble == NULL) return false;
863
864 // 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.
869 scaleVector(*middleMidamble,complex(-1.0,0.0));
870 scaleVector(*midamble,complex(0.0,1.0));
871
872 signalVector *autocorr = correlate(midamble,middleMidamble,NULL,NO_DELAY);
873
874 if (autocorr == NULL) return false;
875
876 gMidambles[TSC] = new CorrelationSequence;
877 gMidambles[TSC]->sequence = middleMidamble;
878 gMidambles[TSC]->sequenceReversedConjugated = reverseConjugate(middleMidamble);
879 gMidambles[TSC]->gain = peakDetect(*autocorr,&gMidambles[TSC]->TOA,NULL);
880
881 LOG(DEBUG) << "midamble autocorr: " << *autocorr;
882
883 LOG(DEBUG) << "TOA: " << gMidambles[TSC]->TOA;
884
885 //gMidambles[TSC]->TOA -= 5*samplesPerSymbol;
886
887 delete autocorr;
888 delete midamble;
889
890 return true;
891}
892
893bool generateRACHSequence(signalVector &gsmPulse,
894 int samplesPerSymbol)
895{
896
897 if (gRACHSequence) {
898 if (gRACHSequence->sequence!=NULL) delete gRACHSequence->sequence;
899 if (gRACHSequence->sequenceReversedConjugated!=NULL) delete gRACHSequence->sequenceReversedConjugated;
900 }
901
902 signalVector *RACHSeq = modulateBurst(gRACHSynchSequence,
903 gsmPulse,
904 0,
905 samplesPerSymbol);
906
907 assert(RACHSeq);
908
909 signalVector *autocorr = correlate(RACHSeq,RACHSeq,NULL,NO_DELAY);
910
911 assert(autocorr);
912
913 gRACHSequence = new CorrelationSequence;
914 gRACHSequence->sequence = RACHSeq;
915 gRACHSequence->sequenceReversedConjugated = reverseConjugate(RACHSeq);
916 gRACHSequence->gain = peakDetect(*autocorr,&gRACHSequence->TOA,NULL);
917
918 delete autocorr;
919
920 return true;
921
922}
923
924
925bool detectRACHBurst(signalVector &rxBurst,
926 float detectThreshold,
927 int samplesPerSymbol,
928 complex *amplitude,
929 float* TOA)
930{
931
932 //static complex staticData[500];
933
934 //signalVector correlatedRACH(staticData,0,rxBurst.size());
935 signalVector correlatedRACH(rxBurst.size());
936 correlate(&rxBurst,gRACHSequence->sequenceReversedConjugated,&correlatedRACH,NO_DELAY,true);
937
938 float meanPower;
939 complex peakAmpl = peakDetect(correlatedRACH,TOA,&meanPower);
940
941 float valleyPower = 0.0;
942
943 // check for bogus results
944 if ((*TOA < 0.0) || (*TOA > correlatedRACH.size())) {
945 *amplitude = 0.0;
946 return false;
947 }
948 complex *peakPtr = correlatedRACH.begin() + (int) rint(*TOA);
949
950 LOG(DEBUG) << "RACH corr: " << correlatedRACH;
951
952 float numSamples = 0.0;
953 for (int i = 57*samplesPerSymbol; i <= 107*samplesPerSymbol;i++) {
954 if (peakPtr+i >= correlatedRACH.end())
955 break;
956 valleyPower += (peakPtr+i)->norm2();
957 numSamples++;
958 }
959
960 if (numSamples < 2) {
961 *amplitude = 0.0;
962 return false;
963 }
964
965 float RMS = sqrtf(valleyPower/(float) numSamples)+0.00001;
966 float peakToMean = peakAmpl.abs()/RMS;
967
968 LOG(DEBUG) << "RACH peakAmpl=" << peakAmpl << " RMS=" << RMS << " peakToMean=" << peakToMean;
969 *amplitude = peakAmpl/(gRACHSequence->gain);
970
971 *TOA = (*TOA) - gRACHSequence->TOA - 8*samplesPerSymbol;
972
973 LOG(DEBUG) << "RACH thresh: " << peakToMean;
974
975 return (peakToMean > detectThreshold);
976}
977
978bool energyDetect(signalVector &rxBurst,
979 unsigned windowLength,
980 float detectThreshold,
981 float *avgPwr)
982{
983
984 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
985 float energy = 0.0;
986 if (windowLength < 0) windowLength = 20;
987 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
988 for (unsigned i = 0; i < windowLength; i++) {
989 energy += windowItr->norm2();
990 windowItr+=4;
991 }
992 if (avgPwr) *avgPwr = energy/windowLength;
993 LOG(DEBUG) << "detected energy: " << energy/windowLength;
994 return (energy/windowLength > detectThreshold*detectThreshold);
995}
996
997
998bool analyzeTrafficBurst(signalVector &rxBurst,
999 unsigned TSC,
1000 float detectThreshold,
1001 int samplesPerSymbol,
1002 complex *amplitude,
1003 float *TOA,
1004 unsigned maxTOA,
1005 bool requestChannel,
1006 signalVector **channelResponse,
1007 float *channelResponseOffset)
1008{
1009
1010 assert(TSC<8);
1011 assert(amplitude);
1012 assert(TOA);
1013 assert(gMidambles[TSC]);
1014
1015 if (maxTOA < 3*samplesPerSymbol) maxTOA = 3*samplesPerSymbol;
1016 unsigned spanTOA = maxTOA;
1017 if (spanTOA < 5*samplesPerSymbol) spanTOA = 5*samplesPerSymbol;
1018
1019 unsigned startIx = (66-spanTOA)*samplesPerSymbol;
1020 unsigned endIx = (66+16+spanTOA)*samplesPerSymbol;
1021 unsigned windowLen = endIx - startIx;
1022 unsigned corrLen = 2*maxTOA+1;
1023
1024 unsigned expectedTOAPeak = (unsigned) round(gMidambles[TSC]->TOA + (gMidambles[TSC]->sequenceReversedConjugated->size()-1)/2);
1025
1026 signalVector burstSegment(rxBurst.begin(),startIx,windowLen);
1027
1028 //static complex staticData[200];
1029 //signalVector correlatedBurst(staticData,0,corrLen);
1030 signalVector correlatedBurst(corrLen);
1031 correlate(&burstSegment, gMidambles[TSC]->sequenceReversedConjugated,
1032 &correlatedBurst, CUSTOM,true,
1033 expectedTOAPeak-maxTOA,corrLen);
1034
1035 float meanPower;
1036 *amplitude = peakDetect(correlatedBurst,TOA,&meanPower);
1037 float valleyPower = 0.0; //amplitude->norm2();
1038 complex *peakPtr = correlatedBurst.begin() + (int) rint(*TOA);
1039
1040 // check for bogus results
1041 if ((*TOA < 0.0) || (*TOA > correlatedBurst.size())) {
1042 *amplitude = 0.0;
1043 return false;
1044 }
1045
1046 int numRms = 0;
1047 for (int i = 2*samplesPerSymbol; i <= 5*samplesPerSymbol;i++) {
1048 if (peakPtr - i >= correlatedBurst.begin()) {
1049 valleyPower += (peakPtr-i)->norm2();
1050 numRms++;
1051 }
1052 if (peakPtr + i < correlatedBurst.end()) {
1053 valleyPower += (peakPtr+i)->norm2();
1054 numRms++;
1055 }
1056 }
1057
1058 if (numRms < 2) {
1059 // check for bogus results
1060 *amplitude = 0.0;
1061 return false;
1062 }
1063
1064 float RMS = sqrtf(valleyPower/(float)numRms)+0.00001;
1065 float peakToMean = (amplitude->abs())/RMS;
1066
1067 // NOTE: Because ideal TSC is 66 symbols into burst,
1068 // the ideal TSC has an +/- 180 degree phase shift,
1069 // due to the pi/4 frequency shift, that
1070 // needs to be accounted for.
1071
1072 *amplitude = (*amplitude)/gMidambles[TSC]->gain;
1073 *TOA = (*TOA) - (maxTOA);
1074
1075 LOG(DEBUG) << "TCH peakAmpl=" << amplitude->abs() << " RMS=" << RMS << " peakToMean=" << peakToMean << " TOA=" << *TOA;
1076
1077 LOG(DEBUG) << "autocorr: " << correlatedBurst;
1078
1079 if (requestChannel && (peakToMean > detectThreshold)) {
1080 float TOAoffset = maxTOA; //gMidambles[TSC]->TOA+(66*samplesPerSymbol-startIx);
1081 delayVector(correlatedBurst,-(*TOA));
1082 // midamble only allows estimation of a 6-tap channel
1083 signalVector channelVector(6*samplesPerSymbol);
1084 float maxEnergy = -1.0;
1085 int maxI = -1;
1086 for (int i = 0; i < 7; i++) {
1087 if (TOAoffset+(i-5)*samplesPerSymbol + channelVector.size() > correlatedBurst.size()) continue;
1088 if (TOAoffset+(i-5)*samplesPerSymbol < 0) continue;
1089 correlatedBurst.segmentCopyTo(channelVector,(int) floor(TOAoffset+(i-5)*samplesPerSymbol),channelVector.size());
1090 float energy = vectorNorm2(channelVector);
1091 if (energy > 0.95*maxEnergy) {
1092 maxI = i;
1093 maxEnergy = energy;
1094 }
1095 }
1096
1097 *channelResponse = new signalVector(channelVector.size());
1098 correlatedBurst.segmentCopyTo(**channelResponse,(int) floor(TOAoffset+(maxI-5)*samplesPerSymbol),(*channelResponse)->size());
1099 scaleVector(**channelResponse,complex(1.0,0.0)/gMidambles[TSC]->gain);
1100 LOG(DEBUG) << "channelResponse: " << **channelResponse;
1101
1102 if (channelResponseOffset)
1103 *channelResponseOffset = 5*samplesPerSymbol-maxI;
1104
1105 }
1106
1107 return (peakToMean > detectThreshold);
1108
1109}
1110
1111signalVector *decimateVector(signalVector &wVector,
1112 int decimationFactor)
1113{
1114
1115 if (decimationFactor <= 1) return NULL;
1116
1117 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
1118 decVector->isRealOnly(wVector.isRealOnly());
1119
1120 signalVector::iterator vecItr = decVector->begin();
1121 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1122 *vecItr++ = wVector[i];
1123
1124 return decVector;
1125}
1126
1127
1128SoftVector *demodulateBurst(signalVector &rxBurst,
1129 const signalVector &gsmPulse,
1130 int samplesPerSymbol,
1131 complex channel,
1132 float TOA)
1133
1134{
1135 scaleVector(rxBurst,((complex) 1.0)/channel);
1136 delayVector(rxBurst,-TOA);
1137
1138 signalVector *shapedBurst = &rxBurst;
1139
1140 // shift up by a quarter of a frequency
1141 // ignore starting phase, since spec allows for discontinuous phase
1142 GMSKReverseRotate(*shapedBurst);
1143
1144 // run through slicer
1145 if (samplesPerSymbol > 1) {
1146 signalVector *decShapedBurst = decimateVector(*shapedBurst,samplesPerSymbol);
1147 shapedBurst = decShapedBurst;
1148 }
1149
1150 LOG(DEBUG) << "shapedBurst: " << *shapedBurst;
1151
1152 vectorSlicer(shapedBurst);
1153
1154 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1155
1156 SoftVector::iterator burstItr = burstBits->begin();
1157 signalVector::iterator shapedItr = shapedBurst->begin();
1158 for (; shapedItr < shapedBurst->end(); shapedItr++)
1159 *burstItr++ = shapedItr->real();
1160
1161 if (samplesPerSymbol > 1) delete shapedBurst;
1162
1163 return burstBits;
1164
1165}
1166
1167
1168// 1.0 is sampling frequency
1169// must satisfy cutoffFreq > 1/filterLen
1170signalVector *createLPF(float cutoffFreq,
1171 int filterLen,
1172 float gainDC)
1173{
1174
1175 signalVector *LPF = new signalVector(filterLen-1);
1176 LPF->isRealOnly(true);
1177 LPF->setSymmetry(ABSSYM);
1178 signalVector::iterator itr = LPF->begin();
1179 double sum = 0.0;
1180 for (int i = 1; i < filterLen; i++) {
1181 float ys = sinc(M_2PI_F*cutoffFreq*((float)i-(float)(filterLen)/2.0F));
1182 float yg = 4.0F * cutoffFreq;
1183 // Blackman -- less brickwall (sloping transition) but larger stopband attenuation
1184 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));
1185 // Hamming -- more brickwall with smaller stopband attenuation
1186 //float yw = 0.53836F - 0.46164F * cos(((float)i)*M_2PI_F/(float)(filterLen+1));
1187 *itr++ = (complex) ys*yg*yw;
1188 sum += ys*yg*yw;
1189 }
1190
1191 float normFactor = gainDC/sum; //sqrtf(gainDC/vectorNorm2(*LPF));
1192 // normalize power
1193 itr = LPF->begin();
1194 for (int i = 1; i < filterLen; i++) {
1195 *itr = *itr*normFactor;
1196 itr++;
1197 }
1198 return LPF;
1199
1200}
1201
1202
1203
1204#define POLYPHASESPAN 10
1205
1206// assumes filter group delay is 0.5*(length of filter)
1207signalVector *polyphaseResampleVector(signalVector &wVector,
1208 int P, int Q,
1209 signalVector *LPF)
1210
1211{
1212
1213 bool deleteLPF = false;
1214
1215 if (LPF==NULL) {
1216 float cutoffFreq = (P < Q) ? (1.0/(float) Q) : (1.0/(float) P);
1217 LPF = createLPF(cutoffFreq/3.0,100*POLYPHASESPAN+1,Q);
1218 deleteLPF = true;
1219 }
1220
1221 signalVector *resampledVector = new signalVector((int) ceil(wVector.size()*(float) P / (float) Q));
1222 resampledVector->fill(0);
1223 resampledVector->isRealOnly(wVector.isRealOnly());
1224 signalVector::iterator newItr = resampledVector->begin();
1225
1226 //FIXME: need to update for real-only vectors
1227 int outputIx = (LPF->size()+1)/2/Q; //((P > Q) ? P : Q);
1228 while (newItr < resampledVector->end()) {
1229 int outputBranch = (outputIx*Q) % P;
1230 int inputOffset = (outputIx*Q - outputBranch)/P;
1231 signalVector::const_iterator inputItr = wVector.begin() + inputOffset;
1232 signalVector::const_iterator filtItr = LPF->begin() + outputBranch;
1233 while (inputItr >= wVector.end()) {
1234 inputItr--;
1235 filtItr+=P;
1236 }
1237 complex sum = 0.0;
1238 if ((LPF->getSymmetry()!=ABSSYM) || (P>1)) {
1239 if (!LPF->isRealOnly()) {
1240 while ( (inputItr >= wVector.begin()) && (filtItr < LPF->end()) ) {
1241 sum += (*inputItr)*(*filtItr);
1242 inputItr--;
1243 filtItr += P;
1244 }
1245 }
1246 else {
1247 while ( (inputItr >= wVector.begin()) && (filtItr < LPF->end()) ) {
1248 sum += (*inputItr)*(filtItr->real());
1249 inputItr--;
1250 filtItr += P;
1251 }
1252 }
1253 }
1254 else {
1255 signalVector::const_iterator revInputItr = inputItr- LPF->size() + 1;
1256 signalVector::const_iterator filtMidpoint = LPF->begin()+(LPF->size()-1)/2;
1257 if (!LPF->isRealOnly()) {
1258 while (filtItr <= filtMidpoint) {
1259 if (inputItr < revInputItr) break;
1260 if (inputItr == revInputItr)
1261 sum += (*inputItr)*(*filtItr);
1262 else if ( (inputItr < wVector.end()) && (revInputItr >= wVector.begin()) )
1263 sum += (*inputItr + *revInputItr)*(*filtItr);
1264 else if ( inputItr < wVector.end() )
1265 sum += (*inputItr)*(*filtItr);
1266 else if ( revInputItr >= wVector.begin() )
1267 sum += (*revInputItr)*(*filtItr);
1268 inputItr--;
1269 revInputItr++;
1270 filtItr++;
1271 }
1272 }
1273 else {
1274 while (filtItr <= filtMidpoint) {
1275 if (inputItr < revInputItr) break;
1276 if (inputItr == revInputItr)
1277 sum += (*inputItr)*(filtItr->real());
1278 else if ( (inputItr < wVector.end()) && (revInputItr >= wVector.begin()) )
1279 sum += (*inputItr + *revInputItr)*(filtItr->real());
1280 else if ( inputItr < wVector.end() )
1281 sum += (*inputItr)*(filtItr->real());
1282 else if ( revInputItr >= wVector.begin() )
1283 sum += (*revInputItr)*(filtItr->real());
1284 inputItr--;
1285 revInputItr++;
1286 filtItr++;
1287 }
1288 }
1289 }
1290 *newItr = sum;
1291 newItr++;
1292 outputIx++;
1293 }
1294
1295 if (deleteLPF) delete LPF;
1296
1297 return resampledVector;
1298}
1299
1300
1301signalVector *resampleVector(signalVector &wVector,
1302 float expFactor,
1303 complex endPoint)
1304
1305{
1306
1307 if (expFactor < 1.0) return NULL;
1308
1309 signalVector *retVec = new signalVector((int) ceil(wVector.size()*expFactor));
1310
1311 float t = 0.0;
1312
1313 signalVector::iterator retItr = retVec->begin();
1314 while (retItr < retVec->end()) {
1315 unsigned tLow = (unsigned int) floor(t);
1316 unsigned tHigh = tLow + 1;
1317 if (tLow > wVector.size()-1) break;
1318 if (tHigh > wVector.size()) break;
1319 complex lowPoint = wVector[tLow];
1320 complex highPoint = (tHigh == wVector.size()) ? endPoint : wVector[tHigh];
1321 complex a = (tHigh-t);
1322 complex b = (t-tLow);
1323 *retItr = (a*lowPoint + b*highPoint);
1324 t += 1.0/expFactor;
1325 }
1326
1327 return retVec;
1328
1329}
1330
1331
1332// Assumes symbol-spaced sampling!!!
1333// Based upon paper by Al-Dhahir and Cioffi
1334bool designDFE(signalVector &channelResponse,
1335 float SNRestimate,
1336 int Nf,
1337 signalVector **feedForwardFilter,
1338 signalVector **feedbackFilter)
1339{
1340
1341 signalVector G0(Nf);
1342 signalVector G1(Nf);
1343 signalVector::iterator G0ptr = G0.begin();
1344 signalVector::iterator G1ptr = G1.begin();
1345 signalVector::iterator chanPtr = channelResponse.begin();
1346
1347 int nu = channelResponse.size()-1;
1348
1349 *G0ptr = 1.0/sqrtf(SNRestimate);
1350 for(int j = 0; j <= nu; j++) {
1351 *G1ptr = chanPtr->conj();
1352 G1ptr++; chanPtr++;
1353 }
1354
1355 signalVector *L[Nf];
1356 signalVector::iterator Lptr;
1357 float d;
1358 for(int i = 0; i < Nf; i++) {
1359 d = G0.begin()->norm2() + G1.begin()->norm2();
1360 L[i] = new signalVector(Nf+nu);
1361 Lptr = L[i]->begin()+i;
1362 G0ptr = G0.begin(); G1ptr = G1.begin();
1363 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1364 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1365 Lptr++;
1366 G0ptr++;
1367 G1ptr++;
1368 }
1369 complex k = (*G1.begin())/(*G0.begin());
1370
1371 if (i != Nf-1) {
1372 signalVector G0new = G1;
1373 scaleVector(G0new,k.conj());
1374 addVector(G0new,G0);
1375
1376 signalVector G1new = G0;
1377 scaleVector(G1new,k*(-1.0));
1378 addVector(G1new,G1);
1379 delayVector(G1new,-1.0);
1380
1381 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1382 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1383 G0 = G0new;
1384 G1 = G1new;
1385 }
1386 }
1387
1388 *feedbackFilter = new signalVector(nu);
1389 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1390 scaleVector(**feedbackFilter,(complex) -1.0);
1391 conjugateVector(**feedbackFilter);
1392
1393 signalVector v(Nf);
1394 signalVector::iterator vStart = v.begin();
1395 signalVector::iterator vPtr;
1396 *(vStart+Nf-1) = (complex) 1.0;
1397 for(int k = Nf-2; k >= 0; k--) {
1398 Lptr = L[k]->begin()+k+1;
1399 vPtr = vStart + k+1;
1400 complex v_k = 0.0;
1401 for (int j = k+1; j < Nf; j++) {
1402 v_k -= (*vPtr)*(*Lptr);
1403 vPtr++; Lptr++;
1404 }
1405 *(vStart + k) = v_k;
1406 }
1407
1408 *feedForwardFilter = new signalVector(Nf);
1409 signalVector::iterator w = (*feedForwardFilter)->begin();
1410 for (int i = 0; i < Nf; i++) {
1411 delete L[i];
1412 complex w_i = 0.0;
1413 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1414 vPtr = vStart+i;
1415 chanPtr = channelResponse.begin();
1416 for (int k = 0; k < endPt+1; k++) {
1417 w_i += (*vPtr)*(chanPtr->conj());
1418 vPtr++; chanPtr++;
1419 }
1420 *w = w_i/d;
1421 w++;
1422 }
1423
1424
1425 return true;
1426
1427}
1428
1429// Assumes symbol-rate sampling!!!!
1430SoftVector *equalizeBurst(signalVector &rxBurst,
1431 float TOA,
1432 int samplesPerSymbol,
1433 signalVector &w, // feedforward filter
1434 signalVector &b) // feedback filter
1435{
1436
1437 delayVector(rxBurst,-TOA);
1438
1439 signalVector* postForwardFull = convolve(&rxBurst,&w,NULL,FULL_SPAN);
1440
1441 signalVector* postForward = new signalVector(rxBurst.size());
1442 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1443 delete postForwardFull;
1444
1445 signalVector::iterator dPtr = postForward->begin();
1446 signalVector::iterator dBackPtr;
1447 signalVector::iterator rotPtr = GMSKRotation->begin();
1448 signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
1449
1450 signalVector *DFEoutput = new signalVector(postForward->size());
1451 signalVector::iterator DFEItr = DFEoutput->begin();
1452
1453 // NOTE: can insert the midamble and/or use midamble to estimate BER
1454 for (; dPtr < postForward->end(); dPtr++) {
1455 dBackPtr = dPtr-1;
1456 signalVector::iterator bPtr = b.begin();
1457 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1458 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1459 bPtr++;
1460 dBackPtr--;
1461 }
1462 *dPtr = *dPtr * (*revRotPtr);
1463 *DFEItr = *dPtr;
1464 // make decision on symbol
1465 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1466 //*DFEItr = *dPtr;
1467 *dPtr = *dPtr * (*rotPtr);
1468 DFEItr++;
1469 rotPtr++;
1470 revRotPtr++;
1471 }
1472
1473 vectorSlicer(DFEoutput);
1474
1475 SoftVector *burstBits = new SoftVector(postForward->size());
1476 SoftVector::iterator burstItr = burstBits->begin();
1477 DFEItr = DFEoutput->begin();
1478 for (; DFEItr < DFEoutput->end(); DFEItr++)
1479 *burstItr++ = DFEItr->real();
1480
1481 delete postForward;
1482
1483 delete DFEoutput;
1484
1485 return burstBits;
1486}