blob: 3d2bba6f10123f5c863ac3cb41b0afad366eae78 [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
1138
1139void offsetVector(signalVector &x,
1140 complex offset)
1141{
1142 signalVector::iterator xP = x.begin();
1143 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001144 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001145 while (xP < xPEnd) {
1146 *xP += offset;
1147 xP++;
1148 }
1149 }
1150 else {
1151 while (xP < xPEnd) {
1152 *xP = xP->real() + offset;
1153 xP++;
1154 }
1155 }
1156}
1157
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001158bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001159{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001160 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001161 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001162 complex *data = NULL;
1163 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001164 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001165
Thomas Tsou3eaae802013-08-20 19:31:14 -04001166 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001167 return false;
1168
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001169 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001170
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001171 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1172 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1173 if (!midMidamble)
1174 return false;
1175
Thomas Tsou3eaae802013-08-20 19:31:14 -04001176 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001177 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1178 if (!midamble) {
1179 status = false;
1180 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001181 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001182
dburgessb3a0ca42011-10-12 07:44:40 +00001183 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1184 // the ideal TSC has an + 180 degree phase shift,
1185 // due to the pi/2 frequency shift, that
1186 // needs to be accounted for.
1187 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001188 scaleVector(*midMidamble, complex(-1.0, 0.0));
1189 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001190
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001191 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001192
Thomas Tsou3eaae802013-08-20 19:31:14 -04001193 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1194 data = (complex *) convolve_h_alloc(midMidamble->size());
1195 _midMidamble = new signalVector(data, 0, midMidamble->size());
1196 _midMidamble->setAligned(true);
1197 memcpy(_midMidamble->begin(), midMidamble->begin(),
1198 midMidamble->size() * sizeof(complex));
1199
1200 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001201 if (!autocorr) {
1202 status = false;
1203 goto release;
1204 }
dburgessb3a0ca42011-10-12 07:44:40 +00001205
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001206 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001207 gMidambles[tsc]->buffer = data;
1208 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001209 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1210
1211 /* For 1 sps only
1212 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1213 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1214 */
1215 if (sps == 1)
1216 gMidambles[tsc]->toa = toa - 13.5;
1217 else
1218 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001219
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001220release:
dburgessb3a0ca42011-10-12 07:44:40 +00001221 delete autocorr;
1222 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001223 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001224
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001225 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001226 delete _midMidamble;
1227 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001228 gMidambles[tsc] = NULL;
1229 }
1230
1231 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001232}
1233
Thomas Tsou83e06892013-08-20 16:10:01 -04001234bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001235{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001236 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001237 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001238 complex *data = NULL;
1239 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001240 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001241
1242 delete gRACHSequence;
1243
1244 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1245 if (!seq0)
1246 return false;
1247
1248 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1249 if (!seq1) {
1250 status = false;
1251 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001252 }
1253
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001254 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001255
Thomas Tsou3eaae802013-08-20 19:31:14 -04001256 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1257 data = (complex *) convolve_h_alloc(seq1->size());
1258 _seq1 = new signalVector(data, 0, seq1->size());
1259 _seq1->setAligned(true);
1260 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1261
1262 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1263 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001264 status = false;
1265 goto release;
1266 }
dburgessb3a0ca42011-10-12 07:44:40 +00001267
1268 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001269 gRACHSequence->sequence = _seq1;
1270 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001271 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1272
1273 /* For 1 sps only
1274 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1275 * 20.5 = (40 / 2 - 1) + 1.5
1276 */
1277 if (sps == 1)
1278 gRACHSequence->toa = toa - 20.5;
1279 else
1280 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001281
1282release:
dburgessb3a0ca42011-10-12 07:44:40 +00001283 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001284 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001285 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001286
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001287 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001288 delete _seq1;
1289 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001290 gRACHSequence = NULL;
1291 }
dburgessb3a0ca42011-10-12 07:44:40 +00001292
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001293 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001294}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001295
Thomas Tsou865bca42013-08-21 20:58:00 -04001296static float computePeakRatio(signalVector *corr,
1297 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001298{
Thomas Tsou865bca42013-08-21 20:58:00 -04001299 int num = 0;
1300 complex *peak;
1301 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001302
Thomas Tsou865bca42013-08-21 20:58:00 -04001303 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001304
Thomas Tsou865bca42013-08-21 20:58:00 -04001305 /* Check for bogus results */
1306 if ((toa < 0.0) || (toa > corr->size()))
1307 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001308
Thomas Tsou3eaae802013-08-20 19:31:14 -04001309 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001310 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001311 avg += (peak - i)->norm2();
1312 num++;
1313 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001314 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001315 avg += (peak + i)->norm2();
1316 num++;
1317 }
dburgessb3a0ca42011-10-12 07:44:40 +00001318 }
1319
Thomas Tsou3eaae802013-08-20 19:31:14 -04001320 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001321 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001322
Thomas Tsou3eaae802013-08-20 19:31:14 -04001323 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001324
Thomas Tsou865bca42013-08-21 20:58:00 -04001325 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001326}
1327
1328bool energyDetect(signalVector &rxBurst,
1329 unsigned windowLength,
1330 float detectThreshold,
1331 float *avgPwr)
1332{
1333
1334 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1335 float energy = 0.0;
1336 if (windowLength < 0) windowLength = 20;
1337 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1338 for (unsigned i = 0; i < windowLength; i++) {
1339 energy += windowItr->norm2();
1340 windowItr+=4;
1341 }
1342 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001343 return (energy/windowLength > detectThreshold*detectThreshold);
1344}
dburgessb3a0ca42011-10-12 07:44:40 +00001345
Thomas Tsou865bca42013-08-21 20:58:00 -04001346/*
1347 * Detect a burst based on correlation and peak-to-average ratio
1348 *
1349 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1350 * for initial gating. We do this because energy detection should be disabled.
1351 * For higher oversampling values, we assume the energy detector is in place
1352 * and we run full interpolating peak detection.
1353 */
1354static int detectBurst(signalVector &burst,
1355 signalVector &corr, CorrelationSequence *sync,
1356 float thresh, int sps, complex *amp, float *toa,
1357 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001358{
Thomas Tsou865bca42013-08-21 20:58:00 -04001359 /* Correlate */
1360 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001361 CUSTOM, start, len, sps, 0)) {
1362 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001363 }
1364
Thomas Tsou865bca42013-08-21 20:58:00 -04001365 /* Peak detection - place restrictions at correlation edges */
1366 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001367
Thomas Tsou865bca42013-08-21 20:58:00 -04001368 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1369 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001370
Thomas Tsou865bca42013-08-21 20:58:00 -04001371 /* Peak -to-average ratio */
1372 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1373 return 0;
1374
1375 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1376 *amp = peakDetect(corr, toa, NULL);
1377
1378 /* Normalize our channel gain */
1379 *amp = *amp / sync->gain;
1380
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001381 /* Compenate for residual rotation with dual Laurent pulse */
1382 if (sps == 4)
1383 *amp = *amp * complex(0.0, 1.0);
1384
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001385 /* Compensate for residuate time lag */
1386 *toa = *toa - sync->toa;
1387
Thomas Tsou865bca42013-08-21 20:58:00 -04001388 return 1;
1389}
1390
1391/*
1392 * RACH burst detection
1393 *
1394 * Correlation window parameters:
1395 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001396 * head: Search 4 symbols before target
1397 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001398 */
1399int detectRACHBurst(signalVector &rxBurst,
1400 float thresh,
1401 int sps,
1402 complex *amp,
1403 float *toa)
1404{
1405 int rc, start, target, head, tail, len;
1406 float _toa;
1407 complex _amp;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001408 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001409 CorrelationSequence *sync;
1410
1411 if ((sps != 1) && (sps != 4))
1412 return -1;
1413
1414 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001415 head = 4;
1416 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001417
1418 start = (target - head) * sps - 1;
1419 len = (head + tail) * sps;
1420 sync = gRACHSequence;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001421 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001422
Thomas Tsoub075dd22013-11-09 22:25:46 -05001423 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001424 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001425 delete corr;
1426
Thomas Tsou865bca42013-08-21 20:58:00 -04001427 if (rc < 0) {
1428 return -1;
1429 } else if (!rc) {
1430 if (amp)
1431 *amp = 0.0f;
1432 if (toa)
1433 *toa = 0.0f;
1434 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001435 }
1436
Thomas Tsou865bca42013-08-21 20:58:00 -04001437 /* Subtract forward search bits from delay */
1438 if (toa)
1439 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001440 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001441 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001442
Thomas Tsou865bca42013-08-21 20:58:00 -04001443 return 1;
1444}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001445
Thomas Tsou865bca42013-08-21 20:58:00 -04001446/*
1447 * Normal burst detection
1448 *
1449 * Correlation window parameters:
1450 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001451 * head: Search 4 symbols before target
1452 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001453 */
1454int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1455 int sps, complex *amp, float *toa, unsigned max_toa,
1456 bool chan_req, signalVector **chan, float *chan_offset)
1457{
1458 int rc, start, target, head, tail, len;
1459 complex _amp;
1460 float _toa;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001461 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001462 CorrelationSequence *sync;
1463
1464 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1465 return -1;
1466
1467 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001468 head = 4;
1469 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001470
1471 start = (target - head) * sps - 1;
1472 len = (head + tail) * sps;
1473 sync = gMidambles[tsc];
Thomas Tsoub075dd22013-11-09 22:25:46 -05001474 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001475
Thomas Tsoub075dd22013-11-09 22:25:46 -05001476 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001477 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001478 delete corr;
1479
Thomas Tsou865bca42013-08-21 20:58:00 -04001480 if (rc < 0) {
1481 return -1;
1482 } else if (!rc) {
1483 if (amp)
1484 *amp = 0.0f;
1485 if (toa)
1486 *toa = 0.0f;
1487 return 0;
1488 }
1489
1490 /* Subtract forward search bits from delay */
1491 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001492 if (toa)
1493 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001494 if (amp)
1495 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001496
Thomas Tsou865bca42013-08-21 20:58:00 -04001497 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001498 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001499 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001500
1501 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001502 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001503 }
1504
Thomas Tsou3eaae802013-08-20 19:31:14 -04001505 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001506}
1507
Thomas Tsou94edaae2013-11-09 22:19:19 -05001508signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001509{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001510 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001511
Thomas Tsou94edaae2013-11-09 22:19:19 -05001512 if (factor <= 1)
1513 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001514
Thomas Tsou94edaae2013-11-09 22:19:19 -05001515 dec = new signalVector(wVector.size() / factor);
1516 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001517
Thomas Tsou94edaae2013-11-09 22:19:19 -05001518 signalVector::iterator itr = dec->begin();
1519 for (size_t i = 0; i < wVector.size(); i += factor)
1520 *itr++ = wVector[i];
1521
1522 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001523}
1524
Thomas Tsou83e06892013-08-20 16:10:01 -04001525SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05001526 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001527{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001528 signalVector *delay, *dec = NULL;
1529 SoftVector *bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001530
Thomas Tsou94edaae2013-11-09 22:19:19 -05001531 scaleVector(rxBurst, ((complex) 1.0) / channel);
1532 delay = delayVector(&rxBurst, NULL, -TOA);
dburgessb3a0ca42011-10-12 07:44:40 +00001533
Thomas Tsou94edaae2013-11-09 22:19:19 -05001534 /* Shift up by a quarter of a frequency */
1535 GMSKReverseRotate(*delay, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001536
Thomas Tsou94edaae2013-11-09 22:19:19 -05001537 /* Decimate and slice */
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001538 if (sps > 1) {
Thomas Tsou94edaae2013-11-09 22:19:19 -05001539 dec = decimateVector(*delay, sps);
1540 delete delay;
1541 delay = NULL;
1542 } else {
1543 dec = delay;
dburgessb3a0ca42011-10-12 07:44:40 +00001544 }
1545
Thomas Tsou94edaae2013-11-09 22:19:19 -05001546 vectorSlicer(dec);
dburgessb3a0ca42011-10-12 07:44:40 +00001547
Thomas Tsou94edaae2013-11-09 22:19:19 -05001548 bits = new SoftVector(dec->size());
dburgessb3a0ca42011-10-12 07:44:40 +00001549
Thomas Tsou94edaae2013-11-09 22:19:19 -05001550 SoftVector::iterator bit_itr = bits->begin();
1551 signalVector::iterator burst_itr = dec->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001552
Thomas Tsou94edaae2013-11-09 22:19:19 -05001553 for (; burst_itr < dec->end(); burst_itr++)
1554 *bit_itr++ = burst_itr->real();
dburgessb3a0ca42011-10-12 07:44:40 +00001555
Thomas Tsou94edaae2013-11-09 22:19:19 -05001556 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001557
Thomas Tsou94edaae2013-11-09 22:19:19 -05001558 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001559}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001560
dburgessb3a0ca42011-10-12 07:44:40 +00001561// Assumes symbol-spaced sampling!!!
1562// Based upon paper by Al-Dhahir and Cioffi
1563bool designDFE(signalVector &channelResponse,
1564 float SNRestimate,
1565 int Nf,
1566 signalVector **feedForwardFilter,
1567 signalVector **feedbackFilter)
1568{
1569
1570 signalVector G0(Nf);
1571 signalVector G1(Nf);
1572 signalVector::iterator G0ptr = G0.begin();
1573 signalVector::iterator G1ptr = G1.begin();
1574 signalVector::iterator chanPtr = channelResponse.begin();
1575
1576 int nu = channelResponse.size()-1;
1577
1578 *G0ptr = 1.0/sqrtf(SNRestimate);
1579 for(int j = 0; j <= nu; j++) {
1580 *G1ptr = chanPtr->conj();
1581 G1ptr++; chanPtr++;
1582 }
1583
1584 signalVector *L[Nf];
1585 signalVector::iterator Lptr;
1586 float d;
1587 for(int i = 0; i < Nf; i++) {
1588 d = G0.begin()->norm2() + G1.begin()->norm2();
1589 L[i] = new signalVector(Nf+nu);
1590 Lptr = L[i]->begin()+i;
1591 G0ptr = G0.begin(); G1ptr = G1.begin();
1592 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1593 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1594 Lptr++;
1595 G0ptr++;
1596 G1ptr++;
1597 }
1598 complex k = (*G1.begin())/(*G0.begin());
1599
1600 if (i != Nf-1) {
1601 signalVector G0new = G1;
1602 scaleVector(G0new,k.conj());
1603 addVector(G0new,G0);
1604
1605 signalVector G1new = G0;
1606 scaleVector(G1new,k*(-1.0));
1607 addVector(G1new,G1);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001608 delayVector(&G1new, &G1new, -1.0);
dburgessb3a0ca42011-10-12 07:44:40 +00001609
1610 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1611 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1612 G0 = G0new;
1613 G1 = G1new;
1614 }
1615 }
1616
1617 *feedbackFilter = new signalVector(nu);
1618 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1619 scaleVector(**feedbackFilter,(complex) -1.0);
1620 conjugateVector(**feedbackFilter);
1621
1622 signalVector v(Nf);
1623 signalVector::iterator vStart = v.begin();
1624 signalVector::iterator vPtr;
1625 *(vStart+Nf-1) = (complex) 1.0;
1626 for(int k = Nf-2; k >= 0; k--) {
1627 Lptr = L[k]->begin()+k+1;
1628 vPtr = vStart + k+1;
1629 complex v_k = 0.0;
1630 for (int j = k+1; j < Nf; j++) {
1631 v_k -= (*vPtr)*(*Lptr);
1632 vPtr++; Lptr++;
1633 }
1634 *(vStart + k) = v_k;
1635 }
1636
1637 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001638 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001639 for (int i = 0; i < Nf; i++) {
1640 delete L[i];
1641 complex w_i = 0.0;
1642 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1643 vPtr = vStart+i;
1644 chanPtr = channelResponse.begin();
1645 for (int k = 0; k < endPt+1; k++) {
1646 w_i += (*vPtr)*(chanPtr->conj());
1647 vPtr++; chanPtr++;
1648 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001649 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001650 }
1651
1652
1653 return true;
1654
1655}
1656
1657// Assumes symbol-rate sampling!!!!
1658SoftVector *equalizeBurst(signalVector &rxBurst,
1659 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001660 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001661 signalVector &w, // feedforward filter
1662 signalVector &b) // feedback filter
1663{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001664 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001665
Thomas Tsou94edaae2013-11-09 22:19:19 -05001666 if (!delayVector(&rxBurst, &rxBurst, -TOA))
Thomas Tsou3eaae802013-08-20 19:31:14 -04001667 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001668
Thomas Tsou3eaae802013-08-20 19:31:14 -04001669 postForwardFull = convolve(&rxBurst, &w, NULL,
1670 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1671 if (!postForwardFull)
1672 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001673
1674 signalVector* postForward = new signalVector(rxBurst.size());
1675 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1676 delete postForwardFull;
1677
1678 signalVector::iterator dPtr = postForward->begin();
1679 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001680 signalVector::iterator rotPtr = GMSKRotationN->begin();
1681 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001682
1683 signalVector *DFEoutput = new signalVector(postForward->size());
1684 signalVector::iterator DFEItr = DFEoutput->begin();
1685
1686 // NOTE: can insert the midamble and/or use midamble to estimate BER
1687 for (; dPtr < postForward->end(); dPtr++) {
1688 dBackPtr = dPtr-1;
1689 signalVector::iterator bPtr = b.begin();
1690 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1691 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1692 bPtr++;
1693 dBackPtr--;
1694 }
1695 *dPtr = *dPtr * (*revRotPtr);
1696 *DFEItr = *dPtr;
1697 // make decision on symbol
1698 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1699 //*DFEItr = *dPtr;
1700 *dPtr = *dPtr * (*rotPtr);
1701 DFEItr++;
1702 rotPtr++;
1703 revRotPtr++;
1704 }
1705
1706 vectorSlicer(DFEoutput);
1707
1708 SoftVector *burstBits = new SoftVector(postForward->size());
1709 SoftVector::iterator burstItr = burstBits->begin();
1710 DFEItr = DFEoutput->begin();
1711 for (; DFEItr < DFEoutput->end(); DFEItr++)
1712 *burstItr++ = DFEItr->real();
1713
1714 delete postForward;
1715
1716 delete DFEoutput;
1717
1718 return burstBits;
1719}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001720
1721bool sigProcLibSetup(int sps)
1722{
1723 if ((sps != 1) && (sps != 4))
1724 return false;
1725
1726 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001727 generateSincTable();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001728 initGMSKRotationTables(sps);
1729
1730 GSMPulse1 = generateGSMPulse(1, 2);
1731 if (sps > 1)
1732 GSMPulse = generateGSMPulse(sps, 2);
1733
1734 if (!generateRACHSequence(1)) {
1735 sigProcLibDestroy();
1736 return false;
1737 }
1738
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001739 generateDelayFilters();
1740
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001741 return true;
1742}