diff options
-rw-r--r-- | GSM/GSMCommon.cpp | 11 | ||||
-rw-r--r-- | GSM/GSMCommon.h | 1 | ||||
-rw-r--r-- | Transceiver52M/Resampler.cpp | 27 | ||||
-rw-r--r-- | Transceiver52M/Resampler.h | 6 | ||||
-rw-r--r-- | Transceiver52M/sigProcLib.cpp | 490 | ||||
-rw-r--r-- | 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<float> psk8_table[8] = { + Complex<float>(-0.70710678, 0.70710678), + Complex<float>( 0.0, -1.0), + Complex<float>( 0.0, 1.0), + Complex<float>( 0.70710678, -0.70710678), + Complex<float>(-1.0, 0.0), + Complex<float>(-0.70710678, -0.70710678), + Complex<float>( 0.70710678, 0.70710678), + Complex<float>( 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<float> rot = Complex<float>(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<float> rot = Complex<float>(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<float> rot = Complex<float>(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<float> rot = Complex<float>(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<float>(-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<float>(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); @@ -202,6 +209,33 @@ int analyzeTrafficBurst(signalVector &rxBurst, 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. @param factor Decimation factor. @@ -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 */ |