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