blob: b0ef21aa4893c3caa4c0d9720bdad317296ac955 [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
Thomas Tsou8181b012013-08-20 21:17:19 -0400656static complex fastPeakDetect(const signalVector &rxBurst, float *index)
657{
658 float val, max = 0.0f;
659 complex amp;
660 int _index = -1;
661
662 for (int i = 0; i < rxBurst.size(); i++) {
663 val = rxBurst[i].norm2();
664 if (val > max) {
665 max = val;
666 _index = i;
667 amp = rxBurst[i];
668 }
669 }
670
671 if (index)
672 *index = (float) _index;
673
674 return amp;
675}
676
dburgessb3a0ca42011-10-12 07:44:40 +0000677complex peakDetect(const signalVector &rxBurst,
678 float *peakIndex,
679 float *avgPwr)
680{
681
682
683 complex maxVal = 0.0;
684 float maxIndex = -1;
685 float sumPower = 0.0;
686
687 for (unsigned int i = 0; i < rxBurst.size(); i++) {
688 float samplePower = rxBurst[i].norm2();
689 if (samplePower > maxVal.real()) {
690 maxVal = samplePower;
691 maxIndex = i;
692 }
693 sumPower += samplePower;
694 }
695
696 // interpolate around the peak
697 // to save computation, we'll use early-late balancing
698 float earlyIndex = maxIndex-1;
699 float lateIndex = maxIndex+1;
700
701 float incr = 0.5;
702 while (incr > 1.0/1024.0) {
703 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
704 complex lateP = interpolatePoint(rxBurst,lateIndex);
705 if (earlyP < lateP)
706 earlyIndex += incr;
707 else if (earlyP > lateP)
708 earlyIndex -= incr;
709 else break;
710 incr /= 2.0;
711 lateIndex = earlyIndex + 2.0;
712 }
713
714 maxIndex = earlyIndex + 1.0;
715 maxVal = interpolatePoint(rxBurst,maxIndex);
716
717 if (peakIndex!=NULL)
718 *peakIndex = maxIndex;
719
720 if (avgPwr!=NULL)
721 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
722
723 return maxVal;
724
725}
726
727void scaleVector(signalVector &x,
728 complex scale)
729{
730 signalVector::iterator xP = x.begin();
731 signalVector::iterator xPEnd = x.end();
732 if (!x.isRealOnly()) {
733 while (xP < xPEnd) {
734 *xP = *xP * scale;
735 xP++;
736 }
737 }
738 else {
739 while (xP < xPEnd) {
740 *xP = xP->real() * scale;
741 xP++;
742 }
743 }
744}
745
746/** in-place conjugation */
747void conjugateVector(signalVector &x)
748{
749 if (x.isRealOnly()) return;
750 signalVector::iterator xP = x.begin();
751 signalVector::iterator xPEnd = x.end();
752 while (xP < xPEnd) {
753 *xP = xP->conj();
754 xP++;
755 }
756}
757
758
759// in-place addition!!
760bool addVector(signalVector &x,
761 signalVector &y)
762{
763 signalVector::iterator xP = x.begin();
764 signalVector::iterator yP = y.begin();
765 signalVector::iterator xPEnd = x.end();
766 signalVector::iterator yPEnd = y.end();
767 while ((xP < xPEnd) && (yP < yPEnd)) {
768 *xP = *xP + *yP;
769 xP++; yP++;
770 }
771 return true;
772}
773
774// in-place multiplication!!
775bool multVector(signalVector &x,
776 signalVector &y)
777{
778 signalVector::iterator xP = x.begin();
779 signalVector::iterator yP = y.begin();
780 signalVector::iterator xPEnd = x.end();
781 signalVector::iterator yPEnd = y.end();
782 while ((xP < xPEnd) && (yP < yPEnd)) {
783 *xP = (*xP) * (*yP);
784 xP++; yP++;
785 }
786 return true;
787}
788
789
790void offsetVector(signalVector &x,
791 complex offset)
792{
793 signalVector::iterator xP = x.begin();
794 signalVector::iterator xPEnd = x.end();
795 if (!x.isRealOnly()) {
796 while (xP < xPEnd) {
797 *xP += offset;
798 xP++;
799 }
800 }
801 else {
802 while (xP < xPEnd) {
803 *xP = xP->real() + offset;
804 xP++;
805 }
806 }
807}
808
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400809bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +0000810{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400811 bool status = true;
812 complex *data = NULL;
813 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400814 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400815
Thomas Tsou3eaae802013-08-20 19:31:14 -0400816 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +0000817 return false;
818
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400819 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -0400820
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400821 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
822 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
823 if (!midMidamble)
824 return false;
825
Thomas Tsou3eaae802013-08-20 19:31:14 -0400826 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400827 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
828 if (!midamble) {
829 status = false;
830 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000831 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400832
dburgessb3a0ca42011-10-12 07:44:40 +0000833 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
834 // the ideal TSC has an + 180 degree phase shift,
835 // due to the pi/2 frequency shift, that
836 // needs to be accounted for.
837 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400838 scaleVector(*midMidamble, complex(-1.0, 0.0));
839 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +0000840
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400841 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +0000842
Thomas Tsou3eaae802013-08-20 19:31:14 -0400843 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
844 data = (complex *) convolve_h_alloc(midMidamble->size());
845 _midMidamble = new signalVector(data, 0, midMidamble->size());
846 _midMidamble->setAligned(true);
847 memcpy(_midMidamble->begin(), midMidamble->begin(),
848 midMidamble->size() * sizeof(complex));
849
850 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400851 if (!autocorr) {
852 status = false;
853 goto release;
854 }
dburgessb3a0ca42011-10-12 07:44:40 +0000855
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400856 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400857 gMidambles[tsc]->buffer = data;
858 gMidambles[tsc]->sequence = _midMidamble;
859 gMidambles[tsc]->gain = peakDetect(*autocorr,&gMidambles[tsc]->TOA, NULL);
dburgessb3a0ca42011-10-12 07:44:40 +0000860
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400861release:
dburgessb3a0ca42011-10-12 07:44:40 +0000862 delete autocorr;
863 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400864 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +0000865
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400866 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400867 delete _midMidamble;
868 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400869 gMidambles[tsc] = NULL;
870 }
871
872 return status;
dburgessb3a0ca42011-10-12 07:44:40 +0000873}
874
Thomas Tsou83e06892013-08-20 16:10:01 -0400875bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +0000876{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400877 bool status = true;
878 complex *data = NULL;
879 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400880 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400881
882 delete gRACHSequence;
883
884 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
885 if (!seq0)
886 return false;
887
888 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
889 if (!seq1) {
890 status = false;
891 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +0000892 }
893
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400894 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +0000895
Thomas Tsou3eaae802013-08-20 19:31:14 -0400896 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
897 data = (complex *) convolve_h_alloc(seq1->size());
898 _seq1 = new signalVector(data, 0, seq1->size());
899 _seq1->setAligned(true);
900 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
901
902 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
903 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400904 status = false;
905 goto release;
906 }
dburgessb3a0ca42011-10-12 07:44:40 +0000907
908 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400909 gRACHSequence->sequence = _seq1;
910 gRACHSequence->buffer = data;
911 gRACHSequence->gain = peakDetect(*autocorr,&gRACHSequence->TOA, NULL);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400912
913release:
dburgessb3a0ca42011-10-12 07:44:40 +0000914 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400915 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400916 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +0000917
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400918 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400919 delete _seq1;
920 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400921 gRACHSequence = NULL;
922 }
dburgessb3a0ca42011-10-12 07:44:40 +0000923
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400924 return status;
dburgessb3a0ca42011-10-12 07:44:40 +0000925}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400926
927int detectRACHBurst(signalVector &rxBurst,
928 float thresh,
929 int sps,
930 complex *amp,
931 float *toa)
dburgessb3a0ca42011-10-12 07:44:40 +0000932{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400933 int start, len, num = 0;
934 float _toa, rms, par, avg = 0.0f;
935 complex _amp, *peak;
936 signalVector corr, *sync = gRACHSequence->sequence;
dburgessb3a0ca42011-10-12 07:44:40 +0000937
Thomas Tsou3eaae802013-08-20 19:31:14 -0400938 if ((sps != 1) && (sps != 2) && (sps != 4))
939 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000940
Thomas Tsou3eaae802013-08-20 19:31:14 -0400941 start = 40 * sps;
942 len = 24 * sps;
943 corr = signalVector(len);
dburgessb3a0ca42011-10-12 07:44:40 +0000944
Thomas Tsou3eaae802013-08-20 19:31:14 -0400945 if (!convolve(&rxBurst, sync, &corr,
946 CUSTOM, start, len, sps, 0)) {
947 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +0000948 }
949
Thomas Tsou8181b012013-08-20 21:17:19 -0400950 _amp = fastPeakDetect(corr, &_toa);
951
952 /* Restrict peak-to-average calculations at the edges */
Thomas Tsou3eaae802013-08-20 19:31:14 -0400953 if ((_toa < 3) || (_toa > len - 3))
954 goto notfound;
955
956 peak = corr.begin() + (int) rint(_toa);
957
Thomas Tsou8181b012013-08-20 21:17:19 -0400958 /* Compute peak-to-average ratio. Reject if we don't have enough values */
Thomas Tsou3eaae802013-08-20 19:31:14 -0400959 for (int i = 2 * sps; i <= 5 * sps; i++) {
960 if (peak - i >= corr.begin()) {
961 avg += (peak - i)->norm2();
962 num++;
963 }
964 if (peak + i < corr.end()) {
965 avg += (peak + i)->norm2();
966 num++;
967 }
dburgessb3a0ca42011-10-12 07:44:40 +0000968 }
969
Thomas Tsou3eaae802013-08-20 19:31:14 -0400970 if (num < 2)
971 goto notfound;
dburgessb3a0ca42011-10-12 07:44:40 +0000972
Thomas Tsou3eaae802013-08-20 19:31:14 -0400973 rms = sqrtf(avg / (float) num) + 0.00001;
974 par = _amp.abs() / rms;
975 if (par < thresh)
976 goto notfound;
dburgessb3a0ca42011-10-12 07:44:40 +0000977
Thomas Tsou8181b012013-08-20 21:17:19 -0400978 /* Run the full peak detection to obtain interpolated values */
979 _amp = peakDetect(corr, &_toa, NULL);
980
Thomas Tsou3eaae802013-08-20 19:31:14 -0400981 /* Subtract forward tail bits from delay */
982 if (toa)
983 *toa = _toa - 8 * sps;
Thomas Tsou8181b012013-08-20 21:17:19 -0400984
985 /* Normalize our channel gain */
Thomas Tsou3eaae802013-08-20 19:31:14 -0400986 if (amp)
987 *amp = _amp / gRACHSequence->gain;
dburgessb3a0ca42011-10-12 07:44:40 +0000988
Thomas Tsou3eaae802013-08-20 19:31:14 -0400989 return 1;
990
991notfound:
992 if (amp)
993 *amp = 0.0f;
994 if (toa)
995 *toa = 0.0f;
996
997 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +0000998}
999
1000bool energyDetect(signalVector &rxBurst,
1001 unsigned windowLength,
1002 float detectThreshold,
1003 float *avgPwr)
1004{
1005
1006 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1007 float energy = 0.0;
1008 if (windowLength < 0) windowLength = 20;
1009 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1010 for (unsigned i = 0; i < windowLength; i++) {
1011 energy += windowItr->norm2();
1012 windowItr+=4;
1013 }
1014 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001015 return (energy/windowLength > detectThreshold*detectThreshold);
1016}
dburgessb3a0ca42011-10-12 07:44:40 +00001017
Thomas Tsou3eaae802013-08-20 19:31:14 -04001018int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1019 int sps, complex *amp, float *toa, unsigned max_toa,
1020 bool chan_req, signalVector **chan, float *chan_offset)
dburgessb3a0ca42011-10-12 07:44:40 +00001021{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001022 int start, target, len, num = 0;
1023 complex _amp, *peak;
1024 float _toa, rms, par, avg = 0.0f;
1025 signalVector corr, *sync, *_chan;
dburgessb3a0ca42011-10-12 07:44:40 +00001026
Thomas Tsou3eaae802013-08-20 19:31:14 -04001027 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 2) && (sps != 4)))
1028 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001029
Thomas Tsou3eaae802013-08-20 19:31:14 -04001030 target = 3 + 58 + 5 + 16;
1031 start = (target - 8) * sps;
1032 len = (8 + 8 + max_toa) * sps;
dburgessb3a0ca42011-10-12 07:44:40 +00001033
Thomas Tsou3eaae802013-08-20 19:31:14 -04001034 sync = gMidambles[tsc]->sequence;
1035 sync = gMidambles[tsc]->sequence;
1036 corr = signalVector(len);
dburgessb3a0ca42011-10-12 07:44:40 +00001037
Thomas Tsou3eaae802013-08-20 19:31:14 -04001038 if (!convolve(&rxBurst, sync, &corr,
1039 CUSTOM, start, len, sps, 0)) {
1040 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001041 }
1042
Thomas Tsou3eaae802013-08-20 19:31:14 -04001043 _amp = peakDetect(corr, &_toa, NULL);
1044 peak = corr.begin() + (int) rint(_toa);
1045
1046 /* Check for bogus results */
1047 if ((_toa < 0.0) || (_toa > corr.size()))
1048 goto notfound;
1049
1050 for (int i = 2 * sps; i <= 5 * sps; i++) {
1051 if (peak - i >= corr.begin()) {
1052 avg += (peak - i)->norm2();
1053 num++;
dburgessb3a0ca42011-10-12 07:44:40 +00001054 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001055 if (peak + i < corr.end()) {
1056 avg += (peak + i)->norm2();
1057 num++;
dburgessb3a0ca42011-10-12 07:44:40 +00001058 }
1059 }
1060
Thomas Tsou3eaae802013-08-20 19:31:14 -04001061 if (num < 2)
1062 goto notfound;
1063
1064 rms = sqrtf(avg / (float) num) + 0.00001;
1065 par = (_amp.abs()) / rms;
1066 if (par < thresh)
1067 goto notfound;
1068
1069 /*
1070 * NOTE: Because ideal TSC is 66 symbols into burst,
1071 * the ideal TSC has an +/- 180 degree phase shift,
1072 * due to the pi/4 frequency shift, that
1073 * needs to be accounted for.
1074 */
1075 if (amp)
1076 *amp = _amp / gMidambles[tsc]->gain;
1077
1078 /* Delay one half of peak-centred correlation length */
1079 _toa -= sps * 8;
1080
1081 if (toa)
1082 *toa = _toa;
1083
1084 if (chan_req) {
1085 _chan = new signalVector(6 * sps);
1086
1087 delayVector(corr, -_toa);
1088 corr.segmentCopyTo(*_chan, target - 3, _chan->size());
1089 scaleVector(*_chan, complex(1.0, 0.0) / gMidambles[tsc]->gain);
1090
1091 *chan = _chan;
1092
1093 if (chan_offset)
1094 *chan_offset = 3.0 * sps;;
dburgessb3a0ca42011-10-12 07:44:40 +00001095 }
1096
Thomas Tsou3eaae802013-08-20 19:31:14 -04001097 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001098
Thomas Tsou3eaae802013-08-20 19:31:14 -04001099notfound:
1100 if (amp)
1101 *amp = 0.0f;
1102 if (toa)
1103 *toa = 0.0f;
dburgessb3a0ca42011-10-12 07:44:40 +00001104
Thomas Tsou3eaae802013-08-20 19:31:14 -04001105 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001106}
1107
1108signalVector *decimateVector(signalVector &wVector,
1109 int decimationFactor)
1110{
1111
1112 if (decimationFactor <= 1) return NULL;
1113
1114 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
1115 decVector->isRealOnly(wVector.isRealOnly());
1116
1117 signalVector::iterator vecItr = decVector->begin();
1118 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1119 *vecItr++ = wVector[i];
1120
1121 return decVector;
1122}
1123
1124
Thomas Tsou83e06892013-08-20 16:10:01 -04001125SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
1126 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001127{
1128 scaleVector(rxBurst,((complex) 1.0)/channel);
1129 delayVector(rxBurst,-TOA);
1130
1131 signalVector *shapedBurst = &rxBurst;
1132
1133 // shift up by a quarter of a frequency
1134 // ignore starting phase, since spec allows for discontinuous phase
1135 GMSKReverseRotate(*shapedBurst);
1136
1137 // run through slicer
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001138 if (sps > 1) {
1139 signalVector *decShapedBurst = decimateVector(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001140 shapedBurst = decShapedBurst;
1141 }
1142
dburgessb3a0ca42011-10-12 07:44:40 +00001143 vectorSlicer(shapedBurst);
1144
1145 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1146
1147 SoftVector::iterator burstItr = burstBits->begin();
1148 signalVector::iterator shapedItr = shapedBurst->begin();
1149 for (; shapedItr < shapedBurst->end(); shapedItr++)
1150 *burstItr++ = shapedItr->real();
1151
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001152 if (sps > 1)
1153 delete shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +00001154
1155 return burstBits;
1156
1157}
dburgessb3a0ca42011-10-12 07:44:40 +00001158
dburgessb3a0ca42011-10-12 07:44:40 +00001159// Assumes symbol-spaced sampling!!!
1160// Based upon paper by Al-Dhahir and Cioffi
1161bool designDFE(signalVector &channelResponse,
1162 float SNRestimate,
1163 int Nf,
1164 signalVector **feedForwardFilter,
1165 signalVector **feedbackFilter)
1166{
1167
1168 signalVector G0(Nf);
1169 signalVector G1(Nf);
1170 signalVector::iterator G0ptr = G0.begin();
1171 signalVector::iterator G1ptr = G1.begin();
1172 signalVector::iterator chanPtr = channelResponse.begin();
1173
1174 int nu = channelResponse.size()-1;
1175
1176 *G0ptr = 1.0/sqrtf(SNRestimate);
1177 for(int j = 0; j <= nu; j++) {
1178 *G1ptr = chanPtr->conj();
1179 G1ptr++; chanPtr++;
1180 }
1181
1182 signalVector *L[Nf];
1183 signalVector::iterator Lptr;
1184 float d;
1185 for(int i = 0; i < Nf; i++) {
1186 d = G0.begin()->norm2() + G1.begin()->norm2();
1187 L[i] = new signalVector(Nf+nu);
1188 Lptr = L[i]->begin()+i;
1189 G0ptr = G0.begin(); G1ptr = G1.begin();
1190 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1191 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1192 Lptr++;
1193 G0ptr++;
1194 G1ptr++;
1195 }
1196 complex k = (*G1.begin())/(*G0.begin());
1197
1198 if (i != Nf-1) {
1199 signalVector G0new = G1;
1200 scaleVector(G0new,k.conj());
1201 addVector(G0new,G0);
1202
1203 signalVector G1new = G0;
1204 scaleVector(G1new,k*(-1.0));
1205 addVector(G1new,G1);
1206 delayVector(G1new,-1.0);
1207
1208 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1209 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1210 G0 = G0new;
1211 G1 = G1new;
1212 }
1213 }
1214
1215 *feedbackFilter = new signalVector(nu);
1216 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1217 scaleVector(**feedbackFilter,(complex) -1.0);
1218 conjugateVector(**feedbackFilter);
1219
1220 signalVector v(Nf);
1221 signalVector::iterator vStart = v.begin();
1222 signalVector::iterator vPtr;
1223 *(vStart+Nf-1) = (complex) 1.0;
1224 for(int k = Nf-2; k >= 0; k--) {
1225 Lptr = L[k]->begin()+k+1;
1226 vPtr = vStart + k+1;
1227 complex v_k = 0.0;
1228 for (int j = k+1; j < Nf; j++) {
1229 v_k -= (*vPtr)*(*Lptr);
1230 vPtr++; Lptr++;
1231 }
1232 *(vStart + k) = v_k;
1233 }
1234
1235 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001236 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001237 for (int i = 0; i < Nf; i++) {
1238 delete L[i];
1239 complex w_i = 0.0;
1240 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1241 vPtr = vStart+i;
1242 chanPtr = channelResponse.begin();
1243 for (int k = 0; k < endPt+1; k++) {
1244 w_i += (*vPtr)*(chanPtr->conj());
1245 vPtr++; chanPtr++;
1246 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001247 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001248 }
1249
1250
1251 return true;
1252
1253}
1254
1255// Assumes symbol-rate sampling!!!!
1256SoftVector *equalizeBurst(signalVector &rxBurst,
1257 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001258 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001259 signalVector &w, // feedforward filter
1260 signalVector &b) // feedback filter
1261{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001262 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001263
Thomas Tsou3eaae802013-08-20 19:31:14 -04001264 if (!delayVector(rxBurst, -TOA))
1265 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001266
Thomas Tsou3eaae802013-08-20 19:31:14 -04001267 postForwardFull = convolve(&rxBurst, &w, NULL,
1268 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1269 if (!postForwardFull)
1270 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001271
1272 signalVector* postForward = new signalVector(rxBurst.size());
1273 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1274 delete postForwardFull;
1275
1276 signalVector::iterator dPtr = postForward->begin();
1277 signalVector::iterator dBackPtr;
1278 signalVector::iterator rotPtr = GMSKRotation->begin();
1279 signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
1280
1281 signalVector *DFEoutput = new signalVector(postForward->size());
1282 signalVector::iterator DFEItr = DFEoutput->begin();
1283
1284 // NOTE: can insert the midamble and/or use midamble to estimate BER
1285 for (; dPtr < postForward->end(); dPtr++) {
1286 dBackPtr = dPtr-1;
1287 signalVector::iterator bPtr = b.begin();
1288 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1289 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1290 bPtr++;
1291 dBackPtr--;
1292 }
1293 *dPtr = *dPtr * (*revRotPtr);
1294 *DFEItr = *dPtr;
1295 // make decision on symbol
1296 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1297 //*DFEItr = *dPtr;
1298 *dPtr = *dPtr * (*rotPtr);
1299 DFEItr++;
1300 rotPtr++;
1301 revRotPtr++;
1302 }
1303
1304 vectorSlicer(DFEoutput);
1305
1306 SoftVector *burstBits = new SoftVector(postForward->size());
1307 SoftVector::iterator burstItr = burstBits->begin();
1308 DFEItr = DFEoutput->begin();
1309 for (; DFEItr < DFEoutput->end(); DFEItr++)
1310 *burstItr++ = DFEItr->real();
1311
1312 delete postForward;
1313
1314 delete DFEoutput;
1315
1316 return burstBits;
1317}