aboutsummaryrefslogtreecommitdiffstats
path: root/Transceiver52M/sigProcLib.cpp
diff options
context:
space:
mode:
authorThomas Tsou <tom@tsou.cc>2013-10-11 13:49:55 -0400
committerThomas Tsou <tom@tsou.cc>2013-10-18 13:10:17 -0400
commitc1f7c42a33a1125f8b39f53a1b6e1bae38376857 (patch)
treefd79543a262281b4cbf04bfb09f305b95a715dd4 /Transceiver52M/sigProcLib.cpp
parent2c282f5e1268146761413a145fd8ae2fb523fa4f (diff)
Transceiver52M: Setup dual sample rate transceiver
This patch applies oversampling, when selected with 4 sps, to the downlink only, while running the receiver with minimal sampling at 1 sps. These split sample rates allow us to run a highly accurate downlink signal with minimal distortion, while keeping receive path channel filtering on the FPGA. Without this patch, we oversample the receive path and require a steep receive filter to get similar adjacent channel suppression as the FPGA halfband / CIC filter combination, which comes with a high computational cost. Signed-off-by: Thomas Tsou <tom@tsou.cc>
Diffstat (limited to 'Transceiver52M/sigProcLib.cpp')
-rw-r--r--Transceiver52M/sigProcLib.cpp201
1 files changed, 133 insertions, 68 deletions
diff --git a/Transceiver52M/sigProcLib.cpp b/Transceiver52M/sigProcLib.cpp
index ab771ac..aa35647 100644
--- a/Transceiver52M/sigProcLib.cpp
+++ b/Transceiver52M/sigProcLib.cpp
@@ -44,9 +44,11 @@ static const float M_PI_F = (float)M_PI;
static const float M_2PI_F = (float)(2.0*M_PI);
static const float M_1_2PI_F = 1/M_2PI_F;
-/** Static vectors that contain a precomputed +/- f_b/4 sinusoid */
-signalVector *GMSKRotation = NULL;
-signalVector *GMSKReverseRotation = NULL;
+/* Precomputed rotation vectors */
+static signalVector *GMSKRotationN = NULL;
+static signalVector *GMSKReverseRotationN = NULL;
+static signalVector *GMSKRotation1 = NULL;
+static signalVector *GMSKReverseRotation1 = NULL;
/*
* RACH and midamble correlation waveforms. Store the buffer separately
@@ -67,7 +69,7 @@ struct CorrelationSequence {
signalVector *sequence;
void *buffer;
- float TOA;
+ float toa;
complex gain;
};
@@ -101,6 +103,7 @@ struct PulseSequence {
CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
CorrelationSequence *gRACHSequence = NULL;
PulseSequence *GSMPulse = NULL;
+PulseSequence *GSMPulse1 = NULL;
void sigProcLibDestroy()
{
@@ -109,15 +112,21 @@ void sigProcLibDestroy()
gMidambles[i] = NULL;
}
- delete GMSKRotation;
- delete GMSKReverseRotation;
+ delete GMSKRotationN;
+ delete GMSKReverseRotationN;
+ delete GMSKRotation1;
+ delete GMSKReverseRotation1;
delete gRACHSequence;
delete GSMPulse;
+ delete GSMPulse1;
- GMSKRotation = NULL;
- GMSKReverseRotation = NULL;
+ GMSKRotationN = NULL;
+ GMSKRotation1 = NULL;
+ GMSKReverseRotationN = NULL;
+ GMSKReverseRotation1 = NULL;
gRACHSequence = NULL;
GSMPulse = NULL;
+ GSMPulse1 = NULL;
}
// dB relative to 1.0.
@@ -250,38 +259,38 @@ void initTrigTables() {
void initGMSKRotationTables(int sps)
{
- GMSKRotation = new signalVector(157 * sps);
- GMSKReverseRotation = new signalVector(157 * sps);
- signalVector::iterator rotPtr = GMSKRotation->begin();
- signalVector::iterator revPtr = GMSKReverseRotation->begin();
+ GMSKRotationN = new signalVector(157 * sps);
+ GMSKReverseRotationN = new signalVector(157 * sps);
+ signalVector::iterator rotPtr = GMSKRotationN->begin();
+ signalVector::iterator revPtr = GMSKReverseRotationN->begin();
float phase = 0.0;
- while (rotPtr != GMSKRotation->end()) {
+ while (rotPtr != GMSKRotationN->end()) {
*rotPtr++ = expjLookup(phase);
*revPtr++ = expjLookup(-phase);
phase += M_PI_F / 2.0F / (float) sps;
}
+
+ GMSKRotation1 = new signalVector(157);
+ GMSKReverseRotation1 = new signalVector(157);
+ rotPtr = GMSKRotation1->begin();
+ revPtr = GMSKReverseRotation1->begin();
+ phase = 0.0;
+ while (rotPtr != GMSKRotation1->end()) {
+ *rotPtr++ = expjLookup(phase);
+ *revPtr++ = expjLookup(-phase);
+ phase += M_PI_F / 2.0F;
+ }
}
-bool sigProcLibSetup(int sps)
+static void GMSKRotate(signalVector &x, int sps)
{
- if ((sps != 1) && (sps != 4))
- return false;
-
- initTrigTables();
- initGMSKRotationTables(sps);
- generateGSMPulse(sps, 2);
-
- if (!generateRACHSequence(sps)) {
- sigProcLibDestroy();
- return false;
- }
+ signalVector::iterator rotPtr, xPtr = x.begin();
- return true;
-}
+ if (sps == 1)
+ rotPtr = GMSKRotation1->begin();
+ else
+ rotPtr = GMSKRotationN->begin();
-void GMSKRotate(signalVector &x) {
- signalVector::iterator xPtr = x.begin();
- signalVector::iterator rotPtr = GMSKRotation->begin();
if (x.isRealOnly()) {
while (xPtr < x.end()) {
*xPtr = *rotPtr++ * (xPtr->real());
@@ -296,9 +305,15 @@ void GMSKRotate(signalVector &x) {
}
}
-void GMSKReverseRotate(signalVector &x) {
- signalVector::iterator xPtr= x.begin();
- signalVector::iterator rotPtr = GMSKReverseRotation->begin();
+static void GMSKReverseRotate(signalVector &x, int sps)
+{
+ signalVector::iterator rotPtr, xPtr= x.begin();
+
+ if (sps == 1)
+ rotPtr = GMSKReverseRotation1->begin();
+ else
+ rotPtr = GMSKReverseRotationN->begin();
+
if (x.isRealOnly()) {
while (xPtr < x.end()) {
*xPtr = *rotPtr++ * (xPtr->real());
@@ -414,10 +429,13 @@ signalVector *convolve(const signalVector *x,
return y;
}
-bool generateC1Pulse(int sps)
+static bool generateC1Pulse(int sps, PulseSequence *pulse)
{
int len;
+ if (!pulse)
+ return false;
+
switch (sps) {
case 4:
len = 8;
@@ -426,20 +444,20 @@ bool generateC1Pulse(int sps)
return false;
}
- GSMPulse->c1_buffer = convolve_h_alloc(len);
- GSMPulse->c1 = new signalVector((complex *)
- GSMPulse->c1_buffer, 0, len);
- GSMPulse->c1->isRealOnly(true);
+ pulse->c1_buffer = convolve_h_alloc(len);
+ pulse->c1 = new signalVector((complex *)
+ pulse->c1_buffer, 0, len);
+ pulse->c1->isRealOnly(true);
/* Enable alignment for SSE usage */
- GSMPulse->c1->setAligned(true);
+ pulse->c1->setAligned(true);
- signalVector::iterator xP = GSMPulse->c1->begin();
+ signalVector::iterator xP = pulse->c1->begin();
switch (sps) {
case 4:
/* BT = 0.30 */
- *xP++ = 0.0;
+ *xP++ = 0.0;
*xP++ = 8.16373112e-03;
*xP++ = 2.84385729e-02;
*xP++ = 5.64158904e-02;
@@ -452,18 +470,17 @@ bool generateC1Pulse(int sps)
return true;
}
-void generateGSMPulse(int sps, int symbolLength)
+static PulseSequence *generateGSMPulse(int sps, int symbolLength)
{
int len;
float arg, avg, center;
-
- delete GSMPulse;
+ PulseSequence *pulse;
/* Store a single tap filter used for correlation sequence generation */
- GSMPulse = new PulseSequence();
- GSMPulse->empty = new signalVector(1);
- GSMPulse->empty->isRealOnly(true);
- *(GSMPulse->empty->begin()) = 1.0f;
+ pulse = new PulseSequence();
+ pulse->empty = new signalVector(1);
+ pulse->empty->isRealOnly(true);
+ *(pulse->empty->begin()) = 1.0f;
/*
* For 4 samples-per-symbol use a precomputed single pulse Laurent
@@ -481,15 +498,14 @@ void generateGSMPulse(int sps, int symbolLength)
len = 4;
}
- GSMPulse->c0_buffer = convolve_h_alloc(len);
- GSMPulse->c0 = new signalVector((complex *)
- GSMPulse->c0_buffer, 0, len);
- GSMPulse->c0->isRealOnly(true);
+ pulse->c0_buffer = convolve_h_alloc(len);
+ pulse->c0 = new signalVector((complex *) pulse->c0_buffer, 0, len);
+ pulse->c0->isRealOnly(true);
/* Enable alingnment for SSE usage */
- GSMPulse->c0->setAligned(true);
+ pulse->c0->setAligned(true);
- signalVector::iterator xP = GSMPulse->c0->begin();
+ signalVector::iterator xP = pulse->c0->begin();
if (sps == 4) {
*xP++ = 0.0;
@@ -508,7 +524,7 @@ void generateGSMPulse(int sps, int symbolLength)
*xP++ = 1.03184855e-01;
*xP++ = 2.84385729e-02;
*xP++ = 4.46348606e-03;
- generateC1Pulse(sps);
+ generateC1Pulse(sps, pulse);
} else {
center = (float) (len - 1.0) / 2.0;
@@ -519,11 +535,13 @@ void generateGSMPulse(int sps, int symbolLength)
0.527 * arg * arg * arg * arg);
}
- avg = sqrtf(vectorNorm2(*GSMPulse->c0) / sps);
- xP = GSMPulse->c0->begin();
- for (int i = 0; i < len; i++)
+ avg = sqrtf(vectorNorm2(*pulse->c0) / sps);
+ xP = pulse->c0->begin();
+ for (int i = 0; i < len; i++)
*xP++ /= avg;
}
+
+ return pulse;
}
signalVector* frequencyShift(signalVector *y,
@@ -612,7 +630,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
signalVector *pulse, rotated, *shaped;
signalVector::iterator itr;
- pulse = GSMPulse->empty;
+ pulse = GSMPulse1->empty;
burst_len = sps * (wBurst.size() + guardPeriodLength);
rotated = signalVector(burst_len);
itr = rotated.begin();
@@ -622,7 +640,7 @@ static signalVector *rotateBurst(const BitVector &wBurst,
itr += sps;
}
- GMSKRotate(rotated);
+ GMSKRotate(rotated, sps);
rotated.isRealOnly(false);
/* Dummy filter operation */
@@ -675,7 +693,7 @@ static signalVector *modulateBurstLaurent(const BitVector &bits,
*c0_itr = 2.0 * (0x01 & 0x01) - 1.0;
/* Generate C0 phase coefficients */
- GMSKRotate(c0_burst);
+ GMSKRotate(c0_burst, sps);
c0_burst.isRealOnly(false);
c0_itr = c0_burst.begin();
@@ -724,7 +742,11 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
signalVector *pulse, burst, *shaped;
signalVector::iterator burst_itr;
- pulse = GSMPulse->c0;
+ if (sps == 1)
+ pulse = GSMPulse1->c0;
+ else
+ pulse = GSMPulse->c0;
+
burst_len = sps * (bits.size() + guard_len);
burst = signalVector(burst_len);
@@ -737,7 +759,7 @@ static signalVector *modulateBurstBasic(const BitVector &bits,
burst_itr += sps;
}
- GMSKRotate(burst);
+ GMSKRotate(burst, sps);
burst.isRealOnly(false);
/* Single Gaussian pulse approximation shaping */
@@ -1020,6 +1042,7 @@ void offsetVector(signalVector &x,
bool generateMidamble(int sps, int tsc)
{
bool status = true;
+ float toa;
complex *data = NULL;
signalVector *autocorr = NULL, *midamble = NULL;
signalVector *midMidamble = NULL, *_midMidamble = NULL;
@@ -1067,7 +1090,16 @@ bool generateMidamble(int sps, int tsc)
gMidambles[tsc] = new CorrelationSequence;
gMidambles[tsc]->buffer = data;
gMidambles[tsc]->sequence = _midMidamble;
- gMidambles[tsc]->gain = peakDetect(*autocorr,&gMidambles[tsc]->TOA, NULL);
+ gMidambles[tsc]->gain = peakDetect(*autocorr, &toa, NULL);
+
+ /* For 1 sps only
+ * (Half of correlation length - 1) + midpoint of pulse shape + remainder
+ * 13.5 = (16 / 2 - 1) + 1.5 + (26 - 10) / 2
+ */
+ if (sps == 1)
+ gMidambles[tsc]->toa = toa - 13.5;
+ else
+ gMidambles[tsc]->toa = 0;
release:
delete autocorr;
@@ -1086,6 +1118,7 @@ release:
bool generateRACHSequence(int sps)
{
bool status = true;
+ float toa;
complex *data = NULL;
signalVector *autocorr = NULL;
signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL;
@@ -1119,7 +1152,16 @@ bool generateRACHSequence(int sps)
gRACHSequence = new CorrelationSequence;
gRACHSequence->sequence = _seq1;
gRACHSequence->buffer = data;
- gRACHSequence->gain = peakDetect(*autocorr,&gRACHSequence->TOA, NULL);
+ gRACHSequence->gain = peakDetect(*autocorr, &toa, NULL);
+
+ /* For 1 sps only
+ * (Half of correlation length - 1) + midpoint of pulse shaping filer
+ * 20.5 = (40 / 2 - 1) + 1.5
+ */
+ if (sps == 1)
+ gRACHSequence->toa = toa - 20.5;
+ else
+ gRACHSequence->toa = 0.0;
release:
delete autocorr;
@@ -1224,6 +1266,9 @@ static int detectBurst(signalVector &burst,
if (sps == 4)
*amp = *amp * complex(0.0, 1.0);
+ /* Compensate for residuate time lag */
+ *toa = *toa - sync->toa;
+
return 1;
}
@@ -1367,7 +1412,7 @@ SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
// shift up by a quarter of a frequency
// ignore starting phase, since spec allows for discontinuous phase
- GMSKReverseRotate(*shapedBurst);
+ GMSKReverseRotate(*shapedBurst, sps);
// run through slicer
if (sps > 1) {
@@ -1510,8 +1555,8 @@ SoftVector *equalizeBurst(signalVector &rxBurst,
signalVector::iterator dPtr = postForward->begin();
signalVector::iterator dBackPtr;
- signalVector::iterator rotPtr = GMSKRotation->begin();
- signalVector::iterator revRotPtr = GMSKReverseRotation->begin();
+ signalVector::iterator rotPtr = GMSKRotationN->begin();
+ signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
signalVector *DFEoutput = new signalVector(postForward->size());
signalVector::iterator DFEItr = DFEoutput->begin();
@@ -1550,3 +1595,23 @@ SoftVector *equalizeBurst(signalVector &rxBurst,
return burstBits;
}
+
+bool sigProcLibSetup(int sps)
+{
+ if ((sps != 1) && (sps != 4))
+ return false;
+
+ initTrigTables();
+ initGMSKRotationTables(sps);
+
+ GSMPulse1 = generateGSMPulse(1, 2);
+ if (sps > 1)
+ GSMPulse = generateGSMPulse(sps, 2);
+
+ if (!generateRACHSequence(1)) {
+ sigProcLibDestroy();
+ return false;
+ }
+
+ return true;
+}