blob: aa35647e77b9cc596086ce983bbe9fb3892dfcc7 [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
dburgessb3a0ca42011-10-12 07:44:40 +000025#include "sigProcLib.h"
26#include "GSMCommon.h"
kurtis.heimerla198d452011-11-26 03:19:28 +000027#include "sendLPF_961.h"
28#include "rcvLPF_651.h"
dburgessb3a0ca42011-10-12 07:44:40 +000029
Alexander Chemerisd734e2d2013-06-16 14:30:58 +040030using namespace GSM;
31
Thomas Tsou3eaae802013-08-20 19:31:14 -040032extern "C" {
33#include "convolve.h"
34}
35
dburgessb3a0ca42011-10-12 07:44:40 +000036#define TABLESIZE 1024
37
38/** Lookup tables for trigonometric approximation */
39float cosTable[TABLESIZE+1]; // add 1 element for wrap around
40float sinTable[TABLESIZE+1];
41
42/** Constants */
43static const float M_PI_F = (float)M_PI;
44static const float M_2PI_F = (float)(2.0*M_PI);
45static const float M_1_2PI_F = 1/M_2PI_F;
46
Thomas Tsouc1f7c422013-10-11 13:49:55 -040047/* Precomputed rotation vectors */
48static signalVector *GMSKRotationN = NULL;
49static signalVector *GMSKReverseRotationN = NULL;
50static signalVector *GMSKRotation1 = NULL;
51static signalVector *GMSKReverseRotation1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +000052
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040053/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040054 * RACH and midamble correlation waveforms. Store the buffer separately
55 * because we need to allocate it explicitly outside of the signal vector
56 * constructor. This is because C++ (prior to C++11) is unable to natively
57 * perform 16-byte memory alignment required by many SSE instructions.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040058 */
59struct CorrelationSequence {
Thomas Tsou3eaae802013-08-20 19:31:14 -040060 CorrelationSequence() : sequence(NULL), buffer(NULL)
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040061 {
62 }
63
64 ~CorrelationSequence()
65 {
66 delete sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040067 free(buffer);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040068 }
69
dburgessb3a0ca42011-10-12 07:44:40 +000070 signalVector *sequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -040071 void *buffer;
Thomas Tsouc1f7c422013-10-11 13:49:55 -040072 float toa;
dburgessb3a0ca42011-10-12 07:44:40 +000073 complex gain;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -040074};
dburgessb3a0ca42011-10-12 07:44:40 +000075
Thomas Tsou83e06892013-08-20 16:10:01 -040076/*
Thomas Tsou3eaae802013-08-20 19:31:14 -040077 * Gaussian and empty modulation pulses. Like the correlation sequences,
78 * store the runtime (Gaussian) buffer separately because of needed alignment
79 * for SSE instructions.
Thomas Tsou83e06892013-08-20 16:10:01 -040080 */
81struct PulseSequence {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080082 PulseSequence() : c0(NULL), c1(NULL), empty(NULL),
83 c0_buffer(NULL), c1_buffer(NULL)
Thomas Tsou83e06892013-08-20 16:10:01 -040084 {
85 }
86
87 ~PulseSequence()
88 {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080089 delete c0;
90 delete c1;
Thomas Tsou83e06892013-08-20 16:10:01 -040091 delete empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080092 free(c0_buffer);
93 free(c1_buffer);
Thomas Tsou83e06892013-08-20 16:10:01 -040094 }
95
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080096 signalVector *c0;
97 signalVector *c1;
Thomas Tsou83e06892013-08-20 16:10:01 -040098 signalVector *empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +080099 void *c0_buffer;
100 void *c1_buffer;
Thomas Tsou83e06892013-08-20 16:10:01 -0400101};
102
dburgessb3a0ca42011-10-12 07:44:40 +0000103CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
104CorrelationSequence *gRACHSequence = NULL;
Thomas Tsou83e06892013-08-20 16:10:01 -0400105PulseSequence *GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400106PulseSequence *GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000107
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400108void sigProcLibDestroy()
109{
dburgessb3a0ca42011-10-12 07:44:40 +0000110 for (int i = 0; i < 8; i++) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400111 delete gMidambles[i];
112 gMidambles[i] = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000113 }
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400114
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400115 delete GMSKRotationN;
116 delete GMSKReverseRotationN;
117 delete GMSKRotation1;
118 delete GMSKReverseRotation1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400119 delete gRACHSequence;
120 delete GSMPulse;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400121 delete GSMPulse1;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400122
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400123 GMSKRotationN = NULL;
124 GMSKRotation1 = NULL;
125 GMSKReverseRotationN = NULL;
126 GMSKReverseRotation1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -0400127 gRACHSequence = NULL;
128 GSMPulse = NULL;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400129 GSMPulse1 = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000130}
131
dburgessb3a0ca42011-10-12 07:44:40 +0000132// dB relative to 1.0.
133// if > 1.0, then return 0 dB
134float dB(float x) {
135
136 float arg = 1.0F;
137 float dB = 0.0F;
138
139 if (x >= 1.0F) return 0.0F;
140 if (x <= 0.0F) return -200.0F;
141
142 float prevArg = arg;
143 float prevdB = dB;
144 float stepSize = 16.0F;
145 float dBstepSize = 12.0F;
146 while (stepSize > 1.0F) {
147 do {
148 prevArg = arg;
149 prevdB = dB;
150 arg /= stepSize;
151 dB -= dBstepSize;
152 } while (arg > x);
153 arg = prevArg;
154 dB = prevdB;
155 stepSize *= 0.5F;
156 dBstepSize -= 3.0F;
157 }
158 return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
159
160}
161
162// 10^(-dB/10), inverse of dB func.
163float dBinv(float x) {
164
165 float arg = 1.0F;
166 float dB = 0.0F;
167
168 if (x >= 0.0F) return 1.0F;
169 if (x <= -200.0F) return 0.0F;
170
171 float prevArg = arg;
172 float prevdB = dB;
173 float stepSize = 16.0F;
174 float dBstepSize = 12.0F;
175 while (stepSize > 1.0F) {
176 do {
177 prevArg = arg;
178 prevdB = dB;
179 arg /= stepSize;
180 dB -= dBstepSize;
181 } while (dB > x);
182 arg = prevArg;
183 dB = prevdB;
184 stepSize *= 0.5F;
185 dBstepSize -= 3.0F;
186 }
187
188 return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
189
190}
191
192float vectorNorm2(const signalVector &x)
193{
194 signalVector::const_iterator xPtr = x.begin();
195 float Energy = 0.0;
196 for (;xPtr != x.end();xPtr++) {
197 Energy += xPtr->norm2();
198 }
199 return Energy;
200}
201
202
203float vectorPower(const signalVector &x)
204{
205 return vectorNorm2(x)/x.size();
206}
207
208/** compute cosine via lookup table */
209float cosLookup(const float x)
210{
211 float arg = x*M_1_2PI_F;
212 while (arg > 1.0F) arg -= 1.0F;
213 while (arg < 0.0F) arg += 1.0F;
214
215 const float argT = arg*((float)TABLESIZE);
216 const int argI = (int)argT;
217 const float delta = argT-argI;
218 const float iDelta = 1.0F-delta;
219 return iDelta*cosTable[argI] + delta*cosTable[argI+1];
220}
221
222/** compute sine via lookup table */
223float sinLookup(const float x)
224{
225 float arg = x*M_1_2PI_F;
226 while (arg > 1.0F) arg -= 1.0F;
227 while (arg < 0.0F) arg += 1.0F;
228
229 const float argT = arg*((float)TABLESIZE);
230 const int argI = (int)argT;
231 const float delta = argT-argI;
232 const float iDelta = 1.0F-delta;
233 return iDelta*sinTable[argI] + delta*sinTable[argI+1];
234}
235
236
237/** compute e^(-jx) via lookup table. */
238complex expjLookup(float x)
239{
240 float arg = x*M_1_2PI_F;
241 while (arg > 1.0F) arg -= 1.0F;
242 while (arg < 0.0F) arg += 1.0F;
243
244 const float argT = arg*((float)TABLESIZE);
245 const int argI = (int)argT;
246 const float delta = argT-argI;
247 const float iDelta = 1.0F-delta;
248 return complex(iDelta*cosTable[argI] + delta*cosTable[argI+1],
249 iDelta*sinTable[argI] + delta*sinTable[argI+1]);
250}
251
252/** Library setup functions */
253void initTrigTables() {
254 for (int i = 0; i < TABLESIZE+1; i++) {
255 cosTable[i] = cos(2.0*M_PI*i/TABLESIZE);
256 sinTable[i] = sin(2.0*M_PI*i/TABLESIZE);
257 }
258}
259
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400260void initGMSKRotationTables(int sps)
261{
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400262 GMSKRotationN = new signalVector(157 * sps);
263 GMSKReverseRotationN = new signalVector(157 * sps);
264 signalVector::iterator rotPtr = GMSKRotationN->begin();
265 signalVector::iterator revPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +0000266 float phase = 0.0;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400267 while (rotPtr != GMSKRotationN->end()) {
dburgessb3a0ca42011-10-12 07:44:40 +0000268 *rotPtr++ = expjLookup(phase);
269 *revPtr++ = expjLookup(-phase);
Thomas Tsoud24cc2c2013-08-20 15:41:45 -0400270 phase += M_PI_F / 2.0F / (float) sps;
dburgessb3a0ca42011-10-12 07:44:40 +0000271 }
dburgessb3a0ca42011-10-12 07:44:40 +0000272
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400273 GMSKRotation1 = new signalVector(157);
274 GMSKReverseRotation1 = new signalVector(157);
275 rotPtr = GMSKRotation1->begin();
276 revPtr = GMSKReverseRotation1->begin();
277 phase = 0.0;
278 while (rotPtr != GMSKRotation1->end()) {
279 *rotPtr++ = expjLookup(phase);
280 *revPtr++ = expjLookup(-phase);
281 phase += M_PI_F / 2.0F;
Thomas Tsoue57004d2013-08-20 18:55:33 -0400282 }
dburgessb3a0ca42011-10-12 07:44:40 +0000283}
284
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400285static void GMSKRotate(signalVector &x, int sps)
286{
287 signalVector::iterator rotPtr, xPtr = x.begin();
288
289 if (sps == 1)
290 rotPtr = GMSKRotation1->begin();
291 else
292 rotPtr = GMSKRotationN->begin();
293
dburgessb3a0ca42011-10-12 07:44:40 +0000294 if (x.isRealOnly()) {
295 while (xPtr < x.end()) {
296 *xPtr = *rotPtr++ * (xPtr->real());
297 xPtr++;
298 }
299 }
300 else {
301 while (xPtr < x.end()) {
302 *xPtr = *rotPtr++ * (*xPtr);
303 xPtr++;
304 }
305 }
306}
307
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400308static void GMSKReverseRotate(signalVector &x, int sps)
309{
310 signalVector::iterator rotPtr, xPtr= x.begin();
311
312 if (sps == 1)
313 rotPtr = GMSKReverseRotation1->begin();
314 else
315 rotPtr = GMSKReverseRotationN->begin();
316
dburgessb3a0ca42011-10-12 07:44:40 +0000317 if (x.isRealOnly()) {
318 while (xPtr < x.end()) {
319 *xPtr = *rotPtr++ * (xPtr->real());
320 xPtr++;
321 }
322 }
323 else {
324 while (xPtr < x.end()) {
325 *xPtr = *rotPtr++ * (*xPtr);
326 xPtr++;
327 }
328 }
329}
330
Thomas Tsou3eaae802013-08-20 19:31:14 -0400331signalVector *convolve(const signalVector *x,
332 const signalVector *h,
333 signalVector *y,
334 ConvType spanType, int start,
335 unsigned len, unsigned step, int offset)
dburgessb3a0ca42011-10-12 07:44:40 +0000336{
Thomas Tsou3eaae802013-08-20 19:31:14 -0400337 int rc, head = 0, tail = 0;
338 bool alloc = false, append = false;
339 const signalVector *_x = NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000340
Thomas Tsou3eaae802013-08-20 19:31:14 -0400341 if (!x || !h)
dburgessb3a0ca42011-10-12 07:44:40 +0000342 return NULL;
343
Thomas Tsou3eaae802013-08-20 19:31:14 -0400344 switch (spanType) {
345 case START_ONLY:
346 start = 0;
347 head = h->size();
348 len = x->size();
349 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000350 break;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400351 case NO_DELAY:
352 start = h->size() / 2;
353 head = start;
354 tail = start;
355 len = x->size();
356 append = true;
357 break;
358 case CUSTOM:
359 if (start < h->size() - 1) {
360 head = h->size() - start;
361 append = true;
362 }
363 if (start + len > x->size()) {
364 tail = start + len - x->size();
365 append = true;
dburgessb3a0ca42011-10-12 07:44:40 +0000366 }
367 break;
368 default:
369 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +0000370 }
dburgessb3a0ca42011-10-12 07:44:40 +0000371
Thomas Tsou3eaae802013-08-20 19:31:14 -0400372 /*
373 * Error if the output vector is too small. Create the output vector
374 * if the pointer is NULL.
375 */
376 if (y && (len > y->size()))
377 return NULL;
378 if (!y) {
379 y = new signalVector(len);
380 alloc = true;
381 }
382
383 /* Prepend or post-pend the input vector if the parameters require it */
384 if (append)
385 _x = new signalVector(*x, head, tail);
386 else
387 _x = x;
388
389 /*
390 * Four convovle types:
391 * 1. Complex-Real (aligned)
392 * 2. Complex-Complex (aligned)
393 * 3. Complex-Real (!aligned)
394 * 4. Complex-Complex (!aligned)
395 */
396 if (h->isRealOnly() && h->isAligned()) {
397 rc = convolve_real((float *) _x->begin(), _x->size(),
398 (float *) h->begin(), h->size(),
399 (float *) y->begin(), y->size(),
400 start, len, step, offset);
401 } else if (!h->isRealOnly() && h->isAligned()) {
402 rc = convolve_complex((float *) _x->begin(), _x->size(),
403 (float *) h->begin(), h->size(),
404 (float *) y->begin(), y->size(),
405 start, len, step, offset);
406 } else if (h->isRealOnly() && !h->isAligned()) {
407 rc = base_convolve_real((float *) _x->begin(), _x->size(),
408 (float *) h->begin(), h->size(),
409 (float *) y->begin(), y->size(),
410 start, len, step, offset);
411 } else if (!h->isRealOnly() && !h->isAligned()) {
412 rc = base_convolve_complex((float *) _x->begin(), _x->size(),
413 (float *) h->begin(), h->size(),
414 (float *) y->begin(), y->size(),
415 start, len, step, offset);
416 } else {
417 rc = -1;
418 }
419
420 if (append)
421 delete _x;
422
423 if (rc < 0) {
424 if (alloc)
425 delete y;
426 return NULL;
427 }
428
429 return y;
430}
dburgessb3a0ca42011-10-12 07:44:40 +0000431
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400432static bool generateC1Pulse(int sps, PulseSequence *pulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800433{
434 int len;
435
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400436 if (!pulse)
437 return false;
438
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800439 switch (sps) {
440 case 4:
441 len = 8;
442 break;
443 default:
444 return false;
445 }
446
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400447 pulse->c1_buffer = convolve_h_alloc(len);
448 pulse->c1 = new signalVector((complex *)
449 pulse->c1_buffer, 0, len);
450 pulse->c1->isRealOnly(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800451
452 /* Enable alignment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400453 pulse->c1->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800454
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400455 signalVector::iterator xP = pulse->c1->begin();
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800456
457 switch (sps) {
458 case 4:
459 /* BT = 0.30 */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400460 *xP++ = 0.0;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800461 *xP++ = 8.16373112e-03;
462 *xP++ = 2.84385729e-02;
463 *xP++ = 5.64158904e-02;
464 *xP++ = 7.05463553e-02;
465 *xP++ = 5.64158904e-02;
466 *xP++ = 2.84385729e-02;
467 *xP++ = 8.16373112e-03;
468 }
469
470 return true;
471}
472
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400473static PulseSequence *generateGSMPulse(int sps, int symbolLength)
dburgessb3a0ca42011-10-12 07:44:40 +0000474{
Thomas Tsou83e06892013-08-20 16:10:01 -0400475 int len;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800476 float arg, avg, center;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400477 PulseSequence *pulse;
Thomas Tsou83e06892013-08-20 16:10:01 -0400478
479 /* Store a single tap filter used for correlation sequence generation */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400480 pulse = new PulseSequence();
481 pulse->empty = new signalVector(1);
482 pulse->empty->isRealOnly(true);
483 *(pulse->empty->begin()) = 1.0f;
Thomas Tsou83e06892013-08-20 16:10:01 -0400484
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400485 /*
486 * For 4 samples-per-symbol use a precomputed single pulse Laurent
487 * approximation. This should yields below 2 degrees of phase error at
488 * the modulator output. Use the existing pulse approximation for all
489 * other oversampling factors.
490 */
491 switch (sps) {
492 case 4:
493 len = 16;
494 break;
495 default:
496 len = sps * symbolLength;
497 if (len < 4)
498 len = 4;
499 }
Thomas Tsou3eaae802013-08-20 19:31:14 -0400500
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400501 pulse->c0_buffer = convolve_h_alloc(len);
502 pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
503 pulse->c0->isRealOnly(true);
Thomas Tsou3eaae802013-08-20 19:31:14 -0400504
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800505 /* Enable alingnment for SSE usage */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400506 pulse->c0->setAligned(true);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800507
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400508 signalVector::iterator xP = pulse->c0->begin();
Thomas Tsou83e06892013-08-20 16:10:01 -0400509
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400510 if (sps == 4) {
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800511 *xP++ = 0.0;
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400512 *xP++ = 4.46348606e-03;
513 *xP++ = 2.84385729e-02;
514 *xP++ = 1.03184855e-01;
515 *xP++ = 2.56065552e-01;
516 *xP++ = 4.76375085e-01;
517 *xP++ = 7.05961177e-01;
518 *xP++ = 8.71291644e-01;
519 *xP++ = 9.29453645e-01;
520 *xP++ = 8.71291644e-01;
521 *xP++ = 7.05961177e-01;
522 *xP++ = 4.76375085e-01;
523 *xP++ = 2.56065552e-01;
524 *xP++ = 1.03184855e-01;
525 *xP++ = 2.84385729e-02;
526 *xP++ = 4.46348606e-03;
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400527 generateC1Pulse(sps, pulse);
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400528 } else {
529 center = (float) (len - 1.0) / 2.0;
Thomas Tsou83e06892013-08-20 16:10:01 -0400530
Thomas Tsou9ccd9f22013-08-21 13:59:52 -0400531 /* GSM pulse approximation */
532 for (int i = 0; i < len; i++) {
533 arg = ((float) i - center) / (float) sps;
534 *xP++ = 0.96 * exp(-1.1380 * arg * arg -
535 0.527 * arg * arg * arg * arg);
536 }
dburgessb3a0ca42011-10-12 07:44:40 +0000537
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400538 avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
539 xP = pulse->c0->begin();
540 for (int i = 0; i < len; i++)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800541 *xP++ /= avg;
542 }
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400543
544 return pulse;
dburgessb3a0ca42011-10-12 07:44:40 +0000545}
546
547signalVector* frequencyShift(signalVector *y,
548 signalVector *x,
549 float freq,
550 float startPhase,
551 float *finalPhase)
552{
553
554 if (!x) return NULL;
555
556 if (y==NULL) {
557 y = new signalVector(x->size());
558 y->isRealOnly(x->isRealOnly());
559 if (y==NULL) return NULL;
560 }
561
562 if (y->size() < x->size()) return NULL;
563
564 float phase = startPhase;
565 signalVector::iterator yP = y->begin();
566 signalVector::iterator xPEnd = x->end();
567 signalVector::iterator xP = x->begin();
568
569 if (x->isRealOnly()) {
570 while (xP < xPEnd) {
571 (*yP++) = expjLookup(phase)*( (xP++)->real() );
572 phase += freq;
573 }
574 }
575 else {
576 while (xP < xPEnd) {
577 (*yP++) = (*xP++)*expjLookup(phase);
578 phase += freq;
579 }
580 }
581
582
583 if (finalPhase) *finalPhase = phase;
584
585 return y;
586}
587
588signalVector* reverseConjugate(signalVector *b)
589{
590 signalVector *tmp = new signalVector(b->size());
591 tmp->isRealOnly(b->isRealOnly());
592 signalVector::iterator bP = b->begin();
593 signalVector::iterator bPEnd = b->end();
594 signalVector::iterator tmpP = tmp->end()-1;
595 if (!b->isRealOnly()) {
596 while (bP < bPEnd) {
597 *tmpP-- = bP->conj();
598 bP++;
599 }
600 }
601 else {
602 while (bP < bPEnd) {
603 *tmpP-- = bP->real();
604 bP++;
605 }
606 }
607
608 return tmp;
609}
610
dburgessb3a0ca42011-10-12 07:44:40 +0000611/* soft output slicer */
612bool vectorSlicer(signalVector *x)
613{
614
615 signalVector::iterator xP = x->begin();
616 signalVector::iterator xPEnd = x->end();
617 while (xP < xPEnd) {
618 *xP = (complex) (0.5*(xP->real()+1.0F));
619 if (xP->real() > 1.0) *xP = 1.0;
620 if (xP->real() < 0.0) *xP = 0.0;
621 xP++;
622 }
623 return true;
624}
Thomas Tsou3eaae802013-08-20 19:31:14 -0400625
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800626static signalVector *rotateBurst(const BitVector &wBurst,
627 int guardPeriodLength, int sps)
628{
629 int burst_len;
630 signalVector *pulse, rotated, *shaped;
631 signalVector::iterator itr;
632
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400633 pulse = GSMPulse1->empty;
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800634 burst_len = sps * (wBurst.size() + guardPeriodLength);
635 rotated = signalVector(burst_len);
636 itr = rotated.begin();
637
638 for (unsigned i = 0; i < wBurst.size(); i++) {
639 *itr = 2.0 * (wBurst[i] & 0x01) - 1.0;
640 itr += sps;
641 }
642
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400643 GMSKRotate(rotated, sps);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800644 rotated.isRealOnly(false);
645
646 /* Dummy filter operation */
647 shaped = convolve(&rotated, pulse, NULL, START_ONLY);
648 if (!shaped)
649 return NULL;
650
651 return shaped;
652}
653
654static signalVector *modulateBurstLaurent(const BitVector &bits,
655 int guard_len, int sps)
656{
657 int burst_len;
658 float phase;
659 signalVector *c0_pulse, *c1_pulse, c0_burst, c1_burst, *c0_shaped, *c1_shaped;
660 signalVector::iterator c0_itr, c1_itr;
661
662 /*
663 * Apply before and after bits to reduce phase error at burst edges.
664 * Make sure there is enough room in the burst to accomodate all bits.
665 */
666 if (guard_len < 4)
667 guard_len = 4;
668
669 c0_pulse = GSMPulse->c0;
670 c1_pulse = GSMPulse->c1;
671
672 burst_len = sps * (bits.size() + guard_len);
673
674 c0_burst = signalVector(burst_len);
675 c0_burst.isRealOnly(true);
676 c0_itr = c0_burst.begin();
677
678 c1_burst = signalVector(burst_len);
679 c1_burst.isRealOnly(true);
680 c1_itr = c1_burst.begin();
681
682 /* Padded differential start bits */
683 *c0_itr = 2.0 * (0x00 & 0x01) - 1.0;
684 c0_itr += sps;
685
686 /* Main burst bits */
687 for (unsigned i = 0; i < bits.size(); i++) {
688 *c0_itr = 2.0 * (bits[i] & 0x01) - 1.0;
689 c0_itr += sps;
690 }
691
692 /* Padded differential end bits */
693 *c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
694
695 /* Generate C0 phase coefficients */
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400696 GMSKRotate(c0_burst, sps);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800697 c0_burst.isRealOnly(false);
698
699 c0_itr = c0_burst.begin();
700 c0_itr += sps * 2;
701 c1_itr += sps * 2;
702
703 /* Start magic */
704 phase = 2.0 * ((0x01 & 0x01) ^ (0x01 & 0x01)) - 1.0;
705 *c1_itr = *c0_itr * Complex<float>(0, phase);
706 c0_itr += sps;
707 c1_itr += sps;
708
709 /* Generate C1 phase coefficients */
710 for (unsigned i = 2; i < bits.size(); i++) {
711 phase = 2.0 * ((bits[i - 1] & 0x01) ^ (bits[i - 2] & 0x01)) - 1.0;
712 *c1_itr = *c0_itr * Complex<float>(0, phase);
713
714 c0_itr += sps;
715 c1_itr += sps;
716 }
717
718 /* End magic */
719 int i = bits.size();
720 phase = 2.0 * ((bits[i-1] & 0x01) ^ (bits[i-2] & 0x01)) - 1.0;
721 *c1_itr = *c0_itr * Complex<float>(0, phase);
722
723 /* Primary (C0) and secondary (C1) pulse shaping */
724 c0_shaped = convolve(&c0_burst, c0_pulse, NULL, START_ONLY);
725 c1_shaped = convolve(&c1_burst, c1_pulse, NULL, START_ONLY);
726
727 /* Sum shaped outputs into C0 */
728 c0_itr = c0_shaped->begin();
729 c1_itr = c1_shaped->begin();
730 for (unsigned i = 0; i < c0_shaped->size(); i++ )
731 *c0_itr++ += *c1_itr++;
732
733 delete c1_shaped;
734
735 return c0_shaped;
736}
737
738static signalVector *modulateBurstBasic(const BitVector &bits,
739 int guard_len, int sps)
740{
741 int burst_len;
742 signalVector *pulse, burst, *shaped;
743 signalVector::iterator burst_itr;
744
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400745 if (sps == 1)
746 pulse = GSMPulse1->c0;
747 else
748 pulse = GSMPulse->c0;
749
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800750 burst_len = sps * (bits.size() + guard_len);
751
752 burst = signalVector(burst_len);
753 burst.isRealOnly(true);
754 burst_itr = burst.begin();
755
756 /* Raw bits are not differentially encoded */
757 for (unsigned i = 0; i < bits.size(); i++) {
758 *burst_itr = 2.0 * (bits[i] & 0x01) - 1.0;
759 burst_itr += sps;
760 }
761
Thomas Tsouc1f7c422013-10-11 13:49:55 -0400762 GMSKRotate(burst, sps);
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800763 burst.isRealOnly(false);
764
765 /* Single Gaussian pulse approximation shaping */
766 shaped = convolve(&burst, pulse, NULL, START_ONLY);
767
768 return shaped;
769}
770
Thomas Tsou3eaae802013-08-20 19:31:14 -0400771/* Assume input bits are not differentially encoded */
Thomas Tsou83e06892013-08-20 16:10:01 -0400772signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
773 int sps, bool emptyPulse)
dburgessb3a0ca42011-10-12 07:44:40 +0000774{
Thomas Tsou83e06892013-08-20 16:10:01 -0400775 if (emptyPulse)
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800776 return rotateBurst(wBurst, guardPeriodLength, sps);
777 else if (sps == 4)
778 return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
Thomas Tsou83e06892013-08-20 16:10:01 -0400779 else
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800780 return modulateBurstBasic(wBurst, guardPeriodLength, sps);
dburgessb3a0ca42011-10-12 07:44:40 +0000781}
782
Thomas Tsoua57bc8a2013-09-05 08:16:47 +0800783float sinc(float x)
dburgessb3a0ca42011-10-12 07:44:40 +0000784{
785 if ((x >= 0.01F) || (x <= -0.01F)) return (sinLookup(x)/x);
786 return 1.0F;
787}
788
Thomas Tsou3eaae802013-08-20 19:31:14 -0400789bool delayVector(signalVector &wBurst, float delay)
dburgessb3a0ca42011-10-12 07:44:40 +0000790{
Thomas Tsou2c282f52013-10-08 21:34:35 -0400791 int whole, h_len = 20;
792 float frac;
793 complex *data;
794 signalVector *h, *shift;
795 signalVector::iterator itr;
Thomas Tsou3eaae802013-08-20 19:31:14 -0400796
Thomas Tsou2c282f52013-10-08 21:34:35 -0400797 whole = floor(delay);
798 frac = delay - whole;
799
800 /* Sinc interpolated fractional shift (if allowable) */
801 if (fabs(frac) > 1e-2) {
802 data = (complex *) convolve_h_alloc(h_len);
803 h = new signalVector(data, 0, h_len);
804 h->setAligned(true);
805 h->isRealOnly(true);
806
807 itr = h->end();
808 for (int i = 0; i < h_len; i++)
809 *--itr = (complex) sinc(M_PI_F * (i - h_len / 2 - frac));
810
811 shift = convolve(&wBurst, h, NULL, NO_DELAY);
812
813 delete h;
814 free(data);
815
816 if (!shift)
Thomas Tsou3eaae802013-08-20 19:31:14 -0400817 return false;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400818
819 wBurst.clone(*shift);
820 delete shift;
dburgessb3a0ca42011-10-12 07:44:40 +0000821 }
822
Thomas Tsou2c282f52013-10-08 21:34:35 -0400823 /* Integer sample shift */
824 if (whole < 0) {
825 whole = -whole;
dburgessb3a0ca42011-10-12 07:44:40 +0000826 signalVector::iterator wBurstItr = wBurst.begin();
Thomas Tsou2c282f52013-10-08 21:34:35 -0400827 signalVector::iterator shiftedItr = wBurst.begin() + whole;
828
dburgessb3a0ca42011-10-12 07:44:40 +0000829 while (shiftedItr < wBurst.end())
830 *wBurstItr++ = *shiftedItr++;
831 while (wBurstItr < wBurst.end())
832 *wBurstItr++ = 0.0;
Thomas Tsou2c282f52013-10-08 21:34:35 -0400833 } else {
834 signalVector::iterator wBurstItr = wBurst.end() - 1;
835 signalVector::iterator shiftedItr = wBurst.end() - 1 - whole;
836
dburgessb3a0ca42011-10-12 07:44:40 +0000837 while (shiftedItr >= wBurst.begin())
838 *wBurstItr-- = *shiftedItr--;
839 while (wBurstItr >= wBurst.begin())
840 *wBurstItr-- = 0.0;
841 }
Thomas Tsou2c282f52013-10-08 21:34:35 -0400842
843 return true;
dburgessb3a0ca42011-10-12 07:44:40 +0000844}
Thomas Tsou2c282f52013-10-08 21:34:35 -0400845
dburgessb3a0ca42011-10-12 07:44:40 +0000846signalVector *gaussianNoise(int length,
847 float variance,
848 complex mean)
849{
850
851 signalVector *noise = new signalVector(length);
852 signalVector::iterator nPtr = noise->begin();
853 float stddev = sqrtf(variance);
854 while (nPtr < noise->end()) {
855 float u1 = (float) rand()/ (float) RAND_MAX;
856 while (u1==0.0)
857 u1 = (float) rand()/ (float) RAND_MAX;
858 float u2 = (float) rand()/ (float) RAND_MAX;
859 float arg = 2.0*M_PI*u2;
860 *nPtr = mean + stddev*complex(cos(arg),sin(arg))*sqrtf(-2.0*log(u1));
861 nPtr++;
862 }
863
864 return noise;
865}
866
867complex interpolatePoint(const signalVector &inSig,
868 float ix)
869{
870
871 int start = (int) (floor(ix) - 10);
872 if (start < 0) start = 0;
873 int end = (int) (floor(ix) + 11);
874 if ((unsigned) end > inSig.size()-1) end = inSig.size()-1;
875
876 complex pVal = 0.0;
877 if (!inSig.isRealOnly()) {
878 for (int i = start; i < end; i++)
879 pVal += inSig[i] * sinc(M_PI_F*(i-ix));
880 }
881 else {
882 for (int i = start; i < end; i++)
883 pVal += inSig[i].real() * sinc(M_PI_F*(i-ix));
884 }
885
886 return pVal;
887}
888
Thomas Tsou8181b012013-08-20 21:17:19 -0400889static complex fastPeakDetect(const signalVector &rxBurst, float *index)
890{
891 float val, max = 0.0f;
892 complex amp;
893 int _index = -1;
894
895 for (int i = 0; i < rxBurst.size(); i++) {
896 val = rxBurst[i].norm2();
897 if (val > max) {
898 max = val;
899 _index = i;
900 amp = rxBurst[i];
901 }
902 }
903
904 if (index)
905 *index = (float) _index;
906
907 return amp;
908}
909
dburgessb3a0ca42011-10-12 07:44:40 +0000910complex peakDetect(const signalVector &rxBurst,
911 float *peakIndex,
912 float *avgPwr)
913{
914
915
916 complex maxVal = 0.0;
917 float maxIndex = -1;
918 float sumPower = 0.0;
919
920 for (unsigned int i = 0; i < rxBurst.size(); i++) {
921 float samplePower = rxBurst[i].norm2();
922 if (samplePower > maxVal.real()) {
923 maxVal = samplePower;
924 maxIndex = i;
925 }
926 sumPower += samplePower;
927 }
928
929 // interpolate around the peak
930 // to save computation, we'll use early-late balancing
931 float earlyIndex = maxIndex-1;
932 float lateIndex = maxIndex+1;
933
934 float incr = 0.5;
935 while (incr > 1.0/1024.0) {
936 complex earlyP = interpolatePoint(rxBurst,earlyIndex);
937 complex lateP = interpolatePoint(rxBurst,lateIndex);
938 if (earlyP < lateP)
939 earlyIndex += incr;
940 else if (earlyP > lateP)
941 earlyIndex -= incr;
942 else break;
943 incr /= 2.0;
944 lateIndex = earlyIndex + 2.0;
945 }
946
947 maxIndex = earlyIndex + 1.0;
948 maxVal = interpolatePoint(rxBurst,maxIndex);
949
950 if (peakIndex!=NULL)
951 *peakIndex = maxIndex;
952
953 if (avgPwr!=NULL)
954 *avgPwr = (sumPower-maxVal.norm2()) / (rxBurst.size()-1);
955
956 return maxVal;
957
958}
959
960void scaleVector(signalVector &x,
961 complex scale)
962{
963 signalVector::iterator xP = x.begin();
964 signalVector::iterator xPEnd = x.end();
965 if (!x.isRealOnly()) {
966 while (xP < xPEnd) {
967 *xP = *xP * scale;
968 xP++;
969 }
970 }
971 else {
972 while (xP < xPEnd) {
973 *xP = xP->real() * scale;
974 xP++;
975 }
976 }
977}
978
979/** in-place conjugation */
980void conjugateVector(signalVector &x)
981{
982 if (x.isRealOnly()) return;
983 signalVector::iterator xP = x.begin();
984 signalVector::iterator xPEnd = x.end();
985 while (xP < xPEnd) {
986 *xP = xP->conj();
987 xP++;
988 }
989}
990
991
992// in-place addition!!
993bool addVector(signalVector &x,
994 signalVector &y)
995{
996 signalVector::iterator xP = x.begin();
997 signalVector::iterator yP = y.begin();
998 signalVector::iterator xPEnd = x.end();
999 signalVector::iterator yPEnd = y.end();
1000 while ((xP < xPEnd) && (yP < yPEnd)) {
1001 *xP = *xP + *yP;
1002 xP++; yP++;
1003 }
1004 return true;
1005}
1006
1007// in-place multiplication!!
1008bool multVector(signalVector &x,
1009 signalVector &y)
1010{
1011 signalVector::iterator xP = x.begin();
1012 signalVector::iterator yP = y.begin();
1013 signalVector::iterator xPEnd = x.end();
1014 signalVector::iterator yPEnd = y.end();
1015 while ((xP < xPEnd) && (yP < yPEnd)) {
1016 *xP = (*xP) * (*yP);
1017 xP++; yP++;
1018 }
1019 return true;
1020}
1021
1022
1023void offsetVector(signalVector &x,
1024 complex offset)
1025{
1026 signalVector::iterator xP = x.begin();
1027 signalVector::iterator xPEnd = x.end();
1028 if (!x.isRealOnly()) {
1029 while (xP < xPEnd) {
1030 *xP += offset;
1031 xP++;
1032 }
1033 }
1034 else {
1035 while (xP < xPEnd) {
1036 *xP = xP->real() + offset;
1037 xP++;
1038 }
1039 }
1040}
1041
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001042bool generateMidamble(int sps, int tsc)
dburgessb3a0ca42011-10-12 07:44:40 +00001043{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001044 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001045 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001046 complex *data = NULL;
1047 signalVector *autocorr = NULL, *midamble = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001048 signalVector *midMidamble = NULL, *_midMidamble = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001049
Thomas Tsou3eaae802013-08-20 19:31:14 -04001050 if ((tsc < 0) || (tsc > 7))
dburgessb3a0ca42011-10-12 07:44:40 +00001051 return false;
1052
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001053 delete gMidambles[tsc];
Thomas Tsou3eaae802013-08-20 19:31:14 -04001054
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001055 /* Use middle 16 bits of each TSC. Correlation sequence is not pulse shaped */
1056 midMidamble = modulateBurst(gTrainingSequence[tsc].segment(5,16), 0, sps, true);
1057 if (!midMidamble)
1058 return false;
1059
Thomas Tsou3eaae802013-08-20 19:31:14 -04001060 /* Simulated receive sequence is pulse shaped */
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001061 midamble = modulateBurst(gTrainingSequence[tsc], 0, sps, false);
1062 if (!midamble) {
1063 status = false;
1064 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001065 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001066
dburgessb3a0ca42011-10-12 07:44:40 +00001067 // NOTE: Because ideal TSC 16-bit midamble is 66 symbols into burst,
1068 // the ideal TSC has an + 180 degree phase shift,
1069 // due to the pi/2 frequency shift, that
1070 // needs to be accounted for.
1071 // 26-midamble is 61 symbols into burst, has +90 degree phase shift.
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001072 scaleVector(*midMidamble, complex(-1.0, 0.0));
1073 scaleVector(*midamble, complex(0.0, 1.0));
dburgessb3a0ca42011-10-12 07:44:40 +00001074
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001075 conjugateVector(*midMidamble);
dburgessb3a0ca42011-10-12 07:44:40 +00001076
Thomas Tsou3eaae802013-08-20 19:31:14 -04001077 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1078 data = (complex *) convolve_h_alloc(midMidamble->size());
1079 _midMidamble = new signalVector(data, 0, midMidamble->size());
1080 _midMidamble->setAligned(true);
1081 memcpy(_midMidamble->begin(), midMidamble->begin(),
1082 midMidamble->size() * sizeof(complex));
1083
1084 autocorr = convolve(midamble, _midMidamble, NULL, NO_DELAY);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001085 if (!autocorr) {
1086 status = false;
1087 goto release;
1088 }
dburgessb3a0ca42011-10-12 07:44:40 +00001089
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001090 gMidambles[tsc] = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001091 gMidambles[tsc]->buffer = data;
1092 gMidambles[tsc]->sequence = _midMidamble;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001093 gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
1094
1095 /* For 1 sps only
1096 * (Half of correlation length - 1) + midpoint of pulse shape + remainder
1097 * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
1098 */
1099 if (sps == 1)
1100 gMidambles[tsc]->toa = toa - 13.5;
1101 else
1102 gMidambles[tsc]->toa = 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001103
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001104release:
dburgessb3a0ca42011-10-12 07:44:40 +00001105 delete autocorr;
1106 delete midamble;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001107 delete midMidamble;
dburgessb3a0ca42011-10-12 07:44:40 +00001108
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001109 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001110 delete _midMidamble;
1111 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001112 gMidambles[tsc] = NULL;
1113 }
1114
1115 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001116}
1117
Thomas Tsou83e06892013-08-20 16:10:01 -04001118bool generateRACHSequence(int sps)
dburgessb3a0ca42011-10-12 07:44:40 +00001119{
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001120 bool status = true;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001121 float toa;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001122 complex *data = NULL;
1123 signalVector *autocorr = NULL;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001124 signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001125
1126 delete gRACHSequence;
1127
1128 seq0 = modulateBurst(gRACHSynchSequence, 0, sps, false);
1129 if (!seq0)
1130 return false;
1131
1132 seq1 = modulateBurst(gRACHSynchSequence.segment(0, 40), 0, sps, true);
1133 if (!seq1) {
1134 status = false;
1135 goto release;
dburgessb3a0ca42011-10-12 07:44:40 +00001136 }
1137
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001138 conjugateVector(*seq1);
dburgessb3a0ca42011-10-12 07:44:40 +00001139
Thomas Tsou3eaae802013-08-20 19:31:14 -04001140 /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */
1141 data = (complex *) convolve_h_alloc(seq1->size());
1142 _seq1 = new signalVector(data, 0, seq1->size());
1143 _seq1->setAligned(true);
1144 memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex));
1145
1146 autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY);
1147 if (!autocorr) {
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001148 status = false;
1149 goto release;
1150 }
dburgessb3a0ca42011-10-12 07:44:40 +00001151
1152 gRACHSequence = new CorrelationSequence;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001153 gRACHSequence->sequence = _seq1;
1154 gRACHSequence->buffer = data;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001155 gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
1156
1157 /* For 1 sps only
1158 * (Half of correlation length - 1) + midpoint of pulse shaping filer
1159 * 20.5 = (40 / 2 - 1) + 1.5
1160 */
1161 if (sps == 1)
1162 gRACHSequence->toa = toa - 20.5;
1163 else
1164 gRACHSequence->toa = 0.0;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001165
1166release:
dburgessb3a0ca42011-10-12 07:44:40 +00001167 delete autocorr;
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001168 delete seq0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001169 delete seq1;
dburgessb3a0ca42011-10-12 07:44:40 +00001170
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001171 if (!status) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001172 delete _seq1;
1173 free(data);
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001174 gRACHSequence = NULL;
1175 }
dburgessb3a0ca42011-10-12 07:44:40 +00001176
Thomas Tsoue5dcfc42013-08-20 16:27:12 -04001177 return status;
dburgessb3a0ca42011-10-12 07:44:40 +00001178}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001179
Thomas Tsou865bca42013-08-21 20:58:00 -04001180static float computePeakRatio(signalVector *corr,
1181 int sps, float toa, complex amp)
dburgessb3a0ca42011-10-12 07:44:40 +00001182{
Thomas Tsou865bca42013-08-21 20:58:00 -04001183 int num = 0;
1184 complex *peak;
1185 float rms, avg = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001186
Thomas Tsou865bca42013-08-21 20:58:00 -04001187 peak = corr->begin() + (int) rint(toa);
dburgessb3a0ca42011-10-12 07:44:40 +00001188
Thomas Tsou865bca42013-08-21 20:58:00 -04001189 /* Check for bogus results */
1190 if ((toa < 0.0) || (toa > corr->size()))
1191 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001192
Thomas Tsou3eaae802013-08-20 19:31:14 -04001193 for (int i = 2 * sps; i <= 5 * sps; i++) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001194 if (peak - i >= corr->begin()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001195 avg += (peak - i)->norm2();
1196 num++;
1197 }
Thomas Tsou865bca42013-08-21 20:58:00 -04001198 if (peak + i < corr->end()) {
Thomas Tsou3eaae802013-08-20 19:31:14 -04001199 avg += (peak + i)->norm2();
1200 num++;
1201 }
dburgessb3a0ca42011-10-12 07:44:40 +00001202 }
1203
Thomas Tsou3eaae802013-08-20 19:31:14 -04001204 if (num < 2)
Thomas Tsou865bca42013-08-21 20:58:00 -04001205 return 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001206
Thomas Tsou3eaae802013-08-20 19:31:14 -04001207 rms = sqrtf(avg / (float) num) + 0.00001;
dburgessb3a0ca42011-10-12 07:44:40 +00001208
Thomas Tsou865bca42013-08-21 20:58:00 -04001209 return (amp.abs()) / rms;
dburgessb3a0ca42011-10-12 07:44:40 +00001210}
1211
1212bool energyDetect(signalVector &rxBurst,
1213 unsigned windowLength,
1214 float detectThreshold,
1215 float *avgPwr)
1216{
1217
1218 signalVector::const_iterator windowItr = rxBurst.begin(); //+rxBurst.size()/2 - 5*windowLength/2;
1219 float energy = 0.0;
1220 if (windowLength < 0) windowLength = 20;
1221 if (windowLength > rxBurst.size()) windowLength = rxBurst.size();
1222 for (unsigned i = 0; i < windowLength; i++) {
1223 energy += windowItr->norm2();
1224 windowItr+=4;
1225 }
1226 if (avgPwr) *avgPwr = energy/windowLength;
dburgessb3a0ca42011-10-12 07:44:40 +00001227 return (energy/windowLength > detectThreshold*detectThreshold);
1228}
dburgessb3a0ca42011-10-12 07:44:40 +00001229
Thomas Tsou865bca42013-08-21 20:58:00 -04001230/*
1231 * Detect a burst based on correlation and peak-to-average ratio
1232 *
1233 * For one sampler-per-symbol, perform fast peak detection (no interpolation)
1234 * for initial gating. We do this because energy detection should be disabled.
1235 * For higher oversampling values, we assume the energy detector is in place
1236 * and we run full interpolating peak detection.
1237 */
1238static int detectBurst(signalVector &burst,
1239 signalVector &corr, CorrelationSequence *sync,
1240 float thresh, int sps, complex *amp, float *toa,
1241 int start, int len)
dburgessb3a0ca42011-10-12 07:44:40 +00001242{
Thomas Tsou865bca42013-08-21 20:58:00 -04001243 /* Correlate */
1244 if (!convolve(&burst, sync->sequence, &corr,
Thomas Tsou3eaae802013-08-20 19:31:14 -04001245 CUSTOM, start, len, sps, 0)) {
1246 return -1;
dburgessb3a0ca42011-10-12 07:44:40 +00001247 }
1248
Thomas Tsou865bca42013-08-21 20:58:00 -04001249 /* Peak detection - place restrictions at correlation edges */
1250 *amp = fastPeakDetect(corr, toa);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001251
Thomas Tsou865bca42013-08-21 20:58:00 -04001252 if ((*toa < 3 * sps) || (*toa > len - 3 * sps))
1253 return 0;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001254
Thomas Tsou865bca42013-08-21 20:58:00 -04001255 /* Peak -to-average ratio */
1256 if (computePeakRatio(&corr, sps, *toa, *amp) < thresh)
1257 return 0;
1258
1259 /* Compute peak-to-average ratio. Reject if we don't have enough values */
1260 *amp = peakDetect(corr, toa, NULL);
1261
1262 /* Normalize our channel gain */
1263 *amp = *amp / sync->gain;
1264
Thomas Tsoua57bc8a2013-09-05 08:16:47 +08001265 /* Compenate for residual rotation with dual Laurent pulse */
1266 if (sps == 4)
1267 *amp = *amp * complex(0.0, 1.0);
1268
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001269 /* Compensate for residuate time lag */
1270 *toa = *toa - sync->toa;
1271
Thomas Tsou865bca42013-08-21 20:58:00 -04001272 return 1;
1273}
1274
1275/*
1276 * RACH burst detection
1277 *
1278 * Correlation window parameters:
1279 * target: Tail bits + RACH length (reduced from 41 to a multiple of 4)
Thomas Tsoudafb3372013-09-18 16:21:26 -04001280 * head: Search 4 symbols before target
1281 * tail: Search 10 symbols after target
Thomas Tsou865bca42013-08-21 20:58:00 -04001282 */
1283int detectRACHBurst(signalVector &rxBurst,
1284 float thresh,
1285 int sps,
1286 complex *amp,
1287 float *toa)
1288{
1289 int rc, start, target, head, tail, len;
1290 float _toa;
1291 complex _amp;
1292 signalVector corr;
1293 CorrelationSequence *sync;
1294
1295 if ((sps != 1) && (sps != 4))
1296 return -1;
1297
1298 target = 8 + 40;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001299 head = 4;
1300 tail = 10;
Thomas Tsou865bca42013-08-21 20:58:00 -04001301
1302 start = (target - head) * sps - 1;
1303 len = (head + tail) * sps;
1304 sync = gRACHSequence;
1305 corr = signalVector(len);
1306
1307 rc = detectBurst(rxBurst, corr, sync,
1308 thresh, sps, &_amp, &_toa, start, len);
1309 if (rc < 0) {
1310 return -1;
1311 } else if (!rc) {
1312 if (amp)
1313 *amp = 0.0f;
1314 if (toa)
1315 *toa = 0.0f;
1316 return 0;
dburgessb3a0ca42011-10-12 07:44:40 +00001317 }
1318
Thomas Tsou865bca42013-08-21 20:58:00 -04001319 /* Subtract forward search bits from delay */
1320 if (toa)
1321 *toa = _toa - head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001322 if (amp)
Thomas Tsou865bca42013-08-21 20:58:00 -04001323 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001324
Thomas Tsou865bca42013-08-21 20:58:00 -04001325 return 1;
1326}
Thomas Tsou3eaae802013-08-20 19:31:14 -04001327
Thomas Tsou865bca42013-08-21 20:58:00 -04001328/*
1329 * Normal burst detection
1330 *
1331 * Correlation window parameters:
1332 * target: Tail + data + mid-midamble + 1/2 remaining midamblebits
Thomas Tsoudafb3372013-09-18 16:21:26 -04001333 * head: Search 4 symbols before target
1334 * tail: Search 4 symbols + maximum expected delay
Thomas Tsou865bca42013-08-21 20:58:00 -04001335 */
1336int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
1337 int sps, complex *amp, float *toa, unsigned max_toa,
1338 bool chan_req, signalVector **chan, float *chan_offset)
1339{
1340 int rc, start, target, head, tail, len;
1341 complex _amp;
1342 float _toa;
1343 signalVector corr;
1344 CorrelationSequence *sync;
1345
1346 if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
1347 return -1;
1348
1349 target = 3 + 58 + 16 + 5;
Thomas Tsoudafb3372013-09-18 16:21:26 -04001350 head = 4;
1351 tail = 4 + max_toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001352
1353 start = (target - head) * sps - 1;
1354 len = (head + tail) * sps;
1355 sync = gMidambles[tsc];
1356 corr = signalVector(len);
1357
1358 rc = detectBurst(rxBurst, corr, sync,
1359 thresh, sps, &_amp, &_toa, start, len);
1360 if (rc < 0) {
1361 return -1;
1362 } else if (!rc) {
1363 if (amp)
1364 *amp = 0.0f;
1365 if (toa)
1366 *toa = 0.0f;
1367 return 0;
1368 }
1369
1370 /* Subtract forward search bits from delay */
1371 _toa -= head * sps;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001372 if (toa)
1373 *toa = _toa;
Thomas Tsou865bca42013-08-21 20:58:00 -04001374 if (amp)
1375 *amp = _amp;
Thomas Tsou3eaae802013-08-20 19:31:14 -04001376
Thomas Tsou865bca42013-08-21 20:58:00 -04001377 /* Equalization not currently supported */
Thomas Tsou3eaae802013-08-20 19:31:14 -04001378 if (chan_req) {
Thomas Tsou865bca42013-08-21 20:58:00 -04001379 *chan = new signalVector(6 * sps);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001380
1381 if (chan_offset)
Thomas Tsou865bca42013-08-21 20:58:00 -04001382 *chan_offset = 0.0;
dburgessb3a0ca42011-10-12 07:44:40 +00001383 }
1384
Thomas Tsou3eaae802013-08-20 19:31:14 -04001385 return 1;
dburgessb3a0ca42011-10-12 07:44:40 +00001386}
1387
1388signalVector *decimateVector(signalVector &wVector,
1389 int decimationFactor)
1390{
1391
1392 if (decimationFactor <= 1) return NULL;
1393
1394 signalVector *decVector = new signalVector(wVector.size()/decimationFactor);
1395 decVector->isRealOnly(wVector.isRealOnly());
1396
1397 signalVector::iterator vecItr = decVector->begin();
1398 for (unsigned int i = 0; i < wVector.size();i+=decimationFactor)
1399 *vecItr++ = wVector[i];
1400
1401 return decVector;
1402}
1403
1404
Thomas Tsou83e06892013-08-20 16:10:01 -04001405SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
1406 complex channel, float TOA)
dburgessb3a0ca42011-10-12 07:44:40 +00001407{
1408 scaleVector(rxBurst,((complex) 1.0)/channel);
1409 delayVector(rxBurst,-TOA);
1410
1411 signalVector *shapedBurst = &rxBurst;
1412
1413 // shift up by a quarter of a frequency
1414 // ignore starting phase, since spec allows for discontinuous phase
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001415 GMSKReverseRotate(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001416
1417 // run through slicer
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001418 if (sps > 1) {
1419 signalVector *decShapedBurst = decimateVector(*shapedBurst, sps);
dburgessb3a0ca42011-10-12 07:44:40 +00001420 shapedBurst = decShapedBurst;
1421 }
1422
dburgessb3a0ca42011-10-12 07:44:40 +00001423 vectorSlicer(shapedBurst);
1424
1425 SoftVector *burstBits = new SoftVector(shapedBurst->size());
1426
1427 SoftVector::iterator burstItr = burstBits->begin();
1428 signalVector::iterator shapedItr = shapedBurst->begin();
1429 for (; shapedItr < shapedBurst->end(); shapedItr++)
1430 *burstItr++ = shapedItr->real();
1431
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001432 if (sps > 1)
1433 delete shapedBurst;
dburgessb3a0ca42011-10-12 07:44:40 +00001434
1435 return burstBits;
1436
1437}
dburgessb3a0ca42011-10-12 07:44:40 +00001438
dburgessb3a0ca42011-10-12 07:44:40 +00001439// Assumes symbol-spaced sampling!!!
1440// Based upon paper by Al-Dhahir and Cioffi
1441bool designDFE(signalVector &channelResponse,
1442 float SNRestimate,
1443 int Nf,
1444 signalVector **feedForwardFilter,
1445 signalVector **feedbackFilter)
1446{
1447
1448 signalVector G0(Nf);
1449 signalVector G1(Nf);
1450 signalVector::iterator G0ptr = G0.begin();
1451 signalVector::iterator G1ptr = G1.begin();
1452 signalVector::iterator chanPtr = channelResponse.begin();
1453
1454 int nu = channelResponse.size()-1;
1455
1456 *G0ptr = 1.0/sqrtf(SNRestimate);
1457 for(int j = 0; j <= nu; j++) {
1458 *G1ptr = chanPtr->conj();
1459 G1ptr++; chanPtr++;
1460 }
1461
1462 signalVector *L[Nf];
1463 signalVector::iterator Lptr;
1464 float d;
1465 for(int i = 0; i < Nf; i++) {
1466 d = G0.begin()->norm2() + G1.begin()->norm2();
1467 L[i] = new signalVector(Nf+nu);
1468 Lptr = L[i]->begin()+i;
1469 G0ptr = G0.begin(); G1ptr = G1.begin();
1470 while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
1471 *Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
1472 Lptr++;
1473 G0ptr++;
1474 G1ptr++;
1475 }
1476 complex k = (*G1.begin())/(*G0.begin());
1477
1478 if (i != Nf-1) {
1479 signalVector G0new = G1;
1480 scaleVector(G0new,k.conj());
1481 addVector(G0new,G0);
1482
1483 signalVector G1new = G0;
1484 scaleVector(G1new,k*(-1.0));
1485 addVector(G1new,G1);
1486 delayVector(G1new,-1.0);
1487
1488 scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
1489 scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
1490 G0 = G0new;
1491 G1 = G1new;
1492 }
1493 }
1494
1495 *feedbackFilter = new signalVector(nu);
1496 L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
1497 scaleVector(**feedbackFilter,(complex) -1.0);
1498 conjugateVector(**feedbackFilter);
1499
1500 signalVector v(Nf);
1501 signalVector::iterator vStart = v.begin();
1502 signalVector::iterator vPtr;
1503 *(vStart+Nf-1) = (complex) 1.0;
1504 for(int k = Nf-2; k >= 0; k--) {
1505 Lptr = L[k]->begin()+k+1;
1506 vPtr = vStart + k+1;
1507 complex v_k = 0.0;
1508 for (int j = k+1; j < Nf; j++) {
1509 v_k -= (*vPtr)*(*Lptr);
1510 vPtr++; Lptr++;
1511 }
1512 *(vStart + k) = v_k;
1513 }
1514
1515 *feedForwardFilter = new signalVector(Nf);
Thomas Tsou3eaae802013-08-20 19:31:14 -04001516 signalVector::iterator w = (*feedForwardFilter)->end();
dburgessb3a0ca42011-10-12 07:44:40 +00001517 for (int i = 0; i < Nf; i++) {
1518 delete L[i];
1519 complex w_i = 0.0;
1520 int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
1521 vPtr = vStart+i;
1522 chanPtr = channelResponse.begin();
1523 for (int k = 0; k < endPt+1; k++) {
1524 w_i += (*vPtr)*(chanPtr->conj());
1525 vPtr++; chanPtr++;
1526 }
Thomas Tsou3eaae802013-08-20 19:31:14 -04001527 *--w = w_i/d;
dburgessb3a0ca42011-10-12 07:44:40 +00001528 }
1529
1530
1531 return true;
1532
1533}
1534
1535// Assumes symbol-rate sampling!!!!
1536SoftVector *equalizeBurst(signalVector &rxBurst,
1537 float TOA,
Thomas Tsoud24cc2c2013-08-20 15:41:45 -04001538 int sps,
dburgessb3a0ca42011-10-12 07:44:40 +00001539 signalVector &w, // feedforward filter
1540 signalVector &b) // feedback filter
1541{
Thomas Tsou3eaae802013-08-20 19:31:14 -04001542 signalVector *postForwardFull;
dburgessb3a0ca42011-10-12 07:44:40 +00001543
Thomas Tsou3eaae802013-08-20 19:31:14 -04001544 if (!delayVector(rxBurst, -TOA))
1545 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001546
Thomas Tsou3eaae802013-08-20 19:31:14 -04001547 postForwardFull = convolve(&rxBurst, &w, NULL,
1548 CUSTOM, 0, rxBurst.size() + w.size() - 1);
1549 if (!postForwardFull)
1550 return NULL;
dburgessb3a0ca42011-10-12 07:44:40 +00001551
1552 signalVector* postForward = new signalVector(rxBurst.size());
1553 postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
1554 delete postForwardFull;
1555
1556 signalVector::iterator dPtr = postForward->begin();
1557 signalVector::iterator dBackPtr;
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001558 signalVector::iterator rotPtr = GMSKRotationN->begin();
1559 signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
dburgessb3a0ca42011-10-12 07:44:40 +00001560
1561 signalVector *DFEoutput = new signalVector(postForward->size());
1562 signalVector::iterator DFEItr = DFEoutput->begin();
1563
1564 // NOTE: can insert the midamble and/or use midamble to estimate BER
1565 for (; dPtr < postForward->end(); dPtr++) {
1566 dBackPtr = dPtr-1;
1567 signalVector::iterator bPtr = b.begin();
1568 while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
1569 *dPtr = *dPtr + (*bPtr)*(*dBackPtr);
1570 bPtr++;
1571 dBackPtr--;
1572 }
1573 *dPtr = *dPtr * (*revRotPtr);
1574 *DFEItr = *dPtr;
1575 // make decision on symbol
1576 *dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
1577 //*DFEItr = *dPtr;
1578 *dPtr = *dPtr * (*rotPtr);
1579 DFEItr++;
1580 rotPtr++;
1581 revRotPtr++;
1582 }
1583
1584 vectorSlicer(DFEoutput);
1585
1586 SoftVector *burstBits = new SoftVector(postForward->size());
1587 SoftVector::iterator burstItr = burstBits->begin();
1588 DFEItr = DFEoutput->begin();
1589 for (; DFEItr < DFEoutput->end(); DFEItr++)
1590 *burstItr++ = DFEItr->real();
1591
1592 delete postForward;
1593
1594 delete DFEoutput;
1595
1596 return burstBits;
1597}
Thomas Tsouc1f7c422013-10-11 13:49:55 -04001598
1599bool sigProcLibSetup(int sps)
1600{
1601 if ((sps != 1) && (sps != 4))
1602 return false;
1603
1604 initTrigTables();
1605 initGMSKRotationTables(sps);
1606
1607 GSMPulse1 = generateGSMPulse(1, 2);
1608 if (sps > 1)
1609 GSMPulse = generateGSMPulse(sps, 2);
1610
1611 if (!generateRACHSequence(1)) {
1612 sigProcLibDestroy();
1613 return false;
1614 }
1615
1616 return true;
1617}