blob: efa8f5d45a2a3220b7cb6df76a55ac9c58dcef08 [file] [log] [blame]
dburgessb3a0ca42011-10-12 07:44:40 +00001/*
kurtis.heimerla198d452011-11-26 03:19:28 +00002* Copyright 2008, 2011 Free Software Foundation, Inc.
dburgessb3a0ca42011-10-12 07:44:40 +00003*
4* This software is distributed under the terms of the GNU Affero Public License.
5* See the COPYING file in the main directory for details.
6*
7* This use of this software may be subject to additional restrictions.
8* See the LEGAL file in the main directory for details.
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
19
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22
23*/
24
Thomas Tsou7e4e5362013-10-30 21:18:55 -040025#ifdef HAVE_CONFIG_H
26#include "config.h"
27#endif
28
dburgessb3a0ca42011-10-12 07:44:40 +000029#include "sigProcLib.h"
30#include "GSMCommon.h"
31
Thomas Tsou3eaae802013-08-20 19:31:14 -040032extern "C" {
33#include "convolve.h"
Thomas Tsou7e4e5362013-10-30 21:18:55 -040034#include "scale.h"
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -050035#include "mult.h"
Thomas Tsou3eaae802013-08-20 19:31:14 -040036}
37
Thomas Tsou7e4e5362013-10-30 21:18:55 -040038using namespace GSM;
39
Thomas Tsouf79c4d02013-11-09 15:51:56 -060040#define TABLESIZE 1024
41#define DELAYFILTS 64
dburgessb3a0ca42011-10-12 07:44:40 +000042
43/** Lookup tables for trigonometric approximation */
44float cosTable[TABLESIZE+1]; // add 1 element for wrap around
45float sinTable[TABLESIZE+1];
46
47/** Constants */
48static const float M_PI_F = (float)M_PI;
49static const float M_2PI_F = (float)(2.0*M_PI);
50static const float M_1_2PI_F = 1/M_2PI_F;
51
Thomas Tsouc1f7c422013-10-11 13:49:55 -040052/* Precomputed rotation vectors */
53static signalVector *GMSKRotationN = NULL;
54static signalVector *GMSKReverseRotationN = NULL;
55static signalVector *GMSKRotation1 = NULL;
56static signalVector *GMSKReverseRotation1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000057
Thomas Tsouf79c4d02013-11-09 15:51:56 -060058/* Precomputed fractional delay filters */
59static signalVector *delayFilters[DELAYFILTS];
60
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040061/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040062 * RACH and midamble correlation waveforms. Store the buffer separately
63 * because we need to allocate it explicitly outside of the signal vector
64 * constructor. This is because C++ (prior to C++11) is unable to natively
65 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040066 */
67struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040068 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040069 {
70 }
71
72 ~CorrelationSequence()
73 {
74 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040075 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040076 }
77
dburgessb3a0ca42011-10-12 07:44:40 +000078 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040079 void *buffer;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040080 float toa;
dburgessb3a0ca42011-10-12 07:44:40 +000081 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040082};
dburgessb3a0ca42011-10-12 07:44:40 +000083
Thomas Tsou83e06892013-08-20 16:10:01 -040084/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040085 * Gaussian and empty modulation pulses. Like the correlation sequences,
86 * store the runtime (Gaussian) buffer separately because of needed alignment
87 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -040088 */
89struct PulseSequence {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080090 PulseSequence() : c0(NULL), c1(NULL), empty(NULL),
91 c0_buffer(NULL), c1_buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -040092 {
93 }
94
95 ~PulseSequence()
96 {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080097 delete c0;
98 delete c1;
Thomas Tsou83e06892013-08-20 16:10:01 -040099 delete empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800100 free(c0_buffer);
101 free(c1_buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -0400102 }
103
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800104 signalVector *c0;
105 signalVector *c1;
Thomas Tsou83e06892013-08-20 16:10:01 -0400106 signalVector *empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800107 void *c0_buffer;
108 void *c1_buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -0400109};
110
dburgessb3a0ca42011-10-12 07:44:40 +0000111CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
112CorrelationSequence *gRACHSequence = NULL;
Thomas Tsou83e06892013-08-20 16:10:01 -0400113PulseSequence *GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400114PulseSequence *GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000115
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400116void sigProcLibDestroy()
117{
dburgessb3a0ca42011-10-12 07:44:40 +0000118 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400119 delete gMidambles[i];
120 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000121 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400122
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600123 for (int i = 0; i < DELAYFILTS; i++) {
124 delete delayFilters[i];
125 delayFilters[i] = NULL;
126 }
127
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400128 delete GMSKRotationN;
129 delete GMSKReverseRotationN;
130 delete GMSKRotation1;
131 delete GMSKReverseRotation1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400132 delete gRACHSequence;
133 delete GSMPulse;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400134 delete GSMPulse1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400135
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400136 GMSKRotationN = NULL;
137 GMSKRotation1 = NULL;
138 GMSKReverseRotationN = NULL;
139 GMSKReverseRotation1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400140 gRACHSequence = NULL;
141 GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400142 GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000143}
144
dburgessb3a0ca42011-10-12 07:44:40 +0000145// dB relative to 1.0.
146// if > 1.0, then return 0 dB
147float dB(float x) {
148
149 float arg = 1.0F;
150 float dB = 0.0F;
151
152 if (x >= 1.0F) return 0.0F;
153 if (x <= 0.0F) return -200.0F;
154
155 float prevArg = arg;
156 float prevdB = dB;
157 float stepSize = 16.0F;
158 float dBstepSize = 12.0F;
159 while (stepSize > 1.0F) {
160 do {
161 prevArg = arg;
162 prevdB = dB;
163 arg /= stepSize;
164 dB -= dBstepSize;
165 } while (arg > x);
166 arg = prevArg;
167 dB = prevdB;
168 stepSize *= 0.5F;
169 dBstepSize -= 3.0F;
170 }
171 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
172
173}
174
175// 10^(-dB/10), inverse of dB func.
176float dBinv(float x) {
177
178 float arg = 1.0F;
179 float dB = 0.0F;
180
181 if (x >= 0.0F) return 1.0F;
182 if (x <= -200.0F) return 0.0F;
183
184 float prevArg = arg;
185 float prevdB = dB;
186 float stepSize = 16.0F;
187 float dBstepSize = 12.0F;
188 while (stepSize > 1.0F) {
189 do {
190 prevArg = arg;
191 prevdB = dB;
192 arg /= stepSize;
193 dB -= dBstepSize;
194 } while (dB > x);
195 arg = prevArg;
196 dB = prevdB;
197 stepSize *= 0.5F;
198 dBstepSize -= 3.0F;
199 }
200
201 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
202
203}
204
205float vectorNorm2(const signalVector &x)
206{
207 signalVector::const_iterator xPtr = x.begin();
208 float Energy = 0.0;
209 for (;xPtr != x.end();xPtr++) {
210 Energy += xPtr->norm2();
211 }
212 return Energy;
213}
214
215
216float vectorPower(const signalVector &x)
217{
218 return vectorNorm2(x)/x.size();
219}
220
221/** compute cosine via lookup table */
222float cosLookup(const float x)
223{
224 float arg = x*M_1_2PI_F;
225 while (arg > 1.0F) arg -= 1.0F;
226 while (arg < 0.0F) arg += 1.0F;
227
228 const float argT = arg*((float)TABLESIZE);
229 const int argI = (int)argT;
230 const float delta = argT-argI;
231 const float iDelta = 1.0F-delta;
232 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
233}
234
235/** compute sine via lookup table */
236float sinLookup(const float x)
237{
238 float arg = x*M_1_2PI_F;
239 while (arg > 1.0F) arg -= 1.0F;
240 while (arg < 0.0F) arg += 1.0F;
241
242 const float argT = arg*((float)TABLESIZE);
243 const int argI = (int)argT;
244 const float delta = argT-argI;
245 const float iDelta = 1.0F-delta;
246 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
247}
248
249
250/** compute e^(-jx) via lookup table. */
251complex expjLookup(float x)
252{
253 float arg = x*M_1_2PI_F;
254 while (arg > 1.0F) arg -= 1.0F;
255 while (arg < 0.0F) arg += 1.0F;
256
257 const float argT = arg*((float)TABLESIZE);
258 const int argI = (int)argT;
259 const float delta = argT-argI;
260 const float iDelta = 1.0F-delta;
261 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
262 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
263}
264
265/** Library setup functions */
266void initTrigTables() {
267 for (int i = 0; i < TABLESIZE+1; i++) {
268 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
269 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
270 }
271}
272
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400273void initGMSKRotationTables(int sps)
274{
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400275 GMSKRotationN = new signalVector(157 * sps);
276 GMSKReverseRotationN = new signalVector(157 * sps);
277 signalVector::iterator rotPtr = GMSKRotationN->begin();
278 signalVector::iterator revPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000279 float phase = 0.0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400280 while (rotPtr != GMSKRotationN->end()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000281 *rotPtr++ = expjLookup(phase);
282 *revPtr++ = expjLookup(-phase);
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400283 phase += M_PI_F / 2.0F / (float) sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000284 }
dburgessb3a0ca42011-10-12 07:44:40 +0000285
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400286 GMSKRotation1 = new signalVector(157);
287 GMSKReverseRotation1 = new signalVector(157);
288 rotPtr = GMSKRotation1->begin();
289 revPtr = GMSKReverseRotation1->begin();
290 phase = 0.0;
291 while (rotPtr != GMSKRotation1->end()) {
292 *rotPtr++ = expjLookup(phase);
293 *revPtr++ = expjLookup(-phase);
294 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400295 }
dburgessb3a0ca42011-10-12 07:44:40 +0000296}
297
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400298static void GMSKRotate(signalVector &x, int sps)
299{
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500300#if HAVE_NEON
301 size_t len;
302 signalVector *a, *b, *out;
303
304 a = &x;
305 out = &x;
306 len = out->size();
307
308 if (len == 157)
309 len--;
310
311 if (sps == 1)
312 b = GMSKRotation1;
313 else
314 b = GMSKRotationN;
315
316 mul_complex((float *) out->begin(),
317 (float *) a->begin(),
318 (float *) b->begin(), len);
319#else
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400320 signalVector::iterator rotPtr, xPtr = x.begin();
321
322 if (sps == 1)
323 rotPtr = GMSKRotation1->begin();
324 else
325 rotPtr = GMSKRotationN->begin();
326
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500327 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000328 while (xPtr < x.end()) {
329 *xPtr = *rotPtr++ * (xPtr->real());
330 xPtr++;
331 }
332 }
333 else {
334 while (xPtr < x.end()) {
335 *xPtr = *rotPtr++ * (*xPtr);
336 xPtr++;
337 }
338 }
Thomas Tsou0a3dc4c2013-11-09 02:29:55 -0500339#endif
dburgessb3a0ca42011-10-12 07:44:40 +0000340}
341
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400342static void GMSKReverseRotate(signalVector &x, int sps)
343{
344 signalVector::iterator rotPtr, xPtr= x.begin();
345
346 if (sps == 1)
347 rotPtr = GMSKReverseRotation1->begin();
348 else
349 rotPtr = GMSKReverseRotationN->begin();
350
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500351 if (x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000352 while (xPtr < x.end()) {
353 *xPtr = *rotPtr++ * (xPtr->real());
354 xPtr++;
355 }
356 }
357 else {
358 while (xPtr < x.end()) {
359 *xPtr = *rotPtr++ * (*xPtr);
360 xPtr++;
361 }
362 }
363}
364
Thomas Tsou3eaae802013-08-20 19:31:14 -0400365signalVector *convolve(const signalVector *x,
366 const signalVector *h,
367 signalVector *y,
368 ConvType spanType, int start,
369 unsigned len, unsigned step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000370{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400371 int rc, head = 0, tail = 0;
372 bool alloc = false, append = false;
373 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000374
Thomas Tsou3eaae802013-08-20 19:31:14 -0400375 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000376 return NULL;
377
Thomas Tsou3eaae802013-08-20 19:31:14 -0400378 switch (spanType) {
379 case START_ONLY:
380 start = 0;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500381 head = h->size() - 1;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400382 len = x->size();
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500383
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500384 if (x->getStart() < head)
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500385 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000386 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400387 case NO_DELAY:
388 start = h->size() / 2;
389 head = start;
390 tail = start;
391 len = x->size();
392 append = true;
393 break;
394 case CUSTOM:
395 if (start < h->size() - 1) {
396 head = h->size() - start;
397 append = true;
398 }
399 if (start + len > x->size()) {
400 tail = start + len - x->size();
401 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000402 }
403 break;
404 default:
405 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000406 }
dburgessb3a0ca42011-10-12 07:44:40 +0000407
Thomas Tsou3eaae802013-08-20 19:31:14 -0400408 /*
409 * Error if the output vector is too small. Create the output vector
410 * if the pointer is NULL.
411 */
412 if (y && (len > y->size()))
413 return NULL;
414 if (!y) {
415 y = new signalVector(len);
416 alloc = true;
417 }
418
419 /* Prepend or post-pend the input vector if the parameters require it */
420 if (append)
421 _x = new signalVector(*x, head, tail);
422 else
423 _x = x;
424
425 /*
426 * Four convovle types:
427 * 1. Complex-Real (aligned)
428 * 2. Complex-Complex (aligned)
429 * 3. Complex-Real (!aligned)
430 * 4. Complex-Complex (!aligned)
431 */
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500432 if (h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400433 rc = convolve_real((float *) _x->begin(), _x->size(),
434 (float *) h->begin(), h->size(),
435 (float *) y->begin(), y->size(),
436 start, len, step, offset);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500437 } else if (!h->isReal() && h->isAligned()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -0400438 rc = convolve_complex((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 = base_convolve_real((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_complex((float *) _x->begin(), _x->size(),
449 (float *) h->begin(), h->size(),
450 (float *) y->begin(), y->size(),
451 start, len, step, offset);
452 } else {
453 rc = -1;
454 }
455
456 if (append)
457 delete _x;
458
459 if (rc < 0) {
460 if (alloc)
461 delete y;
462 return NULL;
463 }
464
465 return y;
466}
dburgessb3a0ca42011-10-12 07:44:40 +0000467
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400468static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800469{
470 int len;
471
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400472 if (!pulse)
473 return false;
474
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800475 switch (sps) {
476 case 4:
477 len = 8;
478 break;
479 default:
480 return false;
481 }
482
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400483 pulse->c1_buffer = convolve_h_alloc(len);
484 pulse->c1 = new signalVector((complex *)
485 pulse->c1_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500486 pulse->c1->isReal(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800487
488 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400489 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800490
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400491 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800492
493 switch (sps) {
494 case 4:
495 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400496 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800497 *xP++ = 8.16373112e-03;
498 *xP++ = 2.84385729e-02;
499 *xP++ = 5.64158904e-02;
500 *xP++ = 7.05463553e-02;
501 *xP++ = 5.64158904e-02;
502 *xP++ = 2.84385729e-02;
503 *xP++ = 8.16373112e-03;
504 }
505
506 return true;
507}
508
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400509static PulseSequence *generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000510{
Thomas Tsou83e06892013-08-20 16:10:01 -0400511 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800512 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400513 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400514
515 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400516 pulse = new PulseSequence();
517 pulse->empty = new signalVector(1);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500518 pulse->empty->isReal(true);
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400519 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400520
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400521 /*
522 * For 4 samples-per-symbol use a precomputed single pulse Laurent
523 * approximation. This should yields below 2 degrees of phase error at
524 * the modulator output. Use the existing pulse approximation for all
525 * other oversampling factors.
526 */
527 switch (sps) {
528 case 4:
529 len = 16;
530 break;
531 default:
532 len = sps * symbolLength;
533 if (len < 4)
534 len = 4;
535 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400536
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400537 pulse->c0_buffer = convolve_h_alloc(len);
538 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500539 pulse->c0->isReal(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400540
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800541 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400542 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800543
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400544 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400545
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400546 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800547 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400548 *xP++ = 4.46348606e-03;
549 *xP++ = 2.84385729e-02;
550 *xP++ = 1.03184855e-01;
551 *xP++ = 2.56065552e-01;
552 *xP++ = 4.76375085e-01;
553 *xP++ = 7.05961177e-01;
554 *xP++ = 8.71291644e-01;
555 *xP++ = 9.29453645e-01;
556 *xP++ = 8.71291644e-01;
557 *xP++ = 7.05961177e-01;
558 *xP++ = 4.76375085e-01;
559 *xP++ = 2.56065552e-01;
560 *xP++ = 1.03184855e-01;
561 *xP++ = 2.84385729e-02;
562 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400563 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400564 } else {
565 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400566
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400567 /* GSM pulse approximation */
568 for (int i = 0; i < len; i++) {
569 arg = ((float) i - center) / (float) sps;
570 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
571 0.527 * arg * arg * arg * arg);
572 }
dburgessb3a0ca42011-10-12 07:44:40 +0000573
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400574 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
575 xP = pulse->c0->begin();
576 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800577 *xP++ /= avg;
578 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400579
580 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000581}
582
583signalVector* frequencyShift(signalVector *y,
584 signalVector *x,
585 float freq,
586 float startPhase,
587 float *finalPhase)
588{
589
590 if (!x) return NULL;
591
592 if (y==NULL) {
593 y = new signalVector(x->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500594 y->isReal(x->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000595 if (y==NULL) return NULL;
596 }
597
598 if (y->size() < x->size()) return NULL;
599
600 float phase = startPhase;
601 signalVector::iterator yP = y->begin();
602 signalVector::iterator xPEnd = x->end();
603 signalVector::iterator xP = x->begin();
604
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500605 if (x->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000606 while (xP < xPEnd) {
607 (*yP++) = expjLookup(phase)*( (xP++)->real() );
608 phase += freq;
609 }
610 }
611 else {
612 while (xP < xPEnd) {
613 (*yP++) = (*xP++)*expjLookup(phase);
614 phase += freq;
615 }
616 }
617
618
619 if (finalPhase) *finalPhase = phase;
620
621 return y;
622}
623
624signalVector* reverseConjugate(signalVector *b)
625{
626 signalVector *tmp = new signalVector(b->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500627 tmp->isReal(b->isReal());
dburgessb3a0ca42011-10-12 07:44:40 +0000628 signalVector::iterator bP = b->begin();
629 signalVector::iterator bPEnd = b->end();
630 signalVector::iterator tmpP = tmp->end()-1;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500631 if (!b->isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000632 while (bP < bPEnd) {
633 *tmpP-- = bP->conj();
634 bP++;
635 }
636 }
637 else {
638 while (bP < bPEnd) {
639 *tmpP-- = bP->real();
640 bP++;
641 }
642 }
643
644 return tmp;
645}
646
dburgessb3a0ca42011-10-12 07:44:40 +0000647/* soft output slicer */
648bool vectorSlicer(signalVector *x)
649{
650
651 signalVector::iterator xP = x->begin();
652 signalVector::iterator xPEnd = x->end();
653 while (xP < xPEnd) {
654 *xP = (complex) (0.5*(xP->real()+1.0F));
655 if (xP->real() > 1.0) *xP = 1.0;
656 if (xP->real() < 0.0) *xP = 0.0;
657 xP++;
658 }
659 return true;
660}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400661
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800662static signalVector *rotateBurst(const BitVector &wBurst,
663 int guardPeriodLength, int sps)
664{
665 int burst_len;
666 signalVector *pulse, rotated, *shaped;
667 signalVector::iterator itr;
668
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400669 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800670 burst_len = sps * (wBurst.size() + guardPeriodLength);
671 rotated = signalVector(burst_len);
672 itr = rotated.begin();
673
674 for (unsigned i = 0; i < wBurst.size(); i++) {
675 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
676 itr += sps;
677 }
678
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400679 GMSKRotate(rotated, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500680 rotated.isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800681
682 /* Dummy filter operation */
683 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
684 if (!shaped)
685 return NULL;
686
687 return shaped;
688}
689
690static signalVector *modulateBurstLaurent(const BitVector &bits,
691 int guard_len, int sps)
692{
693 int burst_len;
694 float phase;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500695 signalVector *c0_pulse, *c1_pulse, *c0_burst;
696 signalVector *c1_burst, *c0_shaped, *c1_shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800697 signalVector::iterator c0_itr, c1_itr;
698
699 /*
700 * Apply before and after bits to reduce phase error at burst edges.
701 * Make sure there is enough room in the burst to accomodate all bits.
702 */
703 if (guard_len < 4)
704 guard_len = 4;
705
706 c0_pulse = GSMPulse->c0;
707 c1_pulse = GSMPulse->c1;
708
709 burst_len = sps * (bits.size() + guard_len);
710
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500711 c0_burst = new signalVector(burst_len, c0_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500712 c0_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500713 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800714
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500715 c1_burst = new signalVector(burst_len, c1_pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500716 c1_burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500717 c1_itr = c1_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800718
719 /* Padded differential start bits */
720 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
721 c0_itr += sps;
722
723 /* Main burst bits */
724 for (unsigned i = 0; i < bits.size(); i++) {
725 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
726 c0_itr += sps;
727 }
728
729 /* Padded differential end bits */
730 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
731
732 /* Generate C0 phase coefficients */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500733 GMSKRotate(*c0_burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500734 c0_burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800735
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500736 c0_itr = c0_burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800737 c0_itr += sps * 2;
738 c1_itr += sps * 2;
739
740 /* Start magic */
741 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
742 *c1_itr = *c0_itr * Complex<float>(0, phase);
743 c0_itr += sps;
744 c1_itr += sps;
745
746 /* Generate C1 phase coefficients */
747 for (unsigned i = 2; i < bits.size(); i++) {
748 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
749 *c1_itr = *c0_itr * Complex<float>(0, phase);
750
751 c0_itr += sps;
752 c1_itr += sps;
753 }
754
755 /* End magic */
756 int i = bits.size();
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 /* Primary (C0) and secondary (C1) pulse shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500761 c0_shaped = convolve(c0_burst, c0_pulse, NULL, START_ONLY);
762 c1_shaped = convolve(c1_burst, c1_pulse, NULL, START_ONLY);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800763
764 /* Sum shaped outputs into C0 */
765 c0_itr = c0_shaped->begin();
766 c1_itr = c1_shaped->begin();
767 for (unsigned i = 0; i < c0_shaped->size(); i++ )
768 *c0_itr++ += *c1_itr++;
769
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500770 delete c0_burst;
771 delete c1_burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800772 delete c1_shaped;
773
774 return c0_shaped;
775}
776
777static signalVector *modulateBurstBasic(const BitVector &bits,
778 int guard_len, int sps)
779{
780 int burst_len;
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500781 signalVector *pulse, *burst, *shaped;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800782 signalVector::iterator burst_itr;
783
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400784 if (sps == 1)
785 pulse = GSMPulse1->c0;
786 else
787 pulse = GSMPulse->c0;
788
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800789 burst_len = sps * (bits.size() + guard_len);
790
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500791 burst = new signalVector(burst_len, pulse->size());
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500792 burst->isReal(true);
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500793 burst_itr = burst->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800794
795 /* Raw bits are not differentially encoded */
796 for (unsigned i = 0; i < bits.size(); i++) {
797 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
798 burst_itr += sps;
799 }
800
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500801 GMSKRotate(*burst, sps);
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500802 burst->isReal(false);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800803
804 /* Single Gaussian pulse approximation shaping */
Thomas Tsou6f4906e2013-11-09 02:40:18 -0500805 shaped = convolve(burst, pulse, NULL, START_ONLY);
806
807 delete burst;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800808
809 return shaped;
810}
811
Thomas Tsou3eaae802013-08-20 19:31:14 -0400812/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400813signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
814 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000815{
Thomas Tsou83e06892013-08-20 16:10:01 -0400816 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800817 return rotateBurst(wBurst, guardPeriodLength, sps);
818 else if (sps == 4)
819 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400820 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800821 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000822}
823
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800824float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000825{
826 if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
827 return 1.0F;
828}
829
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600830/*
831 * Create fractional delay filterbank with Blackman-harris windowed
832 * sinc function generator. The number of filters generated is specified
833 * by the DELAYFILTS value.
834 */
835void generateDelayFilters()
836{
837 int h_len = 20;
838 complex *data;
839 signalVector *h;
840 signalVector::iterator itr;
841
842 float k, sum;
843 float a0 = 0.35875;
844 float a1 = 0.48829;
845 float a2 = 0.14128;
846 float a3 = 0.01168;
847
848 for (int i = 0; i < DELAYFILTS; i++) {
849 data = (complex *) convolve_h_alloc(h_len);
850 h = new signalVector(data, 0, h_len);
851 h->setAligned(true);
852 h->isReal(true);
853
854 sum = 0.0;
855 itr = h->end();
856 for (int n = 0; n < h_len; n++) {
857 k = (float) n;
858 *--itr = (complex) sinc(M_PI_F *
859 (k - (float) h_len / 2.0 - (float) i / DELAYFILTS));
860 *itr *= a0 -
861 a1 * cos(2 * M_PI * n / (h_len - 1)) +
862 a2 * cos(4 * M_PI * n / (h_len - 1)) -
863 a3 * cos(6 * M_PI * n / (h_len - 1));
864
865 sum += itr->real();
866 }
867
868 itr = h->begin();
869 for (int n = 0; n < h_len; n++)
870 *itr++ /= sum;
871
872 delayFilters[i] = h;
873 }
874}
875
Thomas Tsou3eaae802013-08-20 19:31:14 -0400876bool delayVector(signalVector &wBurst, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000877{
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600878 int whole, index;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400879 float frac;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400880 signalVector *h, *shift;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400881
Thomas Tsou2c282f52013-10-08 21:34:35 -0400882 whole = floor(delay);
883 frac = delay - whole;
884
885 /* Sinc interpolated fractional shift (if allowable) */
886 if (fabs(frac) > 1e-2) {
Thomas Tsouf79c4d02013-11-09 15:51:56 -0600887 index = floorf(frac * (float) DELAYFILTS);
888 h = delayFilters[index];
Thomas Tsou2c282f52013-10-08 21:34:35 -0400889
890 shift = convolve(&wBurst, h, NULL, NO_DELAY);
Thomas Tsou2c282f52013-10-08 21:34:35 -0400891 if (!shift)
Thomas Tsou3eaae802013-08-20 19:31:14 -0400892 return false;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400893
894 wBurst.clone(*shift);
895 delete shift;
dburgessb3a0ca42011-10-12 07:44:40 +0000896 }
897
Thomas Tsou2c282f52013-10-08 21:34:35 -0400898 /* Integer sample shift */
899 if (whole < 0) {
900 whole = -whole;
dburgessb3a0ca42011-10-12 07:44:40 +0000901 signalVector::iterator wBurstItr = wBurst.begin();
Thomas Tsou2c282f52013-10-08 21:34:35 -0400902 signalVector::iterator shiftedItr = wBurst.begin() + whole;
903
dburgessb3a0ca42011-10-12 07:44:40 +0000904 while (shiftedItr < wBurst.end())
905 *wBurstItr++ = *shiftedItr++;
906 while (wBurstItr < wBurst.end())
907 *wBurstItr++ = 0.0;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400908 } else {
909 signalVector::iterator wBurstItr = wBurst.end() - 1;
910 signalVector::iterator shiftedItr = wBurst.end() - 1 - whole;
911
dburgessb3a0ca42011-10-12 07:44:40 +0000912 while (shiftedItr >= wBurst.begin())
913 *wBurstItr-- = *shiftedItr--;
914 while (wBurstItr >= wBurst.begin())
915 *wBurstItr-- = 0.0;
916 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400917
918 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000919}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400920
dburgessb3a0ca42011-10-12 07:44:40 +0000921signalVector *gaussianNoise(int length,
922 float variance,
923 complex mean)
924{
925
926 signalVector *noise = new signalVector(length);
927 signalVector::iterator nPtr = noise->begin();
928 float stddev = sqrtf(variance);
929 while (nPtr < noise->end()) {
930 float u1 = (float) rand()/ (float) RAND_MAX;
931 while (u1==0.0)
932 u1 = (float) rand()/ (float) RAND_MAX;
933 float u2 = (float) rand()/ (float) RAND_MAX;
934 float arg = 2.0*M_PI*u2;
935 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
936 nPtr++;
937 }
938
939 return noise;
940}
941
942complex interpolatePoint(const signalVector &inSig,
943 float ix)
944{
945
946 int start = (int) (floor(ix) - 10);
947 if (start < 0) start = 0;
948 int end = (int) (floor(ix) + 11);
949 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
950
951 complex pVal = 0.0;
Thomas Tsou20eb6d62013-11-09 14:30:41 -0500952 if (!inSig.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000953 for (int i = start; i < end; i++)
954 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
955 }
956 else {
957 for (int i = start; i < end; i++)
958 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
959 }
960
961 return pVal;
962}
963
Thomas Tsou8181b012013-08-20 21:17:19 -0400964static complex fastPeakDetect(const signalVector &rxBurst, float *index)
965{
966 float val, max = 0.0f;
967 complex amp;
968 int _index = -1;
969
970 for (int i = 0; i < rxBurst.size(); i++) {
971 val = rxBurst[i].norm2();
972 if (val > max) {
973 max = val;
974 _index = i;
975 amp = rxBurst[i];
976 }
977 }
978
979 if (index)
980 *index = (float) _index;
981
982 return amp;
983}
984
dburgessb3a0ca42011-10-12 07:44:40 +0000985complex peakDetect(const signalVector &rxBurst,
986 float *peakIndex,
987 float *avgPwr)
988{
989
990
991 complex maxVal = 0.0;
992 float maxIndex = -1;
993 float sumPower = 0.0;
994
995 for (unsigned int i = 0; i < rxBurst.size(); i++) {
996 float samplePower = rxBurst[i].norm2();
997 if (samplePower > maxVal.real()) {
998 maxVal = samplePower;
999 maxIndex = i;
1000 }
1001 sumPower += samplePower;
1002 }
1003
1004 // interpolate around the peak
1005 // to save computation, we'll use early-late balancing
1006 float earlyIndex = maxIndex-1;
1007 float lateIndex = maxIndex+1;
1008
1009 float incr = 0.5;
1010 while (incr > 1.0/1024.0) {
1011 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
1012 complex lateP = interpolatePoint(rxBurst,lateIndex);
1013 if (earlyP < lateP)
1014 earlyIndex += incr;
1015 else if (earlyP > lateP)
1016 earlyIndex -= incr;
1017 else break;
1018 incr /= 2.0;
1019 lateIndex = earlyIndex + 2.0;
1020 }
1021
1022 maxIndex = earlyIndex + 1.0;
1023 maxVal = interpolatePoint(rxBurst,maxIndex);
1024
1025 if (peakIndex!=NULL)
1026 *peakIndex = maxIndex;
1027
1028 if (avgPwr!=NULL)
1029 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
1030
1031 return maxVal;
1032
1033}
1034
1035void scaleVector(signalVector &x,
1036 complex scale)
1037{
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001038#ifdef HAVE_NEON
1039 int len = x.size();
1040
1041 scale_complex((float *) x.begin(),
1042 (float *) x.begin(),
1043 (float *) &scale, len);
1044#else
dburgessb3a0ca42011-10-12 07:44:40 +00001045 signalVector::iterator xP = x.begin();
1046 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001047 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001048 while (xP < xPEnd) {
1049 *xP = *xP * scale;
1050 xP++;
1051 }
1052 }
1053 else {
1054 while (xP < xPEnd) {
1055 *xP = xP->real() * scale;
1056 xP++;
1057 }
1058 }
Thomas Tsou7e4e5362013-10-30 21:18:55 -04001059#endif
dburgessb3a0ca42011-10-12 07:44:40 +00001060}
1061
1062/** in-place conjugation */
1063void conjugateVector(signalVector &x)
1064{
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001065 if (x.isReal()) return;
dburgessb3a0ca42011-10-12 07:44:40 +00001066 signalVector::iterator xP = x.begin();
1067 signalVector::iterator xPEnd = x.end();
1068 while (xP < xPEnd) {
1069 *xP = xP->conj();
1070 xP++;
1071 }
1072}
1073
1074
1075// in-place addition!!
1076bool addVector(signalVector &x,
1077 signalVector &y)
1078{
1079 signalVector::iterator xP = x.begin();
1080 signalVector::iterator yP = y.begin();
1081 signalVector::iterator xPEnd = x.end();
1082 signalVector::iterator yPEnd = y.end();
1083 while ((xP < xPEnd) && (yP < yPEnd)) {
1084 *xP = *xP + *yP;
1085 xP++; yP++;
1086 }
1087 return true;
1088}
1089
1090// in-place multiplication!!
1091bool multVector(signalVector &x,
1092 signalVector &y)
1093{
1094 signalVector::iterator xP = x.begin();
1095 signalVector::iterator yP = y.begin();
1096 signalVector::iterator xPEnd = x.end();
1097 signalVector::iterator yPEnd = y.end();
1098 while ((xP < xPEnd) && (yP < yPEnd)) {
1099 *xP = (*xP) * (*yP);
1100 xP++; yP++;
1101 }
1102 return true;
1103}
1104
1105
1106void offsetVector(signalVector &x,
1107 complex offset)
1108{
1109 signalVector::iterator xP = x.begin();
1110 signalVector::iterator xPEnd = x.end();
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001111 if (!x.isReal()) {
dburgessb3a0ca42011-10-12 07:44:40 +00001112 while (xP < xPEnd) {
1113 *xP += offset;
1114 xP++;
1115 }
1116 }
1117 else {
1118 while (xP < xPEnd) {
1119 *xP = xP->real() + offset;
1120 xP++;
1121 }
1122 }
1123}
1124
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001125bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001126{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001127 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001128 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001129 complex *data = NULL;
1130 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001131 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001132
Thomas Tsou3eaae802013-08-20 19:31:14 -04001133 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001134 return false;
1135
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001136 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001137
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001138 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1139 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1140 if (!midMidamble)
1141 return false;
1142
Thomas Tsou3eaae802013-08-20 19:31:14 -04001143 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001144 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1145 if (!midamble) {
1146 status = false;
1147 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001148 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001149
dburgessb3a0ca42011-10-12 07:44:40 +00001150 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1151 // the ideal TSC has an + 180 degree phase shift,
1152 // due to the pi/2 frequency shift, that
1153 // needs to be accounted for.
1154 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001155 scaleVector(*midMidamble, complex(-1.0, 0.0));
1156 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001157
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001158 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001159
Thomas Tsou3eaae802013-08-20 19:31:14 -04001160 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1161 data = (complex *) convolve_h_alloc(midMidamble->size());
1162 _midMidamble = new signalVector(data, 0, midMidamble->size());
1163 _midMidamble->setAligned(true);
1164 memcpy(_midMidamble->begin(), midMidamble->begin(),
1165 midMidamble->size() * sizeof(complex));
1166
1167 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001168 if (!autocorr) {
1169 status = false;
1170 goto release;
1171 }
dburgessb3a0ca42011-10-12 07:44:40 +00001172
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001173 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001174 gMidambles[tsc]->buffer = data;
1175 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001176 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1177
1178 /* For 1 sps only
1179 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1180 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1181 */
1182 if (sps == 1)
1183 gMidambles[tsc]->toa = toa - 13.5;
1184 else
1185 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001186
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001187release:
dburgessb3a0ca42011-10-12 07:44:40 +00001188 delete autocorr;
1189 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001190 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001191
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001192 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001193 delete _midMidamble;
1194 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001195 gMidambles[tsc] = NULL;
1196 }
1197
1198 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001199}
1200
Thomas Tsou83e06892013-08-20 16:10:01 -04001201bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001202{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001203 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001204 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001205 complex *data = NULL;
1206 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001207 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001208
1209 delete gRACHSequence;
1210
1211 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1212 if (!seq0)
1213 return false;
1214
1215 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1216 if (!seq1) {
1217 status = false;
1218 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001219 }
1220
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001221 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001222
Thomas Tsou3eaae802013-08-20 19:31:14 -04001223 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1224 data = (complex *) convolve_h_alloc(seq1->size());
1225 _seq1 = new signalVector(data, 0, seq1->size());
1226 _seq1->setAligned(true);
1227 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1228
1229 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1230 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001231 status = false;
1232 goto release;
1233 }
dburgessb3a0ca42011-10-12 07:44:40 +00001234
1235 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001236 gRACHSequence->sequence = _seq1;
1237 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001238 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1239
1240 /* For 1 sps only
1241 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1242 * 20.5 = (40 / 2 - 1) + 1.5
1243 */
1244 if (sps == 1)
1245 gRACHSequence->toa = toa - 20.5;
1246 else
1247 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001248
1249release:
dburgessb3a0ca42011-10-12 07:44:40 +00001250 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001251 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001252 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001253
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001254 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001255 delete _seq1;
1256 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001257 gRACHSequence = NULL;
1258 }
dburgessb3a0ca42011-10-12 07:44:40 +00001259
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001260 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001261}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001262
Thomas Tsou865bca42013-08-21 20:58:00 -04001263static float computePeakRatio(signalVector *corr,
1264 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001265{
Thomas Tsou865bca42013-08-21 20:58:00 -04001266 int num = 0;
1267 complex *peak;
1268 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001269
Thomas Tsou865bca42013-08-21 20:58:00 -04001270 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001271
Thomas Tsou865bca42013-08-21 20:58:00 -04001272 /* Check for bogus results */
1273 if ((toa < 0.0) || (toa > corr->size()))
1274 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001275
Thomas Tsou3eaae802013-08-20 19:31:14 -04001276 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001277 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001278 avg += (peak - i)->norm2();
1279 num++;
1280 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001281 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001282 avg += (peak + i)->norm2();
1283 num++;
1284 }
dburgessb3a0ca42011-10-12 07:44:40 +00001285 }
1286
Thomas Tsou3eaae802013-08-20 19:31:14 -04001287 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001288 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001289
Thomas Tsou3eaae802013-08-20 19:31:14 -04001290 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001291
Thomas Tsou865bca42013-08-21 20:58:00 -04001292 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001293}
1294
1295bool energyDetect(signalVector &rxBurst,
1296 unsigned windowLength,
1297 float detectThreshold,
1298 float *avgPwr)
1299{
1300
1301 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1302 float energy = 0.0;
1303 if (windowLength < 0) windowLength = 20;
1304 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1305 for (unsigned i = 0; i < windowLength; i++) {
1306 energy += windowItr->norm2();
1307 windowItr+=4;
1308 }
1309 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001310 return (energy/windowLength > detectThreshold*detectThreshold);
1311}
dburgessb3a0ca42011-10-12 07:44:40 +00001312
Thomas Tsou865bca42013-08-21 20:58:00 -04001313/*
1314 * Detect a burst based on correlation and peak-to-average ratio
1315 *
1316 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1317 * for initial gating. We do this because energy detection should be disabled.
1318 * For higher oversampling values, we assume the energy detector is in place
1319 * and we run full interpolating peak detection.
1320 */
1321static int detectBurst(signalVector &burst,
1322 signalVector &corr, CorrelationSequence *sync,
1323 float thresh, int sps, complex *amp, float *toa,
1324 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001325{
Thomas Tsou865bca42013-08-21 20:58:00 -04001326 /* Correlate */
1327 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001328 CUSTOM, start, len, sps, 0)) {
1329 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001330 }
1331
Thomas Tsou865bca42013-08-21 20:58:00 -04001332 /* Peak detection - place restrictions at correlation edges */
1333 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001334
Thomas Tsou865bca42013-08-21 20:58:00 -04001335 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1336 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001337
Thomas Tsou865bca42013-08-21 20:58:00 -04001338 /* Peak -to-average ratio */
1339 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1340 return 0;
1341
1342 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1343 *amp = peakDetect(corr, toa, NULL);
1344
1345 /* Normalize our channel gain */
1346 *amp = *amp / sync->gain;
1347
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001348 /* Compenate for residual rotation with dual Laurent pulse */
1349 if (sps == 4)
1350 *amp = *amp * complex(0.0, 1.0);
1351
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001352 /* Compensate for residuate time lag */
1353 *toa = *toa - sync->toa;
1354
Thomas Tsou865bca42013-08-21 20:58:00 -04001355 return 1;
1356}
1357
1358/*
1359 * RACH burst detection
1360 *
1361 * Correlation window parameters:
1362 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001363 * head: Search 4 symbols before target
1364 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001365 */
1366int detectRACHBurst(signalVector &rxBurst,
1367 float thresh,
1368 int sps,
1369 complex *amp,
1370 float *toa)
1371{
1372 int rc, start, target, head, tail, len;
1373 float _toa;
1374 complex _amp;
1375 signalVector corr;
1376 CorrelationSequence *sync;
1377
1378 if ((sps != 1) && (sps != 4))
1379 return -1;
1380
1381 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001382 head = 4;
1383 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001384
1385 start = (target - head) * sps - 1;
1386 len = (head + tail) * sps;
1387 sync = gRACHSequence;
1388 corr = signalVector(len);
1389
1390 rc = detectBurst(rxBurst, corr, sync,
1391 thresh, sps, &_amp, &_toa, start, len);
1392 if (rc < 0) {
1393 return -1;
1394 } else if (!rc) {
1395 if (amp)
1396 *amp = 0.0f;
1397 if (toa)
1398 *toa = 0.0f;
1399 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001400 }
1401
Thomas Tsou865bca42013-08-21 20:58:00 -04001402 /* Subtract forward search bits from delay */
1403 if (toa)
1404 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001405 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001406 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001407
Thomas Tsou865bca42013-08-21 20:58:00 -04001408 return 1;
1409}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001410
Thomas Tsou865bca42013-08-21 20:58:00 -04001411/*
1412 * Normal burst detection
1413 *
1414 * Correlation window parameters:
1415 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001416 * head: Search 4 symbols before target
1417 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001418 */
1419int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1420 int sps, complex *amp, float *toa, unsigned max_toa,
1421 bool chan_req, signalVector **chan, float *chan_offset)
1422{
1423 int rc, start, target, head, tail, len;
1424 complex _amp;
1425 float _toa;
1426 signalVector corr;
1427 CorrelationSequence *sync;
1428
1429 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1430 return -1;
1431
1432 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001433 head = 4;
1434 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001435
1436 start = (target - head) * sps - 1;
1437 len = (head + tail) * sps;
1438 sync = gMidambles[tsc];
1439 corr = signalVector(len);
1440
1441 rc = detectBurst(rxBurst, corr, sync,
1442 thresh, sps, &_amp, &_toa, start, len);
1443 if (rc < 0) {
1444 return -1;
1445 } else if (!rc) {
1446 if (amp)
1447 *amp = 0.0f;
1448 if (toa)
1449 *toa = 0.0f;
1450 return 0;
1451 }
1452
1453 /* Subtract forward search bits from delay */
1454 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001455 if (toa)
1456 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001457 if (amp)
1458 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001459
Thomas Tsou865bca42013-08-21 20:58:00 -04001460 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001461 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001462 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001463
1464 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001465 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001466 }
1467
Thomas Tsou3eaae802013-08-20 19:31:14 -04001468 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001469}
1470
1471signalVector *decimateVector(signalVector &wVector,
1472 int decimationFactor)
1473{
1474
1475 if (decimationFactor <= 1) return NULL;
1476
1477 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
Thomas Tsou20eb6d62013-11-09 14:30:41 -05001478 decVector->isReal(wVector.isReal());
dburgessb3a0ca42011-10-12 07:44:40 +00001479
1480 signalVector::iterator vecItr = decVector->begin();
1481 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1482 *vecItr++ = wVector[i];
1483
1484 return decVector;
1485}
1486
1487
Thomas Tsou83e06892013-08-20 16:10:01 -04001488SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
1489 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001490{
1491 scaleVector(rxBurst,((complex) 1.0)/channel);
1492 delayVector(rxBurst,-TOA);
1493
1494 signalVector *shapedBurst = &rxBurst;
1495
1496 // shift up by a quarter of a frequency
1497 // ignore starting phase, since spec allows for discontinuous phase
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001498 GMSKReverseRotate(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001499
1500 // run through slicer
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001501 if (sps > 1) {
1502 signalVector *decShapedBurst = decimateVector(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001503 shapedBurst = decShapedBurst;
1504 }
1505
dburgessb3a0ca42011-10-12 07:44:40 +00001506 vectorSlicer(shapedBurst);
1507
1508 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1509
1510 SoftVector::iterator burstItr = burstBits->begin();
1511 signalVector::iterator shapedItr = shapedBurst->begin();
1512 for (; shapedItr < shapedBurst->end(); shapedItr++)
1513 *burstItr++ = shapedItr->real();
1514
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001515 if (sps > 1)
1516 delete shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +00001517
1518 return burstBits;
1519
1520}
dburgessb3a0ca42011-10-12 07:44:40 +00001521
dburgessb3a0ca42011-10-12 07:44:40 +00001522// Assumes symbol-spaced sampling!!!
1523// Based upon paper by Al-Dhahir and Cioffi
1524bool designDFE(signalVector &channelResponse,
1525 float SNRestimate,
1526 int Nf,
1527 signalVector **feedForwardFilter,
1528 signalVector **feedbackFilter)
1529{
1530
1531 signalVector G0(Nf);
1532 signalVector G1(Nf);
1533 signalVector::iterator G0ptr = G0.begin();
1534 signalVector::iterator G1ptr = G1.begin();
1535 signalVector::iterator chanPtr = channelResponse.begin();
1536
1537 int nu = channelResponse.size()-1;
1538
1539 *G0ptr = 1.0/sqrtf(SNRestimate);
1540 for(int j = 0; j <= nu; j++) {
1541 *G1ptr = chanPtr->conj();
1542 G1ptr++; chanPtr++;
1543 }
1544
1545 signalVector *L[Nf];
1546 signalVector::iterator Lptr;
1547 float d;
1548 for(int i = 0; i < Nf; i++) {
1549 d = G0.begin()->norm2() + G1.begin()->norm2();
1550 L[i] = new signalVector(Nf+nu);
1551 Lptr = L[i]->begin()+i;
1552 G0ptr = G0.begin(); G1ptr = G1.begin();
1553 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1554 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1555 Lptr++;
1556 G0ptr++;
1557 G1ptr++;
1558 }
1559 complex k = (*G1.begin())/(*G0.begin());
1560
1561 if (i != Nf-1) {
1562 signalVector G0new = G1;
1563 scaleVector(G0new,k.conj());
1564 addVector(G0new,G0);
1565
1566 signalVector G1new = G0;
1567 scaleVector(G1new,k*(-1.0));
1568 addVector(G1new,G1);
1569 delayVector(G1new,-1.0);
1570
1571 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1572 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1573 G0 = G0new;
1574 G1 = G1new;
1575 }
1576 }
1577
1578 *feedbackFilter = new signalVector(nu);
1579 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1580 scaleVector(**feedbackFilter,(complex) -1.0);
1581 conjugateVector(**feedbackFilter);
1582
1583 signalVector v(Nf);
1584 signalVector::iterator vStart = v.begin();
1585 signalVector::iterator vPtr;
1586 *(vStart+Nf-1) = (complex) 1.0;
1587 for(int k = Nf-2; k >= 0; k--) {
1588 Lptr = L[k]->begin()+k+1;
1589 vPtr = vStart + k+1;
1590 complex v_k = 0.0;
1591 for (int j = k+1; j < Nf; j++) {
1592 v_k -= (*vPtr)*(*Lptr);
1593 vPtr++; Lptr++;
1594 }
1595 *(vStart + k) = v_k;
1596 }
1597
1598 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001599 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001600 for (int i = 0; i < Nf; i++) {
1601 delete L[i];
1602 complex w_i = 0.0;
1603 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1604 vPtr = vStart+i;
1605 chanPtr = channelResponse.begin();
1606 for (int k = 0; k < endPt+1; k++) {
1607 w_i += (*vPtr)*(chanPtr->conj());
1608 vPtr++; chanPtr++;
1609 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001610 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001611 }
1612
1613
1614 return true;
1615
1616}
1617
1618// Assumes symbol-rate sampling!!!!
1619SoftVector *equalizeBurst(signalVector &rxBurst,
1620 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001621 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001622 signalVector &w, // feedforward filter
1623 signalVector &b) // feedback filter
1624{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001625 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001626
Thomas Tsou3eaae802013-08-20 19:31:14 -04001627 if (!delayVector(rxBurst, -TOA))
1628 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001629
Thomas Tsou3eaae802013-08-20 19:31:14 -04001630 postForwardFull = convolve(&rxBurst, &w, NULL,
1631 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1632 if (!postForwardFull)
1633 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001634
1635 signalVector* postForward = new signalVector(rxBurst.size());
1636 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1637 delete postForwardFull;
1638
1639 signalVector::iterator dPtr = postForward->begin();
1640 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001641 signalVector::iterator rotPtr = GMSKRotationN->begin();
1642 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001643
1644 signalVector *DFEoutput = new signalVector(postForward->size());
1645 signalVector::iterator DFEItr = DFEoutput->begin();
1646
1647 // NOTE: can insert the midamble and/or use midamble to estimate BER
1648 for (; dPtr < postForward->end(); dPtr++) {
1649 dBackPtr = dPtr-1;
1650 signalVector::iterator bPtr = b.begin();
1651 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1652 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1653 bPtr++;
1654 dBackPtr--;
1655 }
1656 *dPtr = *dPtr * (*revRotPtr);
1657 *DFEItr = *dPtr;
1658 // make decision on symbol
1659 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1660 //*DFEItr = *dPtr;
1661 *dPtr = *dPtr * (*rotPtr);
1662 DFEItr++;
1663 rotPtr++;
1664 revRotPtr++;
1665 }
1666
1667 vectorSlicer(DFEoutput);
1668
1669 SoftVector *burstBits = new SoftVector(postForward->size());
1670 SoftVector::iterator burstItr = burstBits->begin();
1671 DFEItr = DFEoutput->begin();
1672 for (; DFEItr < DFEoutput->end(); DFEItr++)
1673 *burstItr++ = DFEItr->real();
1674
1675 delete postForward;
1676
1677 delete DFEoutput;
1678
1679 return burstBits;
1680}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001681
1682bool sigProcLibSetup(int sps)
1683{
1684 if ((sps != 1) && (sps != 4))
1685 return false;
1686
1687 initTrigTables();
1688 initGMSKRotationTables(sps);
1689
1690 GSMPulse1 = generateGSMPulse(1, 2);
1691 if (sps > 1)
1692 GSMPulse = generateGSMPulse(sps, 2);
1693
1694 if (!generateRACHSequence(1)) {
1695 sigProcLibDestroy();
1696 return false;
1697 }
1698
Thomas Tsouf79c4d02013-11-09 15:51:56 -06001699 generateDelayFilters();
1700
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001701 return true;
1702}