From 1189019c30c1208c95868cb6998f6b7af25d2c45 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Wed, 16 Apr 2014 19:36:30 -0400 Subject: Transceiver52M: Add SCH detection capability Use similar approach for detecting normal and RACH bursts, but apply a sample shift after detection in order to gradually zero the measured timing offset. SCH synchronization sequence and setup are added similar to RACH detection with the main difference, aside being the SCH runs full length of the burst. History is also added to accommodate full length burst correlation. Signed-off-by: Thomas Tsou --- GSM/GSMCommon.cpp | 2 + GSM/GSMCommon.h | 2 + Transceiver52M/Transceiver.cpp | 25 ++++++ Transceiver52M/Transceiver.h | 5 ++ Transceiver52M/radioInterface.cpp | 4 +- Transceiver52M/radioInterface.h | 3 +- Transceiver52M/radioInterfaceDiversity.cpp | 2 +- Transceiver52M/radioInterfaceResamp.cpp | 2 +- Transceiver52M/sigProcLib.cpp | 134 ++++++++++++++++++++++++++++- Transceiver52M/sigProcLib.h | 7 ++ 10 files changed, 179 insertions(+), 7 deletions(-) diff --git a/GSM/GSMCommon.cpp b/GSM/GSMCommon.cpp index 87f5ab2..e389e96 100644 --- a/GSM/GSMCommon.cpp +++ b/GSM/GSMCommon.cpp @@ -45,6 +45,8 @@ const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000 const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000"); +const BitVector GSM::gSCHSynchSequence("1011100101100010000001000000111100101101010001010111011000011011"); + int32_t GSM::FNDelta(int32_t v1, int32_t v2) { diff --git a/GSM/GSMCommon.h b/GSM/GSMCommon.h index 80c5608..db315be 100644 --- a/GSM/GSMCommon.h +++ b/GSM/GSMCommon.h @@ -53,6 +53,8 @@ extern const BitVector gDummyBurst; /** Random access burst synch. sequence */ extern const BitVector gRACHSynchSequence; +/** Synchronization burst sync sequence */ +extern const BitVector gSCHSynchSequence; /**@name Modulus operations for frame numbers. */ //@{ diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp index 415505c..af10a7a 100644 --- a/Transceiver52M/Transceiver.cpp +++ b/Transceiver52M/Transceiver.cpp @@ -376,6 +376,31 @@ bool Transceiver::detectRACH(TransceiverState *state, return detectRACHBurst(burst, threshold, mSPSRx, &, &toa); } +/* Detect SCH synchronization sequence within a burst */ +bool Transceiver::detectSCH(TransceiverState *state, + signalVector &burst, + complex &, float &toa) +{ + int shift; + float mag, threshold = 7.0; + + if (!detectSCHBurst(burst, threshold, mSPSRx, &, &toa)) + return false; + + std::cout << "SCH : Timing offset " << toa << " symbols" << std::endl; + + mag = fabsf(toa); + if (mag < 1.0f) + return true; + + shift = (int) (mag / 2.0f); + if (!shift) + shift++; + + mRadioInterface->applyOffset(toa > 0 ? shift : -shift); + return false; +} + /* * Detect normal burst training sequence midamble. Update equalization * state information and channel estimate if necessary. Equalization diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h index df029a6..8433406 100644 --- a/Transceiver52M/Transceiver.h +++ b/Transceiver52M/Transceiver.h @@ -116,6 +116,7 @@ private: OFF, ///< timeslot is off TSC, ///< timeslot should contain a normal burst RACH, ///< timeslot should contain an access burst + SCH, ///< timeslot should contain a SCH burst IDLE ///< timeslot is an idle (or dummy) burst } CorrType; @@ -147,6 +148,10 @@ private: signalVector &burst, complex &, float &toa); + bool detectSCH(TransceiverState *state, + signalVector &burst, + complex &, float &toa); + /** Detect normal bursts */ bool detectTSC(TransceiverState *state, signalVector &burst, diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp index 1329ef1..d55761a 100644 --- a/Transceiver52M/radioInterface.cpp +++ b/Transceiver52M/radioInterface.cpp @@ -38,7 +38,7 @@ RadioInterface::RadioInterface(RadioDevice *wRadio, int wReceiveOffset, GSM::Time wStartTime) : mRadio(wRadio), mSPSTx(sps), mSPSRx(1), mChans(chans), mMIMO(diversity), sendCursor(0), recvCursor(0), underrun(false), overrun(false), - receiveOffset(wReceiveOffset), mOn(false) + receiveOffset(wReceiveOffset), shiftOffset(0), mOn(false) { mClock.set(wStartTime); } @@ -330,7 +330,7 @@ void RadioInterface::pullBuffer() num_recv = mRadio->readSamples(convertRecvBuffer, CHUNK, &overrun, - readTimestamp, + readTimestamp + shiftOffset, &local_underrun); if (num_recv != CHUNK) { LOG(ALERT) << "Receive error " << num_recv; diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h index b88fe6b..36bc6ea 100644 --- a/Transceiver52M/radioInterface.h +++ b/Transceiver52M/radioInterface.h @@ -56,7 +56,7 @@ protected: RadioClock mClock; ///< the basestation clock! int receiveOffset; ///< offset b/w transmit and receive GSM timestamps, in timeslots - + int shiftOffset; bool mOn; ///< indicates radio is on private: @@ -94,6 +94,7 @@ public: /** check for underrun, resets underrun value */ bool isUnderrun(); + void applyOffset(int offset) { shiftOffset += offset; } /** return the receive FIFO */ VectorFIFO* receiveFIFO(size_t chan = 0); diff --git a/Transceiver52M/radioInterfaceDiversity.cpp b/Transceiver52M/radioInterfaceDiversity.cpp index 8e921b1..b76a15f 100644 --- a/Transceiver52M/radioInterfaceDiversity.cpp +++ b/Transceiver52M/radioInterfaceDiversity.cpp @@ -189,7 +189,7 @@ void RadioInterfaceDiversity::pullBuffer() num = mRadio->readSamples(convertRecvBuffer, resamp_outchunk, &overrun, - readTimestamp, + readTimestamp + shiftOffset, &local_underrun); if ((size_t) num != resamp_outchunk) { LOG(ALERT) << "Receive error " << num; diff --git a/Transceiver52M/radioInterfaceResamp.cpp b/Transceiver52M/radioInterfaceResamp.cpp index f898d65..c6e5ee1 100644 --- a/Transceiver52M/radioInterfaceResamp.cpp +++ b/Transceiver52M/radioInterfaceResamp.cpp @@ -188,7 +188,7 @@ void RadioInterfaceResamp::pullBuffer() num_recv = mRadio->readSamples(convertRecvBuffer, resamp_outchunk, &overrun, - readTimestamp, + readTimestamp + shiftOffset, &local_underrun); if (num_recv != (int) resamp_outchunk) { LOG(ALERT) << "Receive error " << num_recv; diff --git a/Transceiver52M/sigProcLib.cpp b/Transceiver52M/sigProcLib.cpp index 54dd8fc..0db3a81 100644 --- a/Transceiver52M/sigProcLib.cpp +++ b/Transceiver52M/sigProcLib.cpp @@ -78,6 +78,7 @@ struct CorrelationSequence { signalVector *sequence; void *buffer; + void *history; float toa; complex gain; }; @@ -111,6 +112,7 @@ struct PulseSequence { CorrelationSequence *gMidambles[] = {NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL}; CorrelationSequence *gRACHSequence = NULL; +CorrelationSequence *gSCHSequence = NULL; PulseSequence *GSMPulse = NULL; PulseSequence *GSMPulse1 = NULL; @@ -131,6 +133,7 @@ void sigProcLibDestroy() delete GMSKRotation1; delete GMSKReverseRotation1; delete gRACHSequence; + delete gSCHSequence; delete GSMPulse; delete GSMPulse1; @@ -139,6 +142,7 @@ void sigProcLibDestroy() GMSKReverseRotationN = NULL; GMSKReverseRotation1 = NULL; gRACHSequence = NULL; + gSCHSequence = NULL; GSMPulse = NULL; GSMPulse1 = NULL; } @@ -395,8 +399,10 @@ signalVector *convolve(const signalVector *x, break; case CUSTOM: if (start < h->size() - 1) { - head = h->size() - start; - append = true; + if (x->getStart() < h->size() - 1) { + head = h->size() - start; + append = true; + } } if (start + len > x->size()) { tail = start + len - x->size(); @@ -1274,6 +1280,69 @@ release: return status; } +bool generateSCHSequence(int sps) +{ + bool status = true; + float toa; + complex *data = NULL; + signalVector *autocorr = NULL; + signalVector *seq0 = NULL, *seq1 = NULL, *_seq1 = NULL; + + delete gSCHSequence; + + seq0 = modulateBurst(gSCHSynchSequence, 0, sps, false); + if (!seq0) + return false; + + seq1 = modulateBurst(gSCHSynchSequence, 0, sps, true); + if (!seq1) { + status = false; + goto release; + } + + conjugateVector(*seq1); + + /* For SSE alignment, reallocate the midamble sequence on 16-byte boundary */ + data = (complex *) convolve_h_alloc(seq1->size()); + _seq1 = new signalVector(data, 0, seq1->size()); + _seq1->setAligned(true); + memcpy(_seq1->begin(), seq1->begin(), seq1->size() * sizeof(complex)); + + autocorr = convolve(seq0, _seq1, autocorr, NO_DELAY); + if (!autocorr) { + status = false; + goto release; + } + + gSCHSequence = new CorrelationSequence; + gSCHSequence->sequence = _seq1; + gSCHSequence->buffer = data; + gSCHSequence->gain = peakDetect(*autocorr, &toa, NULL); + gSCHSequence->history = new complex[_seq1->size()]; + + /* For 1 sps only + * (Half of correlation length - 1) + midpoint of pulse shaping filer + * 20.5 = (64 / 2 - 1) + 1.5 + */ + if (sps == 1) + gSCHSequence->toa = toa - 32.5; + else + gSCHSequence->toa = 0.0; + +release: + delete autocorr; + delete seq0; + delete seq1; + + if (!status) { + delete _seq1; + free(data); + gSCHSequence = NULL; + } + + return status; +} + static float computePeakRatio(signalVector *corr, int sps, float toa, complex amp) { @@ -1424,6 +1493,62 @@ int detectRACHBurst(signalVector &rxBurst, return 1; } +int detectSCHBurst(signalVector &burst, + float thresh, + int sps, + complex *amp, + float *toa) +{ + int rc, start, target, head, tail, len; + float _toa; + complex _amp; + signalVector *corr, *_burst; + CorrelationSequence *sync; + + if ((sps != 1) && (sps != 4)) + return -1; + + /* Search full length */ + target = 3 + 39 + 64; + head = target - 1; + tail = 39 + 3 + 9; + + start = (target - head) * sps - 1; + len = (head + tail) * sps; + sync = gSCHSequence; + corr = new signalVector(len); + + _burst = new signalVector(burst, sync->sequence->size(), 5); + + memcpy(_burst->begin() - sync->sequence->size(), sync->history, + sync->sequence->size() * sizeof(complex)); + + memcpy(sync->history, &burst.begin()[burst.size() - sync->sequence->size()], + sync->sequence->size() * sizeof(complex)); + + rc = detectBurst(*_burst, *corr, sync, + thresh, sps, &_amp, &_toa, start, len); + delete corr; + + if (rc < 0) { + return -1; + } else if (!rc) { + if (amp) + *amp = 0.0f; + if (toa) + *toa = 0.0f; + return 0; + } + + /* Subtract forward search bits from delay */ + if (toa) + *toa = _toa - head * sps; + if (amp) + *amp = _amp; + + return 1; +} + /* * Normal burst detection * @@ -1717,6 +1842,11 @@ bool sigProcLibSetup(int sps) return false; } + if (!generateSCHSequence(1)) { + sigProcLibDestroy(); + return false; + } + generateDelayFilters(); return true; diff --git a/Transceiver52M/sigProcLib.h b/Transceiver52M/sigProcLib.h index 147c14c..90b6852 100644 --- a/Transceiver52M/sigProcLib.h +++ b/Transceiver52M/sigProcLib.h @@ -158,6 +158,7 @@ bool generateMidamble(int sps, int tsc); @return Success. */ bool generateRACHSequence(int sps); +bool generateSCHSequence(int sps); /** Energy detector, checks to see if received burst energy is above a threshold. @@ -187,6 +188,12 @@ int detectRACHBurst(signalVector &rxBurst, complex *amplitude, float* TOA); +int detectSCHBurst(signalVector &rxBurst, + float detectThreshold, + int sps, + complex *amplitude, + float* TOA); + /** Normal burst correlator, detector, channel estimator. @param rxBurst The received GSM burst of interest. -- cgit v1.2.3