blob: 4501a1303e9fca8ca20eca6f7433d906b841f922 [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 */
47float cosTable[TABLESIZE+1]; // add 1 element for wrap around
48float sinTable[TABLESIZE+1];
Thomas Tsou0e0e1f42013-11-09 22:08:51 -050049float sincTable[TABLESIZE+1];
dburgessb3a0ca42011-10-12 07:44:40 +000050
51/** Constants */
52static const float M_PI_F = (float)M_PI;
53static const float M_2PI_F = (float)(2.0*M_PI);
54static const float M_1_2PI_F = 1/M_2PI_F;
55
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++) {
272 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
273 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
274 }
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();
dburgessb3a0ca42011-10-12 07:44:40 +0000283 float phase = 0.0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400284 while (rotPtr != GMSKRotationN->end()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000285 *rotPtr++ = expjLookup(phase);
286 *revPtr++ = expjLookup(-phase);
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400287 phase += M_PI_F / 2.0F / (float) sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000288 }
dburgessb3a0ca42011-10-12 07:44:40 +0000289
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400290 GMSKRotation1 = new signalVector(157);
291 GMSKReverseRotation1 = new signalVector(157);
292 rotPtr = GMSKRotation1->begin();
293 revPtr = GMSKReverseRotation1->begin();
294 phase = 0.0;
295 while (rotPtr != GMSKRotation1->end()) {
296 *rotPtr++ = expjLookup(phase);
297 *revPtr++ = expjLookup(-phase);
298 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400299 }
dburgessb3a0ca42011-10-12 07:44:40 +0000300}
301
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400302static void GMSKRotate(signalVector &x, int sps)
303{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500304#if HAVE_NEON
305 size_t len;
306 signalVector *a, *b, *out;
307
308 a = &x;
309 out = &x;
310 len = out->size();
311
312 if (len == 157)
313 len--;
314
315 if (sps == 1)
316 b = GMSKRotation1;
317 else
318 b = GMSKRotationN;
319
320 mul_complex((float *) out->begin(),
321 (float *) a->begin(),
322 (float *) b->begin(), len);
323#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400324 signalVector::iterator rotPtr, xPtr = x.begin();
325
326 if (sps == 1)
327 rotPtr = GMSKRotation1->begin();
328 else
329 rotPtr = GMSKRotationN->begin();
330
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500331 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000332 while (xPtr < x.end()) {
333 *xPtr = *rotPtr++ * (xPtr->real());
334 xPtr++;
335 }
336 }
337 else {
338 while (xPtr < x.end()) {
339 *xPtr = *rotPtr++ * (*xPtr);
340 xPtr++;
341 }
342 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500343#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000344}
345
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400346static void GMSKReverseRotate(signalVector &x, int sps)
347{
348 signalVector::iterator rotPtr, xPtr= x.begin();
349
350 if (sps == 1)
351 rotPtr = GMSKReverseRotation1->begin();
352 else
353 rotPtr = GMSKReverseRotationN->begin();
354
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500355 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000356 while (xPtr < x.end()) {
357 *xPtr = *rotPtr++ * (xPtr->real());
358 xPtr++;
359 }
360 }
361 else {
362 while (xPtr < x.end()) {
363 *xPtr = *rotPtr++ * (*xPtr);
364 xPtr++;
365 }
366 }
367}
368
Thomas Tsou3eaae802013-08-20 19:31:14 -0400369signalVector *convolve(const signalVector *x,
370 const signalVector *h,
371 signalVector *y,
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500372 ConvType spanType, size_t start,
373 size_t len, size_t step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000374{
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500375 int rc;
376 size_t head = 0, tail = 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400377 bool alloc = false, append = false;
378 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000379
Thomas Tsou3eaae802013-08-20 19:31:14 -0400380 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000381 return NULL;
382
Thomas Tsou3eaae802013-08-20 19:31:14 -0400383 switch (spanType) {
384 case START_ONLY:
385 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500386 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400387 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500388
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500389 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500390 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000391 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400392 case NO_DELAY:
393 start = h->size() / 2;
394 head = start;
395 tail = start;
396 len = x->size();
397 append = true;
398 break;
399 case CUSTOM:
400 if (start < h->size() - 1) {
401 head = h->size() - start;
402 append = true;
403 }
404 if (start + len > x->size()) {
405 tail = start + len - x->size();
406 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000407 }
408 break;
409 default:
410 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000411 }
dburgessb3a0ca42011-10-12 07:44:40 +0000412
Thomas Tsou3eaae802013-08-20 19:31:14 -0400413 /*
414 * Error if the output vector is too small. Create the output vector
415 * if the pointer is NULL.
416 */
417 if (y && (len > y->size()))
418 return NULL;
419 if (!y) {
420 y = new signalVector(len);
421 alloc = true;
422 }
423
424 /* Prepend or post-pend the input vector if the parameters require it */
425 if (append)
426 _x = new signalVector(*x, head, tail);
427 else
428 _x = x;
429
430 /*
431 * Four convovle types:
432 * 1. Complex-Real (aligned)
433 * 2. Complex-Complex (aligned)
434 * 3. Complex-Real (!aligned)
435 * 4. Complex-Complex (!aligned)
436 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500437 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400438 rc = convolve_real((float *) _x->begin(), _x->size(),
439 (float *) h->begin(), h->size(),
440 (float *) y->begin(), y->size(),
441 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500442 } else if (!h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400443 rc = convolve_complex((float *) _x->begin(), _x->size(),
444 (float *) h->begin(), h->size(),
445 (float *) y->begin(), y->size(),
446 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500447 } else if (h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400448 rc = base_convolve_real((float *) _x->begin(), _x->size(),
449 (float *) h->begin(), h->size(),
450 (float *) y->begin(), y->size(),
451 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500452 } else if (!h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400453 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
454 (float *) h->begin(), h->size(),
455 (float *) y->begin(), y->size(),
456 start, len, step, offset);
457 } else {
458 rc = -1;
459 }
460
461 if (append)
462 delete _x;
463
464 if (rc < 0) {
465 if (alloc)
466 delete y;
467 return NULL;
468 }
469
470 return y;
471}
dburgessb3a0ca42011-10-12 07:44:40 +0000472
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400473static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800474{
475 int len;
476
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400477 if (!pulse)
478 return false;
479
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800480 switch (sps) {
481 case 4:
482 len = 8;
483 break;
484 default:
485 return false;
486 }
487
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400488 pulse->c1_buffer = convolve_h_alloc(len);
489 pulse->c1 = new signalVector((complex *)
490 pulse->c1_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500491 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800492
493 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400494 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800495
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400496 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800497
498 switch (sps) {
499 case 4:
500 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400501 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800502 *xP++ = 8.16373112e-03;
503 *xP++ = 2.84385729e-02;
504 *xP++ = 5.64158904e-02;
505 *xP++ = 7.05463553e-02;
506 *xP++ = 5.64158904e-02;
507 *xP++ = 2.84385729e-02;
508 *xP++ = 8.16373112e-03;
509 }
510
511 return true;
512}
513
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400514static PulseSequence *generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000515{
Thomas Tsou83e06892013-08-20 16:10:01 -0400516 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800517 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400518 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400519
520 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400521 pulse = new PulseSequence();
522 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500523 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400524 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400525
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400526 /*
527 * For 4 samples-per-symbol use a precomputed single pulse Laurent
528 * approximation. This should yields below 2 degrees of phase error at
529 * the modulator output. Use the existing pulse approximation for all
530 * other oversampling factors.
531 */
532 switch (sps) {
533 case 4:
534 len = 16;
535 break;
536 default:
537 len = sps * symbolLength;
538 if (len < 4)
539 len = 4;
540 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400541
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400542 pulse->c0_buffer = convolve_h_alloc(len);
543 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500544 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400545
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800546 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400547 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800548
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400549 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400550
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400551 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800552 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400553 *xP++ = 4.46348606e-03;
554 *xP++ = 2.84385729e-02;
555 *xP++ = 1.03184855e-01;
556 *xP++ = 2.56065552e-01;
557 *xP++ = 4.76375085e-01;
558 *xP++ = 7.05961177e-01;
559 *xP++ = 8.71291644e-01;
560 *xP++ = 9.29453645e-01;
561 *xP++ = 8.71291644e-01;
562 *xP++ = 7.05961177e-01;
563 *xP++ = 4.76375085e-01;
564 *xP++ = 2.56065552e-01;
565 *xP++ = 1.03184855e-01;
566 *xP++ = 2.84385729e-02;
567 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400568 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400569 } else {
570 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400571
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400572 /* GSM pulse approximation */
573 for (int i = 0; i < len; i++) {
574 arg = ((float) i - center) / (float) sps;
575 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
576 0.527 * arg * arg * arg * arg);
577 }
dburgessb3a0ca42011-10-12 07:44:40 +0000578
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400579 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
580 xP = pulse->c0->begin();
581 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800582 *xP++ /= avg;
583 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400584
585 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000586}
587
588signalVector* frequencyShift(signalVector *y,
589 signalVector *x,
590 float freq,
591 float startPhase,
592 float *finalPhase)
593{
594
595 if (!x) return NULL;
596
597 if (y==NULL) {
598 y = new signalVector(x->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500599 y->isReal(x->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000600 if (y==NULL) return NULL;
601 }
602
603 if (y->size() < x->size()) return NULL;
604
605 float phase = startPhase;
606 signalVector::iterator yP = y->begin();
607 signalVector::iterator xPEnd = x->end();
608 signalVector::iterator xP = x->begin();
609
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500610 if (x->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000611 while (xP < xPEnd) {
612 (*yP++) = expjLookup(phase)*( (xP++)->real() );
613 phase += freq;
614 }
615 }
616 else {
617 while (xP < xPEnd) {
618 (*yP++) = (*xP++)*expjLookup(phase);
619 phase += freq;
Thomas Tsou34bbef72013-11-13 22:58:15 -0500620 if (phase > 2 * M_PI)
621 phase -= 2 * M_PI;
622 else if (phase < -2 * M_PI)
623 phase += 2 * M_PI;
dburgessb3a0ca42011-10-12 07:44:40 +0000624 }
625 }
626
627
628 if (finalPhase) *finalPhase = phase;
629
630 return y;
631}
632
633signalVector* reverseConjugate(signalVector *b)
634{
635 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500636 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000637 signalVector::iterator bP = b->begin();
638 signalVector::iterator bPEnd = b->end();
639 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500640 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000641 while (bP < bPEnd) {
642 *tmpP-- = bP->conj();
643 bP++;
644 }
645 }
646 else {
647 while (bP < bPEnd) {
648 *tmpP-- = bP->real();
649 bP++;
650 }
651 }
652
653 return tmp;
654}
655
dburgessb3a0ca42011-10-12 07:44:40 +0000656/* soft output slicer */
657bool vectorSlicer(signalVector *x)
658{
659
660 signalVector::iterator xP = x->begin();
661 signalVector::iterator xPEnd = x->end();
662 while (xP < xPEnd) {
663 *xP = (complex) (0.5*(xP->real()+1.0F));
664 if (xP->real() > 1.0) *xP = 1.0;
665 if (xP->real() < 0.0) *xP = 0.0;
666 xP++;
667 }
668 return true;
669}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400670
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800671static signalVector *rotateBurst(const BitVector &wBurst,
672 int guardPeriodLength, int sps)
673{
674 int burst_len;
675 signalVector *pulse, rotated, *shaped;
676 signalVector::iterator itr;
677
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400678 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800679 burst_len = sps * (wBurst.size() + guardPeriodLength);
680 rotated = signalVector(burst_len);
681 itr = rotated.begin();
682
683 for (unsigned i = 0; i < wBurst.size(); i++) {
684 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
685 itr += sps;
686 }
687
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400688 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500689 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800690
691 /* Dummy filter operation */
692 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
693 if (!shaped)
694 return NULL;
695
696 return shaped;
697}
698
699static signalVector *modulateBurstLaurent(const BitVector &bits,
700 int guard_len, int sps)
701{
702 int burst_len;
703 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500704 signalVector *c0_pulse, *c1_pulse, *c0_burst;
705 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800706 signalVector::iterator c0_itr, c1_itr;
707
708 /*
709 * Apply before and after bits to reduce phase error at burst edges.
710 * Make sure there is enough room in the burst to accomodate all bits.
711 */
712 if (guard_len < 4)
713 guard_len = 4;
714
715 c0_pulse = GSMPulse->c0;
716 c1_pulse = GSMPulse->c1;
717
718 burst_len = sps * (bits.size() + guard_len);
719
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500720 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500721 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500722 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800723
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500724 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500725 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500726 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800727
728 /* Padded differential start bits */
729 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
730 c0_itr += sps;
731
732 /* Main burst bits */
733 for (unsigned i = 0; i < bits.size(); i++) {
734 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
735 c0_itr += sps;
736 }
737
738 /* Padded differential end bits */
739 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
740
741 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500742 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500743 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800744
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500745 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800746 c0_itr += sps * 2;
747 c1_itr += sps * 2;
748
749 /* Start magic */
750 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
751 *c1_itr = *c0_itr * Complex<float>(0, phase);
752 c0_itr += sps;
753 c1_itr += sps;
754
755 /* Generate C1 phase coefficients */
756 for (unsigned i = 2; i < bits.size(); i++) {
757 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
758 *c1_itr = *c0_itr * Complex<float>(0, phase);
759
760 c0_itr += sps;
761 c1_itr += sps;
762 }
763
764 /* End magic */
765 int i = bits.size();
766 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
767 *c1_itr = *c0_itr * Complex<float>(0, phase);
768
769 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500770 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
771 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800772
773 /* Sum shaped outputs into C0 */
774 c0_itr = c0_shaped->begin();
775 c1_itr = c1_shaped->begin();
776 for (unsigned i = 0; i < c0_shaped->size(); i++ )
777 *c0_itr++ += *c1_itr++;
778
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500779 delete c0_burst;
780 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800781 delete c1_shaped;
782
783 return c0_shaped;
784}
785
786static signalVector *modulateBurstBasic(const BitVector &bits,
787 int guard_len, int sps)
788{
789 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500790 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800791 signalVector::iterator burst_itr;
792
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400793 if (sps == 1)
794 pulse = GSMPulse1->c0;
795 else
796 pulse = GSMPulse->c0;
797
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800798 burst_len = sps * (bits.size() + guard_len);
799
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500800 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500801 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500802 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800803
804 /* Raw bits are not differentially encoded */
805 for (unsigned i = 0; i < bits.size(); i++) {
806 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
807 burst_itr += sps;
808 }
809
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500810 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500811 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800812
813 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500814 shaped = convolve(burst, pulse, NULL, START_ONLY);
815
816 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800817
818 return shaped;
819}
820
Thomas Tsou3eaae802013-08-20 19:31:14 -0400821/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400822signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
823 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000824{
Thomas Tsou83e06892013-08-20 16:10:01 -0400825 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800826 return rotateBurst(wBurst, guardPeriodLength, sps);
827 else if (sps == 4)
828 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400829 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800830 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000831}
832
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500833void generateSincTable()
834{
835 float x;
836
837 for (int i = 0; i < TABLESIZE; i++) {
838 x = (float) i / TABLESIZE * 8 * M_PI;
839 if (fabs(x) < 0.01) {
840 sincTable[i] = 1.0f;
841 continue;
842 }
843
844 sincTable[i] = sinf(x) / x;
845 }
846}
847
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800848float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000849{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500850 if (fabs(x) >= 8 * M_PI)
851 return 0.0;
852
853 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
854
855 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +0000856}
857
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600858/*
859 * Create fractional delay filterbank with Blackman-harris windowed
860 * sinc function generator. The number of filters generated is specified
861 * by the DELAYFILTS value.
862 */
863void generateDelayFilters()
864{
865 int h_len = 20;
866 complex *data;
867 signalVector *h;
868 signalVector::iterator itr;
869
870 float k, sum;
871 float a0 = 0.35875;
872 float a1 = 0.48829;
873 float a2 = 0.14128;
874 float a3 = 0.01168;
875
876 for (int i = 0; i < DELAYFILTS; i++) {
877 data = (complex *) convolve_h_alloc(h_len);
878 h = new signalVector(data, 0, h_len);
879 h->setAligned(true);
880 h->isReal(true);
881
882 sum = 0.0;
883 itr = h->end();
884 for (int n = 0; n < h_len; n++) {
885 k = (float) n;
886 *--itr = (complex) sinc(M_PI_F *
887 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
888 *itr *= a0 -
889 a1 * cos(2 * M_PI * n / (h_len - 1)) +
890 a2 * cos(4 * M_PI * n / (h_len - 1)) -
891 a3 * cos(6 * M_PI * n / (h_len - 1));
892
893 sum += itr->real();
894 }
895
896 itr = h->begin();
897 for (int n = 0; n < h_len; n++)
898 *itr++ /= sum;
899
900 delayFilters[i] = h;
901 }
902}
903
Thomas Tsou94edaae2013-11-09 22:19:19 -0500904signalVector *delayVector(signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000905{
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600906 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400907 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500908 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400909
Thomas Tsou2c282f52013-10-08 21:34:35 -0400910 whole = floor(delay);
911 frac = delay - whole;
912
913 /* Sinc interpolated fractional shift (if allowable) */
914 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600915 index = floorf(frac * (float) DELAYFILTS);
916 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -0400917
Thomas Tsou94edaae2013-11-09 22:19:19 -0500918 fshift = convolve(in, h, NULL, NO_DELAY);
919 if (!fshift)
920 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000921 }
922
Thomas Tsou94edaae2013-11-09 22:19:19 -0500923 if (!fshift)
924 shift = new signalVector(*in);
925 else
926 shift = fshift;
927
Thomas Tsou2c282f52013-10-08 21:34:35 -0400928 /* Integer sample shift */
929 if (whole < 0) {
930 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500931 signalVector::iterator wBurstItr = shift->begin();
932 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400933
Thomas Tsou94edaae2013-11-09 22:19:19 -0500934 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +0000935 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400936
Thomas Tsou94edaae2013-11-09 22:19:19 -0500937 while (wBurstItr < shift->end())
938 *wBurstItr++ = 0.0;
939 } else if (whole >= 0) {
940 signalVector::iterator wBurstItr = shift->end() - 1;
941 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
942
943 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000944 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500945
946 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000947 *wBurstItr-- = 0.0;
948 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400949
Thomas Tsou94edaae2013-11-09 22:19:19 -0500950 if (!out)
951 return shift;
952
953 out->clone(*shift);
954 delete shift;
955 return out;
dburgessb3a0ca42011-10-12 07:44:40 +0000956}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400957
dburgessb3a0ca42011-10-12 07:44:40 +0000958signalVector *gaussianNoise(int length,
959 float variance,
960 complex mean)
961{
962
963 signalVector *noise = new signalVector(length);
964 signalVector::iterator nPtr = noise->begin();
965 float stddev = sqrtf(variance);
966 while (nPtr < noise->end()) {
967 float u1 = (float) rand()/ (float) RAND_MAX;
968 while (u1==0.0)
969 u1 = (float) rand()/ (float) RAND_MAX;
970 float u2 = (float) rand()/ (float) RAND_MAX;
971 float arg = 2.0*M_PI*u2;
972 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
973 nPtr++;
974 }
975
976 return noise;
977}
978
979complex interpolatePoint(const signalVector &inSig,
980 float ix)
981{
982
983 int start = (int) (floor(ix) - 10);
984 if (start < 0) start = 0;
985 int end = (int) (floor(ix) + 11);
986 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
987
988 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500989 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000990 for (int i = start; i < end; i++)
991 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
992 }
993 else {
994 for (int i = start; i < end; i++)
995 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
996 }
997
998 return pVal;
999}
1000
Thomas Tsou8181b012013-08-20 21:17:19 -04001001static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1002{
1003 float val, max = 0.0f;
1004 complex amp;
1005 int _index = -1;
1006
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001007 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001008 val = rxBurst[i].norm2();
1009 if (val > max) {
1010 max = val;
1011 _index = i;
1012 amp = rxBurst[i];
1013 }
1014 }
1015
1016 if (index)
1017 *index = (float) _index;
1018
1019 return amp;
1020}
1021
dburgessb3a0ca42011-10-12 07:44:40 +00001022complex peakDetect(const signalVector &rxBurst,
1023 float *peakIndex,
1024 float *avgPwr)
1025{
1026
1027
1028 complex maxVal = 0.0;
1029 float maxIndex = -1;
1030 float sumPower = 0.0;
1031
1032 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1033 float samplePower = rxBurst[i].norm2();
1034 if (samplePower > maxVal.real()) {
1035 maxVal = samplePower;
1036 maxIndex = i;
1037 }
1038 sumPower += samplePower;
1039 }
1040
1041 // interpolate around the peak
1042 // to save computation, we'll use early-late balancing
1043 float earlyIndex = maxIndex-1;
1044 float lateIndex = maxIndex+1;
1045
1046 float incr = 0.5;
1047 while (incr > 1.0/1024.0) {
1048 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1049 complex lateP = interpolatePoint(rxBurst,lateIndex);
1050 if (earlyP < lateP)
1051 earlyIndex += incr;
1052 else if (earlyP > lateP)
1053 earlyIndex -= incr;
1054 else break;
1055 incr /= 2.0;
1056 lateIndex = earlyIndex + 2.0;
1057 }
1058
1059 maxIndex = earlyIndex + 1.0;
1060 maxVal = interpolatePoint(rxBurst,maxIndex);
1061
1062 if (peakIndex!=NULL)
1063 *peakIndex = maxIndex;
1064
1065 if (avgPwr!=NULL)
1066 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1067
1068 return maxVal;
1069
1070}
1071
1072void scaleVector(signalVector &x,
1073 complex scale)
1074{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001075#ifdef HAVE_NEON
1076 int len = x.size();
1077
1078 scale_complex((float *) x.begin(),
1079 (float *) x.begin(),
1080 (float *) &scale, len);
1081#else
dburgessb3a0ca42011-10-12 07:44:40 +00001082 signalVector::iterator xP = x.begin();
1083 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001084 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001085 while (xP < xPEnd) {
1086 *xP = *xP * scale;
1087 xP++;
1088 }
1089 }
1090 else {
1091 while (xP < xPEnd) {
1092 *xP = xP->real() * scale;
1093 xP++;
1094 }
1095 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001096#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001097}
1098
1099/** in-place conjugation */
1100void conjugateVector(signalVector &x)
1101{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001102 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001103 signalVector::iterator xP = x.begin();
1104 signalVector::iterator xPEnd = x.end();
1105 while (xP < xPEnd) {
1106 *xP = xP->conj();
1107 xP++;
1108 }
1109}
1110
1111
1112// in-place addition!!
1113bool addVector(signalVector &x,
1114 signalVector &y)
1115{
1116 signalVector::iterator xP = x.begin();
1117 signalVector::iterator yP = y.begin();
1118 signalVector::iterator xPEnd = x.end();
1119 signalVector::iterator yPEnd = y.end();
1120 while ((xP < xPEnd) && (yP < yPEnd)) {
1121 *xP = *xP + *yP;
1122 xP++; yP++;
1123 }
1124 return true;
1125}
1126
1127// in-place multiplication!!
1128bool multVector(signalVector &x,
1129 signalVector &y)
1130{
1131 signalVector::iterator xP = x.begin();
1132 signalVector::iterator yP = y.begin();
1133 signalVector::iterator xPEnd = x.end();
1134 signalVector::iterator yPEnd = y.end();
1135 while ((xP < xPEnd) && (yP < yPEnd)) {
1136 *xP = (*xP) * (*yP);
1137 xP++; yP++;
1138 }
1139 return true;
1140}
1141
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001142bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001143{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001144 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001145 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001146 complex *data = NULL;
1147 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001148 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001149
Thomas Tsou3eaae802013-08-20 19:31:14 -04001150 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001151 return false;
1152
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001153 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001154
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001155 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1156 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1157 if (!midMidamble)
1158 return false;
1159
Thomas Tsou3eaae802013-08-20 19:31:14 -04001160 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001161 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1162 if (!midamble) {
1163 status = false;
1164 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001165 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001166
dburgessb3a0ca42011-10-12 07:44:40 +00001167 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1168 // the ideal TSC has an + 180 degree phase shift,
1169 // due to the pi/2 frequency shift, that
1170 // needs to be accounted for.
1171 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001172 scaleVector(*midMidamble, complex(-1.0, 0.0));
1173 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001174
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001175 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001176
Thomas Tsou3eaae802013-08-20 19:31:14 -04001177 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1178 data = (complex *) convolve_h_alloc(midMidamble->size());
1179 _midMidamble = new signalVector(data, 0, midMidamble->size());
1180 _midMidamble->setAligned(true);
1181 memcpy(_midMidamble->begin(), midMidamble->begin(),
1182 midMidamble->size() * sizeof(complex));
1183
1184 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001185 if (!autocorr) {
1186 status = false;
1187 goto release;
1188 }
dburgessb3a0ca42011-10-12 07:44:40 +00001189
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001190 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001191 gMidambles[tsc]->buffer = data;
1192 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001193 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1194
1195 /* For 1 sps only
1196 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1197 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1198 */
1199 if (sps == 1)
1200 gMidambles[tsc]->toa = toa - 13.5;
1201 else
1202 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001203
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001204release:
dburgessb3a0ca42011-10-12 07:44:40 +00001205 delete autocorr;
1206 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001207 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001208
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001209 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001210 delete _midMidamble;
1211 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001212 gMidambles[tsc] = NULL;
1213 }
1214
1215 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001216}
1217
Thomas Tsou83e06892013-08-20 16:10:01 -04001218bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001219{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001220 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001221 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001222 complex *data = NULL;
1223 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001224 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001225
1226 delete gRACHSequence;
1227
1228 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1229 if (!seq0)
1230 return false;
1231
1232 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1233 if (!seq1) {
1234 status = false;
1235 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001236 }
1237
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001238 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001239
Thomas Tsou3eaae802013-08-20 19:31:14 -04001240 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1241 data = (complex *) convolve_h_alloc(seq1->size());
1242 _seq1 = new signalVector(data, 0, seq1->size());
1243 _seq1->setAligned(true);
1244 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1245
1246 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1247 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001248 status = false;
1249 goto release;
1250 }
dburgessb3a0ca42011-10-12 07:44:40 +00001251
1252 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001253 gRACHSequence->sequence = _seq1;
1254 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001255 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1256
1257 /* For 1 sps only
1258 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1259 * 20.5 = (40 / 2 - 1) + 1.5
1260 */
1261 if (sps == 1)
1262 gRACHSequence->toa = toa - 20.5;
1263 else
1264 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001265
1266release:
dburgessb3a0ca42011-10-12 07:44:40 +00001267 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001268 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001269 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001270
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001271 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001272 delete _seq1;
1273 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001274 gRACHSequence = NULL;
1275 }
dburgessb3a0ca42011-10-12 07:44:40 +00001276
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001277 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001278}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001279
Thomas Tsou865bca42013-08-21 20:58:00 -04001280static float computePeakRatio(signalVector *corr,
1281 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001282{
Thomas Tsou865bca42013-08-21 20:58:00 -04001283 int num = 0;
1284 complex *peak;
1285 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001286
Thomas Tsou865bca42013-08-21 20:58:00 -04001287 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001288
Thomas Tsou865bca42013-08-21 20:58:00 -04001289 /* Check for bogus results */
1290 if ((toa < 0.0) || (toa > corr->size()))
1291 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001292
Thomas Tsou3eaae802013-08-20 19:31:14 -04001293 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001294 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001295 avg += (peak - i)->norm2();
1296 num++;
1297 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001298 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001299 avg += (peak + i)->norm2();
1300 num++;
1301 }
dburgessb3a0ca42011-10-12 07:44:40 +00001302 }
1303
Thomas Tsou3eaae802013-08-20 19:31:14 -04001304 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001305 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001306
Thomas Tsou3eaae802013-08-20 19:31:14 -04001307 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001308
Thomas Tsou865bca42013-08-21 20:58:00 -04001309 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001310}
1311
1312bool energyDetect(signalVector &rxBurst,
1313 unsigned windowLength,
1314 float detectThreshold,
1315 float *avgPwr)
1316{
1317
1318 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1319 float energy = 0.0;
1320 if (windowLength < 0) windowLength = 20;
1321 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1322 for (unsigned i = 0; i < windowLength; i++) {
1323 energy += windowItr->norm2();
1324 windowItr+=4;
1325 }
1326 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001327 return (energy/windowLength > detectThreshold*detectThreshold);
1328}
dburgessb3a0ca42011-10-12 07:44:40 +00001329
Thomas Tsou865bca42013-08-21 20:58:00 -04001330/*
1331 * Detect a burst based on correlation and peak-to-average ratio
1332 *
1333 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1334 * for initial gating. We do this because energy detection should be disabled.
1335 * For higher oversampling values, we assume the energy detector is in place
1336 * and we run full interpolating peak detection.
1337 */
1338static int detectBurst(signalVector &burst,
1339 signalVector &corr, CorrelationSequence *sync,
1340 float thresh, int sps, complex *amp, float *toa,
1341 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001342{
Thomas Tsou865bca42013-08-21 20:58:00 -04001343 /* Correlate */
1344 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001345 CUSTOM, start, len, sps, 0)) {
1346 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001347 }
1348
Thomas Tsou865bca42013-08-21 20:58:00 -04001349 /* Peak detection - place restrictions at correlation edges */
1350 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001351
Thomas Tsou865bca42013-08-21 20:58:00 -04001352 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1353 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001354
Thomas Tsou865bca42013-08-21 20:58:00 -04001355 /* Peak -to-average ratio */
1356 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1357 return 0;
1358
1359 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1360 *amp = peakDetect(corr, toa, NULL);
1361
1362 /* Normalize our channel gain */
1363 *amp = *amp / sync->gain;
1364
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001365 /* Compenate for residual rotation with dual Laurent pulse */
1366 if (sps == 4)
1367 *amp = *amp * complex(0.0, 1.0);
1368
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001369 /* Compensate for residuate time lag */
1370 *toa = *toa - sync->toa;
1371
Thomas Tsou865bca42013-08-21 20:58:00 -04001372 return 1;
1373}
1374
Tom Tsou577cd022015-05-18 13:57:54 -07001375static int detectClipping(signalVector &burst, float thresh)
1376{
1377 for (size_t i = 0; i < burst.size(); i++) {
1378 if (fabs(burst[i].real()) > thresh)
1379 return 1;
1380 if (fabs(burst[i].imag()) > thresh)
1381 return 1;
1382 }
1383
1384 return 0;
1385}
1386
Thomas Tsou865bca42013-08-21 20:58:00 -04001387/*
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;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001404 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001405 CorrelationSequence *sync;
1406
1407 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001408 return -SIGERR_UNSUPPORTED;
1409
1410 if (detectClipping(rxBurst, CLIP_THRESH))
1411 return -SIGERR_CLIP;
Thomas Tsou865bca42013-08-21 20:58:00 -04001412
1413 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001414 head = 4;
1415 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001416
1417 start = (target - head) * sps - 1;
1418 len = (head + tail) * sps;
1419 sync = gRACHSequence;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001420 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001421
Thomas Tsoub075dd22013-11-09 22:25:46 -05001422 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001423 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001424 delete corr;
1425
Thomas Tsou865bca42013-08-21 20:58:00 -04001426 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001427 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001428 } else if (!rc) {
1429 if (amp)
1430 *amp = 0.0f;
1431 if (toa)
1432 *toa = 0.0f;
1433 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001434 }
1435
Thomas Tsou865bca42013-08-21 20:58:00 -04001436 /* Subtract forward search bits from delay */
1437 if (toa)
1438 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001439 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001440 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001441
Thomas Tsou865bca42013-08-21 20:58:00 -04001442 return 1;
1443}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001444
Thomas Tsou865bca42013-08-21 20:58:00 -04001445/*
1446 * Normal burst detection
1447 *
1448 * Correlation window parameters:
1449 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001450 * head: Search 4 symbols before target
1451 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001452 */
1453int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1454 int sps, complex *amp, float *toa, unsigned max_toa,
1455 bool chan_req, signalVector **chan, float *chan_offset)
1456{
1457 int rc, start, target, head, tail, len;
1458 complex _amp;
1459 float _toa;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001460 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001461 CorrelationSequence *sync;
1462
1463 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
Tom Tsou577cd022015-05-18 13:57:54 -07001464 return -SIGERR_UNSUPPORTED;
1465
1466 if (detectClipping(rxBurst, CLIP_THRESH))
1467 return -SIGERR_CLIP;
Thomas Tsou865bca42013-08-21 20:58:00 -04001468
1469 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001470 head = 4;
1471 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001472
1473 start = (target - head) * sps - 1;
1474 len = (head + tail) * sps;
1475 sync = gMidambles[tsc];
Thomas Tsoub075dd22013-11-09 22:25:46 -05001476 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001477
Thomas Tsoub075dd22013-11-09 22:25:46 -05001478 rc = detectBurst(rxBurst, *corr, sync,
Thomas Tsou865bca42013-08-21 20:58:00 -04001479 thresh, sps, &_amp, &_toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001480 delete corr;
1481
Thomas Tsou865bca42013-08-21 20:58:00 -04001482 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001483 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001484 } else if (!rc) {
1485 if (amp)
1486 *amp = 0.0f;
1487 if (toa)
1488 *toa = 0.0f;
1489 return 0;
1490 }
1491
1492 /* Subtract forward search bits from delay */
1493 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001494 if (toa)
1495 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001496 if (amp)
1497 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001498
Thomas Tsou865bca42013-08-21 20:58:00 -04001499 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001500 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001501 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001502
1503 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001504 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001505 }
1506
Thomas Tsou3eaae802013-08-20 19:31:14 -04001507 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001508}
1509
Thomas Tsou94edaae2013-11-09 22:19:19 -05001510signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001511{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001512 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001513
Thomas Tsou94edaae2013-11-09 22:19:19 -05001514 if (factor <= 1)
1515 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001516
Thomas Tsou94edaae2013-11-09 22:19:19 -05001517 dec = new signalVector(wVector.size() / factor);
1518 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001519
Thomas Tsou94edaae2013-11-09 22:19:19 -05001520 signalVector::iterator itr = dec->begin();
1521 for (size_t i = 0; i < wVector.size(); i += factor)
1522 *itr++ = wVector[i];
1523
1524 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001525}
1526
Thomas Tsou83e06892013-08-20 16:10:01 -04001527SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05001528 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001529{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001530 signalVector *delay, *dec = NULL;
1531 SoftVector *bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001532
Thomas Tsou94edaae2013-11-09 22:19:19 -05001533 scaleVector(rxBurst, ((complex) 1.0) / channel);
1534 delay = delayVector(&rxBurst, NULL, -TOA);
dburgessb3a0ca42011-10-12 07:44:40 +00001535
Thomas Tsou94edaae2013-11-09 22:19:19 -05001536 /* Shift up by a quarter of a frequency */
1537 GMSKReverseRotate(*delay, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001538
Thomas Tsou94edaae2013-11-09 22:19:19 -05001539 /* Decimate and slice */
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001540 if (sps > 1) {
Thomas Tsou94edaae2013-11-09 22:19:19 -05001541 dec = decimateVector(*delay, sps);
1542 delete delay;
1543 delay = NULL;
1544 } else {
1545 dec = delay;
dburgessb3a0ca42011-10-12 07:44:40 +00001546 }
1547
Thomas Tsou94edaae2013-11-09 22:19:19 -05001548 vectorSlicer(dec);
dburgessb3a0ca42011-10-12 07:44:40 +00001549
Thomas Tsou94edaae2013-11-09 22:19:19 -05001550 bits = new SoftVector(dec->size());
dburgessb3a0ca42011-10-12 07:44:40 +00001551
Thomas Tsou94edaae2013-11-09 22:19:19 -05001552 SoftVector::iterator bit_itr = bits->begin();
1553 signalVector::iterator burst_itr = dec->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001554
Thomas Tsou94edaae2013-11-09 22:19:19 -05001555 for (; burst_itr < dec->end(); burst_itr++)
1556 *bit_itr++ = burst_itr->real();
dburgessb3a0ca42011-10-12 07:44:40 +00001557
Thomas Tsou94edaae2013-11-09 22:19:19 -05001558 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001559
Thomas Tsou94edaae2013-11-09 22:19:19 -05001560 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001561}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001562
dburgessb3a0ca42011-10-12 07:44:40 +00001563// Assumes symbol-spaced sampling!!!
1564// Based upon paper by Al-Dhahir and Cioffi
1565bool designDFE(signalVector &channelResponse,
1566 float SNRestimate,
1567 int Nf,
1568 signalVector **feedForwardFilter,
1569 signalVector **feedbackFilter)
1570{
1571
1572 signalVector G0(Nf);
1573 signalVector G1(Nf);
1574 signalVector::iterator G0ptr = G0.begin();
1575 signalVector::iterator G1ptr = G1.begin();
1576 signalVector::iterator chanPtr = channelResponse.begin();
1577
1578 int nu = channelResponse.size()-1;
1579
1580 *G0ptr = 1.0/sqrtf(SNRestimate);
1581 for(int j = 0; j <= nu; j++) {
1582 *G1ptr = chanPtr->conj();
1583 G1ptr++; chanPtr++;
1584 }
1585
1586 signalVector *L[Nf];
1587 signalVector::iterator Lptr;
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001588 float d = 1.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001589 for(int i = 0; i < Nf; i++) {
1590 d = G0.begin()->norm2() + G1.begin()->norm2();
1591 L[i] = new signalVector(Nf+nu);
1592 Lptr = L[i]->begin()+i;
1593 G0ptr = G0.begin(); G1ptr = G1.begin();
1594 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1595 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1596 Lptr++;
1597 G0ptr++;
1598 G1ptr++;
1599 }
1600 complex k = (*G1.begin())/(*G0.begin());
1601
1602 if (i != Nf-1) {
1603 signalVector G0new = G1;
1604 scaleVector(G0new,k.conj());
1605 addVector(G0new,G0);
1606
1607 signalVector G1new = G0;
1608 scaleVector(G1new,k*(-1.0));
1609 addVector(G1new,G1);
Thomas Tsou94edaae2013-11-09 22:19:19 -05001610 delayVector(&G1new, &G1new, -1.0);
dburgessb3a0ca42011-10-12 07:44:40 +00001611
1612 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1613 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1614 G0 = G0new;
1615 G1 = G1new;
1616 }
1617 }
1618
1619 *feedbackFilter = new signalVector(nu);
1620 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1621 scaleVector(**feedbackFilter,(complex) -1.0);
1622 conjugateVector(**feedbackFilter);
1623
1624 signalVector v(Nf);
1625 signalVector::iterator vStart = v.begin();
1626 signalVector::iterator vPtr;
1627 *(vStart+Nf-1) = (complex) 1.0;
1628 for(int k = Nf-2; k >= 0; k--) {
1629 Lptr = L[k]->begin()+k+1;
1630 vPtr = vStart + k+1;
1631 complex v_k = 0.0;
1632 for (int j = k+1; j < Nf; j++) {
1633 v_k -= (*vPtr)*(*Lptr);
1634 vPtr++; Lptr++;
1635 }
1636 *(vStart + k) = v_k;
1637 }
1638
1639 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001640 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001641 for (int i = 0; i < Nf; i++) {
1642 delete L[i];
1643 complex w_i = 0.0;
1644 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1645 vPtr = vStart+i;
1646 chanPtr = channelResponse.begin();
1647 for (int k = 0; k < endPt+1; k++) {
1648 w_i += (*vPtr)*(chanPtr->conj());
1649 vPtr++; chanPtr++;
1650 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001651 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001652 }
1653
1654
1655 return true;
1656
1657}
1658
1659// Assumes symbol-rate sampling!!!!
1660SoftVector *equalizeBurst(signalVector &rxBurst,
1661 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001662 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001663 signalVector &w, // feedforward filter
1664 signalVector &b) // feedback filter
1665{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001666 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001667
Thomas Tsou94edaae2013-11-09 22:19:19 -05001668 if (!delayVector(&rxBurst, &rxBurst, -TOA))
Thomas Tsou3eaae802013-08-20 19:31:14 -04001669 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001670
Thomas Tsou3eaae802013-08-20 19:31:14 -04001671 postForwardFull = convolve(&rxBurst, &w, NULL,
1672 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1673 if (!postForwardFull)
1674 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001675
1676 signalVector* postForward = new signalVector(rxBurst.size());
1677 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1678 delete postForwardFull;
1679
1680 signalVector::iterator dPtr = postForward->begin();
1681 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001682 signalVector::iterator rotPtr = GMSKRotationN->begin();
1683 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001684
1685 signalVector *DFEoutput = new signalVector(postForward->size());
1686 signalVector::iterator DFEItr = DFEoutput->begin();
1687
1688 // NOTE: can insert the midamble and/or use midamble to estimate BER
1689 for (; dPtr < postForward->end(); dPtr++) {
1690 dBackPtr = dPtr-1;
1691 signalVector::iterator bPtr = b.begin();
1692 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1693 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1694 bPtr++;
1695 dBackPtr--;
1696 }
1697 *dPtr = *dPtr * (*revRotPtr);
1698 *DFEItr = *dPtr;
1699 // make decision on symbol
1700 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1701 //*DFEItr = *dPtr;
1702 *dPtr = *dPtr * (*rotPtr);
1703 DFEItr++;
1704 rotPtr++;
1705 revRotPtr++;
1706 }
1707
1708 vectorSlicer(DFEoutput);
1709
1710 SoftVector *burstBits = new SoftVector(postForward->size());
1711 SoftVector::iterator burstItr = burstBits->begin();
1712 DFEItr = DFEoutput->begin();
1713 for (; DFEItr < DFEoutput->end(); DFEItr++)
1714 *burstItr++ = DFEItr->real();
1715
1716 delete postForward;
1717
1718 delete DFEoutput;
1719
1720 return burstBits;
1721}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001722
1723bool sigProcLibSetup(int sps)
1724{
1725 if ((sps != 1) && (sps != 4))
1726 return false;
1727
1728 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001729 generateSincTable();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001730 initGMSKRotationTables(sps);
1731
1732 GSMPulse1 = generateGSMPulse(1, 2);
1733 if (sps > 1)
1734 GSMPulse = generateGSMPulse(sps, 2);
1735
1736 if (!generateRACHSequence(1)) {
1737 sigProcLibDestroy();
1738 return false;
1739 }
1740
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001741 generateDelayFilters();
1742
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001743 return true;
1744}