blob: 61bfe5b13ba419c38ef578b6f39801d78db2eeb1 [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
Thomas Tsou7e4e5362013-10-30 21:18:55 -040025#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
dburgessb3a0ca42011-10-12 07:44:40 +000029#include "sigProcLib.h"
30#include "GSMCommon.h"
31
Thomas Tsou3eaae802013-08-20 19:31:14 -040032extern "C" {
33#include "convolve.h"
Thomas Tsou7e4e5362013-10-30 21:18:55 -040034#include "scale.h"
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -050035#include "mult.h"
Thomas Tsou3eaae802013-08-20 19:31:14 -040036}
37
Thomas Tsou7e4e5362013-10-30 21:18:55 -040038using namespace GSM;
39
Thomas Tsouf79c4d02013-11-09 15:51:56 -060040#define TABLESIZE 1024
41#define DELAYFILTS 64
dburgessb3a0ca42011-10-12 07:44:40 +000042
43/** Lookup tables for trigonometric approximation */
44float cosTable[TABLESIZE+1]; // add 1 element for wrap around
45float sinTable[TABLESIZE+1];
Thomas Tsou0e0e1f42013-11-09 22:08:51 -050046float sincTable[TABLESIZE+1];
dburgessb3a0ca42011-10-12 07:44:40 +000047
48/** Constants */
49static const float M_PI_F = (float)M_PI;
50static const float M_2PI_F = (float)(2.0*M_PI);
51static const float M_1_2PI_F = 1/M_2PI_F;
52
Thomas Tsouc1f7c422013-10-11 13:49:55 -040053/* Precomputed rotation vectors */
54static signalVector *GMSKRotationN = NULL;
55static signalVector *GMSKReverseRotationN = NULL;
56static signalVector *GMSKRotation1 = NULL;
57static signalVector *GMSKReverseRotation1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000058
Thomas Tsouf79c4d02013-11-09 15:51:56 -060059/* Precomputed fractional delay filters */
60static signalVector *delayFilters[DELAYFILTS];
61
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040062/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040063 * RACH and midamble correlation waveforms. Store the buffer separately
64 * because we need to allocate it explicitly outside of the signal vector
65 * constructor. This is because C++ (prior to C++11) is unable to natively
66 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040067 */
68struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040069 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040070 {
71 }
72
73 ~CorrelationSequence()
74 {
75 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040076 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040077 }
78
dburgessb3a0ca42011-10-12 07:44:40 +000079 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040080 void *buffer;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040081 float toa;
dburgessb3a0ca42011-10-12 07:44:40 +000082 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040083};
dburgessb3a0ca42011-10-12 07:44:40 +000084
Thomas Tsou83e06892013-08-20 16:10:01 -040085/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040086 * Gaussian and empty modulation pulses. Like the correlation sequences,
87 * store the runtime (Gaussian) buffer separately because of needed alignment
88 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -040089 */
90struct PulseSequence {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080091 PulseSequence() : c0(NULL), c1(NULL), empty(NULL),
92 c0_buffer(NULL), c1_buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -040093 {
94 }
95
96 ~PulseSequence()
97 {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080098 delete c0;
99 delete c1;
Thomas Tsou83e06892013-08-20 16:10:01 -0400100 delete empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800101 free(c0_buffer);
102 free(c1_buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -0400103 }
104
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800105 signalVector *c0;
106 signalVector *c1;
Thomas Tsou83e06892013-08-20 16:10:01 -0400107 signalVector *empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800108 void *c0_buffer;
109 void *c1_buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -0400110};
111
dburgessb3a0ca42011-10-12 07:44:40 +0000112CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
113CorrelationSequence *gRACHSequence = NULL;
Thomas Tsou83e06892013-08-20 16:10:01 -0400114PulseSequence *GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400115PulseSequence *GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000116
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400117void sigProcLibDestroy()
118{
dburgessb3a0ca42011-10-12 07:44:40 +0000119 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400120 delete gMidambles[i];
121 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000122 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400123
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600124 for (int i = 0; i < DELAYFILTS; i++) {
125 delete delayFilters[i];
126 delayFilters[i] = NULL;
127 }
128
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400129 delete GMSKRotationN;
130 delete GMSKReverseRotationN;
131 delete GMSKRotation1;
132 delete GMSKReverseRotation1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400133 delete gRACHSequence;
134 delete GSMPulse;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400135 delete GSMPulse1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400136
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400137 GMSKRotationN = NULL;
138 GMSKRotation1 = NULL;
139 GMSKReverseRotationN = NULL;
140 GMSKReverseRotation1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400141 gRACHSequence = NULL;
142 GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400143 GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000144}
145
dburgessb3a0ca42011-10-12 07:44:40 +0000146// dB relative to 1.0.
147// if > 1.0, then return 0 dB
148float dB(float x) {
149
150 float arg = 1.0F;
151 float dB = 0.0F;
152
153 if (x >= 1.0F) return 0.0F;
154 if (x <= 0.0F) return -200.0F;
155
156 float prevArg = arg;
157 float prevdB = dB;
158 float stepSize = 16.0F;
159 float dBstepSize = 12.0F;
160 while (stepSize > 1.0F) {
161 do {
162 prevArg = arg;
163 prevdB = dB;
164 arg /= stepSize;
165 dB -= dBstepSize;
166 } while (arg > x);
167 arg = prevArg;
168 dB = prevdB;
169 stepSize *= 0.5F;
170 dBstepSize -= 3.0F;
171 }
172 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
173
174}
175
176// 10^(-dB/10), inverse of dB func.
177float dBinv(float x) {
178
179 float arg = 1.0F;
180 float dB = 0.0F;
181
182 if (x >= 0.0F) return 1.0F;
183 if (x <= -200.0F) return 0.0F;
184
185 float prevArg = arg;
186 float prevdB = dB;
187 float stepSize = 16.0F;
188 float dBstepSize = 12.0F;
189 while (stepSize > 1.0F) {
190 do {
191 prevArg = arg;
192 prevdB = dB;
193 arg /= stepSize;
194 dB -= dBstepSize;
195 } while (dB > x);
196 arg = prevArg;
197 dB = prevdB;
198 stepSize *= 0.5F;
199 dBstepSize -= 3.0F;
200 }
201
202 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
203
204}
205
206float vectorNorm2(const signalVector &x)
207{
208 signalVector::const_iterator xPtr = x.begin();
209 float Energy = 0.0;
210 for (;xPtr != x.end();xPtr++) {
211 Energy += xPtr->norm2();
212 }
213 return Energy;
214}
215
216
217float vectorPower(const signalVector &x)
218{
219 return vectorNorm2(x)/x.size();
220}
221
222/** compute cosine via lookup table */
223float cosLookup(const float x)
224{
225 float arg = x*M_1_2PI_F;
226 while (arg > 1.0F) arg -= 1.0F;
227 while (arg < 0.0F) arg += 1.0F;
228
229 const float argT = arg*((float)TABLESIZE);
230 const int argI = (int)argT;
231 const float delta = argT-argI;
232 const float iDelta = 1.0F-delta;
233 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
234}
235
236/** compute sine via lookup table */
237float sinLookup(const float x)
238{
239 float arg = x*M_1_2PI_F;
240 while (arg > 1.0F) arg -= 1.0F;
241 while (arg < 0.0F) arg += 1.0F;
242
243 const float argT = arg*((float)TABLESIZE);
244 const int argI = (int)argT;
245 const float delta = argT-argI;
246 const float iDelta = 1.0F-delta;
247 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
248}
249
250
251/** compute e^(-jx) via lookup table. */
252complex expjLookup(float x)
253{
254 float arg = x*M_1_2PI_F;
255 while (arg > 1.0F) arg -= 1.0F;
256 while (arg < 0.0F) arg += 1.0F;
257
258 const float argT = arg*((float)TABLESIZE);
259 const int argI = (int)argT;
260 const float delta = argT-argI;
261 const float iDelta = 1.0F-delta;
262 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
263 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
264}
265
266/** Library setup functions */
267void initTrigTables() {
268 for (int i = 0; i < TABLESIZE+1; i++) {
269 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
270 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
271 }
272}
273
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400274void initGMSKRotationTables(int sps)
275{
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400276 GMSKRotationN = new signalVector(157 * sps);
277 GMSKReverseRotationN = new signalVector(157 * sps);
278 signalVector::iterator rotPtr = GMSKRotationN->begin();
279 signalVector::iterator revPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000280 float phase = 0.0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400281 while (rotPtr != GMSKRotationN->end()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000282 *rotPtr++ = expjLookup(phase);
283 *revPtr++ = expjLookup(-phase);
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400284 phase += M_PI_F / 2.0F / (float) sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000285 }
dburgessb3a0ca42011-10-12 07:44:40 +0000286
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400287 GMSKRotation1 = new signalVector(157);
288 GMSKReverseRotation1 = new signalVector(157);
289 rotPtr = GMSKRotation1->begin();
290 revPtr = GMSKReverseRotation1->begin();
291 phase = 0.0;
292 while (rotPtr != GMSKRotation1->end()) {
293 *rotPtr++ = expjLookup(phase);
294 *revPtr++ = expjLookup(-phase);
295 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400296 }
dburgessb3a0ca42011-10-12 07:44:40 +0000297}
298
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400299static void GMSKRotate(signalVector &x, int sps)
300{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500301#if HAVE_NEON
302 size_t len;
303 signalVector *a, *b, *out;
304
305 a = &x;
306 out = &x;
307 len = out->size();
308
309 if (len == 157)
310 len--;
311
312 if (sps == 1)
313 b = GMSKRotation1;
314 else
315 b = GMSKRotationN;
316
317 mul_complex((float *) out->begin(),
318 (float *) a->begin(),
319 (float *) b->begin(), len);
320#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400321 signalVector::iterator rotPtr, xPtr = x.begin();
322
323 if (sps == 1)
324 rotPtr = GMSKRotation1->begin();
325 else
326 rotPtr = GMSKRotationN->begin();
327
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500328 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000329 while (xPtr < x.end()) {
330 *xPtr = *rotPtr++ * (xPtr->real());
331 xPtr++;
332 }
333 }
334 else {
335 while (xPtr < x.end()) {
336 *xPtr = *rotPtr++ * (*xPtr);
337 xPtr++;
338 }
339 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500340#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000341}
342
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400343static void GMSKReverseRotate(signalVector &x, int sps)
344{
345 signalVector::iterator rotPtr, xPtr= x.begin();
346
347 if (sps == 1)
348 rotPtr = GMSKReverseRotation1->begin();
349 else
350 rotPtr = GMSKReverseRotationN->begin();
351
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500352 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000353 while (xPtr < x.end()) {
354 *xPtr = *rotPtr++ * (xPtr->real());
355 xPtr++;
356 }
357 }
358 else {
359 while (xPtr < x.end()) {
360 *xPtr = *rotPtr++ * (*xPtr);
361 xPtr++;
362 }
363 }
364}
365
Thomas Tsou3eaae802013-08-20 19:31:14 -0400366signalVector *convolve(const signalVector *x,
367 const signalVector *h,
368 signalVector *y,
369 ConvType spanType, int start,
370 unsigned len, unsigned step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000371{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400372 int rc, head = 0, tail = 0;
373 bool alloc = false, append = false;
374 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000375
Thomas Tsou3eaae802013-08-20 19:31:14 -0400376 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000377 return NULL;
378
Thomas Tsou3eaae802013-08-20 19:31:14 -0400379 switch (spanType) {
380 case START_ONLY:
381 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500382 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400383 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500384
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500385 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500386 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000387 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400388 case NO_DELAY:
389 start = h->size() / 2;
390 head = start;
391 tail = start;
392 len = x->size();
393 append = true;
394 break;
395 case CUSTOM:
396 if (start < h->size() - 1) {
397 head = h->size() - start;
398 append = true;
399 }
400 if (start + len > x->size()) {
401 tail = start + len - x->size();
402 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000403 }
404 break;
405 default:
406 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000407 }
dburgessb3a0ca42011-10-12 07:44:40 +0000408
Thomas Tsou3eaae802013-08-20 19:31:14 -0400409 /*
410 * Error if the output vector is too small. Create the output vector
411 * if the pointer is NULL.
412 */
413 if (y && (len > y->size()))
414 return NULL;
415 if (!y) {
416 y = new signalVector(len);
417 alloc = true;
418 }
419
420 /* Prepend or post-pend the input vector if the parameters require it */
421 if (append)
422 _x = new signalVector(*x, head, tail);
423 else
424 _x = x;
425
426 /*
427 * Four convovle types:
428 * 1. Complex-Real (aligned)
429 * 2. Complex-Complex (aligned)
430 * 3. Complex-Real (!aligned)
431 * 4. Complex-Complex (!aligned)
432 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500433 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400434 rc = convolve_real((float *) _x->begin(), _x->size(),
435 (float *) h->begin(), h->size(),
436 (float *) y->begin(), y->size(),
437 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500438 } else if (!h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400439 rc = convolve_complex((float *) _x->begin(), _x->size(),
440 (float *) h->begin(), h->size(),
441 (float *) y->begin(), y->size(),
442 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500443 } else if (h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400444 rc = base_convolve_real((float *) _x->begin(), _x->size(),
445 (float *) h->begin(), h->size(),
446 (float *) y->begin(), y->size(),
447 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500448 } else if (!h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400449 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
450 (float *) h->begin(), h->size(),
451 (float *) y->begin(), y->size(),
452 start, len, step, offset);
453 } else {
454 rc = -1;
455 }
456
457 if (append)
458 delete _x;
459
460 if (rc < 0) {
461 if (alloc)
462 delete y;
463 return NULL;
464 }
465
466 return y;
467}
dburgessb3a0ca42011-10-12 07:44:40 +0000468
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400469static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800470{
471 int len;
472
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400473 if (!pulse)
474 return false;
475
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800476 switch (sps) {
477 case 4:
478 len = 8;
479 break;
480 default:
481 return false;
482 }
483
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400484 pulse->c1_buffer = convolve_h_alloc(len);
485 pulse->c1 = new signalVector((complex *)
486 pulse->c1_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500487 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800488
489 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400490 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800491
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400492 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800493
494 switch (sps) {
495 case 4:
496 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400497 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800498 *xP++ = 8.16373112e-03;
499 *xP++ = 2.84385729e-02;
500 *xP++ = 5.64158904e-02;
501 *xP++ = 7.05463553e-02;
502 *xP++ = 5.64158904e-02;
503 *xP++ = 2.84385729e-02;
504 *xP++ = 8.16373112e-03;
505 }
506
507 return true;
508}
509
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400510static PulseSequence *generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000511{
Thomas Tsou83e06892013-08-20 16:10:01 -0400512 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800513 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400514 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400515
516 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400517 pulse = new PulseSequence();
518 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500519 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400520 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400521
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400522 /*
523 * For 4 samples-per-symbol use a precomputed single pulse Laurent
524 * approximation. This should yields below 2 degrees of phase error at
525 * the modulator output. Use the existing pulse approximation for all
526 * other oversampling factors.
527 */
528 switch (sps) {
529 case 4:
530 len = 16;
531 break;
532 default:
533 len = sps * symbolLength;
534 if (len < 4)
535 len = 4;
536 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400537
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400538 pulse->c0_buffer = convolve_h_alloc(len);
539 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500540 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400541
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800542 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400543 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800544
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400545 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400546
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400547 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800548 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400549 *xP++ = 4.46348606e-03;
550 *xP++ = 2.84385729e-02;
551 *xP++ = 1.03184855e-01;
552 *xP++ = 2.56065552e-01;
553 *xP++ = 4.76375085e-01;
554 *xP++ = 7.05961177e-01;
555 *xP++ = 8.71291644e-01;
556 *xP++ = 9.29453645e-01;
557 *xP++ = 8.71291644e-01;
558 *xP++ = 7.05961177e-01;
559 *xP++ = 4.76375085e-01;
560 *xP++ = 2.56065552e-01;
561 *xP++ = 1.03184855e-01;
562 *xP++ = 2.84385729e-02;
563 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400564 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400565 } else {
566 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400567
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400568 /* GSM pulse approximation */
569 for (int i = 0; i < len; i++) {
570 arg = ((float) i - center) / (float) sps;
571 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
572 0.527 * arg * arg * arg * arg);
573 }
dburgessb3a0ca42011-10-12 07:44:40 +0000574
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400575 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
576 xP = pulse->c0->begin();
577 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800578 *xP++ /= avg;
579 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400580
581 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000582}
583
584signalVector* frequencyShift(signalVector *y,
585 signalVector *x,
586 float freq,
587 float startPhase,
588 float *finalPhase)
589{
590
591 if (!x) return NULL;
592
593 if (y==NULL) {
594 y = new signalVector(x->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500595 y->isReal(x->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000596 if (y==NULL) return NULL;
597 }
598
599 if (y->size() < x->size()) return NULL;
600
601 float phase = startPhase;
602 signalVector::iterator yP = y->begin();
603 signalVector::iterator xPEnd = x->end();
604 signalVector::iterator xP = x->begin();
605
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500606 if (x->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000607 while (xP < xPEnd) {
608 (*yP++) = expjLookup(phase)*( (xP++)->real() );
609 phase += freq;
610 }
611 }
612 else {
613 while (xP < xPEnd) {
614 (*yP++) = (*xP++)*expjLookup(phase);
615 phase += freq;
Thomas Tsou34bbef72013-11-13 22:58:15 -0500616 if (phase > 2 * M_PI)
617 phase -= 2 * M_PI;
618 else if (phase < -2 * M_PI)
619 phase += 2 * M_PI;
dburgessb3a0ca42011-10-12 07:44:40 +0000620 }
621 }
622
623
624 if (finalPhase) *finalPhase = phase;
625
626 return y;
627}
628
629signalVector* reverseConjugate(signalVector *b)
630{
631 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500632 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000633 signalVector::iterator bP = b->begin();
634 signalVector::iterator bPEnd = b->end();
635 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500636 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000637 while (bP < bPEnd) {
638 *tmpP-- = bP->conj();
639 bP++;
640 }
641 }
642 else {
643 while (bP < bPEnd) {
644 *tmpP-- = bP->real();
645 bP++;
646 }
647 }
648
649 return tmp;
650}
651
dburgessb3a0ca42011-10-12 07:44:40 +0000652/* soft output slicer */
653bool vectorSlicer(signalVector *x)
654{
655
656 signalVector::iterator xP = x->begin();
657 signalVector::iterator xPEnd = x->end();
658 while (xP < xPEnd) {
659 *xP = (complex) (0.5*(xP->real()+1.0F));
660 if (xP->real() > 1.0) *xP = 1.0;
661 if (xP->real() < 0.0) *xP = 0.0;
662 xP++;
663 }
664 return true;
665}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400666
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800667static signalVector *rotateBurst(const BitVector &wBurst,
668 int guardPeriodLength, int sps)
669{
670 int burst_len;
671 signalVector *pulse, rotated, *shaped;
672 signalVector::iterator itr;
673
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400674 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800675 burst_len = sps * (wBurst.size() + guardPeriodLength);
676 rotated = signalVector(burst_len);
677 itr = rotated.begin();
678
679 for (unsigned i = 0; i < wBurst.size(); i++) {
680 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
681 itr += sps;
682 }
683
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400684 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500685 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800686
687 /* Dummy filter operation */
688 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
689 if (!shaped)
690 return NULL;
691
692 return shaped;
693}
694
695static signalVector *modulateBurstLaurent(const BitVector &bits,
696 int guard_len, int sps)
697{
698 int burst_len;
699 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500700 signalVector *c0_pulse, *c1_pulse, *c0_burst;
701 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800702 signalVector::iterator c0_itr, c1_itr;
703
704 /*
705 * Apply before and after bits to reduce phase error at burst edges.
706 * Make sure there is enough room in the burst to accomodate all bits.
707 */
708 if (guard_len < 4)
709 guard_len = 4;
710
711 c0_pulse = GSMPulse->c0;
712 c1_pulse = GSMPulse->c1;
713
714 burst_len = sps * (bits.size() + guard_len);
715
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500716 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500717 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500718 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800719
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500720 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500721 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500722 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800723
724 /* Padded differential start bits */
725 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
726 c0_itr += sps;
727
728 /* Main burst bits */
729 for (unsigned i = 0; i < bits.size(); i++) {
730 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
731 c0_itr += sps;
732 }
733
734 /* Padded differential end bits */
735 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
736
737 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500738 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500739 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800740
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500741 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800742 c0_itr += sps * 2;
743 c1_itr += sps * 2;
744
745 /* Start magic */
746 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
747 *c1_itr = *c0_itr * Complex<float>(0, phase);
748 c0_itr += sps;
749 c1_itr += sps;
750
751 /* Generate C1 phase coefficients */
752 for (unsigned i = 2; i < bits.size(); i++) {
753 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
754 *c1_itr = *c0_itr * Complex<float>(0, phase);
755
756 c0_itr += sps;
757 c1_itr += sps;
758 }
759
760 /* End magic */
761 int i = bits.size();
762 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
763 *c1_itr = *c0_itr * Complex<float>(0, phase);
764
765 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500766 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
767 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800768
769 /* Sum shaped outputs into C0 */
770 c0_itr = c0_shaped->begin();
771 c1_itr = c1_shaped->begin();
772 for (unsigned i = 0; i < c0_shaped->size(); i++ )
773 *c0_itr++ += *c1_itr++;
774
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500775 delete c0_burst;
776 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800777 delete c1_shaped;
778
779 return c0_shaped;
780}
781
782static signalVector *modulateBurstBasic(const BitVector &bits,
783 int guard_len, int sps)
784{
785 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500786 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800787 signalVector::iterator burst_itr;
788
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400789 if (sps == 1)
790 pulse = GSMPulse1->c0;
791 else
792 pulse = GSMPulse->c0;
793
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800794 burst_len = sps * (bits.size() + guard_len);
795
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500796 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500797 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500798 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800799
800 /* Raw bits are not differentially encoded */
801 for (unsigned i = 0; i < bits.size(); i++) {
802 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
803 burst_itr += sps;
804 }
805
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500806 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500807 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800808
809 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500810 shaped = convolve(burst, pulse, NULL, START_ONLY);
811
812 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800813
814 return shaped;
815}
816
Thomas Tsou3eaae802013-08-20 19:31:14 -0400817/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400818signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
819 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000820{
Thomas Tsou83e06892013-08-20 16:10:01 -0400821 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800822 return rotateBurst(wBurst, guardPeriodLength, sps);
823 else if (sps == 4)
824 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400825 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800826 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000827}
828
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500829void generateSincTable()
830{
831 float x;
832
833 for (int i = 0; i < TABLESIZE; i++) {
834 x = (float) i / TABLESIZE * 8 * M_PI;
835 if (fabs(x) < 0.01) {
836 sincTable[i] = 1.0f;
837 continue;
838 }
839
840 sincTable[i] = sinf(x) / x;
841 }
842}
843
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800844float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000845{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500846 if (fabs(x) >= 8 * M_PI)
847 return 0.0;
848
849 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
850
851 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +0000852}
853
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600854/*
855 * Create fractional delay filterbank with Blackman-harris windowed
856 * sinc function generator. The number of filters generated is specified
857 * by the DELAYFILTS value.
858 */
859void generateDelayFilters()
860{
861 int h_len = 20;
862 complex *data;
863 signalVector *h;
864 signalVector::iterator itr;
865
866 float k, sum;
867 float a0 = 0.35875;
868 float a1 = 0.48829;
869 float a2 = 0.14128;
870 float a3 = 0.01168;
871
872 for (int i = 0; i < DELAYFILTS; i++) {
873 data = (complex *) convolve_h_alloc(h_len);
874 h = new signalVector(data, 0, h_len);
875 h->setAligned(true);
876 h->isReal(true);
877
878 sum = 0.0;
879 itr = h->end();
880 for (int n = 0; n < h_len; n++) {
881 k = (float) n;
882 *--itr = (complex) sinc(M_PI_F *
883 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
884 *itr *= a0 -
885 a1 * cos(2 * M_PI * n / (h_len - 1)) +
886 a2 * cos(4 * M_PI * n / (h_len - 1)) -
887 a3 * cos(6 * M_PI * n / (h_len - 1));
888
889 sum += itr->real();
890 }
891
892 itr = h->begin();
893 for (int n = 0; n < h_len; n++)
894 *itr++ /= sum;
895
896 delayFilters[i] = h;
897 }
898}
899
Thomas Tsou94edaae2013-11-09 22:19:19 -0500900signalVector *delayVector(signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000901{
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600902 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400903 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500904 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400905
Thomas Tsou2c282f52013-10-08 21:34:35 -0400906 whole = floor(delay);
907 frac = delay - whole;
908
909 /* Sinc interpolated fractional shift (if allowable) */
910 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600911 index = floorf(frac * (float) DELAYFILTS);
912 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -0400913
Thomas Tsou94edaae2013-11-09 22:19:19 -0500914 fshift = convolve(in, h, NULL, NO_DELAY);
915 if (!fshift)
916 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000917 }
918
Thomas Tsou94edaae2013-11-09 22:19:19 -0500919 if (!fshift)
920 shift = new signalVector(*in);
921 else
922 shift = fshift;
923
Thomas Tsou2c282f52013-10-08 21:34:35 -0400924 /* Integer sample shift */
925 if (whole < 0) {
926 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500927 signalVector::iterator wBurstItr = shift->begin();
928 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400929
Thomas Tsou94edaae2013-11-09 22:19:19 -0500930 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +0000931 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400932
Thomas Tsou94edaae2013-11-09 22:19:19 -0500933 while (wBurstItr < shift->end())
934 *wBurstItr++ = 0.0;
935 } else if (whole >= 0) {
936 signalVector::iterator wBurstItr = shift->end() - 1;
937 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
938
939 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000940 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500941
942 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000943 *wBurstItr-- = 0.0;
944 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400945
Thomas Tsou94edaae2013-11-09 22:19:19 -0500946 if (!out)
947 return shift;
948
949 out->clone(*shift);
950 delete shift;
951 return out;
dburgessb3a0ca42011-10-12 07:44:40 +0000952}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400953
dburgessb3a0ca42011-10-12 07:44:40 +0000954signalVector *gaussianNoise(int length,
955 float variance,
956 complex mean)
957{
958
959 signalVector *noise = new signalVector(length);
960 signalVector::iterator nPtr = noise->begin();
961 float stddev = sqrtf(variance);
962 while (nPtr < noise->end()) {
963 float u1 = (float) rand()/ (float) RAND_MAX;
964 while (u1==0.0)
965 u1 = (float) rand()/ (float) RAND_MAX;
966 float u2 = (float) rand()/ (float) RAND_MAX;
967 float arg = 2.0*M_PI*u2;
968 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
969 nPtr++;
970 }
971
972 return noise;
973}
974
975complex interpolatePoint(const signalVector &inSig,
976 float ix)
977{
978
979 int start = (int) (floor(ix) - 10);
980 if (start < 0) start = 0;
981 int end = (int) (floor(ix) + 11);
982 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
983
984 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500985 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000986 for (int i = start; i < end; i++)
987 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
988 }
989 else {
990 for (int i = start; i < end; i++)
991 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
992 }
993
994 return pVal;
995}
996
Thomas Tsou8181b012013-08-20 21:17:19 -0400997static complex fastPeakDetect(const signalVector &rxBurst, float *index)
998{
999 float val, max = 0.0f;
1000 complex amp;
1001 int _index = -1;
1002
1003 for (int i = 0; i < rxBurst.size(); i++) {
1004 val = rxBurst[i].norm2();
1005 if (val > max) {
1006 max = val;
1007 _index = i;
1008 amp = rxBurst[i];
1009 }
1010 }
1011
1012 if (index)
1013 *index = (float) _index;
1014
1015 return amp;
1016}
1017
dburgessb3a0ca42011-10-12 07:44:40 +00001018complex peakDetect(const signalVector &rxBurst,
1019 float *peakIndex,
1020 float *avgPwr)
1021{
1022
1023
1024 complex maxVal = 0.0;
1025 float maxIndex = -1;
1026 float sumPower = 0.0;
1027
1028 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1029 float samplePower = rxBurst[i].norm2();
1030 if (samplePower > maxVal.real()) {
1031 maxVal = samplePower;
1032 maxIndex = i;
1033 }
1034 sumPower += samplePower;
1035 }
1036
1037 // interpolate around the peak
1038 // to save computation, we'll use early-late balancing
1039 float earlyIndex = maxIndex-1;
1040 float lateIndex = maxIndex+1;
1041
1042 float incr = 0.5;
1043 while (incr > 1.0/1024.0) {
1044 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1045 complex lateP = interpolatePoint(rxBurst,lateIndex);
1046 if (earlyP < lateP)
1047 earlyIndex += incr;
1048 else if (earlyP > lateP)
1049 earlyIndex -= incr;
1050 else break;
1051 incr /= 2.0;
1052 lateIndex = earlyIndex + 2.0;
1053 }
1054
1055 maxIndex = earlyIndex + 1.0;
1056 maxVal = interpolatePoint(rxBurst,maxIndex);
1057
1058 if (peakIndex!=NULL)
1059 *peakIndex = maxIndex;
1060
1061 if (avgPwr!=NULL)
1062 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1063
1064 return maxVal;
1065
1066}
1067
1068void scaleVector(signalVector &x,
1069 complex scale)
1070{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001071#ifdef HAVE_NEON
1072 int len = x.size();
1073
1074 scale_complex((float *) x.begin(),
1075 (float *) x.begin(),
1076 (float *) &scale, len);
1077#else
dburgessb3a0ca42011-10-12 07:44:40 +00001078 signalVector::iterator xP = x.begin();
1079 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001080 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001081 while (xP < xPEnd) {
1082 *xP = *xP * scale;
1083 xP++;
1084 }
1085 }
1086 else {
1087 while (xP < xPEnd) {
1088 *xP = xP->real() * scale;
1089 xP++;
1090 }
1091 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001092#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001093}
1094
1095/** in-place conjugation */
1096void conjugateVector(signalVector &x)
1097{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001098 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001099 signalVector::iterator xP = x.begin();
1100 signalVector::iterator xPEnd = x.end();
1101 while (xP < xPEnd) {
1102 *xP = xP->conj();
1103 xP++;
1104 }
1105}
1106
1107
1108// in-place addition!!
1109bool addVector(signalVector &x,
1110 signalVector &y)
1111{
1112 signalVector::iterator xP = x.begin();
1113 signalVector::iterator yP = y.begin();
1114 signalVector::iterator xPEnd = x.end();
1115 signalVector::iterator yPEnd = y.end();
1116 while ((xP < xPEnd) && (yP < yPEnd)) {
1117 *xP = *xP + *yP;
1118 xP++; yP++;
1119 }
1120 return true;
1121}
1122
1123// in-place multiplication!!
1124bool multVector(signalVector &x,
1125 signalVector &y)
1126{
1127 signalVector::iterator xP = x.begin();
1128 signalVector::iterator yP = y.begin();
1129 signalVector::iterator xPEnd = x.end();
1130 signalVector::iterator yPEnd = y.end();
1131 while ((xP < xPEnd) && (yP < yPEnd)) {
1132 *xP = (*xP) * (*yP);
1133 xP++; yP++;
1134 }
1135 return true;
1136}
1137
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001138bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001139{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001140 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001141 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001142 complex *data = NULL;
1143 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001144 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001145
Thomas Tsou3eaae802013-08-20 19:31:14 -04001146 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001147 return false;
1148
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001149 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001150
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001151 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1152 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1153 if (!midMidamble)
1154 return false;
1155
Thomas Tsou3eaae802013-08-20 19:31:14 -04001156 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001157 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1158 if (!midamble) {
1159 status = false;
1160 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001161 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001162
dburgessb3a0ca42011-10-12 07:44:40 +00001163 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1164 // the ideal TSC has an + 180 degree phase shift,
1165 // due to the pi/2 frequency shift, that
1166 // needs to be accounted for.
1167 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001168 scaleVector(*midMidamble, complex(-1.0, 0.0));
1169 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001170
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001171 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001172
Thomas Tsou3eaae802013-08-20 19:31:14 -04001173 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1174 data = (complex *) convolve_h_alloc(midMidamble->size());
1175 _midMidamble = new signalVector(data, 0, midMidamble->size());
1176 _midMidamble->setAligned(true);
1177 memcpy(_midMidamble->begin(), midMidamble->begin(),
1178 midMidamble->size() * sizeof(complex));
1179
1180 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001181 if (!autocorr) {
1182 status = false;
1183 goto release;
1184 }
dburgessb3a0ca42011-10-12 07:44:40 +00001185
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001186 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001187 gMidambles[tsc]->buffer = data;
1188 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001189 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1190
1191 /* For 1 sps only
1192 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1193 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1194 */
1195 if (sps == 1)
1196 gMidambles[tsc]->toa = toa - 13.5;
1197 else
1198 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001199
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001200release:
dburgessb3a0ca42011-10-12 07:44:40 +00001201 delete autocorr;
1202 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001203 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001204
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001205 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001206 delete _midMidamble;
1207 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001208 gMidambles[tsc] = NULL;
1209 }
1210
1211 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001212}
1213
Thomas Tsou83e06892013-08-20 16:10:01 -04001214bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001215{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001216 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001217 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001218 complex *data = NULL;
1219 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001220 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001221
1222 delete gRACHSequence;
1223
1224 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1225 if (!seq0)
1226 return false;
1227
1228 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1229 if (!seq1) {
1230 status = false;
1231 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001232 }
1233
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001234 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001235
Thomas Tsou3eaae802013-08-20 19:31:14 -04001236 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1237 data = (complex *) convolve_h_alloc(seq1->size());
1238 _seq1 = new signalVector(data, 0, seq1->size());
1239 _seq1->setAligned(true);
1240 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1241
1242 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1243 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001244 status = false;
1245 goto release;
1246 }
dburgessb3a0ca42011-10-12 07:44:40 +00001247
1248 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001249 gRACHSequence->sequence = _seq1;
1250 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001251 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1252
1253 /* For 1 sps only
1254 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1255 * 20.5 = (40 / 2 - 1) + 1.5
1256 */
1257 if (sps == 1)
1258 gRACHSequence->toa = toa - 20.5;
1259 else
1260 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001261
1262release:
dburgessb3a0ca42011-10-12 07:44:40 +00001263 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001264 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001265 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001266
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001267 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001268 delete _seq1;
1269 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001270 gRACHSequence = NULL;
1271 }
dburgessb3a0ca42011-10-12 07:44:40 +00001272
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001273 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001274}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001275
Thomas Tsou865bca42013-08-21 20:58:00 -04001276static float computePeakRatio(signalVector *corr,
1277 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001278{
Thomas Tsou865bca42013-08-21 20:58:00 -04001279 int num = 0;
1280 complex *peak;
1281 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001282
Thomas Tsou865bca42013-08-21 20:58:00 -04001283 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001284
Thomas Tsou865bca42013-08-21 20:58:00 -04001285 /* Check for bogus results */
1286 if ((toa < 0.0) || (toa > corr->size()))
1287 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001288
Thomas Tsou3eaae802013-08-20 19:31:14 -04001289 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001290 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001291 avg += (peak - i)->norm2();
1292 num++;
1293 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001294 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001295 avg += (peak + i)->norm2();
1296 num++;
1297 }
dburgessb3a0ca42011-10-12 07:44:40 +00001298 }
1299
Thomas Tsou3eaae802013-08-20 19:31:14 -04001300 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001301 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001302
Thomas Tsou3eaae802013-08-20 19:31:14 -04001303 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001304
Thomas Tsou865bca42013-08-21 20:58:00 -04001305 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001306}
1307
1308bool energyDetect(signalVector &rxBurst,
1309 unsigned windowLength,
1310 float detectThreshold,
1311 float *avgPwr)
1312{
1313
1314 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1315 float energy = 0.0;
1316 if (windowLength < 0) windowLength = 20;
1317 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1318 for (unsigned i = 0; i < windowLength; i++) {
1319 energy += windowItr->norm2();
1320 windowItr+=4;
1321 }
1322 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001323 return (energy/windowLength > detectThreshold*detectThreshold);
1324}
dburgessb3a0ca42011-10-12 07:44:40 +00001325
Thomas Tsou865bca42013-08-21 20:58:00 -04001326/*
1327 * Detect a burst based on correlation and peak-to-average ratio
1328 *
1329 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1330 * for initial gating. We do this because energy detection should be disabled.
1331 * For higher oversampling values, we assume the energy detector is in place
1332 * and we run full interpolating peak detection.
1333 */
1334static int detectBurst(signalVector &burst,
1335 signalVector &corr, CorrelationSequence *sync,
1336 float thresh, int sps, complex *amp, float *toa,
1337 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001338{
Thomas Tsou865bca42013-08-21 20:58:00 -04001339 /* Correlate */
1340 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001341 CUSTOM, start, len, sps, 0)) {
1342 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001343 }
1344
Thomas Tsou865bca42013-08-21 20:58:00 -04001345 /* Peak detection - place restrictions at correlation edges */
1346 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001347
Thomas Tsou865bca42013-08-21 20:58:00 -04001348 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1349 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001350
Thomas Tsou865bca42013-08-21 20:58:00 -04001351 /* Peak -to-average ratio */
1352 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1353 return 0;
1354
1355 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1356 *amp = peakDetect(corr, toa, NULL);
1357
1358 /* Normalize our channel gain */
1359 *amp = *amp / sync->gain;
1360
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001361 /* Compenate for residual rotation with dual Laurent pulse */
1362 if (sps == 4)
1363 *amp = *amp * complex(0.0, 1.0);
1364
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001365 /* Compensate for residuate time lag */
1366 *toa = *toa - sync->toa;
1367
Thomas Tsou865bca42013-08-21 20:58:00 -04001368 return 1;
1369}
1370
1371/*
1372 * RACH burst detection
1373 *
1374 * Correlation window parameters:
1375 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001376 * head: Search 4 symbols before target
1377 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001378 */
1379int detectRACHBurst(signalVector &rxBurst,
1380 float thresh,
1381 int sps,
1382 complex *amp,
1383 float *toa)
1384{
1385 int rc, start, target, head, tail, len;
1386 float _toa;
1387 complex _amp;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001388 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001389 CorrelationSequence *sync;
1390
1391 if ((sps != 1) && (sps != 4))
1392 return -1;
1393
1394 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001395 head = 4;
1396 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001397
1398 start = (target - head) * sps - 1;
1399 len = (head + tail) * sps;
1400 sync = gRACHSequence;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001401 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001402
Thomas Tsoub075dd22013-11-09 22:25:46 -05001403 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001404 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001405 delete corr;
1406
Thomas Tsou865bca42013-08-21 20:58:00 -04001407 if (rc < 0) {
1408 return -1;
1409 } else if (!rc) {
1410 if (amp)
1411 *amp = 0.0f;
1412 if (toa)
1413 *toa = 0.0f;
1414 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001415 }
1416
Thomas Tsou865bca42013-08-21 20:58:00 -04001417 /* Subtract forward search bits from delay */
1418 if (toa)
1419 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001420 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001421 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001422
Thomas Tsou865bca42013-08-21 20:58:00 -04001423 return 1;
1424}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001425
Thomas Tsou865bca42013-08-21 20:58:00 -04001426/*
1427 * Normal burst detection
1428 *
1429 * Correlation window parameters:
1430 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001431 * head: Search 4 symbols before target
1432 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001433 */
1434int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1435 int sps, complex *amp, float *toa, unsigned max_toa,
1436 bool chan_req, signalVector **chan, float *chan_offset)
1437{
1438 int rc, start, target, head, tail, len;
1439 complex _amp;
1440 float _toa;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001441 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001442 CorrelationSequence *sync;
1443
1444 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1445 return -1;
1446
1447 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001448 head = 4;
1449 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001450
1451 start = (target - head) * sps - 1;
1452 len = (head + tail) * sps;
1453 sync = gMidambles[tsc];
Thomas Tsoub075dd22013-11-09 22:25:46 -05001454 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001455
Thomas Tsoub075dd22013-11-09 22:25:46 -05001456 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001457 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001458 delete corr;
1459
Thomas Tsou865bca42013-08-21 20:58:00 -04001460 if (rc < 0) {
1461 return -1;
1462 } else if (!rc) {
1463 if (amp)
1464 *amp = 0.0f;
1465 if (toa)
1466 *toa = 0.0f;
1467 return 0;
1468 }
1469
1470 /* Subtract forward search bits from delay */
1471 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001472 if (toa)
1473 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001474 if (amp)
1475 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001476
Thomas Tsou865bca42013-08-21 20:58:00 -04001477 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001478 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001479 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001480
1481 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001482 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001483 }
1484
Thomas Tsou3eaae802013-08-20 19:31:14 -04001485 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001486}
1487
Thomas Tsou94edaae2013-11-09 22:19:19 -05001488signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001489{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001490 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001491
Thomas Tsou94edaae2013-11-09 22:19:19 -05001492 if (factor <= 1)
1493 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001494
Thomas Tsou94edaae2013-11-09 22:19:19 -05001495 dec = new signalVector(wVector.size() / factor);
1496 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001497
Thomas Tsou94edaae2013-11-09 22:19:19 -05001498 signalVector::iterator itr = dec->begin();
1499 for (size_t i = 0; i < wVector.size(); i += factor)
1500 *itr++ = wVector[i];
1501
1502 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001503}
1504
Thomas Tsou83e06892013-08-20 16:10:01 -04001505SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05001506 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001507{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001508 signalVector *delay, *dec = NULL;
1509 SoftVector *bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001510
Thomas Tsou94edaae2013-11-09 22:19:19 -05001511 scaleVector(rxBurst, ((complex) 1.0) / channel);
1512 delay = delayVector(&rxBurst, NULL, -TOA);
dburgessb3a0ca42011-10-12 07:44:40 +00001513
Thomas Tsou94edaae2013-11-09 22:19:19 -05001514 /* Shift up by a quarter of a frequency */
1515 GMSKReverseRotate(*delay, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001516
Thomas Tsou94edaae2013-11-09 22:19:19 -05001517 /* Decimate and slice */
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001518 if (sps > 1) {
Thomas Tsou94edaae2013-11-09 22:19:19 -05001519 dec = decimateVector(*delay, sps);
1520 delete delay;
1521 delay = NULL;
1522 } else {
1523 dec = delay;
dburgessb3a0ca42011-10-12 07:44:40 +00001524 }
1525
Thomas Tsou94edaae2013-11-09 22:19:19 -05001526 vectorSlicer(dec);
dburgessb3a0ca42011-10-12 07:44:40 +00001527
Thomas Tsou94edaae2013-11-09 22:19:19 -05001528 bits = new SoftVector(dec->size());
dburgessb3a0ca42011-10-12 07:44:40 +00001529
Thomas Tsou94edaae2013-11-09 22:19:19 -05001530 SoftVector::iterator bit_itr = bits->begin();
1531 signalVector::iterator burst_itr = dec->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001532
Thomas Tsou94edaae2013-11-09 22:19:19 -05001533 for (; burst_itr < dec->end(); burst_itr++)
1534 *bit_itr++ = burst_itr->real();
dburgessb3a0ca42011-10-12 07:44:40 +00001535
Thomas Tsou94edaae2013-11-09 22:19:19 -05001536 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001537
Thomas Tsou94edaae2013-11-09 22:19:19 -05001538 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001539}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001540
dburgessb3a0ca42011-10-12 07:44:40 +00001541// Assumes symbol-spaced sampling!!!
1542// Based upon paper by Al-Dhahir and Cioffi
1543bool designDFE(signalVector &channelResponse,
1544 float SNRestimate,
1545 int Nf,
1546 signalVector **feedForwardFilter,
1547 signalVector **feedbackFilter)
1548{
1549
1550 signalVector G0(Nf);
1551 signalVector G1(Nf);
1552 signalVector::iterator G0ptr = G0.begin();
1553 signalVector::iterator G1ptr = G1.begin();
1554 signalVector::iterator chanPtr = channelResponse.begin();
1555
1556 int nu = channelResponse.size()-1;
1557
1558 *G0ptr = 1.0/sqrtf(SNRestimate);
1559 for(int j = 0; j <= nu; j++) {
1560 *G1ptr = chanPtr->conj();
1561 G1ptr++; chanPtr++;
1562 }
1563
1564 signalVector *L[Nf];
1565 signalVector::iterator Lptr;
1566 float d;
1567 for(int i = 0; i < Nf; i++) {
1568 d = G0.begin()->norm2() + G1.begin()->norm2();
1569 L[i] = new signalVector(Nf+nu);
1570 Lptr = L[i]->begin()+i;
1571 G0ptr = G0.begin(); G1ptr = G1.begin();
1572 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1573 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1574 Lptr++;
1575 G0ptr++;
1576 G1ptr++;
1577 }
1578 complex k = (*G1.begin())/(*G0.begin());
1579
1580 if (i != Nf-1) {
1581 signalVector G0new = G1;
1582 scaleVector(G0new,k.conj());
1583 addVector(G0new,G0);
1584
1585 signalVector G1new = G0;
1586 scaleVector(G1new,k*(-1.0));
1587 addVector(G1new,G1);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001588 delayVector(&G1new, &G1new, -1.0);
dburgessb3a0ca42011-10-12 07:44:40 +00001589
1590 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1591 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1592 G0 = G0new;
1593 G1 = G1new;
1594 }
1595 }
1596
1597 *feedbackFilter = new signalVector(nu);
1598 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1599 scaleVector(**feedbackFilter,(complex) -1.0);
1600 conjugateVector(**feedbackFilter);
1601
1602 signalVector v(Nf);
1603 signalVector::iterator vStart = v.begin();
1604 signalVector::iterator vPtr;
1605 *(vStart+Nf-1) = (complex) 1.0;
1606 for(int k = Nf-2; k >= 0; k--) {
1607 Lptr = L[k]->begin()+k+1;
1608 vPtr = vStart + k+1;
1609 complex v_k = 0.0;
1610 for (int j = k+1; j < Nf; j++) {
1611 v_k -= (*vPtr)*(*Lptr);
1612 vPtr++; Lptr++;
1613 }
1614 *(vStart + k) = v_k;
1615 }
1616
1617 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001618 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001619 for (int i = 0; i < Nf; i++) {
1620 delete L[i];
1621 complex w_i = 0.0;
1622 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1623 vPtr = vStart+i;
1624 chanPtr = channelResponse.begin();
1625 for (int k = 0; k < endPt+1; k++) {
1626 w_i += (*vPtr)*(chanPtr->conj());
1627 vPtr++; chanPtr++;
1628 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001629 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001630 }
1631
1632
1633 return true;
1634
1635}
1636
1637// Assumes symbol-rate sampling!!!!
1638SoftVector *equalizeBurst(signalVector &rxBurst,
1639 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001640 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001641 signalVector &w, // feedforward filter
1642 signalVector &b) // feedback filter
1643{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001644 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001645
Thomas Tsou94edaae2013-11-09 22:19:19 -05001646 if (!delayVector(&rxBurst, &rxBurst, -TOA))
Thomas Tsou3eaae802013-08-20 19:31:14 -04001647 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001648
Thomas Tsou3eaae802013-08-20 19:31:14 -04001649 postForwardFull = convolve(&rxBurst, &w, NULL,
1650 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1651 if (!postForwardFull)
1652 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001653
1654 signalVector* postForward = new signalVector(rxBurst.size());
1655 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1656 delete postForwardFull;
1657
1658 signalVector::iterator dPtr = postForward->begin();
1659 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001660 signalVector::iterator rotPtr = GMSKRotationN->begin();
1661 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001662
1663 signalVector *DFEoutput = new signalVector(postForward->size());
1664 signalVector::iterator DFEItr = DFEoutput->begin();
1665
1666 // NOTE: can insert the midamble and/or use midamble to estimate BER
1667 for (; dPtr < postForward->end(); dPtr++) {
1668 dBackPtr = dPtr-1;
1669 signalVector::iterator bPtr = b.begin();
1670 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1671 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1672 bPtr++;
1673 dBackPtr--;
1674 }
1675 *dPtr = *dPtr * (*revRotPtr);
1676 *DFEItr = *dPtr;
1677 // make decision on symbol
1678 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1679 //*DFEItr = *dPtr;
1680 *dPtr = *dPtr * (*rotPtr);
1681 DFEItr++;
1682 rotPtr++;
1683 revRotPtr++;
1684 }
1685
1686 vectorSlicer(DFEoutput);
1687
1688 SoftVector *burstBits = new SoftVector(postForward->size());
1689 SoftVector::iterator burstItr = burstBits->begin();
1690 DFEItr = DFEoutput->begin();
1691 for (; DFEItr < DFEoutput->end(); DFEItr++)
1692 *burstItr++ = DFEItr->real();
1693
1694 delete postForward;
1695
1696 delete DFEoutput;
1697
1698 return burstBits;
1699}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001700
1701bool sigProcLibSetup(int sps)
1702{
1703 if ((sps != 1) && (sps != 4))
1704 return false;
1705
1706 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001707 generateSincTable();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001708 initGMSKRotationTables(sps);
1709
1710 GSMPulse1 = generateGSMPulse(1, 2);
1711 if (sps > 1)
1712 GSMPulse = generateGSMPulse(sps, 2);
1713
1714 if (!generateRACHSequence(1)) {
1715 sigProcLibDestroy();
1716 return false;
1717 }
1718
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001719 generateDelayFilters();
1720
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001721 return true;
1722}