blob: fd59e0003134dc613861782f1738c3e9612e7791 [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
Tom Tsou577cd022015-05-18 13:57:54 -070043/* Clipping detection threshold */
44#define CLIP_THRESH 30000.0f
45
dburgessb3a0ca42011-10-12 07:44:40 +000046/** Lookup tables for trigonometric approximation */
Tom Tsoue11ef4d2015-06-29 19:27:35 -070047double cosTable[TABLESIZE+1]; // add 1 element for wrap around
48double sinTable[TABLESIZE+1];
49double sincTable[TABLESIZE+1];
dburgessb3a0ca42011-10-12 07:44:40 +000050
51/** Constants */
Tom Tsoue11ef4d2015-06-29 19:27:35 -070052static const double M_PI_F = M_PI;
53static const double M_2PI_F = (2.0 * M_PI);
54static const double M_1_2PI_F = (1.0 / M_2PI_F);
dburgessb3a0ca42011-10-12 07:44:40 +000055
Thomas Tsouc1f7c422013-10-11 13:49:55 -040056/* Precomputed rotation vectors */
57static signalVector *GMSKRotationN = NULL;
58static signalVector *GMSKReverseRotationN = NULL;
59static signalVector *GMSKRotation1 = NULL;
60static signalVector *GMSKReverseRotation1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000061
Thomas Tsouf79c4d02013-11-09 15:51:56 -060062/* Precomputed fractional delay filters */
63static signalVector *delayFilters[DELAYFILTS];
64
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040065/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040066 * RACH and midamble correlation waveforms. Store the buffer separately
67 * because we need to allocate it explicitly outside of the signal vector
68 * constructor. This is because C++ (prior to C++11) is unable to natively
69 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040070 */
71struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040072 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040073 {
74 }
75
76 ~CorrelationSequence()
77 {
78 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040079 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040080 }
81
dburgessb3a0ca42011-10-12 07:44:40 +000082 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040083 void *buffer;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040084 float toa;
dburgessb3a0ca42011-10-12 07:44:40 +000085 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040086};
dburgessb3a0ca42011-10-12 07:44:40 +000087
Thomas Tsou83e06892013-08-20 16:10:01 -040088/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040089 * Gaussian and empty modulation pulses. Like the correlation sequences,
90 * store the runtime (Gaussian) buffer separately because of needed alignment
91 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -040092 */
93struct PulseSequence {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080094 PulseSequence() : c0(NULL), c1(NULL), empty(NULL),
95 c0_buffer(NULL), c1_buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -040096 {
97 }
98
99 ~PulseSequence()
100 {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800101 delete c0;
102 delete c1;
Thomas Tsou83e06892013-08-20 16:10:01 -0400103 delete empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800104 free(c0_buffer);
105 free(c1_buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -0400106 }
107
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800108 signalVector *c0;
109 signalVector *c1;
Thomas Tsou83e06892013-08-20 16:10:01 -0400110 signalVector *empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800111 void *c0_buffer;
112 void *c1_buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -0400113};
114
dburgessb3a0ca42011-10-12 07:44:40 +0000115CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
116CorrelationSequence *gRACHSequence = NULL;
Thomas Tsou83e06892013-08-20 16:10:01 -0400117PulseSequence *GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400118PulseSequence *GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000119
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400120void sigProcLibDestroy()
121{
dburgessb3a0ca42011-10-12 07:44:40 +0000122 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400123 delete gMidambles[i];
124 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000125 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400126
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600127 for (int i = 0; i < DELAYFILTS; i++) {
128 delete delayFilters[i];
129 delayFilters[i] = NULL;
130 }
131
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400132 delete GMSKRotationN;
133 delete GMSKReverseRotationN;
134 delete GMSKRotation1;
135 delete GMSKReverseRotation1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400136 delete gRACHSequence;
137 delete GSMPulse;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400138 delete GSMPulse1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400139
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400140 GMSKRotationN = NULL;
141 GMSKRotation1 = NULL;
142 GMSKReverseRotationN = NULL;
143 GMSKReverseRotation1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400144 gRACHSequence = NULL;
145 GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400146 GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000147}
148
dburgessb3a0ca42011-10-12 07:44:40 +0000149// dB relative to 1.0.
150// if > 1.0, then return 0 dB
151float dB(float x) {
152
153 float arg = 1.0F;
154 float dB = 0.0F;
155
156 if (x >= 1.0F) return 0.0F;
157 if (x <= 0.0F) return -200.0F;
158
159 float prevArg = arg;
160 float prevdB = dB;
161 float stepSize = 16.0F;
162 float dBstepSize = 12.0F;
163 while (stepSize > 1.0F) {
164 do {
165 prevArg = arg;
166 prevdB = dB;
167 arg /= stepSize;
168 dB -= dBstepSize;
169 } while (arg > x);
170 arg = prevArg;
171 dB = prevdB;
172 stepSize *= 0.5F;
173 dBstepSize -= 3.0F;
174 }
175 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
176
177}
178
179// 10^(-dB/10), inverse of dB func.
180float dBinv(float x) {
181
182 float arg = 1.0F;
183 float dB = 0.0F;
184
185 if (x >= 0.0F) return 1.0F;
186 if (x <= -200.0F) return 0.0F;
187
188 float prevArg = arg;
189 float prevdB = dB;
190 float stepSize = 16.0F;
191 float dBstepSize = 12.0F;
192 while (stepSize > 1.0F) {
193 do {
194 prevArg = arg;
195 prevdB = dB;
196 arg /= stepSize;
197 dB -= dBstepSize;
198 } while (dB > x);
199 arg = prevArg;
200 dB = prevdB;
201 stepSize *= 0.5F;
202 dBstepSize -= 3.0F;
203 }
204
205 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
206
207}
208
209float vectorNorm2(const signalVector &x)
210{
211 signalVector::const_iterator xPtr = x.begin();
212 float Energy = 0.0;
213 for (;xPtr != x.end();xPtr++) {
214 Energy += xPtr->norm2();
215 }
216 return Energy;
217}
218
219
220float vectorPower(const signalVector &x)
221{
222 return vectorNorm2(x)/x.size();
223}
224
225/** compute cosine via lookup table */
226float cosLookup(const float x)
227{
228 float arg = x*M_1_2PI_F;
229 while (arg > 1.0F) arg -= 1.0F;
230 while (arg < 0.0F) arg += 1.0F;
231
232 const float argT = arg*((float)TABLESIZE);
233 const int argI = (int)argT;
234 const float delta = argT-argI;
235 const float iDelta = 1.0F-delta;
236 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
237}
238
239/** compute sine via lookup table */
240float sinLookup(const float x)
241{
242 float arg = x*M_1_2PI_F;
243 while (arg > 1.0F) arg -= 1.0F;
244 while (arg < 0.0F) arg += 1.0F;
245
246 const float argT = arg*((float)TABLESIZE);
247 const int argI = (int)argT;
248 const float delta = argT-argI;
249 const float iDelta = 1.0F-delta;
250 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
251}
252
253
254/** compute e^(-jx) via lookup table. */
255complex expjLookup(float x)
256{
257 float arg = x*M_1_2PI_F;
258 while (arg > 1.0F) arg -= 1.0F;
259 while (arg < 0.0F) arg += 1.0F;
260
261 const float argT = arg*((float)TABLESIZE);
262 const int argI = (int)argT;
263 const float delta = argT-argI;
264 const float iDelta = 1.0F-delta;
265 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
266 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
267}
268
269/** Library setup functions */
270void initTrigTables() {
271 for (int i = 0; i < TABLESIZE+1; i++) {
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700272 cosTable[i] = cos(2.0 * M_PI * (double) i / TABLESIZE);
273 sinTable[i] = sin(2.0 * M_PI * (double) i / TABLESIZE);
dburgessb3a0ca42011-10-12 07:44:40 +0000274 }
275}
276
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400277void initGMSKRotationTables(int sps)
278{
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400279 GMSKRotationN = new signalVector(157 * sps);
280 GMSKReverseRotationN = new signalVector(157 * sps);
281 signalVector::iterator rotPtr = GMSKRotationN->begin();
282 signalVector::iterator revPtr = GMSKReverseRotationN->begin();
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700283 double phase = 0.0;
284
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400285 while (rotPtr != GMSKRotationN->end()) {
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700286 *rotPtr++ = complex(cos(phase), sin(phase));
287 *revPtr++ = complex(cos(-phase), sin(-phase));
288 phase += M_PI_F / 8.0;
289
dburgessb3a0ca42011-10-12 07:44:40 +0000290 }
dburgessb3a0ca42011-10-12 07:44:40 +0000291
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400292 GMSKRotation1 = new signalVector(157);
293 GMSKReverseRotation1 = new signalVector(157);
294 rotPtr = GMSKRotation1->begin();
295 revPtr = GMSKReverseRotation1->begin();
296 phase = 0.0;
297 while (rotPtr != GMSKRotation1->end()) {
298 *rotPtr++ = expjLookup(phase);
299 *revPtr++ = expjLookup(-phase);
300 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400301 }
dburgessb3a0ca42011-10-12 07:44:40 +0000302}
303
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400304static void GMSKRotate(signalVector &x, int sps)
305{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500306#if HAVE_NEON
307 size_t len;
308 signalVector *a, *b, *out;
309
310 a = &x;
311 out = &x;
312 len = out->size();
313
314 if (len == 157)
315 len--;
316
317 if (sps == 1)
318 b = GMSKRotation1;
319 else
320 b = GMSKRotationN;
321
322 mul_complex((float *) out->begin(),
323 (float *) a->begin(),
324 (float *) b->begin(), len);
325#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400326 signalVector::iterator rotPtr, xPtr = x.begin();
327
328 if (sps == 1)
329 rotPtr = GMSKRotation1->begin();
330 else
331 rotPtr = GMSKRotationN->begin();
332
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500333 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000334 while (xPtr < x.end()) {
335 *xPtr = *rotPtr++ * (xPtr->real());
336 xPtr++;
337 }
338 }
339 else {
340 while (xPtr < x.end()) {
341 *xPtr = *rotPtr++ * (*xPtr);
342 xPtr++;
343 }
344 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500345#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000346}
347
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400348static void GMSKReverseRotate(signalVector &x, int sps)
349{
350 signalVector::iterator rotPtr, xPtr= x.begin();
351
352 if (sps == 1)
353 rotPtr = GMSKReverseRotation1->begin();
354 else
355 rotPtr = GMSKReverseRotationN->begin();
356
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500357 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000358 while (xPtr < x.end()) {
359 *xPtr = *rotPtr++ * (xPtr->real());
360 xPtr++;
361 }
362 }
363 else {
364 while (xPtr < x.end()) {
365 *xPtr = *rotPtr++ * (*xPtr);
366 xPtr++;
367 }
368 }
369}
370
Thomas Tsou3eaae802013-08-20 19:31:14 -0400371signalVector *convolve(const signalVector *x,
372 const signalVector *h,
373 signalVector *y,
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500374 ConvType spanType, size_t start,
375 size_t len, size_t step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000376{
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500377 int rc;
378 size_t head = 0, tail = 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400379 bool alloc = false, append = false;
380 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000381
Thomas Tsou3eaae802013-08-20 19:31:14 -0400382 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000383 return NULL;
384
Thomas Tsou3eaae802013-08-20 19:31:14 -0400385 switch (spanType) {
386 case START_ONLY:
387 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500388 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400389 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500390
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500391 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500392 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000393 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400394 case NO_DELAY:
395 start = h->size() / 2;
396 head = start;
397 tail = start;
398 len = x->size();
399 append = true;
400 break;
401 case CUSTOM:
402 if (start < h->size() - 1) {
403 head = h->size() - start;
404 append = true;
405 }
406 if (start + len > x->size()) {
407 tail = start + len - x->size();
408 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000409 }
410 break;
411 default:
412 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000413 }
dburgessb3a0ca42011-10-12 07:44:40 +0000414
Thomas Tsou3eaae802013-08-20 19:31:14 -0400415 /*
416 * Error if the output vector is too small. Create the output vector
417 * if the pointer is NULL.
418 */
419 if (y && (len > y->size()))
420 return NULL;
421 if (!y) {
422 y = new signalVector(len);
423 alloc = true;
424 }
425
426 /* Prepend or post-pend the input vector if the parameters require it */
427 if (append)
428 _x = new signalVector(*x, head, tail);
429 else
430 _x = x;
431
432 /*
433 * Four convovle types:
434 * 1. Complex-Real (aligned)
435 * 2. Complex-Complex (aligned)
436 * 3. Complex-Real (!aligned)
437 * 4. Complex-Complex (!aligned)
438 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500439 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400440 rc = convolve_real((float *) _x->begin(), _x->size(),
441 (float *) h->begin(), h->size(),
442 (float *) y->begin(), y->size(),
443 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500444 } else if (!h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400445 rc = convolve_complex((float *) _x->begin(), _x->size(),
446 (float *) h->begin(), h->size(),
447 (float *) y->begin(), y->size(),
448 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500449 } else if (h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400450 rc = base_convolve_real((float *) _x->begin(), _x->size(),
451 (float *) h->begin(), h->size(),
452 (float *) y->begin(), y->size(),
453 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500454 } else if (!h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400455 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
456 (float *) h->begin(), h->size(),
457 (float *) y->begin(), y->size(),
458 start, len, step, offset);
459 } else {
460 rc = -1;
461 }
462
463 if (append)
464 delete _x;
465
466 if (rc < 0) {
467 if (alloc)
468 delete y;
469 return NULL;
470 }
471
472 return y;
473}
dburgessb3a0ca42011-10-12 07:44:40 +0000474
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400475static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800476{
477 int len;
478
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400479 if (!pulse)
480 return false;
481
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800482 switch (sps) {
483 case 4:
484 len = 8;
485 break;
486 default:
487 return false;
488 }
489
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400490 pulse->c1_buffer = convolve_h_alloc(len);
491 pulse->c1 = new signalVector((complex *)
492 pulse->c1_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500493 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800494
495 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400496 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800497
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400498 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800499
500 switch (sps) {
501 case 4:
502 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400503 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800504 *xP++ = 8.16373112e-03;
505 *xP++ = 2.84385729e-02;
506 *xP++ = 5.64158904e-02;
507 *xP++ = 7.05463553e-02;
508 *xP++ = 5.64158904e-02;
509 *xP++ = 2.84385729e-02;
510 *xP++ = 8.16373112e-03;
511 }
512
513 return true;
514}
515
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400516static PulseSequence *generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000517{
Thomas Tsou83e06892013-08-20 16:10:01 -0400518 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800519 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400520 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400521
522 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400523 pulse = new PulseSequence();
524 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500525 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400526 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400527
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400528 /*
529 * For 4 samples-per-symbol use a precomputed single pulse Laurent
530 * approximation. This should yields below 2 degrees of phase error at
531 * the modulator output. Use the existing pulse approximation for all
532 * other oversampling factors.
533 */
534 switch (sps) {
535 case 4:
536 len = 16;
537 break;
538 default:
539 len = sps * symbolLength;
540 if (len < 4)
541 len = 4;
542 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400543
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400544 pulse->c0_buffer = convolve_h_alloc(len);
545 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500546 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400547
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800548 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400549 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800550
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400551 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400552
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400553 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800554 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400555 *xP++ = 4.46348606e-03;
556 *xP++ = 2.84385729e-02;
557 *xP++ = 1.03184855e-01;
558 *xP++ = 2.56065552e-01;
559 *xP++ = 4.76375085e-01;
560 *xP++ = 7.05961177e-01;
561 *xP++ = 8.71291644e-01;
562 *xP++ = 9.29453645e-01;
563 *xP++ = 8.71291644e-01;
564 *xP++ = 7.05961177e-01;
565 *xP++ = 4.76375085e-01;
566 *xP++ = 2.56065552e-01;
567 *xP++ = 1.03184855e-01;
568 *xP++ = 2.84385729e-02;
569 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400570 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400571 } else {
572 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400573
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400574 /* GSM pulse approximation */
575 for (int i = 0; i < len; i++) {
576 arg = ((float) i - center) / (float) sps;
577 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
578 0.527 * arg * arg * arg * arg);
579 }
dburgessb3a0ca42011-10-12 07:44:40 +0000580
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400581 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
582 xP = pulse->c0->begin();
583 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800584 *xP++ /= avg;
585 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400586
587 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000588}
589
590signalVector* frequencyShift(signalVector *y,
591 signalVector *x,
592 float freq,
593 float startPhase,
594 float *finalPhase)
595{
596
597 if (!x) return NULL;
598
599 if (y==NULL) {
600 y = new signalVector(x->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500601 y->isReal(x->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000602 if (y==NULL) return NULL;
603 }
604
605 if (y->size() < x->size()) return NULL;
606
607 float phase = startPhase;
608 signalVector::iterator yP = y->begin();
609 signalVector::iterator xPEnd = x->end();
610 signalVector::iterator xP = x->begin();
611
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500612 if (x->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000613 while (xP < xPEnd) {
614 (*yP++) = expjLookup(phase)*( (xP++)->real() );
615 phase += freq;
616 }
617 }
618 else {
619 while (xP < xPEnd) {
620 (*yP++) = (*xP++)*expjLookup(phase);
621 phase += freq;
Thomas Tsou34bbef72013-11-13 22:58:15 -0500622 if (phase > 2 * M_PI)
623 phase -= 2 * M_PI;
624 else if (phase < -2 * M_PI)
625 phase += 2 * M_PI;
dburgessb3a0ca42011-10-12 07:44:40 +0000626 }
627 }
628
629
630 if (finalPhase) *finalPhase = phase;
631
632 return y;
633}
634
635signalVector* reverseConjugate(signalVector *b)
636{
637 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500638 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000639 signalVector::iterator bP = b->begin();
640 signalVector::iterator bPEnd = b->end();
641 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500642 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000643 while (bP < bPEnd) {
644 *tmpP-- = bP->conj();
645 bP++;
646 }
647 }
648 else {
649 while (bP < bPEnd) {
650 *tmpP-- = bP->real();
651 bP++;
652 }
653 }
654
655 return tmp;
656}
657
dburgessb3a0ca42011-10-12 07:44:40 +0000658/* soft output slicer */
659bool vectorSlicer(signalVector *x)
660{
661
662 signalVector::iterator xP = x->begin();
663 signalVector::iterator xPEnd = x->end();
664 while (xP < xPEnd) {
665 *xP = (complex) (0.5*(xP->real()+1.0F));
666 if (xP->real() > 1.0) *xP = 1.0;
667 if (xP->real() < 0.0) *xP = 0.0;
668 xP++;
669 }
670 return true;
671}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400672
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800673static signalVector *rotateBurst(const BitVector &wBurst,
674 int guardPeriodLength, int sps)
675{
676 int burst_len;
677 signalVector *pulse, rotated, *shaped;
678 signalVector::iterator itr;
679
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400680 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800681 burst_len = sps * (wBurst.size() + guardPeriodLength);
682 rotated = signalVector(burst_len);
683 itr = rotated.begin();
684
685 for (unsigned i = 0; i < wBurst.size(); i++) {
686 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
687 itr += sps;
688 }
689
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400690 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500691 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800692
693 /* Dummy filter operation */
694 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
695 if (!shaped)
696 return NULL;
697
698 return shaped;
699}
700
701static signalVector *modulateBurstLaurent(const BitVector &bits,
702 int guard_len, int sps)
703{
704 int burst_len;
705 float phase;
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700706 signalVector *c0_pulse, *c1_pulse, *c0_burst, *c2_burst;
707 signalVector *c1_burst, *c0_shaped, *c1_shaped, *c2_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800708 signalVector::iterator c0_itr, c1_itr;
709
710 /*
711 * Apply before and after bits to reduce phase error at burst edges.
712 * Make sure there is enough room in the burst to accomodate all bits.
713 */
714 if (guard_len < 4)
715 guard_len = 4;
716
717 c0_pulse = GSMPulse->c0;
718 c1_pulse = GSMPulse->c1;
719
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700720 int i = 0, head = 4, tail = 4;
721 BitVector _bits = BitVector(148 + head + tail);
722
723 for (; i < head; i++)
724 _bits[i] = 1;
725 for (; i < 148 + head; i++)
726 _bits[i] = bits[i - head];
727 for (; i < 148 + head + tail; i++)
728 _bits[i] = 1;
729
730 burst_len = 625 + (head + tail) * sps;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800731
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500732 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500733 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500734 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800735
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500736 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500737 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500738 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800739
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700740 c2_burst = new signalVector(625, c0_pulse->size());
741 c2_burst->isReal(false);
742
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800743 /* Padded differential start bits */
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700744 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800745 c0_itr += sps;
746
747 /* Main burst bits */
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700748 for (unsigned i = 0; i < _bits.size(); i++) {
749 *c0_itr = 2.0 * (_bits[i] & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800750 c0_itr += sps;
751 }
752
753 /* Padded differential end bits */
754 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
755
756 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500757 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500758 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800759
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500760 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800761 c0_itr += sps * 2;
762 c1_itr += sps * 2;
763
764 /* Start magic */
765 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
766 *c1_itr = *c0_itr * Complex<float>(0, phase);
767 c0_itr += sps;
768 c1_itr += sps;
769
770 /* Generate C1 phase coefficients */
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700771 for (unsigned i = 2; i < _bits.size(); i++) {
772 phase = 2.0 * ((_bits[i - 1] & 0x01) ^ (_bits[i - 2] & 0x01)) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800773 *c1_itr = *c0_itr * Complex<float>(0, phase);
774
775 c0_itr += sps;
776 c1_itr += sps;
777 }
778
779 /* End magic */
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700780 i = _bits.size();
781 phase = 2.0 * ((_bits[i-1] & 0x01) ^ (_bits[i-2] & 0x01)) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800782 *c1_itr = *c0_itr * Complex<float>(0, phase);
783
784 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500785 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
786 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700787 c2_shaped = new signalVector(625);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800788
789 /* Sum shaped outputs into C0 */
790 c0_itr = c0_shaped->begin();
791 c1_itr = c1_shaped->begin();
792 for (unsigned i = 0; i < c0_shaped->size(); i++ )
793 *c0_itr++ += *c1_itr++;
794
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700795 /*
796 * Generate shaping mask with squared-cosine pulse. Only 4 samples-per-symbol
797 * is supported here so use length of 8 samples or 2 symbols.
798 */
799 int len = 8;
800 float mask[len];
801 for (i = 0; i < len; i++)
802 mask[i] = 0.5 * (1.0 - cos(M_PI * (float) i / len));
803
804 /*
805 * Ramp-up mask components:
806 * C0 filter group delay is 7.5 samples
807 * Subtract added head bits
808 * Subtract length of shaping mask
809 * Delay ramp by 1 sample
810 */
811 i = 0;
812 int start = 8 + head * sps - len + 1;
813 for (;i < len; i++)
814 c2_shaped->begin()[i] = mask[i] * c0_shaped->begin()[start + i];
815
816 for (; i < 625; i++)
817 c2_shaped->begin()[i] = c0_shaped->begin()[start + i];
818
819 /*
820 * Ramp-down mask components:
821 * Length of ramp-up mask
822 * 148 useful bits
823 */
824 int j;
825 int end = len + 148 * sps;
826 for (i = end, j = 0; i < end + len; i++, j++)
827 c2_shaped->begin()[i] *= mask[len - j - 1];
828 for (; i < 625; i++)
829 c2_shaped->begin()[i] = 0;
830
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500831 delete c0_burst;
832 delete c1_burst;
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700833 delete c0_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800834 delete c1_shaped;
835
Tom Tsoue11ef4d2015-06-29 19:27:35 -0700836 return c2_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800837}
838
839static signalVector *modulateBurstBasic(const BitVector &bits,
840 int guard_len, int sps)
841{
842 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500843 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800844 signalVector::iterator burst_itr;
845
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400846 if (sps == 1)
847 pulse = GSMPulse1->c0;
848 else
849 pulse = GSMPulse->c0;
850
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800851 burst_len = sps * (bits.size() + guard_len);
852
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500853 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500854 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500855 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800856
857 /* Raw bits are not differentially encoded */
858 for (unsigned i = 0; i < bits.size(); i++) {
859 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
860 burst_itr += sps;
861 }
862
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500863 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500864 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800865
866 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500867 shaped = convolve(burst, pulse, NULL, START_ONLY);
868
869 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800870
871 return shaped;
872}
873
Thomas Tsou3eaae802013-08-20 19:31:14 -0400874/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400875signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
876 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000877{
Thomas Tsou83e06892013-08-20 16:10:01 -0400878 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800879 return rotateBurst(wBurst, guardPeriodLength, sps);
880 else if (sps == 4)
881 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400882 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800883 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000884}
885
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500886void generateSincTable()
887{
888 float x;
889
890 for (int i = 0; i < TABLESIZE; i++) {
891 x = (float) i / TABLESIZE * 8 * M_PI;
892 if (fabs(x) < 0.01) {
893 sincTable[i] = 1.0f;
894 continue;
895 }
896
897 sincTable[i] = sinf(x) / x;
898 }
899}
900
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800901float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000902{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500903 if (fabs(x) >= 8 * M_PI)
904 return 0.0;
905
906 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
907
908 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +0000909}
910
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600911/*
912 * Create fractional delay filterbank with Blackman-harris windowed
913 * sinc function generator. The number of filters generated is specified
914 * by the DELAYFILTS value.
915 */
916void generateDelayFilters()
917{
918 int h_len = 20;
919 complex *data;
920 signalVector *h;
921 signalVector::iterator itr;
922
923 float k, sum;
924 float a0 = 0.35875;
925 float a1 = 0.48829;
926 float a2 = 0.14128;
927 float a3 = 0.01168;
928
929 for (int i = 0; i < DELAYFILTS; i++) {
930 data = (complex *) convolve_h_alloc(h_len);
931 h = new signalVector(data, 0, h_len);
932 h->setAligned(true);
933 h->isReal(true);
934
935 sum = 0.0;
936 itr = h->end();
937 for (int n = 0; n < h_len; n++) {
938 k = (float) n;
939 *--itr = (complex) sinc(M_PI_F *
940 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
941 *itr *= a0 -
942 a1 * cos(2 * M_PI * n / (h_len - 1)) +
943 a2 * cos(4 * M_PI * n / (h_len - 1)) -
944 a3 * cos(6 * M_PI * n / (h_len - 1));
945
946 sum += itr->real();
947 }
948
949 itr = h->begin();
950 for (int n = 0; n < h_len; n++)
951 *itr++ /= sum;
952
953 delayFilters[i] = h;
954 }
955}
956
Thomas Tsou94edaae2013-11-09 22:19:19 -0500957signalVector *delayVector(signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000958{
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600959 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400960 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500961 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400962
Thomas Tsou2c282f52013-10-08 21:34:35 -0400963 whole = floor(delay);
964 frac = delay - whole;
965
966 /* Sinc interpolated fractional shift (if allowable) */
967 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600968 index = floorf(frac * (float) DELAYFILTS);
969 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -0400970
Thomas Tsou94edaae2013-11-09 22:19:19 -0500971 fshift = convolve(in, h, NULL, NO_DELAY);
972 if (!fshift)
973 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000974 }
975
Thomas Tsou94edaae2013-11-09 22:19:19 -0500976 if (!fshift)
977 shift = new signalVector(*in);
978 else
979 shift = fshift;
980
Thomas Tsou2c282f52013-10-08 21:34:35 -0400981 /* Integer sample shift */
982 if (whole < 0) {
983 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500984 signalVector::iterator wBurstItr = shift->begin();
985 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400986
Thomas Tsou94edaae2013-11-09 22:19:19 -0500987 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +0000988 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400989
Thomas Tsou94edaae2013-11-09 22:19:19 -0500990 while (wBurstItr < shift->end())
991 *wBurstItr++ = 0.0;
992 } else if (whole >= 0) {
993 signalVector::iterator wBurstItr = shift->end() - 1;
994 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
995
996 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000997 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500998
999 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +00001000 *wBurstItr-- = 0.0;
1001 }
Thomas Tsou2c282f52013-10-08 21:34:35 -04001002
Thomas Tsou94edaae2013-11-09 22:19:19 -05001003 if (!out)
1004 return shift;
1005
1006 out->clone(*shift);
1007 delete shift;
1008 return out;
dburgessb3a0ca42011-10-12 07:44:40 +00001009}
Thomas Tsou2c282f52013-10-08 21:34:35 -04001010
dburgessb3a0ca42011-10-12 07:44:40 +00001011signalVector *gaussianNoise(int length,
1012 float variance,
1013 complex mean)
1014{
1015
1016 signalVector *noise = new signalVector(length);
1017 signalVector::iterator nPtr = noise->begin();
1018 float stddev = sqrtf(variance);
1019 while (nPtr < noise->end()) {
1020 float u1 = (float) rand()/ (float) RAND_MAX;
1021 while (u1==0.0)
1022 u1 = (float) rand()/ (float) RAND_MAX;
1023 float u2 = (float) rand()/ (float) RAND_MAX;
1024 float arg = 2.0*M_PI*u2;
1025 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
1026 nPtr++;
1027 }
1028
1029 return noise;
1030}
1031
1032complex interpolatePoint(const signalVector &inSig,
1033 float ix)
1034{
1035
1036 int start = (int) (floor(ix) - 10);
1037 if (start < 0) start = 0;
1038 int end = (int) (floor(ix) + 11);
1039 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
1040
1041 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001042 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001043 for (int i = start; i < end; i++)
1044 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
1045 }
1046 else {
1047 for (int i = start; i < end; i++)
1048 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
1049 }
1050
1051 return pVal;
1052}
1053
Thomas Tsou8181b012013-08-20 21:17:19 -04001054static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1055{
1056 float val, max = 0.0f;
1057 complex amp;
1058 int _index = -1;
1059
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001060 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001061 val = rxBurst[i].norm2();
1062 if (val > max) {
1063 max = val;
1064 _index = i;
1065 amp = rxBurst[i];
1066 }
1067 }
1068
1069 if (index)
1070 *index = (float) _index;
1071
1072 return amp;
1073}
1074
dburgessb3a0ca42011-10-12 07:44:40 +00001075complex peakDetect(const signalVector &rxBurst,
1076 float *peakIndex,
1077 float *avgPwr)
1078{
1079
1080
1081 complex maxVal = 0.0;
1082 float maxIndex = -1;
1083 float sumPower = 0.0;
1084
1085 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1086 float samplePower = rxBurst[i].norm2();
1087 if (samplePower > maxVal.real()) {
1088 maxVal = samplePower;
1089 maxIndex = i;
1090 }
1091 sumPower += samplePower;
1092 }
1093
1094 // interpolate around the peak
1095 // to save computation, we'll use early-late balancing
1096 float earlyIndex = maxIndex-1;
1097 float lateIndex = maxIndex+1;
1098
1099 float incr = 0.5;
1100 while (incr > 1.0/1024.0) {
1101 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1102 complex lateP = interpolatePoint(rxBurst,lateIndex);
1103 if (earlyP < lateP)
1104 earlyIndex += incr;
1105 else if (earlyP > lateP)
1106 earlyIndex -= incr;
1107 else break;
1108 incr /= 2.0;
1109 lateIndex = earlyIndex + 2.0;
1110 }
1111
1112 maxIndex = earlyIndex + 1.0;
1113 maxVal = interpolatePoint(rxBurst,maxIndex);
1114
1115 if (peakIndex!=NULL)
1116 *peakIndex = maxIndex;
1117
1118 if (avgPwr!=NULL)
1119 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1120
1121 return maxVal;
1122
1123}
1124
1125void scaleVector(signalVector &x,
1126 complex scale)
1127{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001128#ifdef HAVE_NEON
1129 int len = x.size();
1130
1131 scale_complex((float *) x.begin(),
1132 (float *) x.begin(),
1133 (float *) &scale, len);
1134#else
dburgessb3a0ca42011-10-12 07:44:40 +00001135 signalVector::iterator xP = x.begin();
1136 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001137 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001138 while (xP < xPEnd) {
1139 *xP = *xP * scale;
1140 xP++;
1141 }
1142 }
1143 else {
1144 while (xP < xPEnd) {
1145 *xP = xP->real() * scale;
1146 xP++;
1147 }
1148 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001149#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001150}
1151
1152/** in-place conjugation */
1153void conjugateVector(signalVector &x)
1154{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001155 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001156 signalVector::iterator xP = x.begin();
1157 signalVector::iterator xPEnd = x.end();
1158 while (xP < xPEnd) {
1159 *xP = xP->conj();
1160 xP++;
1161 }
1162}
1163
1164
1165// in-place addition!!
1166bool addVector(signalVector &x,
1167 signalVector &y)
1168{
1169 signalVector::iterator xP = x.begin();
1170 signalVector::iterator yP = y.begin();
1171 signalVector::iterator xPEnd = x.end();
1172 signalVector::iterator yPEnd = y.end();
1173 while ((xP < xPEnd) && (yP < yPEnd)) {
1174 *xP = *xP + *yP;
1175 xP++; yP++;
1176 }
1177 return true;
1178}
1179
1180// in-place multiplication!!
1181bool multVector(signalVector &x,
1182 signalVector &y)
1183{
1184 signalVector::iterator xP = x.begin();
1185 signalVector::iterator yP = y.begin();
1186 signalVector::iterator xPEnd = x.end();
1187 signalVector::iterator yPEnd = y.end();
1188 while ((xP < xPEnd) && (yP < yPEnd)) {
1189 *xP = (*xP) * (*yP);
1190 xP++; yP++;
1191 }
1192 return true;
1193}
1194
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001195bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001196{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001197 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001198 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001199 complex *data = NULL;
1200 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001201 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001202
Thomas Tsou3eaae802013-08-20 19:31:14 -04001203 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001204 return false;
1205
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001206 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001207
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001208 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1209 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1210 if (!midMidamble)
1211 return false;
1212
Thomas Tsou3eaae802013-08-20 19:31:14 -04001213 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001214 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1215 if (!midamble) {
1216 status = false;
1217 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001218 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001219
dburgessb3a0ca42011-10-12 07:44:40 +00001220 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1221 // the ideal TSC has an + 180 degree phase shift,
1222 // due to the pi/2 frequency shift, that
1223 // needs to be accounted for.
1224 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001225 scaleVector(*midMidamble, complex(-1.0, 0.0));
1226 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001227
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001228 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001229
Thomas Tsou3eaae802013-08-20 19:31:14 -04001230 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1231 data = (complex *) convolve_h_alloc(midMidamble->size());
1232 _midMidamble = new signalVector(data, 0, midMidamble->size());
1233 _midMidamble->setAligned(true);
1234 memcpy(_midMidamble->begin(), midMidamble->begin(),
1235 midMidamble->size() * sizeof(complex));
1236
1237 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001238 if (!autocorr) {
1239 status = false;
1240 goto release;
1241 }
dburgessb3a0ca42011-10-12 07:44:40 +00001242
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001243 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001244 gMidambles[tsc]->buffer = data;
1245 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001246 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1247
1248 /* For 1 sps only
1249 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1250 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1251 */
1252 if (sps == 1)
1253 gMidambles[tsc]->toa = toa - 13.5;
1254 else
1255 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001256
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001257release:
dburgessb3a0ca42011-10-12 07:44:40 +00001258 delete autocorr;
1259 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001260 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001261
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001262 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001263 delete _midMidamble;
1264 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001265 gMidambles[tsc] = NULL;
1266 }
1267
1268 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001269}
1270
Thomas Tsou83e06892013-08-20 16:10:01 -04001271bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001272{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001273 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001274 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001275 complex *data = NULL;
1276 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001277 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001278
1279 delete gRACHSequence;
1280
1281 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1282 if (!seq0)
1283 return false;
1284
1285 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1286 if (!seq1) {
1287 status = false;
1288 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001289 }
1290
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001291 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001292
Thomas Tsou3eaae802013-08-20 19:31:14 -04001293 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1294 data = (complex *) convolve_h_alloc(seq1->size());
1295 _seq1 = new signalVector(data, 0, seq1->size());
1296 _seq1->setAligned(true);
1297 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1298
1299 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1300 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001301 status = false;
1302 goto release;
1303 }
dburgessb3a0ca42011-10-12 07:44:40 +00001304
1305 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001306 gRACHSequence->sequence = _seq1;
1307 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001308 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1309
1310 /* For 1 sps only
1311 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1312 * 20.5 = (40 / 2 - 1) + 1.5
1313 */
1314 if (sps == 1)
1315 gRACHSequence->toa = toa - 20.5;
1316 else
1317 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001318
1319release:
dburgessb3a0ca42011-10-12 07:44:40 +00001320 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001321 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001322 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001323
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001324 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001325 delete _seq1;
1326 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001327 gRACHSequence = NULL;
1328 }
dburgessb3a0ca42011-10-12 07:44:40 +00001329
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001330 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001331}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001332
Thomas Tsou865bca42013-08-21 20:58:00 -04001333static float computePeakRatio(signalVector *corr,
1334 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001335{
Thomas Tsou865bca42013-08-21 20:58:00 -04001336 int num = 0;
1337 complex *peak;
1338 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001339
Thomas Tsou865bca42013-08-21 20:58:00 -04001340 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001341
Thomas Tsou865bca42013-08-21 20:58:00 -04001342 /* Check for bogus results */
1343 if ((toa < 0.0) || (toa > corr->size()))
1344 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001345
Thomas Tsou3eaae802013-08-20 19:31:14 -04001346 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001347 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001348 avg += (peak - i)->norm2();
1349 num++;
1350 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001351 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001352 avg += (peak + i)->norm2();
1353 num++;
1354 }
dburgessb3a0ca42011-10-12 07:44:40 +00001355 }
1356
Thomas Tsou3eaae802013-08-20 19:31:14 -04001357 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001358 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001359
Thomas Tsou3eaae802013-08-20 19:31:14 -04001360 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001361
Thomas Tsou865bca42013-08-21 20:58:00 -04001362 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001363}
1364
1365bool energyDetect(signalVector &rxBurst,
1366 unsigned windowLength,
1367 float detectThreshold,
1368 float *avgPwr)
1369{
1370
1371 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1372 float energy = 0.0;
1373 if (windowLength < 0) windowLength = 20;
1374 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1375 for (unsigned i = 0; i < windowLength; i++) {
1376 energy += windowItr->norm2();
1377 windowItr+=4;
1378 }
1379 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001380 return (energy/windowLength > detectThreshold*detectThreshold);
1381}
dburgessb3a0ca42011-10-12 07:44:40 +00001382
Thomas Tsou865bca42013-08-21 20:58:00 -04001383/*
1384 * Detect a burst based on correlation and peak-to-average ratio
1385 *
1386 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1387 * for initial gating. We do this because energy detection should be disabled.
1388 * For higher oversampling values, we assume the energy detector is in place
1389 * and we run full interpolating peak detection.
1390 */
1391static int detectBurst(signalVector &burst,
1392 signalVector &corr, CorrelationSequence *sync,
1393 float thresh, int sps, complex *amp, float *toa,
1394 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001395{
Thomas Tsou865bca42013-08-21 20:58:00 -04001396 /* Correlate */
1397 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001398 CUSTOM, start, len, sps, 0)) {
1399 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001400 }
1401
Thomas Tsou865bca42013-08-21 20:58:00 -04001402 /* Peak detection - place restrictions at correlation edges */
1403 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001404
Thomas Tsou865bca42013-08-21 20:58:00 -04001405 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1406 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001407
Thomas Tsou865bca42013-08-21 20:58:00 -04001408 /* Peak -to-average ratio */
1409 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1410 return 0;
1411
1412 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1413 *amp = peakDetect(corr, toa, NULL);
1414
1415 /* Normalize our channel gain */
1416 *amp = *amp / sync->gain;
1417
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001418 /* Compenate for residual rotation with dual Laurent pulse */
1419 if (sps == 4)
1420 *amp = *amp * complex(0.0, 1.0);
1421
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001422 /* Compensate for residuate time lag */
1423 *toa = *toa - sync->toa;
1424
Thomas Tsou865bca42013-08-21 20:58:00 -04001425 return 1;
1426}
1427
Tom Tsou577cd022015-05-18 13:57:54 -07001428static int detectClipping(signalVector &burst, float thresh)
1429{
1430 for (size_t i = 0; i < burst.size(); i++) {
1431 if (fabs(burst[i].real()) > thresh)
1432 return 1;
1433 if (fabs(burst[i].imag()) > thresh)
1434 return 1;
1435 }
1436
1437 return 0;
1438}
1439
Thomas Tsou865bca42013-08-21 20:58:00 -04001440/*
1441 * RACH burst detection
1442 *
1443 * Correlation window parameters:
1444 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001445 * head: Search 4 symbols before target
1446 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001447 */
1448int detectRACHBurst(signalVector &rxBurst,
1449 float thresh,
1450 int sps,
1451 complex *amp,
1452 float *toa)
1453{
1454 int rc, start, target, head, tail, len;
1455 float _toa;
1456 complex _amp;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001457 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001458 CorrelationSequence *sync;
1459
1460 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001461 return -SIGERR_UNSUPPORTED;
1462
1463 if (detectClipping(rxBurst, CLIP_THRESH))
1464 return -SIGERR_CLIP;
Thomas Tsou865bca42013-08-21 20:58:00 -04001465
1466 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001467 head = 4;
1468 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001469
1470 start = (target - head) * sps - 1;
1471 len = (head + tail) * sps;
1472 sync = gRACHSequence;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001473 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001474
Thomas Tsoub075dd22013-11-09 22:25:46 -05001475 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001476 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001477 delete corr;
1478
Thomas Tsou865bca42013-08-21 20:58:00 -04001479 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001480 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001481 } else if (!rc) {
1482 if (amp)
1483 *amp = 0.0f;
1484 if (toa)
1485 *toa = 0.0f;
1486 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001487 }
1488
Thomas Tsou865bca42013-08-21 20:58:00 -04001489 /* Subtract forward search bits from delay */
1490 if (toa)
1491 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001492 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001493 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001494
Thomas Tsou865bca42013-08-21 20:58:00 -04001495 return 1;
1496}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001497
Thomas Tsou865bca42013-08-21 20:58:00 -04001498/*
1499 * Normal burst detection
1500 *
1501 * Correlation window parameters:
1502 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001503 * head: Search 4 symbols before target
1504 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001505 */
1506int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1507 int sps, complex *amp, float *toa, unsigned max_toa,
1508 bool chan_req, signalVector **chan, float *chan_offset)
1509{
1510 int rc, start, target, head, tail, len;
1511 complex _amp;
1512 float _toa;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001513 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001514 CorrelationSequence *sync;
1515
1516 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
Tom Tsou577cd022015-05-18 13:57:54 -07001517 return -SIGERR_UNSUPPORTED;
1518
1519 if (detectClipping(rxBurst, CLIP_THRESH))
1520 return -SIGERR_CLIP;
Thomas Tsou865bca42013-08-21 20:58:00 -04001521
1522 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001523 head = 4;
1524 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001525
1526 start = (target - head) * sps - 1;
1527 len = (head + tail) * sps;
1528 sync = gMidambles[tsc];
Thomas Tsoub075dd22013-11-09 22:25:46 -05001529 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001530
Thomas Tsoub075dd22013-11-09 22:25:46 -05001531 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001532 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001533 delete corr;
1534
Thomas Tsou865bca42013-08-21 20:58:00 -04001535 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001536 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001537 } else if (!rc) {
1538 if (amp)
1539 *amp = 0.0f;
1540 if (toa)
1541 *toa = 0.0f;
1542 return 0;
1543 }
1544
1545 /* Subtract forward search bits from delay */
1546 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001547 if (toa)
1548 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001549 if (amp)
1550 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001551
Thomas Tsou865bca42013-08-21 20:58:00 -04001552 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001553 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001554 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001555
1556 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001557 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001558 }
1559
Thomas Tsou3eaae802013-08-20 19:31:14 -04001560 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001561}
1562
Thomas Tsou94edaae2013-11-09 22:19:19 -05001563signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001564{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001565 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001566
Thomas Tsou94edaae2013-11-09 22:19:19 -05001567 if (factor <= 1)
1568 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001569
Thomas Tsou94edaae2013-11-09 22:19:19 -05001570 dec = new signalVector(wVector.size() / factor);
1571 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001572
Thomas Tsou94edaae2013-11-09 22:19:19 -05001573 signalVector::iterator itr = dec->begin();
1574 for (size_t i = 0; i < wVector.size(); i += factor)
1575 *itr++ = wVector[i];
1576
1577 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001578}
1579
Thomas Tsou83e06892013-08-20 16:10:01 -04001580SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05001581 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001582{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001583 signalVector *delay, *dec = NULL;
1584 SoftVector *bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001585
Thomas Tsou94edaae2013-11-09 22:19:19 -05001586 scaleVector(rxBurst, ((complex) 1.0) / channel);
1587 delay = delayVector(&rxBurst, NULL, -TOA);
dburgessb3a0ca42011-10-12 07:44:40 +00001588
Thomas Tsou94edaae2013-11-09 22:19:19 -05001589 /* Shift up by a quarter of a frequency */
1590 GMSKReverseRotate(*delay, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001591
Thomas Tsou94edaae2013-11-09 22:19:19 -05001592 /* Decimate and slice */
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001593 if (sps > 1) {
Thomas Tsou94edaae2013-11-09 22:19:19 -05001594 dec = decimateVector(*delay, sps);
1595 delete delay;
1596 delay = NULL;
1597 } else {
1598 dec = delay;
dburgessb3a0ca42011-10-12 07:44:40 +00001599 }
1600
Thomas Tsou94edaae2013-11-09 22:19:19 -05001601 vectorSlicer(dec);
dburgessb3a0ca42011-10-12 07:44:40 +00001602
Thomas Tsou94edaae2013-11-09 22:19:19 -05001603 bits = new SoftVector(dec->size());
dburgessb3a0ca42011-10-12 07:44:40 +00001604
Thomas Tsou94edaae2013-11-09 22:19:19 -05001605 SoftVector::iterator bit_itr = bits->begin();
1606 signalVector::iterator burst_itr = dec->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001607
Thomas Tsou94edaae2013-11-09 22:19:19 -05001608 for (; burst_itr < dec->end(); burst_itr++)
1609 *bit_itr++ = burst_itr->real();
dburgessb3a0ca42011-10-12 07:44:40 +00001610
Thomas Tsou94edaae2013-11-09 22:19:19 -05001611 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001612
Thomas Tsou94edaae2013-11-09 22:19:19 -05001613 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001614}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001615
dburgessb3a0ca42011-10-12 07:44:40 +00001616// Assumes symbol-spaced sampling!!!
1617// Based upon paper by Al-Dhahir and Cioffi
1618bool designDFE(signalVector &channelResponse,
1619 float SNRestimate,
1620 int Nf,
1621 signalVector **feedForwardFilter,
1622 signalVector **feedbackFilter)
1623{
1624
1625 signalVector G0(Nf);
1626 signalVector G1(Nf);
1627 signalVector::iterator G0ptr = G0.begin();
1628 signalVector::iterator G1ptr = G1.begin();
1629 signalVector::iterator chanPtr = channelResponse.begin();
1630
1631 int nu = channelResponse.size()-1;
1632
1633 *G0ptr = 1.0/sqrtf(SNRestimate);
1634 for(int j = 0; j <= nu; j++) {
1635 *G1ptr = chanPtr->conj();
1636 G1ptr++; chanPtr++;
1637 }
1638
1639 signalVector *L[Nf];
1640 signalVector::iterator Lptr;
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001641 float d = 1.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001642 for(int i = 0; i < Nf; i++) {
1643 d = G0.begin()->norm2() + G1.begin()->norm2();
1644 L[i] = new signalVector(Nf+nu);
1645 Lptr = L[i]->begin()+i;
1646 G0ptr = G0.begin(); G1ptr = G1.begin();
1647 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1648 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1649 Lptr++;
1650 G0ptr++;
1651 G1ptr++;
1652 }
1653 complex k = (*G1.begin())/(*G0.begin());
1654
1655 if (i != Nf-1) {
1656 signalVector G0new = G1;
1657 scaleVector(G0new,k.conj());
1658 addVector(G0new,G0);
1659
1660 signalVector G1new = G0;
1661 scaleVector(G1new,k*(-1.0));
1662 addVector(G1new,G1);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001663 delayVector(&G1new, &G1new, -1.0);
dburgessb3a0ca42011-10-12 07:44:40 +00001664
1665 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1666 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1667 G0 = G0new;
1668 G1 = G1new;
1669 }
1670 }
1671
1672 *feedbackFilter = new signalVector(nu);
1673 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1674 scaleVector(**feedbackFilter,(complex) -1.0);
1675 conjugateVector(**feedbackFilter);
1676
1677 signalVector v(Nf);
1678 signalVector::iterator vStart = v.begin();
1679 signalVector::iterator vPtr;
1680 *(vStart+Nf-1) = (complex) 1.0;
1681 for(int k = Nf-2; k >= 0; k--) {
1682 Lptr = L[k]->begin()+k+1;
1683 vPtr = vStart + k+1;
1684 complex v_k = 0.0;
1685 for (int j = k+1; j < Nf; j++) {
1686 v_k -= (*vPtr)*(*Lptr);
1687 vPtr++; Lptr++;
1688 }
1689 *(vStart + k) = v_k;
1690 }
1691
1692 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001693 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001694 for (int i = 0; i < Nf; i++) {
1695 delete L[i];
1696 complex w_i = 0.0;
1697 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1698 vPtr = vStart+i;
1699 chanPtr = channelResponse.begin();
1700 for (int k = 0; k < endPt+1; k++) {
1701 w_i += (*vPtr)*(chanPtr->conj());
1702 vPtr++; chanPtr++;
1703 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001704 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001705 }
1706
1707
1708 return true;
1709
1710}
1711
1712// Assumes symbol-rate sampling!!!!
1713SoftVector *equalizeBurst(signalVector &rxBurst,
1714 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001715 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001716 signalVector &w, // feedforward filter
1717 signalVector &b) // feedback filter
1718{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001719 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001720
Thomas Tsou94edaae2013-11-09 22:19:19 -05001721 if (!delayVector(&rxBurst, &rxBurst, -TOA))
Thomas Tsou3eaae802013-08-20 19:31:14 -04001722 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001723
Thomas Tsou3eaae802013-08-20 19:31:14 -04001724 postForwardFull = convolve(&rxBurst, &w, NULL,
1725 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1726 if (!postForwardFull)
1727 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001728
1729 signalVector* postForward = new signalVector(rxBurst.size());
1730 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1731 delete postForwardFull;
1732
1733 signalVector::iterator dPtr = postForward->begin();
1734 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001735 signalVector::iterator rotPtr = GMSKRotationN->begin();
1736 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001737
1738 signalVector *DFEoutput = new signalVector(postForward->size());
1739 signalVector::iterator DFEItr = DFEoutput->begin();
1740
1741 // NOTE: can insert the midamble and/or use midamble to estimate BER
1742 for (; dPtr < postForward->end(); dPtr++) {
1743 dBackPtr = dPtr-1;
1744 signalVector::iterator bPtr = b.begin();
1745 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1746 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1747 bPtr++;
1748 dBackPtr--;
1749 }
1750 *dPtr = *dPtr * (*revRotPtr);
1751 *DFEItr = *dPtr;
1752 // make decision on symbol
1753 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1754 //*DFEItr = *dPtr;
1755 *dPtr = *dPtr * (*rotPtr);
1756 DFEItr++;
1757 rotPtr++;
1758 revRotPtr++;
1759 }
1760
1761 vectorSlicer(DFEoutput);
1762
1763 SoftVector *burstBits = new SoftVector(postForward->size());
1764 SoftVector::iterator burstItr = burstBits->begin();
1765 DFEItr = DFEoutput->begin();
1766 for (; DFEItr < DFEoutput->end(); DFEItr++)
1767 *burstItr++ = DFEItr->real();
1768
1769 delete postForward;
1770
1771 delete DFEoutput;
1772
1773 return burstBits;
1774}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001775
1776bool sigProcLibSetup(int sps)
1777{
1778 if ((sps != 1) && (sps != 4))
1779 return false;
1780
1781 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001782 generateSincTable();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001783 initGMSKRotationTables(sps);
1784
1785 GSMPulse1 = generateGSMPulse(1, 2);
1786 if (sps > 1)
1787 GSMPulse = generateGSMPulse(sps, 2);
1788
1789 if (!generateRACHSequence(1)) {
1790 sigProcLibDestroy();
1791 return false;
1792 }
1793
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001794 generateDelayFilters();
1795
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001796 return true;
1797}