blob: a647f846e7db00698daefab5f662f1c61a61a8e3 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
kurtis.heimerla198d452011-11-26 03:19:28 +00002* Copyright 2008, 2011 Free Software Foundation, Inc.
dburgessb3a0ca42011-10-12 07:44:40 +00003*
4* This software is distributed under the terms of the GNU Affero Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
19
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23*/
24
dburgessb3a0ca42011-10-12 07:44:40 +000025#include "sigProcLib.h"
26#include "GSMCommon.h"
kurtis.heimerla198d452011-11-26 03:19:28 +000027#include "sendLPF_961.h"
28#include "rcvLPF_651.h"
dburgessb3a0ca42011-10-12 07:44:40 +000029
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040030using namespace GSM;
31
Thomas Tsou3eaae802013-08-20 19:31:14 -040032extern "C" {
33#include "convolve.h"
34}
35
dburgessb3a0ca42011-10-12 07:44:40 +000036#define TABLESIZE 1024
37
38/** Lookup tables for trigonometric approximation */
39float cosTable[TABLESIZE+1]; // add 1 element for wrap around
40float sinTable[TABLESIZE+1];
41
42/** Constants */
43static const float M_PI_F = (float)M_PI;
44static const float M_2PI_F = (float)(2.0*M_PI);
45static const float M_1_2PI_F = 1/M_2PI_F;
46
47/** Static vectors that contain a precomputed +/- f_b/4 sinusoid */
48signalVector *GMSKRotation = NULL;
49signalVector *GMSKReverseRotation = NULL;
50
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040051/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040052 * RACH and midamble correlation waveforms. Store the buffer separately
53 * because we need to allocate it explicitly outside of the signal vector
54 * constructor. This is because C++ (prior to C++11) is unable to natively
55 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040056 */
57struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040058 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040059 {
60 }
61
62 ~CorrelationSequence()
63 {
64 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040065 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040066 }
67
dburgessb3a0ca42011-10-12 07:44:40 +000068 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040069 void *buffer;
dburgessb3a0ca42011-10-12 07:44:40 +000070 float TOA;
71 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040072};
dburgessb3a0ca42011-10-12 07:44:40 +000073
Thomas Tsou83e06892013-08-20 16:10:01 -040074/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040075 * Gaussian and empty modulation pulses. Like the correlation sequences,
76 * store the runtime (Gaussian) buffer separately because of needed alignment
77 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -040078 */
79struct PulseSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040080 PulseSequence() : gaussian(NULL), empty(NULL), buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -040081 {
82 }
83
84 ~PulseSequence()
85 {
86 delete gaussian;
87 delete empty;
Thomas Tsou3eaae802013-08-20 19:31:14 -040088 free(buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -040089 }
90
91 signalVector *gaussian;
92 signalVector *empty;
Thomas Tsou3eaae802013-08-20 19:31:14 -040093 void *buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -040094};
95
dburgessb3a0ca42011-10-12 07:44:40 +000096CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
97CorrelationSequence *gRACHSequence = NULL;
Thomas Tsou83e06892013-08-20 16:10:01 -040098PulseSequence *GSMPulse = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000099
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400100void sigProcLibDestroy()
101{
dburgessb3a0ca42011-10-12 07:44:40 +0000102 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400103 delete gMidambles[i];
104 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000105 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400106
107 delete GMSKRotation;
108 delete GMSKReverseRotation;
109 delete gRACHSequence;
110 delete GSMPulse;
111
112 GMSKRotation = NULL;
113 GMSKReverseRotation = NULL;
114 gRACHSequence = NULL;
115 GSMPulse = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000116}
117
dburgessb3a0ca42011-10-12 07:44:40 +0000118// dB relative to 1.0.
119// if > 1.0, then return 0 dB
120float dB(float x) {
121
122 float arg = 1.0F;
123 float dB = 0.0F;
124
125 if (x >= 1.0F) return 0.0F;
126 if (x <= 0.0F) return -200.0F;
127
128 float prevArg = arg;
129 float prevdB = dB;
130 float stepSize = 16.0F;
131 float dBstepSize = 12.0F;
132 while (stepSize > 1.0F) {
133 do {
134 prevArg = arg;
135 prevdB = dB;
136 arg /= stepSize;
137 dB -= dBstepSize;
138 } while (arg > x);
139 arg = prevArg;
140 dB = prevdB;
141 stepSize *= 0.5F;
142 dBstepSize -= 3.0F;
143 }
144 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
145
146}
147
148// 10^(-dB/10), inverse of dB func.
149float dBinv(float x) {
150
151 float arg = 1.0F;
152 float dB = 0.0F;
153
154 if (x >= 0.0F) return 1.0F;
155 if (x <= -200.0F) return 0.0F;
156
157 float prevArg = arg;
158 float prevdB = dB;
159 float stepSize = 16.0F;
160 float dBstepSize = 12.0F;
161 while (stepSize > 1.0F) {
162 do {
163 prevArg = arg;
164 prevdB = dB;
165 arg /= stepSize;
166 dB -= dBstepSize;
167 } while (dB > x);
168 arg = prevArg;
169 dB = prevdB;
170 stepSize *= 0.5F;
171 dBstepSize -= 3.0F;
172 }
173
174 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
175
176}
177
178float vectorNorm2(const signalVector &x)
179{
180 signalVector::const_iterator xPtr = x.begin();
181 float Energy = 0.0;
182 for (;xPtr != x.end();xPtr++) {
183 Energy += xPtr->norm2();
184 }
185 return Energy;
186}
187
188
189float vectorPower(const signalVector &x)
190{
191 return vectorNorm2(x)/x.size();
192}
193
194/** compute cosine via lookup table */
195float cosLookup(const float x)
196{
197 float arg = x*M_1_2PI_F;
198 while (arg > 1.0F) arg -= 1.0F;
199 while (arg < 0.0F) arg += 1.0F;
200
201 const float argT = arg*((float)TABLESIZE);
202 const int argI = (int)argT;
203 const float delta = argT-argI;
204 const float iDelta = 1.0F-delta;
205 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
206}
207
208/** compute sine via lookup table */
209float sinLookup(const float x)
210{
211 float arg = x*M_1_2PI_F;
212 while (arg > 1.0F) arg -= 1.0F;
213 while (arg < 0.0F) arg += 1.0F;
214
215 const float argT = arg*((float)TABLESIZE);
216 const int argI = (int)argT;
217 const float delta = argT-argI;
218 const float iDelta = 1.0F-delta;
219 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
220}
221
222
223/** compute e^(-jx) via lookup table. */
224complex expjLookup(float x)
225{
226 float arg = x*M_1_2PI_F;
227 while (arg > 1.0F) arg -= 1.0F;
228 while (arg < 0.0F) arg += 1.0F;
229
230 const float argT = arg*((float)TABLESIZE);
231 const int argI = (int)argT;
232 const float delta = argT-argI;
233 const float iDelta = 1.0F-delta;
234 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
235 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
236}
237
238/** Library setup functions */
239void initTrigTables() {
240 for (int i = 0; i < TABLESIZE+1; i++) {
241 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
242 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
243 }
244}
245
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400246void initGMSKRotationTables(int sps)
247{
248 GMSKRotation = new signalVector(157 * sps);
249 GMSKReverseRotation = new signalVector(157 * sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000250 signalVector::iterator rotPtr = GMSKRotation->begin();
251 signalVector::iterator revPtr = GMSKReverseRotation->begin();
252 float phase = 0.0;
253 while (rotPtr != GMSKRotation->end()) {
254 *rotPtr++ = expjLookup(phase);
255 *revPtr++ = expjLookup(-phase);
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400256 phase += M_PI_F / 2.0F / (float) sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000257 }
258}
259
Thomas Tsoue57004d2013-08-20 18:55:33 -0400260bool sigProcLibSetup(int sps)
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400261{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400262 if ((sps != 1) && (sps != 2) && (sps != 4))
Thomas Tsoue57004d2013-08-20 18:55:33 -0400263 return false;
264
dburgessb3a0ca42011-10-12 07:44:40 +0000265 initTrigTables();
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400266 initGMSKRotationTables(sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400267 generateGSMPulse(sps, 2);
Thomas Tsoue57004d2013-08-20 18:55:33 -0400268
269 if (!generateRACHSequence(sps)) {
270 sigProcLibDestroy();
271 return false;
272 }
273
274 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000275}
276
277void GMSKRotate(signalVector &x) {
278 signalVector::iterator xPtr = x.begin();
279 signalVector::iterator rotPtr = GMSKRotation->begin();
280 if (x.isRealOnly()) {
281 while (xPtr < x.end()) {
282 *xPtr = *rotPtr++ * (xPtr->real());
283 xPtr++;
284 }
285 }
286 else {
287 while (xPtr < x.end()) {
288 *xPtr = *rotPtr++ * (*xPtr);
289 xPtr++;
290 }
291 }
292}
293
294void GMSKReverseRotate(signalVector &x) {
295 signalVector::iterator xPtr= x.begin();
296 signalVector::iterator rotPtr = GMSKReverseRotation->begin();
297 if (x.isRealOnly()) {
298 while (xPtr < x.end()) {
299 *xPtr = *rotPtr++ * (xPtr->real());
300 xPtr++;
301 }
302 }
303 else {
304 while (xPtr < x.end()) {
305 *xPtr = *rotPtr++ * (*xPtr);
306 xPtr++;
307 }
308 }
309}
310
Thomas Tsou3eaae802013-08-20 19:31:14 -0400311signalVector *convolve(const signalVector *x,
312 const signalVector *h,
313 signalVector *y,
314 ConvType spanType, int start,
315 unsigned len, unsigned step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000316{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400317 int rc, head = 0, tail = 0;
318 bool alloc = false, append = false;
319 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000320
Thomas Tsou3eaae802013-08-20 19:31:14 -0400321 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000322 return NULL;
323
Thomas Tsou3eaae802013-08-20 19:31:14 -0400324 switch (spanType) {
325 case START_ONLY:
326 start = 0;
327 head = h->size();
328 len = x->size();
329 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000330 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400331 case NO_DELAY:
332 start = h->size() / 2;
333 head = start;
334 tail = start;
335 len = x->size();
336 append = true;
337 break;
338 case CUSTOM:
339 if (start < h->size() - 1) {
340 head = h->size() - start;
341 append = true;
342 }
343 if (start + len > x->size()) {
344 tail = start + len - x->size();
345 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000346 }
347 break;
348 default:
349 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000350 }
dburgessb3a0ca42011-10-12 07:44:40 +0000351
Thomas Tsou3eaae802013-08-20 19:31:14 -0400352 /*
353 * Error if the output vector is too small. Create the output vector
354 * if the pointer is NULL.
355 */
356 if (y && (len > y->size()))
357 return NULL;
358 if (!y) {
359 y = new signalVector(len);
360 alloc = true;
361 }
362
363 /* Prepend or post-pend the input vector if the parameters require it */
364 if (append)
365 _x = new signalVector(*x, head, tail);
366 else
367 _x = x;
368
369 /*
370 * Four convovle types:
371 * 1. Complex-Real (aligned)
372 * 2. Complex-Complex (aligned)
373 * 3. Complex-Real (!aligned)
374 * 4. Complex-Complex (!aligned)
375 */
376 if (h->isRealOnly() && h->isAligned()) {
377 rc = convolve_real((float *) _x->begin(), _x->size(),
378 (float *) h->begin(), h->size(),
379 (float *) y->begin(), y->size(),
380 start, len, step, offset);
381 } else if (!h->isRealOnly() && h->isAligned()) {
382 rc = convolve_complex((float *) _x->begin(), _x->size(),
383 (float *) h->begin(), h->size(),
384 (float *) y->begin(), y->size(),
385 start, len, step, offset);
386 } else if (h->isRealOnly() && !h->isAligned()) {
387 rc = base_convolve_real((float *) _x->begin(), _x->size(),
388 (float *) h->begin(), h->size(),
389 (float *) y->begin(), y->size(),
390 start, len, step, offset);
391 } else if (!h->isRealOnly() && !h->isAligned()) {
392 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
393 (float *) h->begin(), h->size(),
394 (float *) y->begin(), y->size(),
395 start, len, step, offset);
396 } else {
397 rc = -1;
398 }
399
400 if (append)
401 delete _x;
402
403 if (rc < 0) {
404 if (alloc)
405 delete y;
406 return NULL;
407 }
408
409 return y;
410}
dburgessb3a0ca42011-10-12 07:44:40 +0000411
Thomas Tsou83e06892013-08-20 16:10:01 -0400412void generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000413{
Thomas Tsou83e06892013-08-20 16:10:01 -0400414 int len;
415 float arg, center;
dburgessb3a0ca42011-10-12 07:44:40 +0000416
Thomas Tsou83e06892013-08-20 16:10:01 -0400417 delete GSMPulse;
418
419 /* Store a single tap filter used for correlation sequence generation */
420 GSMPulse = new PulseSequence();
421 GSMPulse->empty = new signalVector(1);
422 GSMPulse->empty->isRealOnly(true);
423 *(GSMPulse->empty->begin()) = 1.0f;
424
Thomas Tsou3eaae802013-08-20 19:31:14 -0400425 len = sps * symbolLength;
426 if (len < 4)
427 len = 4;
428
Thomas Tsou83e06892013-08-20 16:10:01 -0400429 /* GSM pulse approximation */
Thomas Tsou3eaae802013-08-20 19:31:14 -0400430 GSMPulse->buffer = convolve_h_alloc(len);
431 GSMPulse->gaussian = new signalVector((complex *)
432 GSMPulse->buffer, 0, len);
433 GSMPulse->gaussian->setAligned(true);
Thomas Tsou83e06892013-08-20 16:10:01 -0400434 GSMPulse->gaussian->isRealOnly(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400435
Thomas Tsou83e06892013-08-20 16:10:01 -0400436 signalVector::iterator xP = GSMPulse->gaussian->begin();
437
438 center = (float) (len - 1.0) / 2.0;
439
440 for (int i = 0; i < len; i++) {
441 arg = ((float) i - center) / (float) sps;
442 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
443 0.527 * arg * arg * arg * arg);
dburgessb3a0ca42011-10-12 07:44:40 +0000444 }
445
Thomas Tsou83e06892013-08-20 16:10:01 -0400446 float avgAbsval = sqrtf(vectorNorm2(*GSMPulse->gaussian)/sps);
447 xP = GSMPulse->gaussian->begin();
448 for (int i = 0; i < len; i++)
dburgessb3a0ca42011-10-12 07:44:40 +0000449 *xP++ /= avgAbsval;
dburgessb3a0ca42011-10-12 07:44:40 +0000450}
451
452signalVector* frequencyShift(signalVector *y,
453 signalVector *x,
454 float freq,
455 float startPhase,
456 float *finalPhase)
457{
458
459 if (!x) return NULL;
460
461 if (y==NULL) {
462 y = new signalVector(x->size());
463 y->isRealOnly(x->isRealOnly());
464 if (y==NULL) return NULL;
465 }
466
467 if (y->size() < x->size()) return NULL;
468
469 float phase = startPhase;
470 signalVector::iterator yP = y->begin();
471 signalVector::iterator xPEnd = x->end();
472 signalVector::iterator xP = x->begin();
473
474 if (x->isRealOnly()) {
475 while (xP < xPEnd) {
476 (*yP++) = expjLookup(phase)*( (xP++)->real() );
477 phase += freq;
478 }
479 }
480 else {
481 while (xP < xPEnd) {
482 (*yP++) = (*xP++)*expjLookup(phase);
483 phase += freq;
484 }
485 }
486
487
488 if (finalPhase) *finalPhase = phase;
489
490 return y;
491}
492
493signalVector* reverseConjugate(signalVector *b)
494{
495 signalVector *tmp = new signalVector(b->size());
496 tmp->isRealOnly(b->isRealOnly());
497 signalVector::iterator bP = b->begin();
498 signalVector::iterator bPEnd = b->end();
499 signalVector::iterator tmpP = tmp->end()-1;
500 if (!b->isRealOnly()) {
501 while (bP < bPEnd) {
502 *tmpP-- = bP->conj();
503 bP++;
504 }
505 }
506 else {
507 while (bP < bPEnd) {
508 *tmpP-- = bP->real();
509 bP++;
510 }
511 }
512
513 return tmp;
514}
515
dburgessb3a0ca42011-10-12 07:44:40 +0000516/* soft output slicer */
517bool vectorSlicer(signalVector *x)
518{
519
520 signalVector::iterator xP = x->begin();
521 signalVector::iterator xPEnd = x->end();
522 while (xP < xPEnd) {
523 *xP = (complex) (0.5*(xP->real()+1.0F));
524 if (xP->real() > 1.0) *xP = 1.0;
525 if (xP->real() < 0.0) *xP = 0.0;
526 xP++;
527 }
528 return true;
529}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400530
531/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400532signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
533 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000534{
Thomas Tsou83e06892013-08-20 16:10:01 -0400535 int burstLen;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400536 signalVector *pulse, *shapedBurst, modBurst;
Thomas Tsou83e06892013-08-20 16:10:01 -0400537 signalVector::iterator modBurstItr;
dburgessb3a0ca42011-10-12 07:44:40 +0000538
Thomas Tsou83e06892013-08-20 16:10:01 -0400539 if (emptyPulse)
540 pulse = GSMPulse->empty;
541 else
542 pulse = GSMPulse->gaussian;
dburgessb3a0ca42011-10-12 07:44:40 +0000543
Thomas Tsou83e06892013-08-20 16:10:01 -0400544 burstLen = sps * (wBurst.size() + guardPeriodLength);
545 modBurst = signalVector(burstLen);
546 modBurstItr = modBurst.begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000547
dburgessb3a0ca42011-10-12 07:44:40 +0000548 for (unsigned int i = 0; i < wBurst.size(); i++) {
549 *modBurstItr = 2.0*(wBurst[i] & 0x01)-1.0;
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400550 modBurstItr += sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000551 }
552
553 // shift up pi/2
554 // ignore starting phase, since spec allows for discontinuous phase
555 GMSKRotate(modBurst);
Thomas Tsou83e06892013-08-20 16:10:01 -0400556
dburgessb3a0ca42011-10-12 07:44:40 +0000557 modBurst.isRealOnly(false);
558
559 // filter w/ pulse shape
Thomas Tsou3eaae802013-08-20 19:31:14 -0400560 shapedBurst = convolve(&modBurst, pulse, NULL, START_ONLY);
561 if (!shapedBurst)
562 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000563
dburgessb3a0ca42011-10-12 07:44:40 +0000564 return shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +0000565}
566
567float sinc(float x)
568{
569 if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
570 return 1.0F;
571}
572
Thomas Tsou3eaae802013-08-20 19:31:14 -0400573bool delayVector(signalVector &wBurst, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000574{
575
576 int intOffset = (int) floor(delay);
577 float fracOffset = delay - intOffset;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400578
dburgessb3a0ca42011-10-12 07:44:40 +0000579 // do fractional shift first, only do it for reasonable offsets
580 if (fabs(fracOffset) > 1e-2) {
581 // create sinc function
582 signalVector sincVector(21);
583 sincVector.isRealOnly(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400584 signalVector::iterator sincBurstItr = sincVector.end();
dburgessb3a0ca42011-10-12 07:44:40 +0000585 for (int i = 0; i < 21; i++)
Thomas Tsou3eaae802013-08-20 19:31:14 -0400586 *--sincBurstItr = (complex) sinc(M_PI_F*(i-10-fracOffset));
dburgessb3a0ca42011-10-12 07:44:40 +0000587
588 signalVector shiftedBurst(wBurst.size());
Thomas Tsou3eaae802013-08-20 19:31:14 -0400589 if (!convolve(&wBurst, &sincVector, &shiftedBurst, NO_DELAY))
590 return false;
dburgessb3a0ca42011-10-12 07:44:40 +0000591 wBurst.clone(shiftedBurst);
592 }
593
594 if (intOffset < 0) {
595 intOffset = -intOffset;
596 signalVector::iterator wBurstItr = wBurst.begin();
597 signalVector::iterator shiftedItr = wBurst.begin()+intOffset;
598 while (shiftedItr < wBurst.end())
599 *wBurstItr++ = *shiftedItr++;
600 while (wBurstItr < wBurst.end())
601 *wBurstItr++ = 0.0;
602 }
603 else {
604 signalVector::iterator wBurstItr = wBurst.end()-1;
605 signalVector::iterator shiftedItr = wBurst.end()-1-intOffset;
606 while (shiftedItr >= wBurst.begin())
607 *wBurstItr-- = *shiftedItr--;
608 while (wBurstItr >= wBurst.begin())
609 *wBurstItr-- = 0.0;
610 }
611}
612
613signalVector *gaussianNoise(int length,
614 float variance,
615 complex mean)
616{
617
618 signalVector *noise = new signalVector(length);
619 signalVector::iterator nPtr = noise->begin();
620 float stddev = sqrtf(variance);
621 while (nPtr < noise->end()) {
622 float u1 = (float) rand()/ (float) RAND_MAX;
623 while (u1==0.0)
624 u1 = (float) rand()/ (float) RAND_MAX;
625 float u2 = (float) rand()/ (float) RAND_MAX;
626 float arg = 2.0*M_PI*u2;
627 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
628 nPtr++;
629 }
630
631 return noise;
632}
633
634complex interpolatePoint(const signalVector &inSig,
635 float ix)
636{
637
638 int start = (int) (floor(ix) - 10);
639 if (start < 0) start = 0;
640 int end = (int) (floor(ix) + 11);
641 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
642
643 complex pVal = 0.0;
644 if (!inSig.isRealOnly()) {
645 for (int i = start; i < end; i++)
646 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
647 }
648 else {
649 for (int i = start; i < end; i++)
650 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
651 }
652
653 return pVal;
654}
655
656
657
658complex peakDetect(const signalVector &rxBurst,
659 float *peakIndex,
660 float *avgPwr)
661{
662
663
664 complex maxVal = 0.0;
665 float maxIndex = -1;
666 float sumPower = 0.0;
667
668 for (unsigned int i = 0; i < rxBurst.size(); i++) {
669 float samplePower = rxBurst[i].norm2();
670 if (samplePower > maxVal.real()) {
671 maxVal = samplePower;
672 maxIndex = i;
673 }
674 sumPower += samplePower;
675 }
676
677 // interpolate around the peak
678 // to save computation, we'll use early-late balancing
679 float earlyIndex = maxIndex-1;
680 float lateIndex = maxIndex+1;
681
682 float incr = 0.5;
683 while (incr > 1.0/1024.0) {
684 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
685 complex lateP = interpolatePoint(rxBurst,lateIndex);
686 if (earlyP < lateP)
687 earlyIndex += incr;
688 else if (earlyP > lateP)
689 earlyIndex -= incr;
690 else break;
691 incr /= 2.0;
692 lateIndex = earlyIndex + 2.0;
693 }
694
695 maxIndex = earlyIndex + 1.0;
696 maxVal = interpolatePoint(rxBurst,maxIndex);
697
698 if (peakIndex!=NULL)
699 *peakIndex = maxIndex;
700
701 if (avgPwr!=NULL)
702 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
703
704 return maxVal;
705
706}
707
708void scaleVector(signalVector &x,
709 complex scale)
710{
711 signalVector::iterator xP = x.begin();
712 signalVector::iterator xPEnd = x.end();
713 if (!x.isRealOnly()) {
714 while (xP < xPEnd) {
715 *xP = *xP * scale;
716 xP++;
717 }
718 }
719 else {
720 while (xP < xPEnd) {
721 *xP = xP->real() * scale;
722 xP++;
723 }
724 }
725}
726
727/** in-place conjugation */
728void conjugateVector(signalVector &x)
729{
730 if (x.isRealOnly()) return;
731 signalVector::iterator xP = x.begin();
732 signalVector::iterator xPEnd = x.end();
733 while (xP < xPEnd) {
734 *xP = xP->conj();
735 xP++;
736 }
737}
738
739
740// in-place addition!!
741bool addVector(signalVector &x,
742 signalVector &y)
743{
744 signalVector::iterator xP = x.begin();
745 signalVector::iterator yP = y.begin();
746 signalVector::iterator xPEnd = x.end();
747 signalVector::iterator yPEnd = y.end();
748 while ((xP < xPEnd) && (yP < yPEnd)) {
749 *xP = *xP + *yP;
750 xP++; yP++;
751 }
752 return true;
753}
754
755// in-place multiplication!!
756bool multVector(signalVector &x,
757 signalVector &y)
758{
759 signalVector::iterator xP = x.begin();
760 signalVector::iterator yP = y.begin();
761 signalVector::iterator xPEnd = x.end();
762 signalVector::iterator yPEnd = y.end();
763 while ((xP < xPEnd) && (yP < yPEnd)) {
764 *xP = (*xP) * (*yP);
765 xP++; yP++;
766 }
767 return true;
768}
769
770
771void offsetVector(signalVector &x,
772 complex offset)
773{
774 signalVector::iterator xP = x.begin();
775 signalVector::iterator xPEnd = x.end();
776 if (!x.isRealOnly()) {
777 while (xP < xPEnd) {
778 *xP += offset;
779 xP++;
780 }
781 }
782 else {
783 while (xP < xPEnd) {
784 *xP = xP->real() + offset;
785 xP++;
786 }
787 }
788}
789
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400790bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +0000791{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400792 bool status = true;
793 complex *data = NULL;
794 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400795 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400796
Thomas Tsou3eaae802013-08-20 19:31:14 -0400797 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +0000798 return false;
799
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400800 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -0400801
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400802 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
803 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
804 if (!midMidamble)
805 return false;
806
Thomas Tsou3eaae802013-08-20 19:31:14 -0400807 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400808 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
809 if (!midamble) {
810 status = false;
811 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000812 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400813
dburgessb3a0ca42011-10-12 07:44:40 +0000814 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
815 // the ideal TSC has an + 180 degree phase shift,
816 // due to the pi/2 frequency shift, that
817 // needs to be accounted for.
818 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400819 scaleVector(*midMidamble, complex(-1.0, 0.0));
820 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +0000821
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400822 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +0000823
Thomas Tsou3eaae802013-08-20 19:31:14 -0400824 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
825 data = (complex *) convolve_h_alloc(midMidamble->size());
826 _midMidamble = new signalVector(data, 0, midMidamble->size());
827 _midMidamble->setAligned(true);
828 memcpy(_midMidamble->begin(), midMidamble->begin(),
829 midMidamble->size() * sizeof(complex));
830
831 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400832 if (!autocorr) {
833 status = false;
834 goto release;
835 }
dburgessb3a0ca42011-10-12 07:44:40 +0000836
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400837 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400838 gMidambles[tsc]->buffer = data;
839 gMidambles[tsc]->sequence = _midMidamble;
840 gMidambles[tsc]->gain = peakDetect(*autocorr,&gMidambles[tsc]->TOA, NULL);
dburgessb3a0ca42011-10-12 07:44:40 +0000841
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400842release:
dburgessb3a0ca42011-10-12 07:44:40 +0000843 delete autocorr;
844 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400845 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +0000846
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400847 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400848 delete _midMidamble;
849 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400850 gMidambles[tsc] = NULL;
851 }
852
853 return status;
dburgessb3a0ca42011-10-12 07:44:40 +0000854}
855
Thomas Tsou83e06892013-08-20 16:10:01 -0400856bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +0000857{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400858 bool status = true;
859 complex *data = NULL;
860 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400861 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400862
863 delete gRACHSequence;
864
865 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
866 if (!seq0)
867 return false;
868
869 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
870 if (!seq1) {
871 status = false;
872 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000873 }
874
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400875 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +0000876
Thomas Tsou3eaae802013-08-20 19:31:14 -0400877 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
878 data = (complex *) convolve_h_alloc(seq1->size());
879 _seq1 = new signalVector(data, 0, seq1->size());
880 _seq1->setAligned(true);
881 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
882
883 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
884 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400885 status = false;
886 goto release;
887 }
dburgessb3a0ca42011-10-12 07:44:40 +0000888
889 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400890 gRACHSequence->sequence = _seq1;
891 gRACHSequence->buffer = data;
892 gRACHSequence->gain = peakDetect(*autocorr,&gRACHSequence->TOA, NULL);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400893
894release:
dburgessb3a0ca42011-10-12 07:44:40 +0000895 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400896 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400897 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +0000898
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400899 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400900 delete _seq1;
901 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400902 gRACHSequence = NULL;
903 }
dburgessb3a0ca42011-10-12 07:44:40 +0000904
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400905 return status;
dburgessb3a0ca42011-10-12 07:44:40 +0000906}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400907
908int detectRACHBurst(signalVector &rxBurst,
909 float thresh,
910 int sps,
911 complex *amp,
912 float *toa)
dburgessb3a0ca42011-10-12 07:44:40 +0000913{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400914 int start, len, num = 0;
915 float _toa, rms, par, avg = 0.0f;
916 complex _amp, *peak;
917 signalVector corr, *sync = gRACHSequence->sequence;
dburgessb3a0ca42011-10-12 07:44:40 +0000918
Thomas Tsou3eaae802013-08-20 19:31:14 -0400919 if ((sps != 1) && (sps != 2) && (sps != 4))
920 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000921
Thomas Tsou3eaae802013-08-20 19:31:14 -0400922 start = 40 * sps;
923 len = 24 * sps;
924 corr = signalVector(len);
dburgessb3a0ca42011-10-12 07:44:40 +0000925
Thomas Tsou3eaae802013-08-20 19:31:14 -0400926 if (!convolve(&rxBurst, sync, &corr,
927 CUSTOM, start, len, sps, 0)) {
928 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000929 }
930
Thomas Tsou3eaae802013-08-20 19:31:14 -0400931 _amp = peakDetect(corr, &_toa, NULL);
932 if ((_toa < 3) || (_toa > len - 3))
933 goto notfound;
934
935 peak = corr.begin() + (int) rint(_toa);
936
937 for (int i = 2 * sps; i <= 5 * sps; i++) {
938 if (peak - i >= corr.begin()) {
939 avg += (peak - i)->norm2();
940 num++;
941 }
942 if (peak + i < corr.end()) {
943 avg += (peak + i)->norm2();
944 num++;
945 }
dburgessb3a0ca42011-10-12 07:44:40 +0000946 }
947
Thomas Tsou3eaae802013-08-20 19:31:14 -0400948 if (num < 2)
949 goto notfound;
dburgessb3a0ca42011-10-12 07:44:40 +0000950
Thomas Tsou3eaae802013-08-20 19:31:14 -0400951 rms = sqrtf(avg / (float) num) + 0.00001;
952 par = _amp.abs() / rms;
953 if (par < thresh)
954 goto notfound;
dburgessb3a0ca42011-10-12 07:44:40 +0000955
Thomas Tsou3eaae802013-08-20 19:31:14 -0400956 /* Subtract forward tail bits from delay */
957 if (toa)
958 *toa = _toa - 8 * sps;
959 if (amp)
960 *amp = _amp / gRACHSequence->gain;
dburgessb3a0ca42011-10-12 07:44:40 +0000961
Thomas Tsou3eaae802013-08-20 19:31:14 -0400962 return 1;
963
964notfound:
965 if (amp)
966 *amp = 0.0f;
967 if (toa)
968 *toa = 0.0f;
969
970 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +0000971}
972
973bool energyDetect(signalVector &rxBurst,
974 unsigned windowLength,
975 float detectThreshold,
976 float *avgPwr)
977{
978
979 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
980 float energy = 0.0;
981 if (windowLength < 0) windowLength = 20;
982 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
983 for (unsigned i = 0; i < windowLength; i++) {
984 energy += windowItr->norm2();
985 windowItr+=4;
986 }
987 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +0000988 return (energy/windowLength > detectThreshold*detectThreshold);
989}
dburgessb3a0ca42011-10-12 07:44:40 +0000990
Thomas Tsou3eaae802013-08-20 19:31:14 -0400991int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
992 int sps, complex *amp, float *toa, unsigned max_toa,
993 bool chan_req, signalVector **chan, float *chan_offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000994{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400995 int start, target, len, num = 0;
996 complex _amp, *peak;
997 float _toa, rms, par, avg = 0.0f;
998 signalVector corr, *sync, *_chan;
dburgessb3a0ca42011-10-12 07:44:40 +0000999
Thomas Tsou3eaae802013-08-20 19:31:14 -04001000 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 2) && (sps != 4)))
1001 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001002
Thomas Tsou3eaae802013-08-20 19:31:14 -04001003 target = 3 + 58 + 5 + 16;
1004 start = (target - 8) * sps;
1005 len = (8 + 8 + max_toa) * sps;
dburgessb3a0ca42011-10-12 07:44:40 +00001006
Thomas Tsou3eaae802013-08-20 19:31:14 -04001007 sync = gMidambles[tsc]->sequence;
1008 sync = gMidambles[tsc]->sequence;
1009 corr = signalVector(len);
dburgessb3a0ca42011-10-12 07:44:40 +00001010
Thomas Tsou3eaae802013-08-20 19:31:14 -04001011 if (!convolve(&rxBurst, sync, &corr,
1012 CUSTOM, start, len, sps, 0)) {
1013 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001014 }
1015
Thomas Tsou3eaae802013-08-20 19:31:14 -04001016 _amp = peakDetect(corr, &_toa, NULL);
1017 peak = corr.begin() + (int) rint(_toa);
1018
1019 /* Check for bogus results */
1020 if ((_toa < 0.0) || (_toa > corr.size()))
1021 goto notfound;
1022
1023 for (int i = 2 * sps; i <= 5 * sps; i++) {
1024 if (peak - i >= corr.begin()) {
1025 avg += (peak - i)->norm2();
1026 num++;
dburgessb3a0ca42011-10-12 07:44:40 +00001027 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001028 if (peak + i < corr.end()) {
1029 avg += (peak + i)->norm2();
1030 num++;
dburgessb3a0ca42011-10-12 07:44:40 +00001031 }
1032 }
1033
Thomas Tsou3eaae802013-08-20 19:31:14 -04001034 if (num < 2)
1035 goto notfound;
1036
1037 rms = sqrtf(avg / (float) num) + 0.00001;
1038 par = (_amp.abs()) / rms;
1039 if (par < thresh)
1040 goto notfound;
1041
1042 /*
1043 * NOTE: Because ideal TSC is 66 symbols into burst,
1044 * the ideal TSC has an +/- 180 degree phase shift,
1045 * due to the pi/4 frequency shift, that
1046 * needs to be accounted for.
1047 */
1048 if (amp)
1049 *amp = _amp / gMidambles[tsc]->gain;
1050
1051 /* Delay one half of peak-centred correlation length */
1052 _toa -= sps * 8;
1053
1054 if (toa)
1055 *toa = _toa;
1056
1057 if (chan_req) {
1058 _chan = new signalVector(6 * sps);
1059
1060 delayVector(corr, -_toa);
1061 corr.segmentCopyTo(*_chan, target - 3, _chan->size());
1062 scaleVector(*_chan, complex(1.0, 0.0) / gMidambles[tsc]->gain);
1063
1064 *chan = _chan;
1065
1066 if (chan_offset)
1067 *chan_offset = 3.0 * sps;;
dburgessb3a0ca42011-10-12 07:44:40 +00001068 }
1069
Thomas Tsou3eaae802013-08-20 19:31:14 -04001070 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001071
Thomas Tsou3eaae802013-08-20 19:31:14 -04001072notfound:
1073 if (amp)
1074 *amp = 0.0f;
1075 if (toa)
1076 *toa = 0.0f;
dburgessb3a0ca42011-10-12 07:44:40 +00001077
Thomas Tsou3eaae802013-08-20 19:31:14 -04001078 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001079}
1080
1081signalVector *decimateVector(signalVector &wVector,
1082 int decimationFactor)
1083{
1084
1085 if (decimationFactor <= 1) return NULL;
1086
1087 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
1088 decVector->isRealOnly(wVector.isRealOnly());
1089
1090 signalVector::iterator vecItr = decVector->begin();
1091 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1092 *vecItr++ = wVector[i];
1093
1094 return decVector;
1095}
1096
1097
Thomas Tsou83e06892013-08-20 16:10:01 -04001098SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
1099 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001100{
1101 scaleVector(rxBurst,((complex) 1.0)/channel);
1102 delayVector(rxBurst,-TOA);
1103
1104 signalVector *shapedBurst = &rxBurst;
1105
1106 // shift up by a quarter of a frequency
1107 // ignore starting phase, since spec allows for discontinuous phase
1108 GMSKReverseRotate(*shapedBurst);
1109
1110 // run through slicer
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001111 if (sps > 1) {
1112 signalVector *decShapedBurst = decimateVector(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001113 shapedBurst = decShapedBurst;
1114 }
1115
dburgessb3a0ca42011-10-12 07:44:40 +00001116 vectorSlicer(shapedBurst);
1117
1118 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1119
1120 SoftVector::iterator burstItr = burstBits->begin();
1121 signalVector::iterator shapedItr = shapedBurst->begin();
1122 for (; shapedItr < shapedBurst->end(); shapedItr++)
1123 *burstItr++ = shapedItr->real();
1124
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001125 if (sps > 1)
1126 delete shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +00001127
1128 return burstBits;
1129
1130}
dburgessb3a0ca42011-10-12 07:44:40 +00001131
dburgessb3a0ca42011-10-12 07:44:40 +00001132// Assumes symbol-spaced sampling!!!
1133// Based upon paper by Al-Dhahir and Cioffi
1134bool designDFE(signalVector &channelResponse,
1135 float SNRestimate,
1136 int Nf,
1137 signalVector **feedForwardFilter,
1138 signalVector **feedbackFilter)
1139{
1140
1141 signalVector G0(Nf);
1142 signalVector G1(Nf);
1143 signalVector::iterator G0ptr = G0.begin();
1144 signalVector::iterator G1ptr = G1.begin();
1145 signalVector::iterator chanPtr = channelResponse.begin();
1146
1147 int nu = channelResponse.size()-1;
1148
1149 *G0ptr = 1.0/sqrtf(SNRestimate);
1150 for(int j = 0; j <= nu; j++) {
1151 *G1ptr = chanPtr->conj();
1152 G1ptr++; chanPtr++;
1153 }
1154
1155 signalVector *L[Nf];
1156 signalVector::iterator Lptr;
1157 float d;
1158 for(int i = 0; i < Nf; i++) {
1159 d = G0.begin()->norm2() + G1.begin()->norm2();
1160 L[i] = new signalVector(Nf+nu);
1161 Lptr = L[i]->begin()+i;
1162 G0ptr = G0.begin(); G1ptr = G1.begin();
1163 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1164 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1165 Lptr++;
1166 G0ptr++;
1167 G1ptr++;
1168 }
1169 complex k = (*G1.begin())/(*G0.begin());
1170
1171 if (i != Nf-1) {
1172 signalVector G0new = G1;
1173 scaleVector(G0new,k.conj());
1174 addVector(G0new,G0);
1175
1176 signalVector G1new = G0;
1177 scaleVector(G1new,k*(-1.0));
1178 addVector(G1new,G1);
1179 delayVector(G1new,-1.0);
1180
1181 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1182 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1183 G0 = G0new;
1184 G1 = G1new;
1185 }
1186 }
1187
1188 *feedbackFilter = new signalVector(nu);
1189 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1190 scaleVector(**feedbackFilter,(complex) -1.0);
1191 conjugateVector(**feedbackFilter);
1192
1193 signalVector v(Nf);
1194 signalVector::iterator vStart = v.begin();
1195 signalVector::iterator vPtr;
1196 *(vStart+Nf-1) = (complex) 1.0;
1197 for(int k = Nf-2; k >= 0; k--) {
1198 Lptr = L[k]->begin()+k+1;
1199 vPtr = vStart + k+1;
1200 complex v_k = 0.0;
1201 for (int j = k+1; j < Nf; j++) {
1202 v_k -= (*vPtr)*(*Lptr);
1203 vPtr++; Lptr++;
1204 }
1205 *(vStart + k) = v_k;
1206 }
1207
1208 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001209 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001210 for (int i = 0; i < Nf; i++) {
1211 delete L[i];
1212 complex w_i = 0.0;
1213 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1214 vPtr = vStart+i;
1215 chanPtr = channelResponse.begin();
1216 for (int k = 0; k < endPt+1; k++) {
1217 w_i += (*vPtr)*(chanPtr->conj());
1218 vPtr++; chanPtr++;
1219 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001220 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001221 }
1222
1223
1224 return true;
1225
1226}
1227
1228// Assumes symbol-rate sampling!!!!
1229SoftVector *equalizeBurst(signalVector &rxBurst,
1230 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001231 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001232 signalVector &w, // feedforward filter
1233 signalVector &b) // feedback filter
1234{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001235 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001236
Thomas Tsou3eaae802013-08-20 19:31:14 -04001237 if (!delayVector(rxBurst, -TOA))
1238 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001239
Thomas Tsou3eaae802013-08-20 19:31:14 -04001240 postForwardFull = convolve(&rxBurst, &w, NULL,
1241 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1242 if (!postForwardFull)
1243 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001244
1245 signalVector* postForward = new signalVector(rxBurst.size());
1246 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1247 delete postForwardFull;
1248
1249 signalVector::iterator dPtr = postForward->begin();
1250 signalVector::iterator dBackPtr;
1251 signalVector::iterator rotPtr = GMSKRotation->begin();
1252 signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
1253
1254 signalVector *DFEoutput = new signalVector(postForward->size());
1255 signalVector::iterator DFEItr = DFEoutput->begin();
1256
1257 // NOTE: can insert the midamble and/or use midamble to estimate BER
1258 for (; dPtr < postForward->end(); dPtr++) {
1259 dBackPtr = dPtr-1;
1260 signalVector::iterator bPtr = b.begin();
1261 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1262 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1263 bPtr++;
1264 dBackPtr--;
1265 }
1266 *dPtr = *dPtr * (*revRotPtr);
1267 *DFEItr = *dPtr;
1268 // make decision on symbol
1269 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1270 //*DFEItr = *dPtr;
1271 *dPtr = *dPtr * (*rotPtr);
1272 DFEItr++;
1273 rotPtr++;
1274 revRotPtr++;
1275 }
1276
1277 vectorSlicer(DFEoutput);
1278
1279 SoftVector *burstBits = new SoftVector(postForward->size());
1280 SoftVector::iterator burstItr = burstBits->begin();
1281 DFEItr = DFEoutput->begin();
1282 for (; DFEItr < DFEoutput->end(); DFEItr++)
1283 *burstItr++ = DFEItr->real();
1284
1285 delete postForward;
1286
1287 delete DFEoutput;
1288
1289 return burstBits;
1290}