blob: 12dcf00753efe8b1f2832f670ebf2d0bcb151e91 [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;
616 }
617 }
618
619
620 if (finalPhase) *finalPhase = phase;
621
622 return y;
623}
624
625signalVector* reverseConjugate(signalVector *b)
626{
627 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500628 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000629 signalVector::iterator bP = b->begin();
630 signalVector::iterator bPEnd = b->end();
631 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500632 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000633 while (bP < bPEnd) {
634 *tmpP-- = bP->conj();
635 bP++;
636 }
637 }
638 else {
639 while (bP < bPEnd) {
640 *tmpP-- = bP->real();
641 bP++;
642 }
643 }
644
645 return tmp;
646}
647
dburgessb3a0ca42011-10-12 07:44:40 +0000648/* soft output slicer */
649bool vectorSlicer(signalVector *x)
650{
651
652 signalVector::iterator xP = x->begin();
653 signalVector::iterator xPEnd = x->end();
654 while (xP < xPEnd) {
655 *xP = (complex) (0.5*(xP->real()+1.0F));
656 if (xP->real() > 1.0) *xP = 1.0;
657 if (xP->real() < 0.0) *xP = 0.0;
658 xP++;
659 }
660 return true;
661}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400662
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800663static signalVector *rotateBurst(const BitVector &wBurst,
664 int guardPeriodLength, int sps)
665{
666 int burst_len;
667 signalVector *pulse, rotated, *shaped;
668 signalVector::iterator itr;
669
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400670 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800671 burst_len = sps * (wBurst.size() + guardPeriodLength);
672 rotated = signalVector(burst_len);
673 itr = rotated.begin();
674
675 for (unsigned i = 0; i < wBurst.size(); i++) {
676 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
677 itr += sps;
678 }
679
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400680 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500681 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800682
683 /* Dummy filter operation */
684 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
685 if (!shaped)
686 return NULL;
687
688 return shaped;
689}
690
691static signalVector *modulateBurstLaurent(const BitVector &bits,
692 int guard_len, int sps)
693{
694 int burst_len;
695 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500696 signalVector *c0_pulse, *c1_pulse, *c0_burst;
697 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800698 signalVector::iterator c0_itr, c1_itr;
699
700 /*
701 * Apply before and after bits to reduce phase error at burst edges.
702 * Make sure there is enough room in the burst to accomodate all bits.
703 */
704 if (guard_len < 4)
705 guard_len = 4;
706
707 c0_pulse = GSMPulse->c0;
708 c1_pulse = GSMPulse->c1;
709
710 burst_len = sps * (bits.size() + guard_len);
711
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500712 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500713 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500714 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800715
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500716 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500717 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500718 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800719
720 /* Padded differential start bits */
721 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
722 c0_itr += sps;
723
724 /* Main burst bits */
725 for (unsigned i = 0; i < bits.size(); i++) {
726 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
727 c0_itr += sps;
728 }
729
730 /* Padded differential end bits */
731 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
732
733 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500734 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500735 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800736
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500737 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800738 c0_itr += sps * 2;
739 c1_itr += sps * 2;
740
741 /* Start magic */
742 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
743 *c1_itr = *c0_itr * Complex<float>(0, phase);
744 c0_itr += sps;
745 c1_itr += sps;
746
747 /* Generate C1 phase coefficients */
748 for (unsigned i = 2; i < bits.size(); i++) {
749 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
750 *c1_itr = *c0_itr * Complex<float>(0, phase);
751
752 c0_itr += sps;
753 c1_itr += sps;
754 }
755
756 /* End magic */
757 int i = bits.size();
758 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
759 *c1_itr = *c0_itr * Complex<float>(0, phase);
760
761 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500762 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
763 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800764
765 /* Sum shaped outputs into C0 */
766 c0_itr = c0_shaped->begin();
767 c1_itr = c1_shaped->begin();
768 for (unsigned i = 0; i < c0_shaped->size(); i++ )
769 *c0_itr++ += *c1_itr++;
770
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500771 delete c0_burst;
772 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800773 delete c1_shaped;
774
775 return c0_shaped;
776}
777
778static signalVector *modulateBurstBasic(const BitVector &bits,
779 int guard_len, int sps)
780{
781 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500782 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800783 signalVector::iterator burst_itr;
784
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400785 if (sps == 1)
786 pulse = GSMPulse1->c0;
787 else
788 pulse = GSMPulse->c0;
789
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800790 burst_len = sps * (bits.size() + guard_len);
791
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500792 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500793 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500794 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800795
796 /* Raw bits are not differentially encoded */
797 for (unsigned i = 0; i < bits.size(); i++) {
798 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
799 burst_itr += sps;
800 }
801
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500802 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500803 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800804
805 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500806 shaped = convolve(burst, pulse, NULL, START_ONLY);
807
808 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800809
810 return shaped;
811}
812
Thomas Tsou3eaae802013-08-20 19:31:14 -0400813/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400814signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
815 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000816{
Thomas Tsou83e06892013-08-20 16:10:01 -0400817 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800818 return rotateBurst(wBurst, guardPeriodLength, sps);
819 else if (sps == 4)
820 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400821 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800822 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000823}
824
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500825void generateSincTable()
826{
827 float x;
828
829 for (int i = 0; i < TABLESIZE; i++) {
830 x = (float) i / TABLESIZE * 8 * M_PI;
831 if (fabs(x) < 0.01) {
832 sincTable[i] = 1.0f;
833 continue;
834 }
835
836 sincTable[i] = sinf(x) / x;
837 }
838}
839
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800840float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000841{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500842 if (fabs(x) >= 8 * M_PI)
843 return 0.0;
844
845 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
846
847 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +0000848}
849
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600850/*
851 * Create fractional delay filterbank with Blackman-harris windowed
852 * sinc function generator. The number of filters generated is specified
853 * by the DELAYFILTS value.
854 */
855void generateDelayFilters()
856{
857 int h_len = 20;
858 complex *data;
859 signalVector *h;
860 signalVector::iterator itr;
861
862 float k, sum;
863 float a0 = 0.35875;
864 float a1 = 0.48829;
865 float a2 = 0.14128;
866 float a3 = 0.01168;
867
868 for (int i = 0; i < DELAYFILTS; i++) {
869 data = (complex *) convolve_h_alloc(h_len);
870 h = new signalVector(data, 0, h_len);
871 h->setAligned(true);
872 h->isReal(true);
873
874 sum = 0.0;
875 itr = h->end();
876 for (int n = 0; n < h_len; n++) {
877 k = (float) n;
878 *--itr = (complex) sinc(M_PI_F *
879 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
880 *itr *= a0 -
881 a1 * cos(2 * M_PI * n / (h_len - 1)) +
882 a2 * cos(4 * M_PI * n / (h_len - 1)) -
883 a3 * cos(6 * M_PI * n / (h_len - 1));
884
885 sum += itr->real();
886 }
887
888 itr = h->begin();
889 for (int n = 0; n < h_len; n++)
890 *itr++ /= sum;
891
892 delayFilters[i] = h;
893 }
894}
895
Thomas Tsou94edaae2013-11-09 22:19:19 -0500896signalVector *delayVector(signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000897{
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600898 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400899 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500900 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400901
Thomas Tsou2c282f52013-10-08 21:34:35 -0400902 whole = floor(delay);
903 frac = delay - whole;
904
905 /* Sinc interpolated fractional shift (if allowable) */
906 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600907 index = floorf(frac * (float) DELAYFILTS);
908 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -0400909
Thomas Tsou94edaae2013-11-09 22:19:19 -0500910 fshift = convolve(in, h, NULL, NO_DELAY);
911 if (!fshift)
912 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000913 }
914
Thomas Tsou94edaae2013-11-09 22:19:19 -0500915 if (!fshift)
916 shift = new signalVector(*in);
917 else
918 shift = fshift;
919
Thomas Tsou2c282f52013-10-08 21:34:35 -0400920 /* Integer sample shift */
921 if (whole < 0) {
922 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500923 signalVector::iterator wBurstItr = shift->begin();
924 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400925
Thomas Tsou94edaae2013-11-09 22:19:19 -0500926 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +0000927 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400928
Thomas Tsou94edaae2013-11-09 22:19:19 -0500929 while (wBurstItr < shift->end())
930 *wBurstItr++ = 0.0;
931 } else if (whole >= 0) {
932 signalVector::iterator wBurstItr = shift->end() - 1;
933 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
934
935 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000936 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500937
938 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000939 *wBurstItr-- = 0.0;
940 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400941
Thomas Tsou94edaae2013-11-09 22:19:19 -0500942 if (!out)
943 return shift;
944
945 out->clone(*shift);
946 delete shift;
947 return out;
dburgessb3a0ca42011-10-12 07:44:40 +0000948}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400949
dburgessb3a0ca42011-10-12 07:44:40 +0000950signalVector *gaussianNoise(int length,
951 float variance,
952 complex mean)
953{
954
955 signalVector *noise = new signalVector(length);
956 signalVector::iterator nPtr = noise->begin();
957 float stddev = sqrtf(variance);
958 while (nPtr < noise->end()) {
959 float u1 = (float) rand()/ (float) RAND_MAX;
960 while (u1==0.0)
961 u1 = (float) rand()/ (float) RAND_MAX;
962 float u2 = (float) rand()/ (float) RAND_MAX;
963 float arg = 2.0*M_PI*u2;
964 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
965 nPtr++;
966 }
967
968 return noise;
969}
970
971complex interpolatePoint(const signalVector &inSig,
972 float ix)
973{
974
975 int start = (int) (floor(ix) - 10);
976 if (start < 0) start = 0;
977 int end = (int) (floor(ix) + 11);
978 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
979
980 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500981 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000982 for (int i = start; i < end; i++)
983 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
984 }
985 else {
986 for (int i = start; i < end; i++)
987 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
988 }
989
990 return pVal;
991}
992
Thomas Tsou8181b012013-08-20 21:17:19 -0400993static complex fastPeakDetect(const signalVector &rxBurst, float *index)
994{
995 float val, max = 0.0f;
996 complex amp;
997 int _index = -1;
998
999 for (int i = 0; i < rxBurst.size(); i++) {
1000 val = rxBurst[i].norm2();
1001 if (val > max) {
1002 max = val;
1003 _index = i;
1004 amp = rxBurst[i];
1005 }
1006 }
1007
1008 if (index)
1009 *index = (float) _index;
1010
1011 return amp;
1012}
1013
dburgessb3a0ca42011-10-12 07:44:40 +00001014complex peakDetect(const signalVector &rxBurst,
1015 float *peakIndex,
1016 float *avgPwr)
1017{
1018
1019
1020 complex maxVal = 0.0;
1021 float maxIndex = -1;
1022 float sumPower = 0.0;
1023
1024 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1025 float samplePower = rxBurst[i].norm2();
1026 if (samplePower > maxVal.real()) {
1027 maxVal = samplePower;
1028 maxIndex = i;
1029 }
1030 sumPower += samplePower;
1031 }
1032
1033 // interpolate around the peak
1034 // to save computation, we'll use early-late balancing
1035 float earlyIndex = maxIndex-1;
1036 float lateIndex = maxIndex+1;
1037
1038 float incr = 0.5;
1039 while (incr > 1.0/1024.0) {
1040 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1041 complex lateP = interpolatePoint(rxBurst,lateIndex);
1042 if (earlyP < lateP)
1043 earlyIndex += incr;
1044 else if (earlyP > lateP)
1045 earlyIndex -= incr;
1046 else break;
1047 incr /= 2.0;
1048 lateIndex = earlyIndex + 2.0;
1049 }
1050
1051 maxIndex = earlyIndex + 1.0;
1052 maxVal = interpolatePoint(rxBurst,maxIndex);
1053
1054 if (peakIndex!=NULL)
1055 *peakIndex = maxIndex;
1056
1057 if (avgPwr!=NULL)
1058 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1059
1060 return maxVal;
1061
1062}
1063
1064void scaleVector(signalVector &x,
1065 complex scale)
1066{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001067#ifdef HAVE_NEON
1068 int len = x.size();
1069
1070 scale_complex((float *) x.begin(),
1071 (float *) x.begin(),
1072 (float *) &scale, len);
1073#else
dburgessb3a0ca42011-10-12 07:44:40 +00001074 signalVector::iterator xP = x.begin();
1075 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001076 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001077 while (xP < xPEnd) {
1078 *xP = *xP * scale;
1079 xP++;
1080 }
1081 }
1082 else {
1083 while (xP < xPEnd) {
1084 *xP = xP->real() * scale;
1085 xP++;
1086 }
1087 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001088#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001089}
1090
1091/** in-place conjugation */
1092void conjugateVector(signalVector &x)
1093{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001094 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001095 signalVector::iterator xP = x.begin();
1096 signalVector::iterator xPEnd = x.end();
1097 while (xP < xPEnd) {
1098 *xP = xP->conj();
1099 xP++;
1100 }
1101}
1102
1103
1104// in-place addition!!
1105bool addVector(signalVector &x,
1106 signalVector &y)
1107{
1108 signalVector::iterator xP = x.begin();
1109 signalVector::iterator yP = y.begin();
1110 signalVector::iterator xPEnd = x.end();
1111 signalVector::iterator yPEnd = y.end();
1112 while ((xP < xPEnd) && (yP < yPEnd)) {
1113 *xP = *xP + *yP;
1114 xP++; yP++;
1115 }
1116 return true;
1117}
1118
1119// in-place multiplication!!
1120bool multVector(signalVector &x,
1121 signalVector &y)
1122{
1123 signalVector::iterator xP = x.begin();
1124 signalVector::iterator yP = y.begin();
1125 signalVector::iterator xPEnd = x.end();
1126 signalVector::iterator yPEnd = y.end();
1127 while ((xP < xPEnd) && (yP < yPEnd)) {
1128 *xP = (*xP) * (*yP);
1129 xP++; yP++;
1130 }
1131 return true;
1132}
1133
1134
1135void offsetVector(signalVector &x,
1136 complex offset)
1137{
1138 signalVector::iterator xP = x.begin();
1139 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001140 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001141 while (xP < xPEnd) {
1142 *xP += offset;
1143 xP++;
1144 }
1145 }
1146 else {
1147 while (xP < xPEnd) {
1148 *xP = xP->real() + offset;
1149 xP++;
1150 }
1151 }
1152}
1153
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001154bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001155{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001156 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001157 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001158 complex *data = NULL;
1159 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001160 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001161
Thomas Tsou3eaae802013-08-20 19:31:14 -04001162 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001163 return false;
1164
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001165 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001166
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001167 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1168 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1169 if (!midMidamble)
1170 return false;
1171
Thomas Tsou3eaae802013-08-20 19:31:14 -04001172 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001173 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1174 if (!midamble) {
1175 status = false;
1176 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001177 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001178
dburgessb3a0ca42011-10-12 07:44:40 +00001179 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1180 // the ideal TSC has an + 180 degree phase shift,
1181 // due to the pi/2 frequency shift, that
1182 // needs to be accounted for.
1183 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001184 scaleVector(*midMidamble, complex(-1.0, 0.0));
1185 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001186
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001187 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001188
Thomas Tsou3eaae802013-08-20 19:31:14 -04001189 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1190 data = (complex *) convolve_h_alloc(midMidamble->size());
1191 _midMidamble = new signalVector(data, 0, midMidamble->size());
1192 _midMidamble->setAligned(true);
1193 memcpy(_midMidamble->begin(), midMidamble->begin(),
1194 midMidamble->size() * sizeof(complex));
1195
1196 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001197 if (!autocorr) {
1198 status = false;
1199 goto release;
1200 }
dburgessb3a0ca42011-10-12 07:44:40 +00001201
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001202 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001203 gMidambles[tsc]->buffer = data;
1204 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001205 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1206
1207 /* For 1 sps only
1208 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1209 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1210 */
1211 if (sps == 1)
1212 gMidambles[tsc]->toa = toa - 13.5;
1213 else
1214 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001215
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001216release:
dburgessb3a0ca42011-10-12 07:44:40 +00001217 delete autocorr;
1218 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001219 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001220
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001221 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001222 delete _midMidamble;
1223 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001224 gMidambles[tsc] = NULL;
1225 }
1226
1227 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001228}
1229
Thomas Tsou83e06892013-08-20 16:10:01 -04001230bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001231{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001232 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001233 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001234 complex *data = NULL;
1235 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001236 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001237
1238 delete gRACHSequence;
1239
1240 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1241 if (!seq0)
1242 return false;
1243
1244 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1245 if (!seq1) {
1246 status = false;
1247 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001248 }
1249
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001250 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001251
Thomas Tsou3eaae802013-08-20 19:31:14 -04001252 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1253 data = (complex *) convolve_h_alloc(seq1->size());
1254 _seq1 = new signalVector(data, 0, seq1->size());
1255 _seq1->setAligned(true);
1256 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1257
1258 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1259 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001260 status = false;
1261 goto release;
1262 }
dburgessb3a0ca42011-10-12 07:44:40 +00001263
1264 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001265 gRACHSequence->sequence = _seq1;
1266 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001267 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1268
1269 /* For 1 sps only
1270 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1271 * 20.5 = (40 / 2 - 1) + 1.5
1272 */
1273 if (sps == 1)
1274 gRACHSequence->toa = toa - 20.5;
1275 else
1276 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001277
1278release:
dburgessb3a0ca42011-10-12 07:44:40 +00001279 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001280 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001281 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001282
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001283 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001284 delete _seq1;
1285 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001286 gRACHSequence = NULL;
1287 }
dburgessb3a0ca42011-10-12 07:44:40 +00001288
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001289 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001290}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001291
Thomas Tsou865bca42013-08-21 20:58:00 -04001292static float computePeakRatio(signalVector *corr,
1293 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001294{
Thomas Tsou865bca42013-08-21 20:58:00 -04001295 int num = 0;
1296 complex *peak;
1297 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001298
Thomas Tsou865bca42013-08-21 20:58:00 -04001299 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001300
Thomas Tsou865bca42013-08-21 20:58:00 -04001301 /* Check for bogus results */
1302 if ((toa < 0.0) || (toa > corr->size()))
1303 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001304
Thomas Tsou3eaae802013-08-20 19:31:14 -04001305 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001306 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001307 avg += (peak - i)->norm2();
1308 num++;
1309 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001310 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001311 avg += (peak + i)->norm2();
1312 num++;
1313 }
dburgessb3a0ca42011-10-12 07:44:40 +00001314 }
1315
Thomas Tsou3eaae802013-08-20 19:31:14 -04001316 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001317 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001318
Thomas Tsou3eaae802013-08-20 19:31:14 -04001319 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001320
Thomas Tsou865bca42013-08-21 20:58:00 -04001321 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001322}
1323
1324bool energyDetect(signalVector &rxBurst,
1325 unsigned windowLength,
1326 float detectThreshold,
1327 float *avgPwr)
1328{
1329
1330 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1331 float energy = 0.0;
1332 if (windowLength < 0) windowLength = 20;
1333 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1334 for (unsigned i = 0; i < windowLength; i++) {
1335 energy += windowItr->norm2();
1336 windowItr+=4;
1337 }
1338 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001339 return (energy/windowLength > detectThreshold*detectThreshold);
1340}
dburgessb3a0ca42011-10-12 07:44:40 +00001341
Thomas Tsou865bca42013-08-21 20:58:00 -04001342/*
1343 * Detect a burst based on correlation and peak-to-average ratio
1344 *
1345 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1346 * for initial gating. We do this because energy detection should be disabled.
1347 * For higher oversampling values, we assume the energy detector is in place
1348 * and we run full interpolating peak detection.
1349 */
1350static int detectBurst(signalVector &burst,
1351 signalVector &corr, CorrelationSequence *sync,
1352 float thresh, int sps, complex *amp, float *toa,
1353 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001354{
Thomas Tsou865bca42013-08-21 20:58:00 -04001355 /* Correlate */
1356 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001357 CUSTOM, start, len, sps, 0)) {
1358 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001359 }
1360
Thomas Tsou865bca42013-08-21 20:58:00 -04001361 /* Peak detection - place restrictions at correlation edges */
1362 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001363
Thomas Tsou865bca42013-08-21 20:58:00 -04001364 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1365 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001366
Thomas Tsou865bca42013-08-21 20:58:00 -04001367 /* Peak -to-average ratio */
1368 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1369 return 0;
1370
1371 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1372 *amp = peakDetect(corr, toa, NULL);
1373
1374 /* Normalize our channel gain */
1375 *amp = *amp / sync->gain;
1376
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001377 /* Compenate for residual rotation with dual Laurent pulse */
1378 if (sps == 4)
1379 *amp = *amp * complex(0.0, 1.0);
1380
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001381 /* Compensate for residuate time lag */
1382 *toa = *toa - sync->toa;
1383
Thomas Tsou865bca42013-08-21 20:58:00 -04001384 return 1;
1385}
1386
1387/*
1388 * RACH burst detection
1389 *
1390 * Correlation window parameters:
1391 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001392 * head: Search 4 symbols before target
1393 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001394 */
1395int detectRACHBurst(signalVector &rxBurst,
1396 float thresh,
1397 int sps,
1398 complex *amp,
1399 float *toa)
1400{
1401 int rc, start, target, head, tail, len;
1402 float _toa;
1403 complex _amp;
1404 signalVector corr;
1405 CorrelationSequence *sync;
1406
1407 if ((sps != 1) && (sps != 4))
1408 return -1;
1409
1410 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001411 head = 4;
1412 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001413
1414 start = (target - head) * sps - 1;
1415 len = (head + tail) * sps;
1416 sync = gRACHSequence;
1417 corr = signalVector(len);
1418
1419 rc = detectBurst(rxBurst, corr, sync,
1420 thresh, sps, &_amp, &_toa, start, len);
1421 if (rc < 0) {
1422 return -1;
1423 } else if (!rc) {
1424 if (amp)
1425 *amp = 0.0f;
1426 if (toa)
1427 *toa = 0.0f;
1428 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001429 }
1430
Thomas Tsou865bca42013-08-21 20:58:00 -04001431 /* Subtract forward search bits from delay */
1432 if (toa)
1433 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001434 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001435 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001436
Thomas Tsou865bca42013-08-21 20:58:00 -04001437 return 1;
1438}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001439
Thomas Tsou865bca42013-08-21 20:58:00 -04001440/*
1441 * Normal burst detection
1442 *
1443 * Correlation window parameters:
1444 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001445 * head: Search 4 symbols before target
1446 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001447 */
1448int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1449 int sps, complex *amp, float *toa, unsigned max_toa,
1450 bool chan_req, signalVector **chan, float *chan_offset)
1451{
1452 int rc, start, target, head, tail, len;
1453 complex _amp;
1454 float _toa;
1455 signalVector corr;
1456 CorrelationSequence *sync;
1457
1458 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1459 return -1;
1460
1461 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001462 head = 4;
1463 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001464
1465 start = (target - head) * sps - 1;
1466 len = (head + tail) * sps;
1467 sync = gMidambles[tsc];
1468 corr = signalVector(len);
1469
1470 rc = detectBurst(rxBurst, corr, sync,
1471 thresh, sps, &_amp, &_toa, start, len);
1472 if (rc < 0) {
1473 return -1;
1474 } else if (!rc) {
1475 if (amp)
1476 *amp = 0.0f;
1477 if (toa)
1478 *toa = 0.0f;
1479 return 0;
1480 }
1481
1482 /* Subtract forward search bits from delay */
1483 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001484 if (toa)
1485 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001486 if (amp)
1487 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001488
Thomas Tsou865bca42013-08-21 20:58:00 -04001489 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001490 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001491 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001492
1493 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001494 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001495 }
1496
Thomas Tsou3eaae802013-08-20 19:31:14 -04001497 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001498}
1499
Thomas Tsou94edaae2013-11-09 22:19:19 -05001500signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001501{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001502 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001503
Thomas Tsou94edaae2013-11-09 22:19:19 -05001504 if (factor <= 1)
1505 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001506
Thomas Tsou94edaae2013-11-09 22:19:19 -05001507 dec = new signalVector(wVector.size() / factor);
1508 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001509
Thomas Tsou94edaae2013-11-09 22:19:19 -05001510 signalVector::iterator itr = dec->begin();
1511 for (size_t i = 0; i < wVector.size(); i += factor)
1512 *itr++ = wVector[i];
1513
1514 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001515}
1516
Thomas Tsou83e06892013-08-20 16:10:01 -04001517SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05001518 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001519{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001520 signalVector *delay, *dec = NULL;
1521 SoftVector *bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001522
Thomas Tsou94edaae2013-11-09 22:19:19 -05001523 scaleVector(rxBurst, ((complex) 1.0) / channel);
1524 delay = delayVector(&rxBurst, NULL, -TOA);
dburgessb3a0ca42011-10-12 07:44:40 +00001525
Thomas Tsou94edaae2013-11-09 22:19:19 -05001526 /* Shift up by a quarter of a frequency */
1527 GMSKReverseRotate(*delay, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001528
Thomas Tsou94edaae2013-11-09 22:19:19 -05001529 /* Decimate and slice */
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001530 if (sps > 1) {
Thomas Tsou94edaae2013-11-09 22:19:19 -05001531 dec = decimateVector(*delay, sps);
1532 delete delay;
1533 delay = NULL;
1534 } else {
1535 dec = delay;
dburgessb3a0ca42011-10-12 07:44:40 +00001536 }
1537
Thomas Tsou94edaae2013-11-09 22:19:19 -05001538 vectorSlicer(dec);
dburgessb3a0ca42011-10-12 07:44:40 +00001539
Thomas Tsou94edaae2013-11-09 22:19:19 -05001540 bits = new SoftVector(dec->size());
dburgessb3a0ca42011-10-12 07:44:40 +00001541
Thomas Tsou94edaae2013-11-09 22:19:19 -05001542 SoftVector::iterator bit_itr = bits->begin();
1543 signalVector::iterator burst_itr = dec->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001544
Thomas Tsou94edaae2013-11-09 22:19:19 -05001545 for (; burst_itr < dec->end(); burst_itr++)
1546 *bit_itr++ = burst_itr->real();
dburgessb3a0ca42011-10-12 07:44:40 +00001547
Thomas Tsou94edaae2013-11-09 22:19:19 -05001548 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001549
Thomas Tsou94edaae2013-11-09 22:19:19 -05001550 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001551}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001552
dburgessb3a0ca42011-10-12 07:44:40 +00001553// Assumes symbol-spaced sampling!!!
1554// Based upon paper by Al-Dhahir and Cioffi
1555bool designDFE(signalVector &channelResponse,
1556 float SNRestimate,
1557 int Nf,
1558 signalVector **feedForwardFilter,
1559 signalVector **feedbackFilter)
1560{
1561
1562 signalVector G0(Nf);
1563 signalVector G1(Nf);
1564 signalVector::iterator G0ptr = G0.begin();
1565 signalVector::iterator G1ptr = G1.begin();
1566 signalVector::iterator chanPtr = channelResponse.begin();
1567
1568 int nu = channelResponse.size()-1;
1569
1570 *G0ptr = 1.0/sqrtf(SNRestimate);
1571 for(int j = 0; j <= nu; j++) {
1572 *G1ptr = chanPtr->conj();
1573 G1ptr++; chanPtr++;
1574 }
1575
1576 signalVector *L[Nf];
1577 signalVector::iterator Lptr;
1578 float d;
1579 for(int i = 0; i < Nf; i++) {
1580 d = G0.begin()->norm2() + G1.begin()->norm2();
1581 L[i] = new signalVector(Nf+nu);
1582 Lptr = L[i]->begin()+i;
1583 G0ptr = G0.begin(); G1ptr = G1.begin();
1584 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1585 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1586 Lptr++;
1587 G0ptr++;
1588 G1ptr++;
1589 }
1590 complex k = (*G1.begin())/(*G0.begin());
1591
1592 if (i != Nf-1) {
1593 signalVector G0new = G1;
1594 scaleVector(G0new,k.conj());
1595 addVector(G0new,G0);
1596
1597 signalVector G1new = G0;
1598 scaleVector(G1new,k*(-1.0));
1599 addVector(G1new,G1);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001600 delayVector(&G1new, &G1new, -1.0);
dburgessb3a0ca42011-10-12 07:44:40 +00001601
1602 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1603 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1604 G0 = G0new;
1605 G1 = G1new;
1606 }
1607 }
1608
1609 *feedbackFilter = new signalVector(nu);
1610 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1611 scaleVector(**feedbackFilter,(complex) -1.0);
1612 conjugateVector(**feedbackFilter);
1613
1614 signalVector v(Nf);
1615 signalVector::iterator vStart = v.begin();
1616 signalVector::iterator vPtr;
1617 *(vStart+Nf-1) = (complex) 1.0;
1618 for(int k = Nf-2; k >= 0; k--) {
1619 Lptr = L[k]->begin()+k+1;
1620 vPtr = vStart + k+1;
1621 complex v_k = 0.0;
1622 for (int j = k+1; j < Nf; j++) {
1623 v_k -= (*vPtr)*(*Lptr);
1624 vPtr++; Lptr++;
1625 }
1626 *(vStart + k) = v_k;
1627 }
1628
1629 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001630 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001631 for (int i = 0; i < Nf; i++) {
1632 delete L[i];
1633 complex w_i = 0.0;
1634 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1635 vPtr = vStart+i;
1636 chanPtr = channelResponse.begin();
1637 for (int k = 0; k < endPt+1; k++) {
1638 w_i += (*vPtr)*(chanPtr->conj());
1639 vPtr++; chanPtr++;
1640 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001641 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001642 }
1643
1644
1645 return true;
1646
1647}
1648
1649// Assumes symbol-rate sampling!!!!
1650SoftVector *equalizeBurst(signalVector &rxBurst,
1651 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001652 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001653 signalVector &w, // feedforward filter
1654 signalVector &b) // feedback filter
1655{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001656 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001657
Thomas Tsou94edaae2013-11-09 22:19:19 -05001658 if (!delayVector(&rxBurst, &rxBurst, -TOA))
Thomas Tsou3eaae802013-08-20 19:31:14 -04001659 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001660
Thomas Tsou3eaae802013-08-20 19:31:14 -04001661 postForwardFull = convolve(&rxBurst, &w, NULL,
1662 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1663 if (!postForwardFull)
1664 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001665
1666 signalVector* postForward = new signalVector(rxBurst.size());
1667 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1668 delete postForwardFull;
1669
1670 signalVector::iterator dPtr = postForward->begin();
1671 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001672 signalVector::iterator rotPtr = GMSKRotationN->begin();
1673 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001674
1675 signalVector *DFEoutput = new signalVector(postForward->size());
1676 signalVector::iterator DFEItr = DFEoutput->begin();
1677
1678 // NOTE: can insert the midamble and/or use midamble to estimate BER
1679 for (; dPtr < postForward->end(); dPtr++) {
1680 dBackPtr = dPtr-1;
1681 signalVector::iterator bPtr = b.begin();
1682 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1683 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1684 bPtr++;
1685 dBackPtr--;
1686 }
1687 *dPtr = *dPtr * (*revRotPtr);
1688 *DFEItr = *dPtr;
1689 // make decision on symbol
1690 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1691 //*DFEItr = *dPtr;
1692 *dPtr = *dPtr * (*rotPtr);
1693 DFEItr++;
1694 rotPtr++;
1695 revRotPtr++;
1696 }
1697
1698 vectorSlicer(DFEoutput);
1699
1700 SoftVector *burstBits = new SoftVector(postForward->size());
1701 SoftVector::iterator burstItr = burstBits->begin();
1702 DFEItr = DFEoutput->begin();
1703 for (; DFEItr < DFEoutput->end(); DFEItr++)
1704 *burstItr++ = DFEItr->real();
1705
1706 delete postForward;
1707
1708 delete DFEoutput;
1709
1710 return burstBits;
1711}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001712
1713bool sigProcLibSetup(int sps)
1714{
1715 if ((sps != 1) && (sps != 4))
1716 return false;
1717
1718 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001719 generateSincTable();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001720 initGMSKRotationTables(sps);
1721
1722 GSMPulse1 = generateGSMPulse(1, 2);
1723 if (sps > 1)
1724 GSMPulse = generateGSMPulse(sps, 2);
1725
1726 if (!generateRACHSequence(1)) {
1727 sigProcLibDestroy();
1728 return false;
1729 }
1730
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001731 generateDelayFilters();
1732
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001733 return true;
1734}