blob: 8786c4a9ee28880dc1b29e5aa40005a800150924 [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"
Alexander Chemeris954b1182015-06-04 15:39:41 -040031#include "Logger.h"
dburgessb3a0ca42011-10-12 07:44:40 +000032
Thomas Tsou3eaae802013-08-20 19:31:14 -040033extern "C" {
34#include "convolve.h"
Thomas Tsou7e4e5362013-10-30 21:18:55 -040035#include "scale.h"
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -050036#include "mult.h"
Thomas Tsou3eaae802013-08-20 19:31:14 -040037}
38
Thomas Tsou7e4e5362013-10-30 21:18:55 -040039using namespace GSM;
40
Thomas Tsouf79c4d02013-11-09 15:51:56 -060041#define TABLESIZE 1024
42#define DELAYFILTS 64
dburgessb3a0ca42011-10-12 07:44:40 +000043
Tom Tsou577cd022015-05-18 13:57:54 -070044/* Clipping detection threshold */
45#define CLIP_THRESH 30000.0f
46
dburgessb3a0ca42011-10-12 07:44:40 +000047/** Lookup tables for trigonometric approximation */
48float cosTable[TABLESIZE+1]; // add 1 element for wrap around
49float sinTable[TABLESIZE+1];
Thomas Tsou0e0e1f42013-11-09 22:08:51 -050050float sincTable[TABLESIZE+1];
dburgessb3a0ca42011-10-12 07:44:40 +000051
52/** Constants */
53static const float M_PI_F = (float)M_PI;
54static const float M_2PI_F = (float)(2.0*M_PI);
55static const float M_1_2PI_F = 1/M_2PI_F;
56
Thomas Tsouc1f7c422013-10-11 13:49:55 -040057/* Precomputed rotation vectors */
Tom Tsou2079a3c2016-03-06 00:58:56 -080058static signalVector *GMSKRotation4 = NULL;
59static signalVector *GMSKReverseRotation4 = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040060static signalVector *GMSKRotation1 = NULL;
61static signalVector *GMSKReverseRotation1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000062
Thomas Tsouf79c4d02013-11-09 15:51:56 -060063/* Precomputed fractional delay filters */
64static signalVector *delayFilters[DELAYFILTS];
65
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040066/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040067 * RACH and midamble correlation waveforms. Store the buffer separately
68 * because we need to allocate it explicitly outside of the signal vector
69 * constructor. This is because C++ (prior to C++11) is unable to natively
70 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040071 */
72struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040073 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040074 {
75 }
76
77 ~CorrelationSequence()
78 {
79 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040080 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040081 }
82
dburgessb3a0ca42011-10-12 07:44:40 +000083 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040084 void *buffer;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040085 float toa;
dburgessb3a0ca42011-10-12 07:44:40 +000086 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040087};
dburgessb3a0ca42011-10-12 07:44:40 +000088
Thomas Tsou83e06892013-08-20 16:10:01 -040089/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040090 * Gaussian and empty modulation pulses. Like the correlation sequences,
91 * store the runtime (Gaussian) buffer separately because of needed alignment
92 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -040093 */
94struct PulseSequence {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080095 PulseSequence() : c0(NULL), c1(NULL), empty(NULL),
96 c0_buffer(NULL), c1_buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -040097 {
98 }
99
100 ~PulseSequence()
101 {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800102 delete c0;
103 delete c1;
Thomas Tsou83e06892013-08-20 16:10:01 -0400104 delete empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800105 free(c0_buffer);
106 free(c1_buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -0400107 }
108
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800109 signalVector *c0;
110 signalVector *c1;
Thomas Tsou83e06892013-08-20 16:10:01 -0400111 signalVector *empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800112 void *c0_buffer;
113 void *c1_buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -0400114};
115
dburgessb3a0ca42011-10-12 07:44:40 +0000116CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
117CorrelationSequence *gRACHSequence = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400118PulseSequence *GSMPulse1 = NULL;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800119PulseSequence *GSMPulse4 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000120
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400121void sigProcLibDestroy()
122{
dburgessb3a0ca42011-10-12 07:44:40 +0000123 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400124 delete gMidambles[i];
125 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000126 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400127
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600128 for (int i = 0; i < DELAYFILTS; i++) {
129 delete delayFilters[i];
130 delayFilters[i] = NULL;
131 }
132
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400133 delete GMSKRotation1;
134 delete GMSKReverseRotation1;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800135 delete GMSKRotation4;
136 delete GMSKReverseRotation4;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400137 delete gRACHSequence;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400138 delete GSMPulse1;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800139 delete GSMPulse4;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400140
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400141 GMSKRotation1 = NULL;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800142 GMSKRotation4 = NULL;
143 GMSKReverseRotation4 = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400144 GMSKReverseRotation1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400145 gRACHSequence = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400146 GSMPulse1 = NULL;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800147 GSMPulse4 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000148}
149
dburgessb3a0ca42011-10-12 07:44:40 +0000150// dB relative to 1.0.
151// if > 1.0, then return 0 dB
152float dB(float x) {
153
154 float arg = 1.0F;
155 float dB = 0.0F;
156
157 if (x >= 1.0F) return 0.0F;
158 if (x <= 0.0F) return -200.0F;
159
160 float prevArg = arg;
161 float prevdB = dB;
162 float stepSize = 16.0F;
163 float dBstepSize = 12.0F;
164 while (stepSize > 1.0F) {
165 do {
166 prevArg = arg;
167 prevdB = dB;
168 arg /= stepSize;
169 dB -= dBstepSize;
170 } while (arg > x);
171 arg = prevArg;
172 dB = prevdB;
173 stepSize *= 0.5F;
174 dBstepSize -= 3.0F;
175 }
176 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
177
178}
179
180// 10^(-dB/10), inverse of dB func.
181float dBinv(float x) {
182
183 float arg = 1.0F;
184 float dB = 0.0F;
185
186 if (x >= 0.0F) return 1.0F;
187 if (x <= -200.0F) return 0.0F;
188
189 float prevArg = arg;
190 float prevdB = dB;
191 float stepSize = 16.0F;
192 float dBstepSize = 12.0F;
193 while (stepSize > 1.0F) {
194 do {
195 prevArg = arg;
196 prevdB = dB;
197 arg /= stepSize;
198 dB -= dBstepSize;
199 } while (dB > x);
200 arg = prevArg;
201 dB = prevdB;
202 stepSize *= 0.5F;
203 dBstepSize -= 3.0F;
204 }
205
206 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
207
208}
209
210float vectorNorm2(const signalVector &x)
211{
212 signalVector::const_iterator xPtr = x.begin();
213 float Energy = 0.0;
214 for (;xPtr != x.end();xPtr++) {
215 Energy += xPtr->norm2();
216 }
217 return Energy;
218}
219
220
221float vectorPower(const signalVector &x)
222{
223 return vectorNorm2(x)/x.size();
224}
225
226/** compute cosine via lookup table */
227float cosLookup(const float x)
228{
229 float arg = x*M_1_2PI_F;
230 while (arg > 1.0F) arg -= 1.0F;
231 while (arg < 0.0F) arg += 1.0F;
232
233 const float argT = arg*((float)TABLESIZE);
234 const int argI = (int)argT;
235 const float delta = argT-argI;
236 const float iDelta = 1.0F-delta;
237 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
238}
239
240/** compute sine via lookup table */
241float sinLookup(const float x)
242{
243 float arg = x*M_1_2PI_F;
244 while (arg > 1.0F) arg -= 1.0F;
245 while (arg < 0.0F) arg += 1.0F;
246
247 const float argT = arg*((float)TABLESIZE);
248 const int argI = (int)argT;
249 const float delta = argT-argI;
250 const float iDelta = 1.0F-delta;
251 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
252}
253
254
255/** compute e^(-jx) via lookup table. */
Tom Tsou2079a3c2016-03-06 00:58:56 -0800256static complex expjLookup(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000257{
258 float arg = x*M_1_2PI_F;
259 while (arg > 1.0F) arg -= 1.0F;
260 while (arg < 0.0F) arg += 1.0F;
261
262 const float argT = arg*((float)TABLESIZE);
263 const int argI = (int)argT;
264 const float delta = argT-argI;
265 const float iDelta = 1.0F-delta;
266 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
267 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
268}
269
270/** Library setup functions */
Tom Tsou2079a3c2016-03-06 00:58:56 -0800271static void initTrigTables() {
dburgessb3a0ca42011-10-12 07:44:40 +0000272 for (int i = 0; i < TABLESIZE+1; i++) {
273 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
274 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
275 }
276}
277
Tom Tsou2079a3c2016-03-06 00:58:56 -0800278/*
279 * Initialize 4 sps and 1 sps rotation tables
280 */
281static void initGMSKRotationTables()
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400282{
Tom Tsou2079a3c2016-03-06 00:58:56 -0800283 size_t len1 = 157, len4 = 625;
284
285 GMSKRotation4 = new signalVector(len4);
286 GMSKReverseRotation4 = new signalVector(len4);
287 signalVector::iterator rotPtr = GMSKRotation4->begin();
288 signalVector::iterator revPtr = GMSKReverseRotation4->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000289 float phase = 0.0;
Tom Tsou2079a3c2016-03-06 00:58:56 -0800290 while (rotPtr != GMSKRotation4->end()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000291 *rotPtr++ = expjLookup(phase);
292 *revPtr++ = expjLookup(-phase);
Tom Tsou2079a3c2016-03-06 00:58:56 -0800293 phase += M_PI_F / 2.0F / 4.0;
dburgessb3a0ca42011-10-12 07:44:40 +0000294 }
dburgessb3a0ca42011-10-12 07:44:40 +0000295
Tom Tsou2079a3c2016-03-06 00:58:56 -0800296 GMSKRotation1 = new signalVector(len1);
297 GMSKReverseRotation1 = new signalVector(len1);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400298 rotPtr = GMSKRotation1->begin();
299 revPtr = GMSKReverseRotation1->begin();
300 phase = 0.0;
301 while (rotPtr != GMSKRotation1->end()) {
302 *rotPtr++ = expjLookup(phase);
303 *revPtr++ = expjLookup(-phase);
304 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400305 }
dburgessb3a0ca42011-10-12 07:44:40 +0000306}
307
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400308static void GMSKRotate(signalVector &x, int sps)
309{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500310#if HAVE_NEON
311 size_t len;
312 signalVector *a, *b, *out;
313
314 a = &x;
315 out = &x;
316 len = out->size();
317
318 if (len == 157)
319 len--;
320
321 if (sps == 1)
322 b = GMSKRotation1;
323 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800324 b = GMSKRotation4;
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500325
326 mul_complex((float *) out->begin(),
327 (float *) a->begin(),
328 (float *) b->begin(), len);
329#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400330 signalVector::iterator rotPtr, xPtr = x.begin();
331
332 if (sps == 1)
333 rotPtr = GMSKRotation1->begin();
334 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800335 rotPtr = GMSKRotation4->begin();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400336
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500337 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000338 while (xPtr < x.end()) {
339 *xPtr = *rotPtr++ * (xPtr->real());
340 xPtr++;
341 }
342 }
343 else {
344 while (xPtr < x.end()) {
345 *xPtr = *rotPtr++ * (*xPtr);
346 xPtr++;
347 }
348 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500349#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000350}
351
Tom Tsou2079a3c2016-03-06 00:58:56 -0800352static bool GMSKReverseRotate(signalVector &x, int sps)
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400353{
354 signalVector::iterator rotPtr, xPtr= x.begin();
355
356 if (sps == 1)
357 rotPtr = GMSKReverseRotation1->begin();
Tom Tsou2079a3c2016-03-06 00:58:56 -0800358 else if (sps == 4)
359 rotPtr = GMSKReverseRotation4->begin();
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400360 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800361 return false;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400362
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500363 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000364 while (xPtr < x.end()) {
365 *xPtr = *rotPtr++ * (xPtr->real());
366 xPtr++;
367 }
368 }
369 else {
370 while (xPtr < x.end()) {
371 *xPtr = *rotPtr++ * (*xPtr);
372 xPtr++;
373 }
374 }
Tom Tsou2079a3c2016-03-06 00:58:56 -0800375
376 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000377}
378
Thomas Tsou3eaae802013-08-20 19:31:14 -0400379signalVector *convolve(const signalVector *x,
380 const signalVector *h,
381 signalVector *y,
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500382 ConvType spanType, size_t start,
383 size_t len, size_t step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000384{
Thomas Tsou3f32ab52013-11-15 16:32:54 -0500385 int rc;
386 size_t head = 0, tail = 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400387 bool alloc = false, append = false;
388 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000389
Thomas Tsou3eaae802013-08-20 19:31:14 -0400390 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000391 return NULL;
392
Thomas Tsou3eaae802013-08-20 19:31:14 -0400393 switch (spanType) {
394 case START_ONLY:
395 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500396 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400397 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500398
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500399 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500400 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000401 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400402 case NO_DELAY:
403 start = h->size() / 2;
404 head = start;
405 tail = start;
406 len = x->size();
407 append = true;
408 break;
409 case CUSTOM:
410 if (start < h->size() - 1) {
411 head = h->size() - start;
412 append = true;
413 }
414 if (start + len > x->size()) {
415 tail = start + len - x->size();
416 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000417 }
418 break;
419 default:
420 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000421 }
dburgessb3a0ca42011-10-12 07:44:40 +0000422
Thomas Tsou3eaae802013-08-20 19:31:14 -0400423 /*
424 * Error if the output vector is too small. Create the output vector
425 * if the pointer is NULL.
426 */
427 if (y && (len > y->size()))
428 return NULL;
429 if (!y) {
430 y = new signalVector(len);
431 alloc = true;
432 }
433
434 /* Prepend or post-pend the input vector if the parameters require it */
435 if (append)
436 _x = new signalVector(*x, head, tail);
437 else
438 _x = x;
439
440 /*
441 * Four convovle types:
442 * 1. Complex-Real (aligned)
443 * 2. Complex-Complex (aligned)
444 * 3. Complex-Real (!aligned)
445 * 4. Complex-Complex (!aligned)
446 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500447 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400448 rc = 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 = convolve_complex((float *) _x->begin(), _x->size(),
454 (float *) h->begin(), h->size(),
455 (float *) y->begin(), y->size(),
456 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500457 } else if (h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400458 rc = base_convolve_real((float *) _x->begin(), _x->size(),
459 (float *) h->begin(), h->size(),
460 (float *) y->begin(), y->size(),
461 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500462 } else if (!h->isReal() && !h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400463 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
464 (float *) h->begin(), h->size(),
465 (float *) y->begin(), y->size(),
466 start, len, step, offset);
467 } else {
468 rc = -1;
469 }
470
471 if (append)
472 delete _x;
473
474 if (rc < 0) {
475 if (alloc)
476 delete y;
477 return NULL;
478 }
479
480 return y;
481}
dburgessb3a0ca42011-10-12 07:44:40 +0000482
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400483static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800484{
485 int len;
486
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400487 if (!pulse)
488 return false;
489
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800490 switch (sps) {
491 case 4:
492 len = 8;
493 break;
494 default:
495 return false;
496 }
497
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400498 pulse->c1_buffer = convolve_h_alloc(len);
499 pulse->c1 = new signalVector((complex *)
500 pulse->c1_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500501 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800502
503 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400504 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800505
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400506 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800507
508 switch (sps) {
509 case 4:
510 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400511 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800512 *xP++ = 8.16373112e-03;
513 *xP++ = 2.84385729e-02;
514 *xP++ = 5.64158904e-02;
515 *xP++ = 7.05463553e-02;
516 *xP++ = 5.64158904e-02;
517 *xP++ = 2.84385729e-02;
518 *xP++ = 8.16373112e-03;
519 }
520
521 return true;
522}
523
Tom Tsou2079a3c2016-03-06 00:58:56 -0800524static PulseSequence *generateGSMPulse(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +0000525{
Thomas Tsou83e06892013-08-20 16:10:01 -0400526 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800527 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400528 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400529
530 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400531 pulse = new PulseSequence();
532 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500533 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400534 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400535
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400536 /*
537 * For 4 samples-per-symbol use a precomputed single pulse Laurent
538 * approximation. This should yields below 2 degrees of phase error at
539 * the modulator output. Use the existing pulse approximation for all
540 * other oversampling factors.
541 */
542 switch (sps) {
543 case 4:
544 len = 16;
545 break;
546 default:
Tom Tsou2079a3c2016-03-06 00:58:56 -0800547 len = 4;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400548 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400549
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400550 pulse->c0_buffer = convolve_h_alloc(len);
551 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500552 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400553
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800554 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400555 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800556
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400557 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400558
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400559 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800560 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400561 *xP++ = 4.46348606e-03;
562 *xP++ = 2.84385729e-02;
563 *xP++ = 1.03184855e-01;
564 *xP++ = 2.56065552e-01;
565 *xP++ = 4.76375085e-01;
566 *xP++ = 7.05961177e-01;
567 *xP++ = 8.71291644e-01;
568 *xP++ = 9.29453645e-01;
569 *xP++ = 8.71291644e-01;
570 *xP++ = 7.05961177e-01;
571 *xP++ = 4.76375085e-01;
572 *xP++ = 2.56065552e-01;
573 *xP++ = 1.03184855e-01;
574 *xP++ = 2.84385729e-02;
575 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400576 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400577 } else {
578 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400579
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400580 /* GSM pulse approximation */
581 for (int i = 0; i < len; i++) {
582 arg = ((float) i - center) / (float) sps;
583 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
584 0.527 * arg * arg * arg * arg);
585 }
dburgessb3a0ca42011-10-12 07:44:40 +0000586
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400587 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
588 xP = pulse->c0->begin();
589 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800590 *xP++ /= avg;
591 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400592
593 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000594}
595
596signalVector* frequencyShift(signalVector *y,
597 signalVector *x,
598 float freq,
599 float startPhase,
600 float *finalPhase)
601{
602
603 if (!x) return NULL;
604
605 if (y==NULL) {
606 y = new signalVector(x->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500607 y->isReal(x->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000608 if (y==NULL) return NULL;
609 }
610
611 if (y->size() < x->size()) return NULL;
612
613 float phase = startPhase;
614 signalVector::iterator yP = y->begin();
615 signalVector::iterator xPEnd = x->end();
616 signalVector::iterator xP = x->begin();
617
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500618 if (x->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000619 while (xP < xPEnd) {
620 (*yP++) = expjLookup(phase)*( (xP++)->real() );
621 phase += freq;
622 }
623 }
624 else {
625 while (xP < xPEnd) {
626 (*yP++) = (*xP++)*expjLookup(phase);
627 phase += freq;
Thomas Tsou34bbef72013-11-13 22:58:15 -0500628 if (phase > 2 * M_PI)
629 phase -= 2 * M_PI;
630 else if (phase < -2 * M_PI)
631 phase += 2 * M_PI;
dburgessb3a0ca42011-10-12 07:44:40 +0000632 }
633 }
634
635
636 if (finalPhase) *finalPhase = phase;
637
638 return y;
639}
640
641signalVector* reverseConjugate(signalVector *b)
642{
643 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500644 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000645 signalVector::iterator bP = b->begin();
646 signalVector::iterator bPEnd = b->end();
647 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500648 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000649 while (bP < bPEnd) {
650 *tmpP-- = bP->conj();
651 bP++;
652 }
653 }
654 else {
655 while (bP < bPEnd) {
656 *tmpP-- = bP->real();
657 bP++;
658 }
659 }
660
661 return tmp;
662}
663
dburgessb3a0ca42011-10-12 07:44:40 +0000664/* soft output slicer */
665bool vectorSlicer(signalVector *x)
666{
667
668 signalVector::iterator xP = x->begin();
669 signalVector::iterator xPEnd = x->end();
670 while (xP < xPEnd) {
671 *xP = (complex) (0.5*(xP->real()+1.0F));
672 if (xP->real() > 1.0) *xP = 1.0;
673 if (xP->real() < 0.0) *xP = 0.0;
674 xP++;
675 }
676 return true;
677}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400678
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800679static signalVector *rotateBurst(const BitVector &wBurst,
680 int guardPeriodLength, int sps)
681{
682 int burst_len;
683 signalVector *pulse, rotated, *shaped;
684 signalVector::iterator itr;
685
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400686 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800687 burst_len = sps * (wBurst.size() + guardPeriodLength);
688 rotated = signalVector(burst_len);
689 itr = rotated.begin();
690
691 for (unsigned i = 0; i < wBurst.size(); i++) {
692 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
693 itr += sps;
694 }
695
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400696 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500697 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800698
699 /* Dummy filter operation */
700 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
701 if (!shaped)
702 return NULL;
703
704 return shaped;
705}
706
707static signalVector *modulateBurstLaurent(const BitVector &bits,
708 int guard_len, int sps)
709{
710 int burst_len;
711 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500712 signalVector *c0_pulse, *c1_pulse, *c0_burst;
713 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800714 signalVector::iterator c0_itr, c1_itr;
715
716 /*
717 * Apply before and after bits to reduce phase error at burst edges.
718 * Make sure there is enough room in the burst to accomodate all bits.
719 */
720 if (guard_len < 4)
721 guard_len = 4;
722
Tom Tsou2079a3c2016-03-06 00:58:56 -0800723 c0_pulse = GSMPulse4->c0;
724 c1_pulse = GSMPulse4->c1;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800725
726 burst_len = sps * (bits.size() + guard_len);
727
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500728 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500729 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500730 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800731
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500732 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500733 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500734 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800735
736 /* Padded differential start bits */
Alexander Chemeris351fd762015-05-24 20:16:51 -0400737 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800738 c0_itr += sps;
739
740 /* Main burst bits */
741 for (unsigned i = 0; i < bits.size(); i++) {
742 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
743 c0_itr += sps;
744 }
745
746 /* Padded differential end bits */
747 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
748
749 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500750 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500751 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800752
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500753 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800754 c0_itr += sps * 2;
755 c1_itr += sps * 2;
756
757 /* Start magic */
758 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
759 *c1_itr = *c0_itr * Complex<float>(0, phase);
760 c0_itr += sps;
761 c1_itr += sps;
762
763 /* Generate C1 phase coefficients */
764 for (unsigned i = 2; i < bits.size(); i++) {
765 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
766 *c1_itr = *c0_itr * Complex<float>(0, phase);
767
768 c0_itr += sps;
769 c1_itr += sps;
770 }
771
772 /* End magic */
773 int i = bits.size();
774 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
775 *c1_itr = *c0_itr * Complex<float>(0, phase);
776
777 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500778 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
779 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800780
781 /* Sum shaped outputs into C0 */
782 c0_itr = c0_shaped->begin();
783 c1_itr = c1_shaped->begin();
784 for (unsigned i = 0; i < c0_shaped->size(); i++ )
785 *c0_itr++ += *c1_itr++;
786
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500787 delete c0_burst;
788 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800789 delete c1_shaped;
790
791 return c0_shaped;
792}
793
794static signalVector *modulateBurstBasic(const BitVector &bits,
795 int guard_len, int sps)
796{
797 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500798 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800799 signalVector::iterator burst_itr;
800
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400801 if (sps == 1)
802 pulse = GSMPulse1->c0;
803 else
Tom Tsou2079a3c2016-03-06 00:58:56 -0800804 pulse = GSMPulse4->c0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400805
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800806 burst_len = sps * (bits.size() + guard_len);
807
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500808 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500809 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500810 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800811
812 /* Raw bits are not differentially encoded */
813 for (unsigned i = 0; i < bits.size(); i++) {
814 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
815 burst_itr += sps;
816 }
817
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500818 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500819 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800820
821 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500822 shaped = convolve(burst, pulse, NULL, START_ONLY);
823
824 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800825
826 return shaped;
827}
828
Thomas Tsou3eaae802013-08-20 19:31:14 -0400829/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400830signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
831 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000832{
Thomas Tsou83e06892013-08-20 16:10:01 -0400833 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800834 return rotateBurst(wBurst, guardPeriodLength, sps);
835 else if (sps == 4)
836 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400837 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800838 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000839}
840
Tom Tsou2079a3c2016-03-06 00:58:56 -0800841static void generateSincTable()
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500842{
843 float x;
844
845 for (int i = 0; i < TABLESIZE; i++) {
846 x = (float) i / TABLESIZE * 8 * M_PI;
847 if (fabs(x) < 0.01) {
848 sincTable[i] = 1.0f;
849 continue;
850 }
851
852 sincTable[i] = sinf(x) / x;
853 }
854}
855
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800856float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000857{
Thomas Tsou0e0e1f42013-11-09 22:08:51 -0500858 if (fabs(x) >= 8 * M_PI)
859 return 0.0;
860
861 int index = (int) floorf(fabs(x) / (8 * M_PI) * TABLESIZE);
862
863 return sincTable[index];
dburgessb3a0ca42011-10-12 07:44:40 +0000864}
865
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600866/*
867 * Create fractional delay filterbank with Blackman-harris windowed
868 * sinc function generator. The number of filters generated is specified
869 * by the DELAYFILTS value.
870 */
871void generateDelayFilters()
872{
873 int h_len = 20;
874 complex *data;
875 signalVector *h;
876 signalVector::iterator itr;
877
878 float k, sum;
879 float a0 = 0.35875;
880 float a1 = 0.48829;
881 float a2 = 0.14128;
882 float a3 = 0.01168;
883
884 for (int i = 0; i < DELAYFILTS; i++) {
885 data = (complex *) convolve_h_alloc(h_len);
886 h = new signalVector(data, 0, h_len);
887 h->setAligned(true);
888 h->isReal(true);
889
890 sum = 0.0;
891 itr = h->end();
892 for (int n = 0; n < h_len; n++) {
893 k = (float) n;
894 *--itr = (complex) sinc(M_PI_F *
895 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
896 *itr *= a0 -
897 a1 * cos(2 * M_PI * n / (h_len - 1)) +
898 a2 * cos(4 * M_PI * n / (h_len - 1)) -
899 a3 * cos(6 * M_PI * n / (h_len - 1));
900
901 sum += itr->real();
902 }
903
904 itr = h->begin();
905 for (int n = 0; n < h_len; n++)
906 *itr++ /= sum;
907
908 delayFilters[i] = h;
909 }
910}
911
Thomas Tsou94edaae2013-11-09 22:19:19 -0500912signalVector *delayVector(signalVector *in, signalVector *out, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000913{
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600914 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400915 float frac;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500916 signalVector *h, *shift, *fshift = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400917
Thomas Tsou2c282f52013-10-08 21:34:35 -0400918 whole = floor(delay);
919 frac = delay - whole;
920
921 /* Sinc interpolated fractional shift (if allowable) */
922 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600923 index = floorf(frac * (float) DELAYFILTS);
924 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -0400925
Thomas Tsou94edaae2013-11-09 22:19:19 -0500926 fshift = convolve(in, h, NULL, NO_DELAY);
927 if (!fshift)
928 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000929 }
930
Thomas Tsou94edaae2013-11-09 22:19:19 -0500931 if (!fshift)
932 shift = new signalVector(*in);
933 else
934 shift = fshift;
935
Thomas Tsou2c282f52013-10-08 21:34:35 -0400936 /* Integer sample shift */
937 if (whole < 0) {
938 whole = -whole;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500939 signalVector::iterator wBurstItr = shift->begin();
940 signalVector::iterator shiftedItr = shift->begin() + whole;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400941
Thomas Tsou94edaae2013-11-09 22:19:19 -0500942 while (shiftedItr < shift->end())
dburgessb3a0ca42011-10-12 07:44:40 +0000943 *wBurstItr++ = *shiftedItr++;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400944
Thomas Tsou94edaae2013-11-09 22:19:19 -0500945 while (wBurstItr < shift->end())
946 *wBurstItr++ = 0.0;
947 } else if (whole >= 0) {
948 signalVector::iterator wBurstItr = shift->end() - 1;
949 signalVector::iterator shiftedItr = shift->end() - 1 - whole;
950
951 while (shiftedItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000952 *wBurstItr-- = *shiftedItr--;
Thomas Tsou94edaae2013-11-09 22:19:19 -0500953
954 while (wBurstItr >= shift->begin())
dburgessb3a0ca42011-10-12 07:44:40 +0000955 *wBurstItr-- = 0.0;
956 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400957
Thomas Tsou94edaae2013-11-09 22:19:19 -0500958 if (!out)
959 return shift;
960
961 out->clone(*shift);
962 delete shift;
963 return out;
dburgessb3a0ca42011-10-12 07:44:40 +0000964}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400965
dburgessb3a0ca42011-10-12 07:44:40 +0000966signalVector *gaussianNoise(int length,
967 float variance,
968 complex mean)
969{
970
971 signalVector *noise = new signalVector(length);
972 signalVector::iterator nPtr = noise->begin();
973 float stddev = sqrtf(variance);
974 while (nPtr < noise->end()) {
975 float u1 = (float) rand()/ (float) RAND_MAX;
976 while (u1==0.0)
977 u1 = (float) rand()/ (float) RAND_MAX;
978 float u2 = (float) rand()/ (float) RAND_MAX;
979 float arg = 2.0*M_PI*u2;
980 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
981 nPtr++;
982 }
983
984 return noise;
985}
986
987complex interpolatePoint(const signalVector &inSig,
988 float ix)
989{
990
991 int start = (int) (floor(ix) - 10);
992 if (start < 0) start = 0;
993 int end = (int) (floor(ix) + 11);
994 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
995
996 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500997 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000998 for (int i = start; i < end; i++)
999 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
1000 }
1001 else {
1002 for (int i = start; i < end; i++)
1003 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
1004 }
1005
1006 return pVal;
1007}
1008
Thomas Tsou8181b012013-08-20 21:17:19 -04001009static complex fastPeakDetect(const signalVector &rxBurst, float *index)
1010{
1011 float val, max = 0.0f;
1012 complex amp;
1013 int _index = -1;
1014
Thomas Tsou3f32ab52013-11-15 16:32:54 -05001015 for (size_t i = 0; i < rxBurst.size(); i++) {
Thomas Tsou8181b012013-08-20 21:17:19 -04001016 val = rxBurst[i].norm2();
1017 if (val > max) {
1018 max = val;
1019 _index = i;
1020 amp = rxBurst[i];
1021 }
1022 }
1023
1024 if (index)
1025 *index = (float) _index;
1026
1027 return amp;
1028}
1029
dburgessb3a0ca42011-10-12 07:44:40 +00001030complex peakDetect(const signalVector &rxBurst,
1031 float *peakIndex,
1032 float *avgPwr)
1033{
1034
1035
1036 complex maxVal = 0.0;
1037 float maxIndex = -1;
1038 float sumPower = 0.0;
1039
1040 for (unsigned int i = 0; i < rxBurst.size(); i++) {
1041 float samplePower = rxBurst[i].norm2();
1042 if (samplePower > maxVal.real()) {
1043 maxVal = samplePower;
1044 maxIndex = i;
1045 }
1046 sumPower += samplePower;
1047 }
1048
1049 // interpolate around the peak
1050 // to save computation, we'll use early-late balancing
1051 float earlyIndex = maxIndex-1;
1052 float lateIndex = maxIndex+1;
1053
1054 float incr = 0.5;
1055 while (incr > 1.0/1024.0) {
1056 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1057 complex lateP = interpolatePoint(rxBurst,lateIndex);
1058 if (earlyP < lateP)
1059 earlyIndex += incr;
1060 else if (earlyP > lateP)
1061 earlyIndex -= incr;
1062 else break;
1063 incr /= 2.0;
1064 lateIndex = earlyIndex + 2.0;
1065 }
1066
1067 maxIndex = earlyIndex + 1.0;
1068 maxVal = interpolatePoint(rxBurst,maxIndex);
1069
1070 if (peakIndex!=NULL)
1071 *peakIndex = maxIndex;
1072
1073 if (avgPwr!=NULL)
1074 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1075
1076 return maxVal;
1077
1078}
1079
1080void scaleVector(signalVector &x,
1081 complex scale)
1082{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001083#ifdef HAVE_NEON
1084 int len = x.size();
1085
1086 scale_complex((float *) x.begin(),
1087 (float *) x.begin(),
1088 (float *) &scale, len);
1089#else
dburgessb3a0ca42011-10-12 07:44:40 +00001090 signalVector::iterator xP = x.begin();
1091 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001092 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001093 while (xP < xPEnd) {
1094 *xP = *xP * scale;
1095 xP++;
1096 }
1097 }
1098 else {
1099 while (xP < xPEnd) {
1100 *xP = xP->real() * scale;
1101 xP++;
1102 }
1103 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001104#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001105}
1106
1107/** in-place conjugation */
1108void conjugateVector(signalVector &x)
1109{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001110 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001111 signalVector::iterator xP = x.begin();
1112 signalVector::iterator xPEnd = x.end();
1113 while (xP < xPEnd) {
1114 *xP = xP->conj();
1115 xP++;
1116 }
1117}
1118
1119
1120// in-place addition!!
1121bool addVector(signalVector &x,
1122 signalVector &y)
1123{
1124 signalVector::iterator xP = x.begin();
1125 signalVector::iterator yP = y.begin();
1126 signalVector::iterator xPEnd = x.end();
1127 signalVector::iterator yPEnd = y.end();
1128 while ((xP < xPEnd) && (yP < yPEnd)) {
1129 *xP = *xP + *yP;
1130 xP++; yP++;
1131 }
1132 return true;
1133}
1134
1135// in-place multiplication!!
1136bool multVector(signalVector &x,
1137 signalVector &y)
1138{
1139 signalVector::iterator xP = x.begin();
1140 signalVector::iterator yP = y.begin();
1141 signalVector::iterator xPEnd = x.end();
1142 signalVector::iterator yPEnd = y.end();
1143 while ((xP < xPEnd) && (yP < yPEnd)) {
1144 *xP = (*xP) * (*yP);
1145 xP++; yP++;
1146 }
1147 return true;
1148}
1149
Tom Tsou2079a3c2016-03-06 00:58:56 -08001150static bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001151{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001152 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001153 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001154 complex *data = NULL;
1155 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001156 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001157
Thomas Tsou3eaae802013-08-20 19:31:14 -04001158 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001159 return false;
1160
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001161 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001162
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001163 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1164 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1165 if (!midMidamble)
1166 return false;
1167
Thomas Tsou3eaae802013-08-20 19:31:14 -04001168 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001169 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1170 if (!midamble) {
1171 status = false;
1172 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001173 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001174
dburgessb3a0ca42011-10-12 07:44:40 +00001175 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1176 // the ideal TSC has an + 180 degree phase shift,
1177 // due to the pi/2 frequency shift, that
1178 // needs to be accounted for.
1179 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001180 scaleVector(*midMidamble, complex(-1.0, 0.0));
1181 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001182
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001183 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001184
Thomas Tsou3eaae802013-08-20 19:31:14 -04001185 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1186 data = (complex *) convolve_h_alloc(midMidamble->size());
1187 _midMidamble = new signalVector(data, 0, midMidamble->size());
1188 _midMidamble->setAligned(true);
1189 memcpy(_midMidamble->begin(), midMidamble->begin(),
1190 midMidamble->size() * sizeof(complex));
1191
1192 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001193 if (!autocorr) {
1194 status = false;
1195 goto release;
1196 }
dburgessb3a0ca42011-10-12 07:44:40 +00001197
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001198 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001199 gMidambles[tsc]->buffer = data;
1200 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001201 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1202
1203 /* For 1 sps only
1204 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1205 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1206 */
1207 if (sps == 1)
1208 gMidambles[tsc]->toa = toa - 13.5;
1209 else
1210 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001211
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001212release:
dburgessb3a0ca42011-10-12 07:44:40 +00001213 delete autocorr;
1214 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001215 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001216
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001217 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001218 delete _midMidamble;
1219 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001220 gMidambles[tsc] = NULL;
1221 }
1222
1223 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001224}
1225
Tom Tsou2079a3c2016-03-06 00:58:56 -08001226static bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001227{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001228 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001229 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001230 complex *data = NULL;
1231 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001232 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001233
1234 delete gRACHSequence;
1235
1236 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1237 if (!seq0)
1238 return false;
1239
1240 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1241 if (!seq1) {
1242 status = false;
1243 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001244 }
1245
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001246 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001247
Thomas Tsou3eaae802013-08-20 19:31:14 -04001248 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1249 data = (complex *) convolve_h_alloc(seq1->size());
1250 _seq1 = new signalVector(data, 0, seq1->size());
1251 _seq1->setAligned(true);
1252 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1253
1254 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1255 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001256 status = false;
1257 goto release;
1258 }
dburgessb3a0ca42011-10-12 07:44:40 +00001259
1260 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001261 gRACHSequence->sequence = _seq1;
1262 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001263 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1264
1265 /* For 1 sps only
1266 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1267 * 20.5 = (40 / 2 - 1) + 1.5
1268 */
1269 if (sps == 1)
1270 gRACHSequence->toa = toa - 20.5;
1271 else
1272 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001273
1274release:
dburgessb3a0ca42011-10-12 07:44:40 +00001275 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001276 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001277 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001278
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001279 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001280 delete _seq1;
1281 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001282 gRACHSequence = NULL;
1283 }
dburgessb3a0ca42011-10-12 07:44:40 +00001284
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001285 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001286}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001287
Thomas Tsou865bca42013-08-21 20:58:00 -04001288static float computePeakRatio(signalVector *corr,
1289 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001290{
Thomas Tsou865bca42013-08-21 20:58:00 -04001291 int num = 0;
1292 complex *peak;
1293 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001294
Thomas Tsou865bca42013-08-21 20:58:00 -04001295 /* Check for bogus results */
1296 if ((toa < 0.0) || (toa > corr->size()))
1297 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001298
Alexander Chemeris1e9b4d52015-06-04 19:05:28 -04001299 peak = corr->begin() + (int) rint(toa);
1300
Thomas Tsou3eaae802013-08-20 19:31:14 -04001301 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001302 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001303 avg += (peak - i)->norm2();
1304 num++;
1305 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001306 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001307 avg += (peak + i)->norm2();
1308 num++;
1309 }
dburgessb3a0ca42011-10-12 07:44:40 +00001310 }
1311
Thomas Tsou3eaae802013-08-20 19:31:14 -04001312 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001313 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001314
Thomas Tsou3eaae802013-08-20 19:31:14 -04001315 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001316
Thomas Tsou865bca42013-08-21 20:58:00 -04001317 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001318}
1319
1320bool energyDetect(signalVector &rxBurst,
1321 unsigned windowLength,
1322 float detectThreshold,
1323 float *avgPwr)
1324{
1325
1326 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1327 float energy = 0.0;
1328 if (windowLength < 0) windowLength = 20;
1329 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1330 for (unsigned i = 0; i < windowLength; i++) {
1331 energy += windowItr->norm2();
1332 windowItr+=4;
1333 }
1334 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001335 return (energy/windowLength > detectThreshold*detectThreshold);
1336}
dburgessb3a0ca42011-10-12 07:44:40 +00001337
Thomas Tsou865bca42013-08-21 20:58:00 -04001338/*
1339 * Detect a burst based on correlation and peak-to-average ratio
1340 *
1341 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1342 * for initial gating. We do this because energy detection should be disabled.
1343 * For higher oversampling values, we assume the energy detector is in place
1344 * and we run full interpolating peak detection.
1345 */
1346static int detectBurst(signalVector &burst,
1347 signalVector &corr, CorrelationSequence *sync,
1348 float thresh, int sps, complex *amp, float *toa,
1349 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001350{
Thomas Tsou865bca42013-08-21 20:58:00 -04001351 /* Correlate */
1352 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001353 CUSTOM, start, len, sps, 0)) {
1354 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001355 }
1356
Thomas Tsou865bca42013-08-21 20:58:00 -04001357 /* Peak detection - place restrictions at correlation edges */
1358 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001359
Thomas Tsou865bca42013-08-21 20:58:00 -04001360 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1361 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001362
Thomas Tsou865bca42013-08-21 20:58:00 -04001363 /* Peak -to-average ratio */
1364 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1365 return 0;
1366
1367 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1368 *amp = peakDetect(corr, toa, NULL);
1369
1370 /* Normalize our channel gain */
1371 *amp = *amp / sync->gain;
1372
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001373 /* Compenate for residual rotation with dual Laurent pulse */
1374 if (sps == 4)
1375 *amp = *amp * complex(0.0, 1.0);
1376
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001377 /* Compensate for residuate time lag */
1378 *toa = *toa - sync->toa;
1379
Thomas Tsou865bca42013-08-21 20:58:00 -04001380 return 1;
1381}
1382
Alexander Chemeris954b1182015-06-04 15:39:41 -04001383static float maxAmplitude(signalVector &burst)
Tom Tsou577cd022015-05-18 13:57:54 -07001384{
Alexander Chemeris954b1182015-06-04 15:39:41 -04001385 float max = 0.0;
1386 for (size_t i = 0; i < burst.size(); i++) {
1387 if (fabs(burst[i].real()) > max)
1388 max = fabs(burst[i].real());
1389 if (fabs(burst[i].imag()) > max)
1390 max = fabs(burst[i].imag());
1391 }
Tom Tsou577cd022015-05-18 13:57:54 -07001392
Alexander Chemeris954b1182015-06-04 15:39:41 -04001393 return max;
Tom Tsou577cd022015-05-18 13:57:54 -07001394}
1395
Alexander Chemeris130a8002015-06-09 20:52:11 -04001396/*
1397 * RACH/Normal burst detection with clipping detection
Thomas Tsou865bca42013-08-21 20:58:00 -04001398 *
1399 * Correlation window parameters:
Alexander Chemeris130a8002015-06-09 20:52:11 -04001400 * target: Tail bits + burst length
1401 * head: Search symbols before target
1402 * tail: Search symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001403 */
Alexander Chemeris130a8002015-06-09 20:52:11 -04001404int detectGeneralBurst(signalVector &rxBurst,
1405 float thresh,
1406 int sps,
1407 complex &amp,
1408 float &toa,
1409 int target, int head, int tail,
1410 CorrelationSequence *sync)
Thomas Tsou865bca42013-08-21 20:58:00 -04001411{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001412 int rc, start, len;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001413 bool clipping = false;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001414 signalVector *corr;
Thomas Tsou865bca42013-08-21 20:58:00 -04001415
1416 if ((sps != 1) && (sps != 4))
Tom Tsou577cd022015-05-18 13:57:54 -07001417 return -SIGERR_UNSUPPORTED;
1418
Alexander Chemeris954b1182015-06-04 15:39:41 -04001419 // Detect potential clipping
1420 // We still may be able to demod the burst, so we'll give it a try
1421 // and only report clipping if we can't demod.
1422 float maxAmpl = maxAmplitude(rxBurst);
1423 if (maxAmpl > CLIP_THRESH) {
1424 LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
1425 clipping = true;
1426 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001427
Thomas Tsou865bca42013-08-21 20:58:00 -04001428 start = (target - head) * sps - 1;
1429 len = (head + tail) * sps;
Thomas Tsoub075dd22013-11-09 22:25:46 -05001430 corr = new signalVector(len);
Thomas Tsou865bca42013-08-21 20:58:00 -04001431
Thomas Tsoub075dd22013-11-09 22:25:46 -05001432 rc = detectBurst(rxBurst, *corr, sync,
Alexander Chemeris130a8002015-06-09 20:52:11 -04001433 thresh, sps, &amp, &toa, start, len);
Thomas Tsoub075dd22013-11-09 22:25:46 -05001434 delete corr;
1435
Thomas Tsou865bca42013-08-21 20:58:00 -04001436 if (rc < 0) {
Tom Tsou577cd022015-05-18 13:57:54 -07001437 return -SIGERR_INTERNAL;
Thomas Tsou865bca42013-08-21 20:58:00 -04001438 } else if (!rc) {
Alexander Chemeris130a8002015-06-09 20:52:11 -04001439 amp = 0.0f;
1440 toa = 0.0f;
Alexander Chemeris954b1182015-06-04 15:39:41 -04001441 return clipping?-SIGERR_CLIP:SIGERR_NONE;
dburgessb3a0ca42011-10-12 07:44:40 +00001442 }
1443
Thomas Tsou865bca42013-08-21 20:58:00 -04001444 /* Subtract forward search bits from delay */
Alexander Chemeris130a8002015-06-09 20:52:11 -04001445 toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001446
Thomas Tsou865bca42013-08-21 20:58:00 -04001447 return 1;
1448}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001449
Alexander Chemeris130a8002015-06-09 20:52:11 -04001450
1451/*
1452 * RACH burst detection
1453 *
1454 * Correlation window parameters:
1455 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
1456 * head: Search 4 symbols before target
1457 * tail: Search 10 symbols after target
1458 */
1459int detectRACHBurst(signalVector &rxBurst,
1460 float thresh,
1461 int sps,
1462 complex &amp,
1463 float &toa)
1464{
1465 int rc, target, head, tail;
1466 CorrelationSequence *sync;
1467
1468 target = 8 + 40;
1469 head = 4;
1470 tail = 10;
1471 sync = gRACHSequence;
1472
1473 rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa,
1474 target, head, tail, sync);
1475
1476 return rc;
1477}
1478
Thomas Tsou865bca42013-08-21 20:58:00 -04001479/*
1480 * Normal burst detection
1481 *
1482 * Correlation window parameters:
1483 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001484 * head: Search 4 symbols before target
1485 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001486 */
1487int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
Tom Tsou46569402016-03-06 01:59:38 -08001488 int sps, complex &amp, float &toa, unsigned max_toa)
Thomas Tsou865bca42013-08-21 20:58:00 -04001489{
Alexander Chemeris130a8002015-06-09 20:52:11 -04001490 int rc, target, head, tail;
Thomas Tsou865bca42013-08-21 20:58:00 -04001491 CorrelationSequence *sync;
1492
Alexander Chemeris130a8002015-06-09 20:52:11 -04001493 if ((tsc < 0) || (tsc > 7))
Tom Tsou577cd022015-05-18 13:57:54 -07001494 return -SIGERR_UNSUPPORTED;
1495
Thomas Tsou865bca42013-08-21 20:58:00 -04001496 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001497 head = 4;
1498 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001499 sync = gMidambles[tsc];
Thomas Tsou865bca42013-08-21 20:58:00 -04001500
Alexander Chemeris130a8002015-06-09 20:52:11 -04001501 rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa,
1502 target, head, tail, sync);
Alexander Chemeris130a8002015-06-09 20:52:11 -04001503 return rc;
dburgessb3a0ca42011-10-12 07:44:40 +00001504}
1505
Thomas Tsou94edaae2013-11-09 22:19:19 -05001506signalVector *decimateVector(signalVector &wVector, size_t factor)
dburgessb3a0ca42011-10-12 07:44:40 +00001507{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001508 signalVector *dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001509
Thomas Tsou94edaae2013-11-09 22:19:19 -05001510 if (factor <= 1)
1511 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001512
Thomas Tsou94edaae2013-11-09 22:19:19 -05001513 dec = new signalVector(wVector.size() / factor);
1514 dec->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001515
Thomas Tsou94edaae2013-11-09 22:19:19 -05001516 signalVector::iterator itr = dec->begin();
1517 for (size_t i = 0; i < wVector.size(); i += factor)
1518 *itr++ = wVector[i];
1519
1520 return dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001521}
1522
Thomas Tsou83e06892013-08-20 16:10:01 -04001523SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
Thomas Tsou94edaae2013-11-09 22:19:19 -05001524 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001525{
Thomas Tsou94edaae2013-11-09 22:19:19 -05001526 signalVector *delay, *dec = NULL;
1527 SoftVector *bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001528
Thomas Tsou94edaae2013-11-09 22:19:19 -05001529 scaleVector(rxBurst, ((complex) 1.0) / channel);
1530 delay = delayVector(&rxBurst, NULL, -TOA);
dburgessb3a0ca42011-10-12 07:44:40 +00001531
Thomas Tsou94edaae2013-11-09 22:19:19 -05001532 /* Shift up by a quarter of a frequency */
1533 GMSKReverseRotate(*delay, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001534
Thomas Tsou94edaae2013-11-09 22:19:19 -05001535 /* Decimate and slice */
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001536 if (sps > 1) {
Thomas Tsou94edaae2013-11-09 22:19:19 -05001537 dec = decimateVector(*delay, sps);
1538 delete delay;
1539 delay = NULL;
1540 } else {
1541 dec = delay;
dburgessb3a0ca42011-10-12 07:44:40 +00001542 }
1543
Thomas Tsou94edaae2013-11-09 22:19:19 -05001544 vectorSlicer(dec);
dburgessb3a0ca42011-10-12 07:44:40 +00001545
Thomas Tsou94edaae2013-11-09 22:19:19 -05001546 bits = new SoftVector(dec->size());
dburgessb3a0ca42011-10-12 07:44:40 +00001547
Thomas Tsou94edaae2013-11-09 22:19:19 -05001548 SoftVector::iterator bit_itr = bits->begin();
1549 signalVector::iterator burst_itr = dec->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001550
Thomas Tsou94edaae2013-11-09 22:19:19 -05001551 for (; burst_itr < dec->end(); burst_itr++)
1552 *bit_itr++ = burst_itr->real();
dburgessb3a0ca42011-10-12 07:44:40 +00001553
Thomas Tsou94edaae2013-11-09 22:19:19 -05001554 delete dec;
dburgessb3a0ca42011-10-12 07:44:40 +00001555
Thomas Tsou94edaae2013-11-09 22:19:19 -05001556 return bits;
dburgessb3a0ca42011-10-12 07:44:40 +00001557}
Thomas Tsou94edaae2013-11-09 22:19:19 -05001558
Tom Tsou2079a3c2016-03-06 00:58:56 -08001559bool sigProcLibSetup()
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001560{
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001561 initTrigTables();
Thomas Tsou0e0e1f42013-11-09 22:08:51 -05001562 generateSincTable();
Tom Tsou2079a3c2016-03-06 00:58:56 -08001563 initGMSKRotationTables();
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001564
Tom Tsou2079a3c2016-03-06 00:58:56 -08001565 GSMPulse1 = generateGSMPulse(1);
1566 GSMPulse4 = generateGSMPulse(4);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001567
Tom Tsou2079a3c2016-03-06 00:58:56 -08001568 generateRACHSequence(1);
1569 for (int tsc = 0; tsc < 8; tsc++)
1570 generateMidamble(1, tsc);
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001571
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001572 generateDelayFilters();
1573
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001574 return true;
1575}