From d325343ecca5c6484eeda5ebf9e230c810ea4b82 Mon Sep 17 00:00:00 2001 From: Tom Tsou Date: Sun, 6 Mar 2016 03:08:01 -0800 Subject: EDGE: Add 8-PSK modulator and demodulator Setup correlator and detection process similar to the GMSK receiver chain. Require 4 SPS sampling on both Rx and Tx paths as 1 SPS sampling adds too much distoration for 8-PSK recovery. Core receiver operations still run at 1 SPS with the exception of fractional delay filtering, which runs at the higher rate. Perform linear equalization to handle the Gaussian pulse induced ISI. The fixed impulse response used for equalizer tap calculation consists of combined EDGE pulse shape filter and effects of the downsampling filter. Note that the non-adaptive equalizer corrects for modulation induced band limiting and does not account for or compensate for fading channel effects. Signed-off-by: Tom Tsou --- GSM/GSMCommon.cpp | 11 + GSM/GSMCommon.h | 1 + Transceiver52M/Resampler.cpp | 27 ++- Transceiver52M/Resampler.h | 6 + Transceiver52M/sigProcLib.cpp | 490 +++++++++++++++++++++++++++++++++++++++--- Transceiver52M/sigProcLib.h | 46 ++++ 6 files changed, 549 insertions(+), 32 deletions(-) diff --git a/GSM/GSMCommon.cpp b/GSM/GSMCommon.cpp index 87f5ab2..3b5331f 100644 --- a/GSM/GSMCommon.cpp +++ b/GSM/GSMCommon.cpp @@ -41,6 +41,17 @@ const BitVector GSM::gTrainingSequence[] = { BitVector("11101111000100101110111100"), }; +const BitVector GSM::gEdgeTrainingSequence[] = { + BitVector("111111001111111001111001001001111111111111001111111111001111111001111001001001"), + BitVector("111111001111001001111001001001111001001001001111111111001111001001111001001001"), + BitVector("111001111111111111001001001111001001001111001111111001111111111111001001001111"), + BitVector("111001111111111001001001001111001001111001111111111001111111111001001001001111"), + BitVector("111111111001001111001111001001001111111001111111111111111001001111001111001001"), + BitVector("111001111111001001001111001111001001111111111111111001111111001001001111001111"), + BitVector("001111001111111001001001001001111001001111111111001111001111111001001001001001"), + BitVector("001001001111001001001001111111111001111111001111001001001111001001001001111111"), +}; + const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000"); const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000"); diff --git a/GSM/GSMCommon.h b/GSM/GSMCommon.h index 80c5608..004536b 100644 --- a/GSM/GSMCommon.h +++ b/GSM/GSMCommon.h @@ -46,6 +46,7 @@ namespace GSM { /** GSM Training sequences from GSM 05.02 5.2.3. */ extern const BitVector gTrainingSequence[]; +extern const BitVector gEdgeTrainingSequence[]; /** C0T0 filler burst, GSM 05.02, 5.2.6 */ extern const BitVector gDummyBurst; diff --git a/Transceiver52M/Resampler.cpp b/Transceiver52M/Resampler.cpp index 624b666..e4b66a7 100644 --- a/Transceiver52M/Resampler.cpp +++ b/Transceiver52M/Resampler.cpp @@ -173,10 +173,15 @@ int Resampler::rotate(float *in, size_t in_len, float *out, size_t out_len) int hist_len = filt_len - 1; if (!check_vec_len(in_len, out_len, p, q)) - return -1; - - /* Insert history */ - memcpy(&in[-2 * hist_len], history, hist_len * 2 * sizeof(float)); + return -1; + + if (history_on) { + memcpy(&in[-2 * hist_len], + history, hist_len * 2 * sizeof(float)); + } else { + memset(&in[-2 * hist_len], 0, + hist_len * 2 * sizeof(float)); + } /* Generate output from precomputed input/output paths */ for (size_t i = 0; i < out_len; i++) { @@ -190,8 +195,10 @@ int Resampler::rotate(float *in, size_t in_len, float *out, size_t out_len) } /* Save history */ - memcpy(history, &in[2 * (in_len - hist_len)], - hist_len * 2 * sizeof(float)); + if (history_on) { + memcpy(history, &in[2 * (in_len - hist_len)], + hist_len * 2 * sizeof(float)); + } return out_len; } @@ -221,8 +228,14 @@ size_t Resampler::len() return filt_len; } +void Resampler::enableHistory(bool on) +{ + history_on = on; +} + Resampler::Resampler(size_t p, size_t q, size_t filt_len) - : in_index(NULL), out_path(NULL), partitions(NULL), history(NULL) + : in_index(NULL), out_path(NULL), partitions(NULL), + history(NULL), history_on(true) { this->p = p; this->q = q; diff --git a/Transceiver52M/Resampler.h b/Transceiver52M/Resampler.h index cf2defd..072ec92 100644 --- a/Transceiver52M/Resampler.h +++ b/Transceiver52M/Resampler.h @@ -59,6 +59,11 @@ public: */ size_t len(); + /* + * Enable/disable history + */ + void enableHistory(bool on); + private: size_t p; size_t q; @@ -68,6 +73,7 @@ private: float **partitions; float *history; + bool history_on; bool initFilters(float bw); void releaseFilters(); diff --git a/Transceiver52M/sigProcLib.cpp b/Transceiver52M/sigProcLib.cpp index 8786c4a..f846950 100644 --- a/Transceiver52M/sigProcLib.cpp +++ b/Transceiver52M/sigProcLib.cpp @@ -29,6 +29,7 @@ #include "sigProcLib.h" #include "GSMCommon.h" #include "Logger.h" +#include "Resampler.h" extern "C" { #include "convolve.h" @@ -63,6 +64,24 @@ static signalVector *GMSKReverseRotation1 = NULL; /* Precomputed fractional delay filters */ static signalVector *delayFilters[DELAYFILTS]; +static Complex psk8_table[8] = { + Complex(-0.70710678, 0.70710678), + Complex( 0.0, -1.0), + Complex( 0.0, 1.0), + Complex( 0.70710678, -0.70710678), + Complex(-1.0, 0.0), + Complex(-0.70710678, -0.70710678), + Complex( 0.70710678, 0.70710678), + Complex( 1.0, 0.0), +}; + +/* Downsampling filterbank - 4 SPS to 1 SPS */ +#define DOWNSAMPLE_IN_LEN 624 +#define DOWNSAMPLE_OUT_LEN 156 + +static Resampler *dnsampler = NULL; +static signalVector *dnsampler_in = NULL; + /* * RACH and midamble correlation waveforms. Store the buffer separately * because we need to allocate it explicitly outside of the signal vector @@ -92,8 +111,8 @@ struct CorrelationSequence { * for SSE instructions. */ struct PulseSequence { - PulseSequence() : c0(NULL), c1(NULL), empty(NULL), - c0_buffer(NULL), c1_buffer(NULL) + PulseSequence() : c0(NULL), c1(NULL), c0_inv(NULL), empty(NULL), + c0_buffer(NULL), c1_buffer(NULL), c0_inv_buffer(NULL) { } @@ -101,6 +120,7 @@ struct PulseSequence { { delete c0; delete c1; + delete c0_inv; delete empty; free(c0_buffer); free(c1_buffer); @@ -108,21 +128,26 @@ struct PulseSequence { signalVector *c0; signalVector *c1; + signalVector *c0_inv; signalVector *empty; void *c0_buffer; void *c1_buffer; + void *c0_inv_buffer; }; -CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; -CorrelationSequence *gRACHSequence = NULL; -PulseSequence *GSMPulse1 = NULL; -PulseSequence *GSMPulse4 = NULL; +static CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +static CorrelationSequence *gEdgeMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; +static CorrelationSequence *gRACHSequence = NULL; +static PulseSequence *GSMPulse1 = NULL; +static PulseSequence *GSMPulse4 = NULL; void sigProcLibDestroy() { for (int i = 0; i < 8; i++) { delete gMidambles[i]; + delete gEdgeMidambles[i]; gMidambles[i] = NULL; + gEdgeMidambles[i] = NULL; } for (int i = 0; i < DELAYFILTS; i++) { @@ -137,6 +162,8 @@ void sigProcLibDestroy() delete gRACHSequence; delete GSMPulse1; delete GSMPulse4; + delete dnsampler; + delete dnsampler_in; GMSKRotation1 = NULL; GMSKRotation4 = NULL; @@ -480,6 +507,31 @@ signalVector *convolve(const signalVector *x, return y; } +/* + * Generate static EDGE linear equalizer. This equalizer is not adaptive. + * Filter taps are generated from the inverted 1 SPS impulse response of + * the EDGE pulse shape captured after the downsampling filter. + */ +static bool generateInvertC0Pulse(PulseSequence *pulse) +{ + if (!pulse) + return false; + + pulse->c0_inv_buffer = convolve_h_alloc(5); + pulse->c0_inv = new signalVector((complex *) pulse->c0_inv_buffer, 0, 5); + pulse->c0_inv->isReal(true); + pulse->c0_inv->setAligned(false); + + signalVector::iterator xP = pulse->c0_inv->begin(); + *xP++ = 0.15884; + *xP++ = -0.43176; + *xP++ = 1.00000; + *xP++ = -0.42608; + *xP++ = 0.14882; + + return true; +} + static bool generateC1Pulse(int sps, PulseSequence *pulse) { int len; @@ -527,6 +579,9 @@ static PulseSequence *generateGSMPulse(int sps) float arg, avg, center; PulseSequence *pulse; + if ((sps != 1) && (sps != 4)) + return NULL; + /* Store a single tap filter used for correlation sequence generation */ pulse = new PulseSequence(); pulse->empty = new signalVector(1); @@ -543,6 +598,7 @@ static PulseSequence *generateGSMPulse(int sps) case 4: len = 16; break; + case 1: default: len = 4; } @@ -590,6 +646,13 @@ static PulseSequence *generateGSMPulse(int sps) *xP++ /= avg; } + /* + * Current form of the EDGE equalization filter non-realizable at 4 SPS. + * Load the onto both 1 SPS and 4 SPS objects for convenience. Note that + * the EDGE demodulator downsamples to 1 SPS prior to equalization. + */ + generateInvertC0Pulse(pulse); + return pulse; } @@ -661,8 +724,22 @@ signalVector* reverseConjugate(signalVector *b) return tmp; } -/* soft output slicer */ -bool vectorSlicer(signalVector *x) +bool vectorSlicer(SoftVector *x) +{ + SoftVector::iterator xP = x->begin(); + SoftVector::iterator xPEnd = x->end(); + while (xP < xPEnd) { + *xP = 0.5 * (*xP + 1.0f); + if (*xP > 1.0) + *xP = 1.0; + if (*xP < 0.0) + *xP = 0.0; + xP++; + } + return true; +} + +bool vectorSlicer(signalVector *x) { signalVector::iterator xP = x->begin(); @@ -704,6 +781,14 @@ static signalVector *rotateBurst(const BitVector &wBurst, return shaped; } +static void rotateBurst2(signalVector &burst, double phase) +{ + Complex rot = Complex(cos(phase), sin(phase)); + + for (size_t i = 0; i < burst.size(); i++) + burst[i] = burst[i] * rot; +} + static signalVector *modulateBurstLaurent(const BitVector &bits, int guard_len, int sps) { @@ -791,6 +876,171 @@ static signalVector *modulateBurstLaurent(const BitVector &bits, return c0_shaped; } +static signalVector *rotateEdgeBurst(const signalVector &symbols, int sps) +{ + signalVector *burst; + signalVector::iterator burst_itr; + + burst = new signalVector(symbols.size() * sps); + burst_itr = burst->begin(); + + for (size_t i = 0; i < symbols.size(); i++) { + float phase = i * 3.0f * M_PI / 8.0f; + Complex rot = Complex(cos(phase), sin(phase)); + + *burst_itr = symbols[i] * rot; + burst_itr += sps; + } + + return burst; +} + +static signalVector *derotateEdgeBurst(const signalVector &symbols, int sps) +{ + signalVector *burst; + signalVector::iterator burst_itr; + + if (symbols.size() % sps) + return NULL; + + burst = new signalVector(symbols.size() / sps); + burst_itr = burst->begin(); + + for (size_t i = 0; i < burst->size(); i++) { + float phase = (float) (i % 16) * 3.0f * M_PI / 8.0f; + Complex rot = Complex(cosf(phase), -sinf(phase)); + + *burst_itr = symbols[sps * i] * rot; + burst_itr++; + } + + return burst; +} + +static signalVector *mapEdgeSymbols(const BitVector &bits) +{ + if (bits.size() % 3) + return NULL; + + signalVector *symbols = new signalVector(bits.size() / 3); + + for (size_t i = 0; i < symbols->size(); i++) { + unsigned index = (((unsigned) bits[3 * i + 0] & 0x01) << 0) | + (((unsigned) bits[3 * i + 1] & 0x01) << 1) | + (((unsigned) bits[3 * i + 2] & 0x01) << 2); + + (*symbols)[i] = psk8_table[index]; + } + + return symbols; +} + +static signalVector *shapeEdgeBurst(const signalVector &symbols) +{ + size_t nsyms, nsamps = 625; + signalVector *burst, *shape; + signalVector::iterator burst_itr; + + nsyms = symbols.size(); + + if (nsyms * 4 > nsamps) + nsyms = 156; + + burst = new signalVector(nsamps, GSMPulse4->c0->size()); + burst_itr = burst->begin(); + + for (size_t i = 0; i < nsyms; i++) { + float phase = i * 3.0f * M_PI / 8.0f; + Complex rot = Complex(cos(phase), sin(phase)); + + *burst_itr = symbols[i] * rot; + burst_itr += 4; + } + + /* Single Gaussian pulse approximation shaping */ + shape = convolve(burst, GSMPulse4->c0, NULL, START_ONLY); + delete burst; + + return shape; +} + +/* + * Generate a random 8-PSK EDGE burst. Only 4 SPS is supported with + * the returned burst being 625 samples in length. + */ +signalVector *generateEdgeBurst(int tsc) +{ + int tail = 9 / 3; + int data = 174 / 3; + int train = 78 / 3; + + if ((tsc < 0) || (tsc > 7)) + return NULL; + + signalVector *shape, *burst = new signalVector(148); + const BitVector *midamble = &gEdgeTrainingSequence[tsc]; + + /* Tail */ + int n, i = 0; + for (; i < tail; i++) + (*burst)[i] = psk8_table[7]; + + /* Body */ + for (; i < tail + data; i++) + (*burst)[i] = psk8_table[rand() % 8]; + + /* TSC */ + for (n = 0; i < tail + data + train; i++, n++) { + unsigned index = (((unsigned) (*midamble)[3 * n + 0] & 0x01) << 0) | + (((unsigned) (*midamble)[3 * n + 1] & 0x01) << 1) | + (((unsigned) (*midamble)[3 * n + 2] & 0x01) << 2); + + (*burst)[i] = psk8_table[index]; + } + + /* Body */ + for (; i < tail + data + train + data; i++) + (*burst)[i] = psk8_table[rand() % 8]; + + /* Tail */ + for (; i < tail + data + train + data + tail; i++) + (*burst)[i] = psk8_table[7]; + + shape = shapeEdgeBurst(*burst); + delete burst; + + return shape; +} + +/* + * Modulate 8-PSK burst. When empty pulse shaping (rotation only) + * is enabled, the output vector length will be bit sequence length + * times the SPS value. When pulse shaping is enabled, the output + * vector length is fixed at 625 samples (156.25 sybols at 4 SPS). + * Pulse shaped bit sequences that go beyond one burst are truncated. + * Pulse shaping at anything but 4 SPS is not supported. + */ +signalVector *modulateEdgeBurst(const BitVector &bits, + int sps, bool empty) +{ + signalVector *shape, *burst; + + if ((sps != 4) && !empty) + return NULL; + + burst = mapEdgeSymbols(bits); + if (!burst) + return NULL; + + if (empty) + shape = rotateEdgeBurst(*burst, sps); + else + shape = shapeEdgeBurst(*burst); + + delete burst; + return shape; +} + static signalVector *modulateBurstBasic(const BitVector &bits, int guard_len, int sps) { @@ -1223,6 +1473,41 @@ release: return status; } +CorrelationSequence *generateEdgeMidamble(int tsc) +{ + complex *data = NULL; + signalVector *midamble = NULL, *_midamble = NULL; + CorrelationSequence *seq; + + if ((tsc < 0) || (tsc > 7)) + return NULL; + + /* Use middle 48 bits of each TSC. Correlation sequence is not pulse shaped */ + const BitVector *bits = &gEdgeTrainingSequence[tsc]; + midamble = modulateEdgeBurst(bits->segment(15, 48), 1, true); + if (!midamble) + return NULL; + + conjugateVector(*midamble); + + data = (complex *) convolve_h_alloc(midamble->size()); + _midamble = new signalVector(data, 0, midamble->size()); + _midamble->setAligned(true); + memcpy(_midamble->begin(), midamble->begin(), + midamble->size() * sizeof(complex)); + + /* Channel gain is an empirically measured value */ + seq = new CorrelationSequence; + seq->buffer = data; + seq->sequence = _midamble; + seq->gain = Complex(-19.6432, 19.5006) / 1.18; + seq->toa = 0; + + delete midamble; + + return seq; +} + static bool generateRACHSequence(int sps) { bool status = true; @@ -1348,12 +1633,28 @@ static int detectBurst(signalVector &burst, float thresh, int sps, complex *amp, float *toa, int start, int len) { + signalVector *corr_in, *dec = NULL; + + if (sps == 4) { + dec = downsampleBurst(burst); + corr_in = dec; + sps = 1; + } else { + corr_in = &burst; + } + /* Correlate */ - if (!convolve(&burst, sync->sequence, &corr, - CUSTOM, start, len, sps, 0)) { + if (!convolve(corr_in, sync->sequence, &corr, + CUSTOM, start, len, 1, 0)) { + delete dec; return -1; } + delete dec; + + /* Running at the downsampled rate at this point */ + sps = 1; + /* Peak detection - place restrictions at correlation edges */ *amp = fastPeakDetect(corr, toa); @@ -1425,8 +1726,8 @@ int detectGeneralBurst(signalVector &rxBurst, clipping = true; } - start = (target - head) * sps - 1; - len = (head + tail) * sps; + start = target - head - 1; + len = head + tail; corr = new signalVector(len); rc = detectBurst(rxBurst, *corr, sync, @@ -1442,7 +1743,7 @@ int detectGeneralBurst(signalVector &rxBurst, } /* Subtract forward search bits from delay */ - toa -= head * sps; + toa -= head; return 1; } @@ -1503,6 +1804,37 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh, return rc; } +int detectEdgeBurst(signalVector &rxBurst, unsigned tsc, float thresh, + int sps, complex &, float &toa, unsigned max_toa) +{ + int rc, target, head, tail; + CorrelationSequence *sync; + + if ((tsc < 0) || (tsc > 7)) + return -SIGERR_UNSUPPORTED; + + target = 3 + 58 + 16 + 5; + head = 5; + tail = 5 + max_toa; + sync = gEdgeMidambles[tsc]; + + rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa, + target, head, tail, sync); + return rc; +} + +signalVector *downsampleBurst(signalVector &burst) +{ + size_t ilen = DOWNSAMPLE_IN_LEN, olen = DOWNSAMPLE_OUT_LEN; + + signalVector *out = new signalVector(olen); + memcpy(dnsampler_in->begin(), burst.begin(), ilen * 2 * sizeof(float)); + + dnsampler->rotate((float *) dnsampler_in->begin(), ilen, + (float *) out->begin(), olen); + return out; +}; + signalVector *decimateVector(signalVector &wVector, size_t factor) { signalVector *dec; @@ -1520,27 +1852,78 @@ signalVector *decimateVector(signalVector &wVector, size_t factor) return dec; } +/* + * Soft 8-PSK decoding using Manhattan distance metric + */ +static SoftVector *softSliceEdgeBurst(signalVector &burst) +{ + size_t nsyms = 148; + + if (burst.size() < nsyms) + return NULL; + + signalVector::iterator itr; + SoftVector *bits = new SoftVector(nsyms * 3); + + /* + * Bits 0 and 1 - First and second bits of the symbol respectively + */ + rotateBurst2(burst, -M_PI / 8.0); + itr = burst.begin(); + for (size_t i = 0; i < nsyms; i++) { + (*bits)[3 * i + 0] = -itr->imag(); + (*bits)[3 * i + 1] = itr->real(); + itr++; + } + + /* + * Bit 2 - Collapse symbols into quadrant 0 (positive X and Y). + * Decision area is then simplified to X=Y axis. Rotate again to + * place decision boundary on X-axis. + */ + itr = burst.begin(); + for (size_t i = 0; i < burst.size(); i++) { + burst[i] = Complex(fabs(itr->real()), fabs(itr->imag())); + itr++; + } + + rotateBurst2(burst, -M_PI / 4.0); + itr = burst.begin(); + for (size_t i = 0; i < nsyms; i++) { + (*bits)[3 * i + 2] = -itr->imag(); + itr++; + } + + signalVector soft(bits->size()); + for (size_t i = 0; i < bits->size(); i++) + soft[i] = (*bits)[i]; + + return bits; +} + +/* + * Demodulate GSMK burst. Prior to symbol rotation, operate at + * 4 SPS (if activated) to minimize distortion through the fractional + * delay filters. Symbol rotation and after always operates at 1 SPS. + */ SoftVector *demodulateBurst(signalVector &rxBurst, int sps, complex channel, float TOA) { - signalVector *delay, *dec = NULL; SoftVector *bits; + signalVector *delay, *dec; scaleVector(rxBurst, ((complex) 1.0) / channel); - delay = delayVector(&rxBurst, NULL, -TOA); - - /* Shift up by a quarter of a frequency */ - GMSKReverseRotate(*delay, sps); + delay = delayVector(&rxBurst, NULL, -TOA * (float) sps); - /* Decimate and slice */ - if (sps > 1) { - dec = decimateVector(*delay, sps); - delete delay; - delay = NULL; + if (sps == 4) { + dec = downsampleBurst(*delay); + delete delay; } else { - dec = delay; + dec = delay; } + /* Shift up by a quarter of a frequency */ + GMSKReverseRotate(*dec, 1); vectorSlicer(dec); bits = new SoftVector(dec->size()); @@ -1556,6 +1939,48 @@ SoftVector *demodulateBurst(signalVector &rxBurst, int sps, return bits; } +/* + * Demodulate an 8-PSK burst. Prior to symbol rotation, operate at + * 4 SPS (if activated) to minimize distortion through the fractional + * delay filters. Symbol rotation and after always operates at 1 SPS. + * + * Allow 1 SPS demodulation here, but note that other parts of the + * transceiver restrict EDGE operatoin to 4 SPS - 8-PSK distortion + * through the fractional delay filters at 1 SPS renders signal + * nearly unrecoverable. + */ +SoftVector *demodEdgeBurst(signalVector &burst, int sps, + complex chan, float toa) +{ + SoftVector *bits; + signalVector *delay, *dec, *rot, *eq; + + if ((sps != 1) && (sps != 4)) + return NULL; + + scaleVector(burst, ((complex) 1.0) / chan); + delay = delayVector(&burst, NULL, -toa * (float) sps); + + if (sps == 4) { + dec = downsampleBurst(*delay); + delete delay; + } else { + dec = delay; + } + + eq = convolve(dec, GSMPulse4->c0_inv, NULL, NO_DELAY); + rot = derotateEdgeBurst(*eq, 1); + + bits = softSliceEdgeBurst(*dec); + vectorSlicer(bits); + + delete dec; + delete eq; + delete rot; + + return bits; +} + bool sigProcLibSetup() { initTrigTables(); @@ -1566,10 +1991,25 @@ bool sigProcLibSetup() GSMPulse4 = generateGSMPulse(4); generateRACHSequence(1); - for (int tsc = 0; tsc < 8; tsc++) + for (int tsc = 0; tsc < 8; tsc++) { generateMidamble(1, tsc); + gEdgeMidambles[tsc] = generateEdgeMidamble(tsc); + } generateDelayFilters(); + dnsampler = new Resampler(1, 4); + if (!dnsampler->init()) { + LOG(ALERT) << "Rx resampler failed to initialize"; + goto fail; + } + + dnsampler->enableHistory(false); + dnsampler_in = new signalVector(DOWNSAMPLE_IN_LEN, dnsampler->len()); + return true; + +fail: + sigProcLibDestroy(); + return false; } diff --git a/Transceiver52M/sigProcLib.h b/Transceiver52M/sigProcLib.h index 8ff8246..2dcc97d 100644 --- a/Transceiver52M/sigProcLib.h +++ b/Transceiver52M/sigProcLib.h @@ -104,6 +104,13 @@ signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength, int sps, bool emptyPulse = false); +/** 8-PSK modulate a burst of bits */ +signalVector *modulateEdgeBurst(const BitVector &bits, + int sps, bool emptyPulse = false); + +/** Generate a EDGE burst with random payload - 4 SPS (625 samples) only */ +signalVector *generateEdgeBurst(int tsc); + /** Sinc function */ float sinc(float x); @@ -201,6 +208,33 @@ int analyzeTrafficBurst(signalVector &rxBurst, float &TOA, unsigned maxTOA); +/** + EDGE burst detector + @param burst The received GSM burst of interest + + @param detectThreshold The threshold that the received burst's post-correlator SNR is compared against to determine validity. + @param sps The number of samples per GSM symbol. + @param amplitude The estimated amplitude of received TSC burst. + @param TOA The estimate time-of-arrival of received TSC burst. + @param maxTOA The maximum expected time-of-arrival + @return positive if threshold value is reached, negative on error, zero otherwise +*/ +int detectEdgeBurst(signalVector &burst, + unsigned TSC, + float detectThreshold, + int sps, + complex &litude, + float &TOA, + unsigned maxTOA); + +/** + Downsample 4 SPS to 1 SPS using a polyphase filterbank + @param burst Input burst of at least 624 symbols + @return Decimated signal vector of 156 symbols +*/ + +signalVector *downsampleBurst(signalVector &burst); + /** Decimate a vector. @param wVector The vector of interest. @@ -220,4 +254,16 @@ signalVector *decimateVector(signalVector &wVector, size_t factor); */ SoftVector *demodulateBurst(signalVector &rxBurst, int sps, complex channel, float TOA); + +/** + Demodulate 8-PSK EDGE burst with soft symbol ooutput + @param rxBurst The burst to be demodulated. + @param sps The number of samples per GSM symbol. + @param channel The amplitude estimate of the received burst. + @param TOA The time-of-arrival of the received burst. + @return The demodulated bit sequence. +*/ +SoftVector *demodEdgeBurst(signalVector &rxBurst, int sps, + complex channel, float TOA); + #endif /* SIGPROCLIB_H */ -- cgit v1.2.3