diff options
author | Thomas Tsou <tom@tsou.cc> | 2013-10-11 13:49:55 -0400 |
---|---|---|
committer | Thomas Tsou <tom@tsou.cc> | 2013-10-18 13:10:17 -0400 |
commit | c1f7c42a33a1125f8b39f53a1b6e1bae38376857 (patch) | |
tree | fd79543a262281b4cbf04bfb09f305b95a715dd4 /Transceiver52M/sigProcLib.cpp | |
parent | 2c282f5e1268146761413a145fd8ae2fb523fa4f (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.cpp | 201 |
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; +} |