From c1f7c42a33a1125f8b39f53a1b6e1bae38376857 Mon Sep 17 00:00:00 2001 From: Thomas Tsou Date: Fri, 11 Oct 2013 13:49:55 -0400 Subject: 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 --- Transceiver52M/Transceiver.cpp | 35 +++--- Transceiver52M/Transceiver.h | 3 +- Transceiver52M/UHDDevice.cpp | 54 ++++----- Transceiver52M/USRPDevice.cpp | 29 ++++- Transceiver52M/USRPDevice.h | 4 +- Transceiver52M/radioInterface.cpp | 34 +++--- Transceiver52M/radioInterface.h | 7 +- Transceiver52M/radioInterfaceResamp.cpp | 14 +-- Transceiver52M/sigProcLib.cpp | 201 +++++++++++++++++++++----------- Transceiver52M/sigProcLib.h | 8 -- 10 files changed, 228 insertions(+), 161 deletions(-) diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp index 03aa3c1..2557fec 100644 --- a/Transceiver52M/Transceiver.cpp +++ b/Transceiver52M/Transceiver.cpp @@ -55,7 +55,8 @@ Transceiver::Transceiver(int wBasePort, RadioInterface *wRadioInterface) :mDataSocket(wBasePort+2,TRXAddress,wBasePort+102), mControlSocket(wBasePort+1,TRXAddress,wBasePort+101), - mClockSocket(wBasePort,TRXAddress,wBasePort+100) + mClockSocket(wBasePort,TRXAddress,wBasePort+100), + mSPSTx(wSPS), mSPSRx(1) { GSM::Time startTime(random() % gHyperframe,0); @@ -64,7 +65,6 @@ Transceiver::Transceiver(int wBasePort, mControlServiceLoopThread = new Thread(32768); ///< thread to process control messages from GSM core mTransmitPriorityQueueServiceLoopThread = new Thread(32768);///< thread to process transmit bursts from GSM core - mSPS = wSPS; mRadioInterface = wRadioInterface; mTransmitLatency = wTransmitLatency; mTransmitDeadlineClock = startTime; @@ -93,7 +93,7 @@ Transceiver::~Transceiver() bool Transceiver::init() { - if (!sigProcLibSetup(mSPS)) { + if (!sigProcLibSetup(mSPSTx)) { LOG(ALERT) << "Failed to initialize signal processing library"; return false; } @@ -102,7 +102,7 @@ bool Transceiver::init() for (int i = 0; i < 8; i++) { signalVector* modBurst = modulateBurst(gDummyBurst, 8 + (i % 4 == 0), - mSPS); + mSPSTx); if (!modBurst) { sigProcLibDestroy(); LOG(ALERT) << "Failed to initialize filler table"; @@ -133,7 +133,7 @@ void Transceiver::addRadioVector(BitVector &burst, // modulate and stick into queue signalVector* modBurst = modulateBurst(burst, 8 + (wTime.TN() % 4 == 0), - mSPS); + mSPSTx); scaleVector(*modBurst,txFullScale * pow(10,-RSSI/10)); radioVector *newVec = new radioVector(*modBurst,wTime); mTransmitPriorityQueue.write(newVec); @@ -144,7 +144,7 @@ void Transceiver::addRadioVector(BitVector &burst, #ifdef TRANSMIT_LOGGING void Transceiver::unModulateVector(signalVector wVector) { - SoftVector *burst = demodulateBurst(wVector, mSPS, 1.0, 0.0); + SoftVector *burst = demodulateBurst(wVector, mSPSTx, 1.0, 0.0); LOG(DEBUG) << "LOGGED BURST: " << *burst; /* @@ -329,7 +329,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, float TOA = 0.0; float avgPwr = 0.0; #ifdef ENERGY_DETECT - if (!energyDetect(*vectorBurst, 20 * mSPS, mEnergyThreshold, &avgPwr)) { + if (!energyDetect(*vectorBurst, 20 * mSPSRx, mEnergyThreshold, &avgPwr)) { LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime(); double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime; if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold @@ -365,7 +365,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, success = analyzeTrafficBurst(*vectorBurst, mTSC, 5.0, - mSPS, + mSPSRx, &litude, &TOA, mMaxExpectedDelay, @@ -398,11 +398,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, } else { // RACH burst - success = detectRACHBurst(*vectorBurst, - 6.0, - mSPS, - &litude, - &TOA); + success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &litude, &TOA); if (success) { LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA; mEnergyThreshold -= (1.0F/10.0F); @@ -421,22 +417,19 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, SoftVector *burst = NULL; if ((rxBurst) && (success)) { if ((corrType==RACH) || (!needDFE)) { - burst = demodulateBurst(*vectorBurst, - mSPS, - amplitude,TOA); - } - else { // TSC + burst = demodulateBurst(*vectorBurst, mSPSRx, amplitude, TOA); + } else { scaleVector(*vectorBurst,complex(1.0,0.0)/amplitude); burst = equalizeBurst(*vectorBurst, TOA-chanRespOffset[timeslot], - mSPS, + mSPSRx, *DFEForward[timeslot], *DFEFeedback[timeslot]); } wTime = rxBurst->getTime(); RSSI = (int) floor(20.0*log10(rxFullScale/amplitude.abs())); LOG(DEBUG) << "RSSI: " << RSSI; - timingOffset = (int) round(TOA * 256.0 / mSPS); + timingOffset = (int) round(TOA * 256.0 / mSPSRx); } //if (burst) LOG(DEBUG) << "burst: " << *burst << '\n'; @@ -595,7 +588,7 @@ void Transceiver::driveControl() sprintf(response,"RSP SETTSC 1 %d",TSC); else { mTSC = TSC; - generateMidamble(mSPS, TSC); + generateMidamble(mSPSRx, TSC); sprintf(response,"RSP SETTSC 0 %d", TSC); } } diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h index 3e4f784..d243214 100644 --- a/Transceiver52M/Transceiver.h +++ b/Transceiver52M/Transceiver.h @@ -125,7 +125,8 @@ private: /** send messages over the clock socket */ void writeClockInterface(void); - int mSPS; ///< number of samples per GSM symbol + int mSPSTx; ///< number of samples per Tx symbol + int mSPSRx; ///< number of samples per Rx symbol bool mOn; ///< flag to indicate that transceiver is powered on ChannelCombination mChanType[8]; ///< channel types for all timeslots diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp index 2bd767c..ad821de 100644 --- a/Transceiver52M/UHDDevice.cpp +++ b/Transceiver52M/UHDDevice.cpp @@ -66,14 +66,14 @@ struct uhd_dev_offset { static struct uhd_dev_offset uhd_offsets[NUM_USRP_TYPES * 2] = { { USRP1, 1, 0.0 }, { USRP1, 4, 0.0 }, - { USRP2, 1, 5.4394e-5 }, - { USRP2, 4, 0.0 }, - { B100, 1, 9.4778e-5 }, - { B100, 4, 2.9418e-5 }, - { B200, 1, 0.0 }, - { B200, 4, 9.8358e-5 }, - { UMTRX, 1, 9.4778e-5 }, - { UMTRX, 4, 0.0 }, + { USRP2, 1, 1.1815e-4 }, + { USRP2, 4, 7.7538e-5 }, + { B100, 1, 9.9692e-5 }, + { B100, 4, 6.5545e-5 }, + { B200, 1, 9.6000e-5 }, + { B200, 4, 6.4615e-5 }, + { UMTRX, 1, 9.9692e-5 }, + { UMTRX, 4, 7.3846e-5 }, }; static double get_dev_offset(enum uhd_dev_type type, int sps) @@ -248,7 +248,7 @@ public: double getTxFreq() { return tx_freq; } double getRxFreq() { return rx_freq; } - inline double getSampleRate() { return actual_smpl_rt; } + inline double getSampleRate() { return tx_rate; } inline double numberRead() { return rx_pkt_cnt; } inline double numberWritten() { return 0; } @@ -271,7 +271,7 @@ private: enum uhd_dev_type dev_type; int sps; - double desired_smpl_rt, actual_smpl_rt; + double tx_rate, rx_rate; double tx_gain, tx_gain_min, tx_gain_max; double rx_gain, rx_gain_min, rx_gain_max; @@ -293,7 +293,7 @@ private: void init_gains(); void set_ref_clk(bool ext_clk); int set_master_clk(double rate); - int set_rates(double rate); + int set_rates(double tx_rate, double rx_rate); bool parse_dev_type(); bool flush_recv(size_t num_pkts); int check_rx_md_err(uhd::rx_metadata_t &md, ssize_t num_smpls); @@ -407,7 +407,7 @@ int uhd_device::set_master_clk(double clk_rate) return 0; } -int uhd_device::set_rates(double rate) +int uhd_device::set_rates(double tx_rate, double rx_rate) { double offset_limit = 1.0; double tx_offset, rx_offset; @@ -420,21 +420,22 @@ int uhd_device::set_rates(double rate) // Set sample rates try { - usrp_dev->set_tx_rate(rate); - usrp_dev->set_rx_rate(rate); + usrp_dev->set_tx_rate(tx_rate); + usrp_dev->set_rx_rate(rx_rate); } catch (const std::exception &ex) { - LOG(ALERT) << "UHD rate setting failed: " << rate; + LOG(ALERT) << "UHD rate setting failed"; LOG(ALERT) << ex.what(); return -1; } - actual_smpl_rt = usrp_dev->get_tx_rate(); + this->tx_rate = usrp_dev->get_tx_rate(); + this->rx_rate = usrp_dev->get_rx_rate(); - tx_offset = fabs(usrp_dev->get_tx_rate() - rate); - rx_offset = fabs(usrp_dev->get_rx_rate() - rate); + tx_offset = fabs(this->tx_rate - tx_rate); + rx_offset = fabs(this->rx_rate - rx_rate); if ((tx_offset > offset_limit) || (rx_offset > offset_limit)) { LOG(ALERT) << "Actual sample rate differs from desired rate"; - LOG(ALERT) << "Tx/Rx (" << usrp_dev->get_rx_rate() << "/" - << usrp_dev->get_rx_rate() << ")"; + LOG(ALERT) << "Tx/Rx (" << this->tx_rate << "/" + << this->rx_rate << ")"; return -1; } @@ -552,13 +553,14 @@ int uhd_device::open(const std::string &args) rx_spp = rx_stream->get_max_num_samps(); // Set rates - desired_smpl_rt = select_rate(dev_type, sps); - if ((desired_smpl_rt > 0.0) && (set_rates(desired_smpl_rt) < 0)) + double _tx_rate = select_rate(dev_type, sps); + double _rx_rate = _tx_rate / sps; + if ((_tx_rate > 0.0) && (set_rates(_tx_rate, _rx_rate) < 0)) return -1; // Create receive buffer size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t); - rx_smpl_buf = new smpl_buf(buf_len, actual_smpl_rt); + rx_smpl_buf = new smpl_buf(buf_len, rx_rate); // Set receive chain sample offset double offset = get_dev_offset(dev_type, sps); @@ -566,7 +568,7 @@ int uhd_device::open(const std::string &args) LOG(ERR) << "Unsupported configuration, no correction applied"; ts_offset = 0; } else { - ts_offset = (TIMESTAMP) (offset * actual_smpl_rt); + ts_offset = (TIMESTAMP) (offset * rx_rate); } // Initialize and shadow gain values @@ -719,7 +721,7 @@ int uhd_device::readSamples(short *buf, int len, bool *overrun, // Shift read time with respect to transmit clock timestamp += ts_offset; - ts = convert_time(timestamp, actual_smpl_rt); + ts = convert_time(timestamp, rx_rate); LOG(DEBUG) << "Requested timestamp = " << ts.get_real_secs(); // Check that timestamp is valid @@ -788,7 +790,7 @@ int uhd_device::writeSamples(short *buf, int len, bool *underrun, metadata.has_time_spec = true; metadata.start_of_burst = false; metadata.end_of_burst = false; - metadata.time_spec = convert_time(timestamp, actual_smpl_rt); + metadata.time_spec = convert_time(timestamp, tx_rate); // No control packets if (isControl) { diff --git a/Transceiver52M/USRPDevice.cpp b/Transceiver52M/USRPDevice.cpp index 5c99003..275f1c4 100644 --- a/Transceiver52M/USRPDevice.cpp +++ b/Transceiver52M/USRPDevice.cpp @@ -63,10 +63,25 @@ USRPDevice::USRPDevice(int sps, bool skipRx) : skipRx(skipRx) { LOG(INFO) << "creating USRP device..."; + + this->sps = sps; decimRate = (unsigned int) round(masterClockRate/((GSMRATE) * (double) sps)); actualSampleRate = masterClockRate/decimRate; rxGain = 0; + /* + * Undetermined delay b/w ping response timestamp and true + * receive timestamp. Values are empirically measured. With + * split sample rate Tx/Rx - 4/1 sps we need to need to + * compensate for advance rather than delay. + */ + if (sps == 1) + pingOffset = 272; + else if (sps == 4) + pingOffset = 269 - 7500; + else + pingOffset = 0; + #ifdef SWLOOPBACK samplePeriod = 1.0e6/actualSampleRate; loopbackBufferSize = 0; @@ -86,9 +101,10 @@ int USRPDevice::open(const std::string &) m_uRx.reset(); if (!skipRx) { try { - m_uRx = usrp_standard_rx_sptr(usrp_standard_rx::make(0,decimRate,1,-1, - usrp_standard_rx::FPGA_MODE_NORMAL, - 1024,16*8,rbf)); + m_uRx = usrp_standard_rx_sptr(usrp_standard_rx::make( + 0, decimRate * sps, 1, -1, + usrp_standard_rx::FPGA_MODE_NORMAL, + 1024, 16 * 8, rbf)); #ifdef HAVE_LIBUSRP_3_2 m_uRx->set_fpga_master_clock_freq(masterClockRate); #endif @@ -110,8 +126,9 @@ int USRPDevice::open(const std::string &) } try { - m_uTx = usrp_standard_tx_sptr(usrp_standard_tx::make(0,decimRate*2,1,-1, - 1024,16*8,rbf)); + m_uTx = usrp_standard_tx_sptr(usrp_standard_tx::make( + 0, decimRate * 2, 1, -1, + 1024, 16 * 8, rbf)); #ifdef HAVE_LIBUSRP_3_2 m_uTx->set_fpga_master_clock_freq(masterClockRate); #endif @@ -341,7 +358,7 @@ int USRPDevice::readSamples(short *buf, int len, bool *overrun, uint32_t word2 = usrp_to_host_u32(tmpBuf[2]); if ((word2 >> 16) == ((0x01 << 8) | 0x02)) { timestamp -= timestampOffset; - timestampOffset = pktTimestamp - pingTimestamp + PINGOFFSET; + timestampOffset = pktTimestamp - pingTimestamp + pingOffset; LOG(DEBUG) << "updating timestamp offset to: " << timestampOffset; timestamp += timestampOffset; isAligned = true; diff --git a/Transceiver52M/USRPDevice.h b/Transceiver52M/USRPDevice.h index f5bc939..01cf261 100644 --- a/Transceiver52M/USRPDevice.h +++ b/Transceiver52M/USRPDevice.h @@ -60,6 +60,7 @@ private: usrp_subdev_spec rxSubdevSpec; usrp_subdev_spec txSubdevSpec; + int sps; double actualSampleRate; ///< the actual USRP sampling rate unsigned int decimRate; ///< the USRP decimation rate @@ -87,7 +88,8 @@ private: TIMESTAMP timestampOffset; ///< timestamp offset b/w Tx and Rx blocks TIMESTAMP latestWriteTimestamp; ///< timestamp of most recent ping command TIMESTAMP pingTimestamp; ///< timestamp of most recent ping response - static const TIMESTAMP PINGOFFSET = 272; ///< undetermined delay b/w ping response timestamp and true receive timestamp + + long long pingOffset; unsigned long hi32Timestamp; unsigned long lastPktTimestamp; diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp index f39a470..e9fcd49 100644 --- a/Transceiver52M/radioInterface.cpp +++ b/Transceiver52M/radioInterface.cpp @@ -23,13 +23,15 @@ */ #include "radioInterface.h" +#include "Resampler.h" #include extern "C" { #include "convert.h" } -bool started = false; +#define INCHUNK (625 * SAMPSPERSYM) +#define OUTCHUNK (625 * SAMPSPERSYM) RadioInterface::RadioInterface(RadioDevice *wRadio, int wReceiveOffset, @@ -37,7 +39,7 @@ RadioInterface::RadioInterface(RadioDevice *wRadio, GSM::Time wStartTime) : underrun(false), sendCursor(0), recvCursor(0), mOn(false), mRadio(wRadio), receiveOffset(wReceiveOffset), - sps(wSPS), powerScaling(1.0), + mSPSTx(wSPS), mSPSRx(1), powerScaling(1.0), loadTest(false), sendBuffer(NULL), recvBuffer(NULL), convertRecvBuffer(NULL), convertSendBuffer(NULL) { @@ -209,8 +211,8 @@ void RadioInterface::driveReceiveRadio() { // while there's enough data in receive buffer, form received // GSM bursts and pass up to Transceiver // Using the 157-156-156-156 symbols per timeslot format. - while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * sps) { - signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * sps); + while (rcvSz > (symbolsPerSlot + (tN % 4 == 0)) * mSPSRx) { + signalVector rxVector((symbolsPerSlot + (tN % 4 == 0)) * mSPSRx); unRadioifyVector((float *) (recvBuffer->begin() + readSz), rxVector); GSM::Time tmpTime = rcvClock; if (rcvClock.FN() >= 0) { @@ -228,8 +230,8 @@ void RadioInterface::driveReceiveRadio() { } mClock.incTN(); rcvClock.incTN(); - readSz += (symbolsPerSlot+(tN % 4 == 0)) * sps; - rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * sps; + readSz += (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx; + rcvSz -= (symbolsPerSlot+(tN % 4 == 0)) * mSPSRx; tN = rcvClock.TN(); } @@ -267,33 +269,35 @@ double RadioInterface::getRxGain() return -1; } -/* Receive a timestamped chunk from the device */ +/* Receive a timestamped chunk from the device */ void RadioInterface::pullBuffer() { bool local_underrun; - int num_recv; + int num_recv, len = OUTCHUNK / mSPSTx; + float *output; - /* Outer buffer access size is fixed */ + /* Outer buffer access size is fixed */ num_recv = mRadio->readSamples(convertRecvBuffer, - OUTCHUNK, + len, &overrun, readTimestamp, &local_underrun); - if (num_recv != OUTCHUNK) { + if (num_recv != len) { LOG(ALERT) << "Receive error " << num_recv; return; } - convert_short_float((float *) (recvBuffer->begin() + recvCursor), - convertRecvBuffer, 2 * OUTCHUNK); + output = (float *) (recvBuffer->begin() + recvCursor); + + convert_short_float(output, convertRecvBuffer, 2 * len); underrun |= local_underrun; - readTimestamp += num_recv; + readTimestamp += num_recv; recvCursor += num_recv; } -/* Send timestamped chunk to the device with arbitrary size */ +/* Send timestamped chunk to the device with arbitrary size */ void RadioInterface::pushBuffer() { int num_sent; diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h index 2a83417..98d0f9d 100644 --- a/Transceiver52M/radioInterface.h +++ b/Transceiver52M/radioInterface.h @@ -23,8 +23,6 @@ /** samples per GSM symbol */ #define SAMPSPERSYM 4 -#define INCHUNK (625) -#define OUTCHUNK (625) static const unsigned gSlotLen = 148; ///< number of symbols per slot, not counting guard periods @@ -38,7 +36,9 @@ protected: VectorFIFO mReceiveFIFO; ///< FIFO that holds receive bursts RadioDevice *mRadio; ///< the USRP object - + + int mSPSTx; + int mSPSRx; signalVector *sendBuffer; signalVector *recvBuffer; unsigned sendCursor; @@ -54,7 +54,6 @@ protected: RadioClock mClock; ///< the basestation clock! - int sps; ///< samples per GSM symbol int receiveOffset; ///< offset b/w transmit and receive GSM timestamps, in timeslots bool mOn; ///< indicates radio is on diff --git a/Transceiver52M/radioInterfaceResamp.cpp b/Transceiver52M/radioInterfaceResamp.cpp index 03cde30..40bf32d 100644 --- a/Transceiver52M/radioInterfaceResamp.cpp +++ b/Transceiver52M/radioInterfaceResamp.cpp @@ -28,14 +28,6 @@ extern "C" { #include "convert.h" } -/* New chunk sizes for resampled rate */ -#ifdef INCHUNK - #undef INCHUNK -#endif -#ifdef OUTCHUNK - #undef OUTCHUNK -#endif - /* Resampling parameters for 100 MHz clocking */ #define RESAMP_INRATE 52 #define RESAMP_OUTRATE 75 @@ -104,7 +96,7 @@ bool RadioInterfaceResamp::init() cutoff = RESAMP_TX4_FILTER; dnsampler = new Resampler(RESAMP_INRATE, RESAMP_OUTRATE); - if (!dnsampler->init(cutoff)) { + if (!dnsampler->init()) { LOG(ALERT) << "Rx resampler failed to initialize"; return false; } @@ -121,10 +113,10 @@ bool RadioInterfaceResamp::init() * and requires headroom equivalent to the filter length. Low * rate buffers are allocated in the main radio interface code. */ - innerSendBuffer = new signalVector(INCHUNK * 20, RESAMP_FILT_LEN); + innerSendBuffer = new signalVector(INCHUNK * 20, upsampler->len()); outerSendBuffer = new signalVector(OUTCHUNK * 20); - outerRecvBuffer = new signalVector(OUTCHUNK * 2, RESAMP_FILT_LEN); + outerRecvBuffer = new signalVector(OUTCHUNK * 2, dnsampler->len()); innerRecvBuffer = new signalVector(INCHUNK * 20); convertSendBuffer = new short[OUTCHUNK * 2 * 20]; 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; +} diff --git a/Transceiver52M/sigProcLib.h b/Transceiver52M/sigProcLib.h index 109ffa8..516d352 100644 --- a/Transceiver52M/sigProcLib.h +++ b/Transceiver52M/sigProcLib.h @@ -141,14 +141,6 @@ signalVector *convolve(const signalVector *a, unsigned len = 0, unsigned step = 1, int offset = 0); -/** - Generate the GSM pulse. - @param sps The number of samples per GSM symbol. - @param symbolLength The size of the pulse. - @return The GSM pulse. -*/ -void generateGSMPulse(int sps, int symbolLength); - /** Frequency shift a vector. @param y The frequency shifted vector. -- cgit v1.2.3