blob: 54dd8fcdd8b89c4d66953c7217ca837322b3b376 [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,
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500369 ConvType spanType, size_t start,
370 size_t len, size_t step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000371{
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500372 int rc;
373 size_t head = 0, tail = 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400374 bool alloc = false, append = false;
375 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000376
Thomas Tsou3eaae802013-08-20 19:31:14 -0400377 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000378 return NULL;
379
Thomas Tsou3eaae802013-08-20 19:31:14 -0400380 switch (spanType) {
381 case START_ONLY:
382 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500383 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400384 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500385
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500386 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500387 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000388 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400389 case NO_DELAY:
390 start = h->size() / 2;
391 head = start;
392 tail = start;
393 len = x->size();
394 append = true;
395 break;
396 case CUSTOM:
397 if (start < h->size() - 1) {
398 head = h->size() - start;
399 append = true;
400 }
401 if (start + len > x->size()) {
402 tail = start + len - x->size();
403 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000404 }
405 break;
406 default:
407 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000408 }
dburgessb3a0ca42011-10-12 07:44:40 +0000409
Thomas Tsou3eaae802013-08-20 19:31:14 -0400410 /*
411 * Error if the output vector is too small. Create the output vector
412 * if the pointer is NULL.
413 */
414 if (y && (len > y->size()))
415 return NULL;
416 if (!y) {
417 y = new signalVector(len);
418 alloc = true;
419 }
420
421 /* Prepend or post-pend the input vector if the parameters require it */
422 if (append)
423 _x = new signalVector(*x, head, tail);
424 else
425 _x = x;
426
427 /*
428 * Four convovle types:
429 * 1. Complex-Real (aligned)
430 * 2. Complex-Complex (aligned)
431 * 3. Complex-Real (!aligned)
432 * 4. Complex-Complex (!aligned)
433 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500434 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400435 rc = convolve_real((float *) _x->begin(), _x->size(),
436 (float *) h->begin(), h->size(),
437 (float *) y->begin(), y->size(),
438 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500439 } else if (!h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400440 rc = convolve_complex((float *) _x->begin(), _x->size(),
441 (float *) h->begin(), h->size(),
442 (float *) y->begin(), y->size(),
443 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500444 } else if (h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400445 rc = base_convolve_real((float *) _x->begin(), _x->size(),
446 (float *) h->begin(), h->size(),
447 (float *) y->begin(), y->size(),
448 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500449 } else if (!h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400450 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
451 (float *) h->begin(), h->size(),
452 (float *) y->begin(), y->size(),
453 start, len, step, offset);
454 } else {
455 rc = -1;
456 }
457
458 if (append)
459 delete _x;
460
461 if (rc < 0) {
462 if (alloc)
463 delete y;
464 return NULL;
465 }
466
467 return y;
468}
dburgessb3a0ca42011-10-12 07:44:40 +0000469
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400470static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800471{
472 int len;
473
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400474 if (!pulse)
475 return false;
476
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800477 switch (sps) {
478 case 4:
479 len = 8;
480 break;
481 default:
482 return false;
483 }
484
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400485 pulse->c1_buffer = convolve_h_alloc(len);
486 pulse->c1 = new signalVector((complex *)
487 pulse->c1_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500488 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800489
490 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400491 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800492
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400493 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800494
495 switch (sps) {
496 case 4:
497 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400498 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800499 *xP++ = 8.16373112e-03;
500 *xP++ = 2.84385729e-02;
501 *xP++ = 5.64158904e-02;
502 *xP++ = 7.05463553e-02;
503 *xP++ = 5.64158904e-02;
504 *xP++ = 2.84385729e-02;
505 *xP++ = 8.16373112e-03;
506 }
507
508 return true;
509}
510
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400511static PulseSequence *generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000512{
Thomas Tsou83e06892013-08-20 16:10:01 -0400513 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800514 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400515 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400516
517 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400518 pulse = new PulseSequence();
519 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500520 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400521 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400522
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400523 /*
524 * For 4 samples-per-symbol use a precomputed single pulse Laurent
525 * approximation. This should yields below 2 degrees of phase error at
526 * the modulator output. Use the existing pulse approximation for all
527 * other oversampling factors.
528 */
529 switch (sps) {
530 case 4:
531 len = 16;
532 break;
533 default:
534 len = sps * symbolLength;
535 if (len < 4)
536 len = 4;
537 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400538
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400539 pulse->c0_buffer = convolve_h_alloc(len);
540 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500541 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400542
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800543 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400544 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800545
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400546 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400547
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400548 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800549 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400550 *xP++ = 4.46348606e-03;
551 *xP++ = 2.84385729e-02;
552 *xP++ = 1.03184855e-01;
553 *xP++ = 2.56065552e-01;
554 *xP++ = 4.76375085e-01;
555 *xP++ = 7.05961177e-01;
556 *xP++ = 8.71291644e-01;
557 *xP++ = 9.29453645e-01;
558 *xP++ = 8.71291644e-01;
559 *xP++ = 7.05961177e-01;
560 *xP++ = 4.76375085e-01;
561 *xP++ = 2.56065552e-01;
562 *xP++ = 1.03184855e-01;
563 *xP++ = 2.84385729e-02;
564 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400565 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400566 } else {
567 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400568
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400569 /* GSM pulse approximation */
570 for (int i = 0; i < len; i++) {
571 arg = ((float) i - center) / (float) sps;
572 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
573 0.527 * arg * arg * arg * arg);
574 }
dburgessb3a0ca42011-10-12 07:44:40 +0000575
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400576 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
577 xP = pulse->c0->begin();
578 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800579 *xP++ /= avg;
580 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400581
582 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000583}
584
585signalVector* frequencyShift(signalVector *y,
586 signalVector *x,
587 float freq,
588 float startPhase,
589 float *finalPhase)
590{
591
592 if (!x) return NULL;
593
594 if (y==NULL) {
595 y = new signalVector(x->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500596 y->isReal(x->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000597 if (y==NULL) return NULL;
598 }
599
600 if (y->size() < x->size()) return NULL;
601
602 float phase = startPhase;
603 signalVector::iterator yP = y->begin();
604 signalVector::iterator xPEnd = x->end();
605 signalVector::iterator xP = x->begin();
606
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500607 if (x->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000608 while (xP < xPEnd) {
609 (*yP++) = expjLookup(phase)*( (xP++)->real() );
610 phase += freq;
611 }
612 }
613 else {
614 while (xP < xPEnd) {
615 (*yP++) = (*xP++)*expjLookup(phase);
616 phase += freq;
Thomas Tsou34bbef72013-11-13 22:58:15 -0500617 if (phase > 2 * M_PI)
618 phase -= 2 * M_PI;
619 else if (phase < -2 * M_PI)
620 phase += 2 * M_PI;
dburgessb3a0ca42011-10-12 07:44:40 +0000621 }
622 }
623
624
625 if (finalPhase) *finalPhase = phase;
626
627 return y;
628}
629
630signalVector* reverseConjugate(signalVector *b)
631{
632 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500633 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000634 signalVector::iterator bP = b->begin();
635 signalVector::iterator bPEnd = b->end();
636 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500637 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000638 while (bP < bPEnd) {
639 *tmpP-- = bP->conj();
640 bP++;
641 }
642 }
643 else {
644 while (bP < bPEnd) {
645 *tmpP-- = bP->real();
646 bP++;
647 }
648 }
649
650 return tmp;
651}
652
dburgessb3a0ca42011-10-12 07:44:40 +0000653/* soft output slicer */
654bool vectorSlicer(signalVector *x)
655{
656
657 signalVector::iterator xP = x->begin();
658 signalVector::iterator xPEnd = x->end();
659 while (xP < xPEnd) {
660 *xP = (complex) (0.5*(xP->real()+1.0F));
661 if (xP->real() > 1.0) *xP = 1.0;
662 if (xP->real() < 0.0) *xP = 0.0;
663 xP++;
664 }
665 return true;
666}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400667
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800668static signalVector *rotateBurst(const BitVector &wBurst,
669 int guardPeriodLength, int sps)
670{
671 int burst_len;
672 signalVector *pulse, rotated, *shaped;
673 signalVector::iterator itr;
674
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400675 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800676 burst_len = sps * (wBurst.size() + guardPeriodLength);
677 rotated = signalVector(burst_len);
678 itr = rotated.begin();
679
680 for (unsigned i = 0; i < wBurst.size(); i++) {
681 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
682 itr += sps;
683 }
684
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400685 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500686 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800687
688 /* Dummy filter operation */
689 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
690 if (!shaped)
691 return NULL;
692
693 return shaped;
694}
695
696static signalVector *modulateBurstLaurent(const BitVector &bits,
697 int guard_len, int sps)
698{
699 int burst_len;
700 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500701 signalVector *c0_pulse, *c1_pulse, *c0_burst;
702 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800703 signalVector::iterator c0_itr, c1_itr;
704
705 /*
706 * Apply before and after bits to reduce phase error at burst edges.
707 * Make sure there is enough room in the burst to accomodate all bits.
708 */
709 if (guard_len < 4)
710 guard_len = 4;
711
712 c0_pulse = GSMPulse->c0;
713 c1_pulse = GSMPulse->c1;
714
715 burst_len = sps * (bits.size() + guard_len);
716
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500717 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500718 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500719 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800720
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500721 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500722 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500723 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800724
725 /* Padded differential start bits */
726 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
727 c0_itr += sps;
728
729 /* Main burst bits */
730 for (unsigned i = 0; i < bits.size(); i++) {
731 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
732 c0_itr += sps;
733 }
734
735 /* Padded differential end bits */
736 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
737
738 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500739 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500740 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800741
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500742 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800743 c0_itr += sps * 2;
744 c1_itr += sps * 2;
745
746 /* Start magic */
747 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
748 *c1_itr = *c0_itr * Complex<float>(0, phase);
749 c0_itr += sps;
750 c1_itr += sps;
751
752 /* Generate C1 phase coefficients */
753 for (unsigned i = 2; i < bits.size(); i++) {
754 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
755 *c1_itr = *c0_itr * Complex<float>(0, phase);
756
757 c0_itr += sps;
758 c1_itr += sps;
759 }
760
761 /* End magic */
762 int i = bits.size();
763 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
764 *c1_itr = *c0_itr * Complex<float>(0, phase);
765
766 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500767 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
768 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800769
770 /* Sum shaped outputs into C0 */
771 c0_itr = c0_shaped->begin();
772 c1_itr = c1_shaped->begin();
773 for (unsigned i = 0; i < c0_shaped->size(); i++ )
774 *c0_itr++ += *c1_itr++;
775
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500776 delete c0_burst;
777 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800778 delete c1_shaped;
779
780 return c0_shaped;
781}
782
783static signalVector *modulateBurstBasic(const BitVector &bits,
784 int guard_len, int sps)
785{
786 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500787 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800788 signalVector::iterator burst_itr;
789
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400790 if (sps == 1)
791 pulse = GSMPulse1->c0;
792 else
793 pulse = GSMPulse->c0;
794
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800795 burst_len = sps * (bits.size() + guard_len);
796
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500797 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500798 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500799 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800800
801 /* Raw bits are not differentially encoded */
802 for (unsigned i = 0; i < bits.size(); i++) {
803 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
804 burst_itr += sps;
805 }
806
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500807 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500808 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800809
810 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500811 shaped = convolve(burst, pulse, NULL, START_ONLY);
812
813 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800814
815 return shaped;
816}
817
Thomas Tsou3eaae802013-08-20 19:31:14 -0400818/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400819signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
820 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000821{
Thomas Tsou83e06892013-08-20 16:10:01 -0400822 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800823 return rotateBurst(wBurst, guardPeriodLength, sps);
824 else if (sps == 4)
825 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400826 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800827 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000828}
829
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500830void generateSincTable()
831{
832 float x;
833
834 for (int i = 0; i < TABLESIZE; i++) {
835 x = (float) i / TABLESIZE * 8 * M_PI;
836 if (fabs(x) < 0.01) {
837 sincTable[i] = 1.0f;
838 continue;
839 }
840
841 sincTable[i] = sinf(x) / x;
842 }
843}
844
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800845float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000846{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500847 if (fabs(x) >= 8 * M_PI)
848 return 0.0;
849
850 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
851
852 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +0000853}
854
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600855/*
856 * Create fractional delay filterbank with Blackman-harris windowed
857 * sinc function generator. The number of filters generated is specified
858 * by the DELAYFILTS value.
859 */
860void generateDelayFilters()
861{
862 int h_len = 20;
863 complex *data;
864 signalVector *h;
865 signalVector::iterator itr;
866
867 float k, sum;
868 float a0 = 0.35875;
869 float a1 = 0.48829;
870 float a2 = 0.14128;
871 float a3 = 0.01168;
872
873 for (int i = 0; i < DELAYFILTS; i++) {
874 data = (complex *) convolve_h_alloc(h_len);
875 h = new signalVector(data, 0, h_len);
876 h->setAligned(true);
877 h->isReal(true);
878
879 sum = 0.0;
880 itr = h->end();
881 for (int n = 0; n < h_len; n++) {
882 k = (float) n;
883 *--itr = (complex) sinc(M_PI_F *
884 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
885 *itr *= a0 -
886 a1 * cos(2 * M_PI * n / (h_len - 1)) +
887 a2 * cos(4 * M_PI * n / (h_len - 1)) -
888 a3 * cos(6 * M_PI * n / (h_len - 1));
889
890 sum += itr->real();
891 }
892
893 itr = h->begin();
894 for (int n = 0; n < h_len; n++)
895 *itr++ /= sum;
896
897 delayFilters[i] = h;
898 }
899}
900
Thomas Tsou94edaae2013-11-09 22:19:19 -0500901signalVector *delayVector(signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000902{
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600903 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400904 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500905 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400906
Thomas Tsou2c282f52013-10-08 21:34:35 -0400907 whole = floor(delay);
908 frac = delay - whole;
909
910 /* Sinc interpolated fractional shift (if allowable) */
911 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600912 index = floorf(frac * (float) DELAYFILTS);
913 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -0400914
Thomas Tsou94edaae2013-11-09 22:19:19 -0500915 fshift = convolve(in, h, NULL, NO_DELAY);
916 if (!fshift)
917 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000918 }
919
Thomas Tsou94edaae2013-11-09 22:19:19 -0500920 if (!fshift)
921 shift = new signalVector(*in);
922 else
923 shift = fshift;
924
Thomas Tsou2c282f52013-10-08 21:34:35 -0400925 /* Integer sample shift */
926 if (whole < 0) {
927 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500928 signalVector::iterator wBurstItr = shift->begin();
929 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400930
Thomas Tsou94edaae2013-11-09 22:19:19 -0500931 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +0000932 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400933
Thomas Tsou94edaae2013-11-09 22:19:19 -0500934 while (wBurstItr < shift->end())
935 *wBurstItr++ = 0.0;
936 } else if (whole >= 0) {
937 signalVector::iterator wBurstItr = shift->end() - 1;
938 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
939
940 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000941 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500942
943 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000944 *wBurstItr-- = 0.0;
945 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400946
Thomas Tsou94edaae2013-11-09 22:19:19 -0500947 if (!out)
948 return shift;
949
950 out->clone(*shift);
951 delete shift;
952 return out;
dburgessb3a0ca42011-10-12 07:44:40 +0000953}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400954
dburgessb3a0ca42011-10-12 07:44:40 +0000955signalVector *gaussianNoise(int length,
956 float variance,
957 complex mean)
958{
959
960 signalVector *noise = new signalVector(length);
961 signalVector::iterator nPtr = noise->begin();
962 float stddev = sqrtf(variance);
963 while (nPtr < noise->end()) {
964 float u1 = (float) rand()/ (float) RAND_MAX;
965 while (u1==0.0)
966 u1 = (float) rand()/ (float) RAND_MAX;
967 float u2 = (float) rand()/ (float) RAND_MAX;
968 float arg = 2.0*M_PI*u2;
969 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
970 nPtr++;
971 }
972
973 return noise;
974}
975
976complex interpolatePoint(const signalVector &inSig,
977 float ix)
978{
979
980 int start = (int) (floor(ix) - 10);
981 if (start < 0) start = 0;
982 int end = (int) (floor(ix) + 11);
983 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
984
985 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500986 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000987 for (int i = start; i < end; i++)
988 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
989 }
990 else {
991 for (int i = start; i < end; i++)
992 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
993 }
994
995 return pVal;
996}
997
Thomas Tsou8181b012013-08-20 21:17:19 -0400998static complex fastPeakDetect(const signalVector &rxBurst, float *index)
999{
1000 float val, max = 0.0f;
1001 complex amp;
1002 int _index = -1;
1003
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001004 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001005 val = rxBurst[i].norm2();
1006 if (val > max) {
1007 max = val;
1008 _index = i;
1009 amp = rxBurst[i];
1010 }
1011 }
1012
1013 if (index)
1014 *index = (float) _index;
1015
1016 return amp;
1017}
1018
dburgessb3a0ca42011-10-12 07:44:40 +00001019complex peakDetect(const signalVector &rxBurst,
1020 float *peakIndex,
1021 float *avgPwr)
1022{
1023
1024
1025 complex maxVal = 0.0;
1026 float maxIndex = -1;
1027 float sumPower = 0.0;
1028
1029 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1030 float samplePower = rxBurst[i].norm2();
1031 if (samplePower > maxVal.real()) {
1032 maxVal = samplePower;
1033 maxIndex = i;
1034 }
1035 sumPower += samplePower;
1036 }
1037
1038 // interpolate around the peak
1039 // to save computation, we'll use early-late balancing
1040 float earlyIndex = maxIndex-1;
1041 float lateIndex = maxIndex+1;
1042
1043 float incr = 0.5;
1044 while (incr > 1.0/1024.0) {
1045 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1046 complex lateP = interpolatePoint(rxBurst,lateIndex);
1047 if (earlyP < lateP)
1048 earlyIndex += incr;
1049 else if (earlyP > lateP)
1050 earlyIndex -= incr;
1051 else break;
1052 incr /= 2.0;
1053 lateIndex = earlyIndex + 2.0;
1054 }
1055
1056 maxIndex = earlyIndex + 1.0;
1057 maxVal = interpolatePoint(rxBurst,maxIndex);
1058
1059 if (peakIndex!=NULL)
1060 *peakIndex = maxIndex;
1061
1062 if (avgPwr!=NULL)
1063 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1064
1065 return maxVal;
1066
1067}
1068
1069void scaleVector(signalVector &x,
1070 complex scale)
1071{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001072#ifdef HAVE_NEON
1073 int len = x.size();
1074
1075 scale_complex((float *) x.begin(),
1076 (float *) x.begin(),
1077 (float *) &scale, len);
1078#else
dburgessb3a0ca42011-10-12 07:44:40 +00001079 signalVector::iterator xP = x.begin();
1080 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001081 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001082 while (xP < xPEnd) {
1083 *xP = *xP * scale;
1084 xP++;
1085 }
1086 }
1087 else {
1088 while (xP < xPEnd) {
1089 *xP = xP->real() * scale;
1090 xP++;
1091 }
1092 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001093#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001094}
1095
1096/** in-place conjugation */
1097void conjugateVector(signalVector &x)
1098{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001099 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001100 signalVector::iterator xP = x.begin();
1101 signalVector::iterator xPEnd = x.end();
1102 while (xP < xPEnd) {
1103 *xP = xP->conj();
1104 xP++;
1105 }
1106}
1107
1108
1109// in-place addition!!
1110bool addVector(signalVector &x,
1111 signalVector &y)
1112{
1113 signalVector::iterator xP = x.begin();
1114 signalVector::iterator yP = y.begin();
1115 signalVector::iterator xPEnd = x.end();
1116 signalVector::iterator yPEnd = y.end();
1117 while ((xP < xPEnd) && (yP < yPEnd)) {
1118 *xP = *xP + *yP;
1119 xP++; yP++;
1120 }
1121 return true;
1122}
1123
1124// in-place multiplication!!
1125bool multVector(signalVector &x,
1126 signalVector &y)
1127{
1128 signalVector::iterator xP = x.begin();
1129 signalVector::iterator yP = y.begin();
1130 signalVector::iterator xPEnd = x.end();
1131 signalVector::iterator yPEnd = y.end();
1132 while ((xP < xPEnd) && (yP < yPEnd)) {
1133 *xP = (*xP) * (*yP);
1134 xP++; yP++;
1135 }
1136 return true;
1137}
1138
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001139bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001140{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001141 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001142 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001143 complex *data = NULL;
1144 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001145 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001146
Thomas Tsou3eaae802013-08-20 19:31:14 -04001147 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001148 return false;
1149
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001150 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001151
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001152 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1153 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1154 if (!midMidamble)
1155 return false;
1156
Thomas Tsou3eaae802013-08-20 19:31:14 -04001157 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001158 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1159 if (!midamble) {
1160 status = false;
1161 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001162 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001163
dburgessb3a0ca42011-10-12 07:44:40 +00001164 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1165 // the ideal TSC has an + 180 degree phase shift,
1166 // due to the pi/2 frequency shift, that
1167 // needs to be accounted for.
1168 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001169 scaleVector(*midMidamble, complex(-1.0, 0.0));
1170 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001171
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001172 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001173
Thomas Tsou3eaae802013-08-20 19:31:14 -04001174 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1175 data = (complex *) convolve_h_alloc(midMidamble->size());
1176 _midMidamble = new signalVector(data, 0, midMidamble->size());
1177 _midMidamble->setAligned(true);
1178 memcpy(_midMidamble->begin(), midMidamble->begin(),
1179 midMidamble->size() * sizeof(complex));
1180
1181 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001182 if (!autocorr) {
1183 status = false;
1184 goto release;
1185 }
dburgessb3a0ca42011-10-12 07:44:40 +00001186
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001187 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001188 gMidambles[tsc]->buffer = data;
1189 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001190 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1191
1192 /* For 1 sps only
1193 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1194 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1195 */
1196 if (sps == 1)
1197 gMidambles[tsc]->toa = toa - 13.5;
1198 else
1199 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001200
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001201release:
dburgessb3a0ca42011-10-12 07:44:40 +00001202 delete autocorr;
1203 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001204 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001205
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001206 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001207 delete _midMidamble;
1208 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001209 gMidambles[tsc] = NULL;
1210 }
1211
1212 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001213}
1214
Thomas Tsou83e06892013-08-20 16:10:01 -04001215bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001216{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001217 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001218 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001219 complex *data = NULL;
1220 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001221 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001222
1223 delete gRACHSequence;
1224
1225 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1226 if (!seq0)
1227 return false;
1228
1229 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1230 if (!seq1) {
1231 status = false;
1232 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001233 }
1234
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001235 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001236
Thomas Tsou3eaae802013-08-20 19:31:14 -04001237 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1238 data = (complex *) convolve_h_alloc(seq1->size());
1239 _seq1 = new signalVector(data, 0, seq1->size());
1240 _seq1->setAligned(true);
1241 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1242
1243 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1244 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001245 status = false;
1246 goto release;
1247 }
dburgessb3a0ca42011-10-12 07:44:40 +00001248
1249 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001250 gRACHSequence->sequence = _seq1;
1251 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001252 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1253
1254 /* For 1 sps only
1255 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1256 * 20.5 = (40 / 2 - 1) + 1.5
1257 */
1258 if (sps == 1)
1259 gRACHSequence->toa = toa - 20.5;
1260 else
1261 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001262
1263release:
dburgessb3a0ca42011-10-12 07:44:40 +00001264 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001265 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001266 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001267
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001268 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001269 delete _seq1;
1270 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001271 gRACHSequence = NULL;
1272 }
dburgessb3a0ca42011-10-12 07:44:40 +00001273
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001274 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001275}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001276
Thomas Tsou865bca42013-08-21 20:58:00 -04001277static float computePeakRatio(signalVector *corr,
1278 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001279{
Thomas Tsou865bca42013-08-21 20:58:00 -04001280 int num = 0;
1281 complex *peak;
1282 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001283
Thomas Tsou865bca42013-08-21 20:58:00 -04001284 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001285
Thomas Tsou865bca42013-08-21 20:58:00 -04001286 /* Check for bogus results */
1287 if ((toa < 0.0) || (toa > corr->size()))
1288 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001289
Thomas Tsou3eaae802013-08-20 19:31:14 -04001290 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001291 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001292 avg += (peak - i)->norm2();
1293 num++;
1294 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001295 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001296 avg += (peak + i)->norm2();
1297 num++;
1298 }
dburgessb3a0ca42011-10-12 07:44:40 +00001299 }
1300
Thomas Tsou3eaae802013-08-20 19:31:14 -04001301 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001302 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001303
Thomas Tsou3eaae802013-08-20 19:31:14 -04001304 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001305
Thomas Tsou865bca42013-08-21 20:58:00 -04001306 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001307}
1308
1309bool energyDetect(signalVector &rxBurst,
1310 unsigned windowLength,
1311 float detectThreshold,
1312 float *avgPwr)
1313{
1314
1315 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1316 float energy = 0.0;
1317 if (windowLength < 0) windowLength = 20;
1318 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1319 for (unsigned i = 0; i < windowLength; i++) {
1320 energy += windowItr->norm2();
1321 windowItr+=4;
1322 }
1323 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001324 return (energy/windowLength > detectThreshold*detectThreshold);
1325}
dburgessb3a0ca42011-10-12 07:44:40 +00001326
Thomas Tsou865bca42013-08-21 20:58:00 -04001327/*
1328 * Detect a burst based on correlation and peak-to-average ratio
1329 *
1330 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1331 * for initial gating. We do this because energy detection should be disabled.
1332 * For higher oversampling values, we assume the energy detector is in place
1333 * and we run full interpolating peak detection.
1334 */
1335static int detectBurst(signalVector &burst,
1336 signalVector &corr, CorrelationSequence *sync,
1337 float thresh, int sps, complex *amp, float *toa,
1338 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001339{
Thomas Tsou865bca42013-08-21 20:58:00 -04001340 /* Correlate */
1341 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001342 CUSTOM, start, len, sps, 0)) {
1343 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001344 }
1345
Thomas Tsou865bca42013-08-21 20:58:00 -04001346 /* Peak detection - place restrictions at correlation edges */
1347 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001348
Thomas Tsou865bca42013-08-21 20:58:00 -04001349 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1350 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001351
Thomas Tsou865bca42013-08-21 20:58:00 -04001352 /* Peak -to-average ratio */
1353 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1354 return 0;
1355
1356 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1357 *amp = peakDetect(corr, toa, NULL);
1358
1359 /* Normalize our channel gain */
1360 *amp = *amp / sync->gain;
1361
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001362 /* Compenate for residual rotation with dual Laurent pulse */
1363 if (sps == 4)
1364 *amp = *amp * complex(0.0, 1.0);
1365
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001366 /* Compensate for residuate time lag */
1367 *toa = *toa - sync->toa;
1368
Thomas Tsou865bca42013-08-21 20:58:00 -04001369 return 1;
1370}
1371
1372/*
1373 * RACH burst detection
1374 *
1375 * Correlation window parameters:
1376 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001377 * head: Search 4 symbols before target
1378 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001379 */
1380int detectRACHBurst(signalVector &rxBurst,
1381 float thresh,
1382 int sps,
1383 complex *amp,
1384 float *toa)
1385{
1386 int rc, start, target, head, tail, len;
1387 float _toa;
1388 complex _amp;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001389 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001390 CorrelationSequence *sync;
1391
1392 if ((sps != 1) && (sps != 4))
1393 return -1;
1394
1395 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001396 head = 4;
1397 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001398
1399 start = (target - head) * sps - 1;
1400 len = (head + tail) * sps;
1401 sync = gRACHSequence;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001402 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001403
Thomas Tsoub075dd22013-11-09 22:25:46 -05001404 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001405 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001406 delete corr;
1407
Thomas Tsou865bca42013-08-21 20:58:00 -04001408 if (rc < 0) {
1409 return -1;
1410 } else if (!rc) {
1411 if (amp)
1412 *amp = 0.0f;
1413 if (toa)
1414 *toa = 0.0f;
1415 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001416 }
1417
Thomas Tsou865bca42013-08-21 20:58:00 -04001418 /* Subtract forward search bits from delay */
1419 if (toa)
1420 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001421 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001422 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001423
Thomas Tsou865bca42013-08-21 20:58:00 -04001424 return 1;
1425}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001426
Thomas Tsou865bca42013-08-21 20:58:00 -04001427/*
1428 * Normal burst detection
1429 *
1430 * Correlation window parameters:
1431 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001432 * head: Search 4 symbols before target
1433 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001434 */
1435int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1436 int sps, complex *amp, float *toa, unsigned max_toa,
1437 bool chan_req, signalVector **chan, float *chan_offset)
1438{
1439 int rc, start, target, head, tail, len;
1440 complex _amp;
1441 float _toa;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001442 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001443 CorrelationSequence *sync;
1444
1445 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1446 return -1;
1447
1448 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001449 head = 4;
1450 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001451
1452 start = (target - head) * sps - 1;
1453 len = (head + tail) * sps;
1454 sync = gMidambles[tsc];
Thomas Tsoub075dd22013-11-09 22:25:46 -05001455 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001456
Thomas Tsoub075dd22013-11-09 22:25:46 -05001457 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001458 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001459 delete corr;
1460
Thomas Tsou865bca42013-08-21 20:58:00 -04001461 if (rc < 0) {
1462 return -1;
1463 } else if (!rc) {
1464 if (amp)
1465 *amp = 0.0f;
1466 if (toa)
1467 *toa = 0.0f;
1468 return 0;
1469 }
1470
1471 /* Subtract forward search bits from delay */
1472 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001473 if (toa)
1474 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001475 if (amp)
1476 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001477
Thomas Tsou865bca42013-08-21 20:58:00 -04001478 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001479 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001480 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001481
1482 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001483 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001484 }
1485
Thomas Tsou3eaae802013-08-20 19:31:14 -04001486 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001487}
1488
Thomas Tsou94edaae2013-11-09 22:19:19 -05001489signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001490{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001491 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001492
Thomas Tsou94edaae2013-11-09 22:19:19 -05001493 if (factor <= 1)
1494 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001495
Thomas Tsou94edaae2013-11-09 22:19:19 -05001496 dec = new signalVector(wVector.size() / factor);
1497 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001498
Thomas Tsou94edaae2013-11-09 22:19:19 -05001499 signalVector::iterator itr = dec->begin();
1500 for (size_t i = 0; i < wVector.size(); i += factor)
1501 *itr++ = wVector[i];
1502
1503 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001504}
1505
Thomas Tsou83e06892013-08-20 16:10:01 -04001506SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05001507 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001508{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001509 signalVector *delay, *dec = NULL;
1510 SoftVector *bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001511
Thomas Tsou94edaae2013-11-09 22:19:19 -05001512 scaleVector(rxBurst, ((complex) 1.0) / channel);
1513 delay = delayVector(&rxBurst, NULL, -TOA);
dburgessb3a0ca42011-10-12 07:44:40 +00001514
Thomas Tsou94edaae2013-11-09 22:19:19 -05001515 /* Shift up by a quarter of a frequency */
1516 GMSKReverseRotate(*delay, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001517
Thomas Tsou94edaae2013-11-09 22:19:19 -05001518 /* Decimate and slice */
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001519 if (sps > 1) {
Thomas Tsou94edaae2013-11-09 22:19:19 -05001520 dec = decimateVector(*delay, sps);
1521 delete delay;
1522 delay = NULL;
1523 } else {
1524 dec = delay;
dburgessb3a0ca42011-10-12 07:44:40 +00001525 }
1526
Thomas Tsou94edaae2013-11-09 22:19:19 -05001527 vectorSlicer(dec);
dburgessb3a0ca42011-10-12 07:44:40 +00001528
Thomas Tsou94edaae2013-11-09 22:19:19 -05001529 bits = new SoftVector(dec->size());
dburgessb3a0ca42011-10-12 07:44:40 +00001530
Thomas Tsou94edaae2013-11-09 22:19:19 -05001531 SoftVector::iterator bit_itr = bits->begin();
1532 signalVector::iterator burst_itr = dec->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001533
Thomas Tsou94edaae2013-11-09 22:19:19 -05001534 for (; burst_itr < dec->end(); burst_itr++)
1535 *bit_itr++ = burst_itr->real();
dburgessb3a0ca42011-10-12 07:44:40 +00001536
Thomas Tsou94edaae2013-11-09 22:19:19 -05001537 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001538
Thomas Tsou94edaae2013-11-09 22:19:19 -05001539 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001540}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001541
dburgessb3a0ca42011-10-12 07:44:40 +00001542// Assumes symbol-spaced sampling!!!
1543// Based upon paper by Al-Dhahir and Cioffi
1544bool designDFE(signalVector &channelResponse,
1545 float SNRestimate,
1546 int Nf,
1547 signalVector **feedForwardFilter,
1548 signalVector **feedbackFilter)
1549{
1550
1551 signalVector G0(Nf);
1552 signalVector G1(Nf);
1553 signalVector::iterator G0ptr = G0.begin();
1554 signalVector::iterator G1ptr = G1.begin();
1555 signalVector::iterator chanPtr = channelResponse.begin();
1556
1557 int nu = channelResponse.size()-1;
1558
1559 *G0ptr = 1.0/sqrtf(SNRestimate);
1560 for(int j = 0; j <= nu; j++) {
1561 *G1ptr = chanPtr->conj();
1562 G1ptr++; chanPtr++;
1563 }
1564
1565 signalVector *L[Nf];
1566 signalVector::iterator Lptr;
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001567 float d = 1.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001568 for(int i = 0; i < Nf; i++) {
1569 d = G0.begin()->norm2() + G1.begin()->norm2();
1570 L[i] = new signalVector(Nf+nu);
1571 Lptr = L[i]->begin()+i;
1572 G0ptr = G0.begin(); G1ptr = G1.begin();
1573 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1574 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1575 Lptr++;
1576 G0ptr++;
1577 G1ptr++;
1578 }
1579 complex k = (*G1.begin())/(*G0.begin());
1580
1581 if (i != Nf-1) {
1582 signalVector G0new = G1;
1583 scaleVector(G0new,k.conj());
1584 addVector(G0new,G0);
1585
1586 signalVector G1new = G0;
1587 scaleVector(G1new,k*(-1.0));
1588 addVector(G1new,G1);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001589 delayVector(&G1new, &G1new, -1.0);
dburgessb3a0ca42011-10-12 07:44:40 +00001590
1591 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1592 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1593 G0 = G0new;
1594 G1 = G1new;
1595 }
1596 }
1597
1598 *feedbackFilter = new signalVector(nu);
1599 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1600 scaleVector(**feedbackFilter,(complex) -1.0);
1601 conjugateVector(**feedbackFilter);
1602
1603 signalVector v(Nf);
1604 signalVector::iterator vStart = v.begin();
1605 signalVector::iterator vPtr;
1606 *(vStart+Nf-1) = (complex) 1.0;
1607 for(int k = Nf-2; k >= 0; k--) {
1608 Lptr = L[k]->begin()+k+1;
1609 vPtr = vStart + k+1;
1610 complex v_k = 0.0;
1611 for (int j = k+1; j < Nf; j++) {
1612 v_k -= (*vPtr)*(*Lptr);
1613 vPtr++; Lptr++;
1614 }
1615 *(vStart + k) = v_k;
1616 }
1617
1618 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001619 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001620 for (int i = 0; i < Nf; i++) {
1621 delete L[i];
1622 complex w_i = 0.0;
1623 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1624 vPtr = vStart+i;
1625 chanPtr = channelResponse.begin();
1626 for (int k = 0; k < endPt+1; k++) {
1627 w_i += (*vPtr)*(chanPtr->conj());
1628 vPtr++; chanPtr++;
1629 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001630 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001631 }
1632
1633
1634 return true;
1635
1636}
1637
1638// Assumes symbol-rate sampling!!!!
1639SoftVector *equalizeBurst(signalVector &rxBurst,
1640 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001641 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001642 signalVector &w, // feedforward filter
1643 signalVector &b) // feedback filter
1644{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001645 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001646
Thomas Tsou94edaae2013-11-09 22:19:19 -05001647 if (!delayVector(&rxBurst, &rxBurst, -TOA))
Thomas Tsou3eaae802013-08-20 19:31:14 -04001648 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001649
Thomas Tsou3eaae802013-08-20 19:31:14 -04001650 postForwardFull = convolve(&rxBurst, &w, NULL,
1651 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1652 if (!postForwardFull)
1653 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001654
1655 signalVector* postForward = new signalVector(rxBurst.size());
1656 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1657 delete postForwardFull;
1658
1659 signalVector::iterator dPtr = postForward->begin();
1660 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001661 signalVector::iterator rotPtr = GMSKRotationN->begin();
1662 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001663
1664 signalVector *DFEoutput = new signalVector(postForward->size());
1665 signalVector::iterator DFEItr = DFEoutput->begin();
1666
1667 // NOTE: can insert the midamble and/or use midamble to estimate BER
1668 for (; dPtr < postForward->end(); dPtr++) {
1669 dBackPtr = dPtr-1;
1670 signalVector::iterator bPtr = b.begin();
1671 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1672 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1673 bPtr++;
1674 dBackPtr--;
1675 }
1676 *dPtr = *dPtr * (*revRotPtr);
1677 *DFEItr = *dPtr;
1678 // make decision on symbol
1679 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1680 //*DFEItr = *dPtr;
1681 *dPtr = *dPtr * (*rotPtr);
1682 DFEItr++;
1683 rotPtr++;
1684 revRotPtr++;
1685 }
1686
1687 vectorSlicer(DFEoutput);
1688
1689 SoftVector *burstBits = new SoftVector(postForward->size());
1690 SoftVector::iterator burstItr = burstBits->begin();
1691 DFEItr = DFEoutput->begin();
1692 for (; DFEItr < DFEoutput->end(); DFEItr++)
1693 *burstItr++ = DFEItr->real();
1694
1695 delete postForward;
1696
1697 delete DFEoutput;
1698
1699 return burstBits;
1700}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001701
1702bool sigProcLibSetup(int sps)
1703{
1704 if ((sps != 1) && (sps != 4))
1705 return false;
1706
1707 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001708 generateSincTable();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001709 initGMSKRotationTables(sps);
1710
1711 GSMPulse1 = generateGSMPulse(1, 2);
1712 if (sps > 1)
1713 GSMPulse = generateGSMPulse(sps, 2);
1714
1715 if (!generateRACHSequence(1)) {
1716 sigProcLibDestroy();
1717 return false;
1718 }
1719
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001720 generateDelayFilters();
1721
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001722 return true;
1723}