diff options
-rw-r--r-- | Transceiver52M/Transceiver.cpp | 40 | ||||
-rw-r--r-- | Transceiver52M/Transceiver.h | 7 | ||||
-rw-r--r-- | Transceiver52M/UHDDevice.cpp | 50 | ||||
-rw-r--r-- | Transceiver52M/radioDevice.h | 3 | ||||
-rw-r--r-- | Transceiver52M/radioInterface.cpp | 4 | ||||
-rw-r--r-- | Transceiver52M/radioInterface.h | 3 | ||||
-rw-r--r-- | Transceiver52M/radioVector.cpp | 28 | ||||
-rw-r--r-- | Transceiver52M/radioVector.h | 7 | ||||
-rw-r--r-- | Transceiver52M/sch.c | 63 | ||||
-rw-r--r-- | Transceiver52M/sch.h | 2 |
10 files changed, 182 insertions, 25 deletions
diff --git a/Transceiver52M/Transceiver.cpp b/Transceiver52M/Transceiver.cpp index c3446f8..60be8d2 100644 --- a/Transceiver52M/Transceiver.cpp +++ b/Transceiver52M/Transceiver.cpp @@ -45,10 +45,11 @@ using namespace GSM; /* Number of running values use in noise average */ #define NOISE_CNT 20 +#define FREQ_CNT 20 TransceiverState::TransceiverState() - : mRetrans(false), mNoiseLev(0.0), mNoises(NOISE_CNT), - mode(Transceiver::TRX_MODE_OFF) + : mRetrans(false), mNoiseLev(0.0), + mNoises(NOISE_CNT), mFreqOffsets(FREQ_CNT), mode(Transceiver::TRX_MODE_OFF) { for (int i = 0; i < 8; i++) { chanType[i] = Transceiver::NONE; @@ -56,6 +57,7 @@ TransceiverState::TransceiverState() chanResponse[i] = NULL; DFEForward[i] = NULL; DFEFeedback[i] = NULL; + prevFrame[i] = NULL; for (int n = 0; n < 102; n++) fillerTable[n][i] = NULL; @@ -452,6 +454,34 @@ bool Transceiver::decodeSCH(SoftVector *burst, GSM::Time *time) return true; } +#define FCCH_OFFSET_LIMIT 2e3 +#define FCCH_ADJUST_LIMIT 20.0 + +/* Apply FCCH frequency correction */ +bool Transceiver::correctFCCH(TransceiverState *state, signalVector *burst) +{ + double offset, avg; + + if (!burst) + return false; + + offset = gsm_fcch_offset((float *) burst->begin(), burst->size()); + if (offset > FCCH_OFFSET_LIMIT) + return false; + + state->mFreqOffsets.insert(offset); + avg = state->mFreqOffsets.avg(); + + if (state->mFreqOffsets.full()) + std::cout << "FCCH: Frequency offset " << avg << " Hz" << std::endl; + + if (state->mFreqOffsets.full() && (fabs(avg) > FCCH_ADJUST_LIMIT)) { + mRadioInterface->tuneRxOffset(-avg); + state->mFreqOffsets.reset(); + } + + return true; +} /* * Detect normal burst training sequence midamble. Update equalization @@ -614,6 +644,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI, /* MS: Decode SCH and adjust GSM clock */ if ((state->mode == TRX_MODE_MS_ACQUIRE) || (state->mode == TRX_MODE_MS_TRACK)) { + correctFCCH(state, state->prevFrame[burst_time.TN()]->getVector()); if (decodeSCH(bits, &sch_time)) { if (state->mode == TRX_MODE_MS_ACQUIRE) { @@ -635,11 +666,14 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI, RSSI = (int) floor(20.0 * log10(rxFullScale / avg)); timingOffset = (int) round(toa * 256.0 / mSPSRx); - delete radio_burst; + delete state->prevFrame[burst_time.TN()]; + state->prevFrame[burst_time.TN()] = radio_burst; return bits; release: + delete state->prevFrame[burst_time.TN()]; + state->prevFrame[burst_time.TN()] = radio_burst; delete bits; return NULL; } diff --git a/Transceiver52M/Transceiver.h b/Transceiver52M/Transceiver.h index 170af77..8f3e47b 100644 --- a/Transceiver52M/Transceiver.h +++ b/Transceiver52M/Transceiver.h @@ -80,7 +80,11 @@ struct TransceiverState { /* Received noise energy levels */ float mNoiseLev; - noiseVector mNoises; + avgVector mNoises; + avgVector mFreqOffsets; + + /* Store pointers to previous frame */ + radioVector *prevFrame[8]; /* Transceiver mode */ int mode; @@ -156,6 +160,7 @@ private: complex &, float &toa); bool decodeSCH(SoftVector *burst, GSM::Time *time); + bool correctFCCH(TransceiverState *state, signalVector *burst); /** Detect normal bursts */ bool detectTSC(TransceiverState *state, diff --git a/Transceiver52M/UHDDevice.cpp b/Transceiver52M/UHDDevice.cpp index e943e73..3b9012a 100644 --- a/Transceiver52M/UHDDevice.cpp +++ b/Transceiver52M/UHDDevice.cpp @@ -58,6 +58,11 @@ struct uhd_dev_offset { const std::string desc; }; +struct tune_result { + uhd::tune_result_t uhd; + double freq; +}; + /* * Tx / Rx sample offset values. In a perfect world, there is no group delay * though analog components, and behaviour through digital filters exactly @@ -282,6 +287,7 @@ public: bool setTxFreq(double wFreq, size_t chan); bool setRxFreq(double wFreq, size_t chan); + bool setRxOffset(double wOffset, size_t chan); inline TIMESTAMP initialWriteTimestamp() { return ts_initial * sps; } inline TIMESTAMP initialReadTimestamp() { return ts_initial; } @@ -332,7 +338,7 @@ private: double offset; std::vector<double> tx_gains, rx_gains; - std::vector<double> tx_freqs, rx_freqs; + std::vector<tune_result> tx_freqs, rx_freqs; size_t tx_spp, rx_spp; bool started; @@ -1004,7 +1010,7 @@ bool uhd_device::updateAlignment(TIMESTAMP timestamp) uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx) { double rf_spread, rf_freq; - std::vector<double> freqs; + std::vector<tune_result> freqs; uhd::tune_request_t treq(freq); if ((chans == 1) || ((chans == 2) && dev_type == UMTRX)) { @@ -1023,17 +1029,17 @@ uhd::tune_request_t uhd_device::select_freq(double freq, size_t chan, bool tx) freqs = rx_freqs; /* Tune directly if other channel isn't tuned */ - if (freqs[!chan] < 10.0) + if (freqs[!chan].freq < 10.0) return treq; /* Find center frequency between channels */ - rf_spread = fabs(freqs[!chan] - freq); + rf_spread = fabs(freqs[!chan].freq - freq); if (rf_spread > B2XX_CLK_RT) { LOG(ALERT) << rf_spread << "Hz tuning spread not supported\n"; return treq; } - rf_freq = (freqs[!chan] + freq) / 2.0f; + rf_freq = (freqs[!chan].freq + freq) / 2.0f; treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL; treq.target_freq = freq; @@ -1050,10 +1056,12 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx) if (tx) { tres = usrp_dev->set_tx_freq(treq, chan); - tx_freqs[chan] = usrp_dev->get_tx_freq(chan); + tx_freqs[chan].uhd = tres; + tx_freqs[chan].freq = usrp_dev->get_tx_freq(chan); } else { tres = usrp_dev->set_rx_freq(treq, chan); - rx_freqs[chan] = usrp_dev->get_rx_freq(chan); + rx_freqs[chan].uhd = tres; + rx_freqs[chan].freq = usrp_dev->get_rx_freq(chan); } LOG(INFO) << "\n" << tres.to_pp_string() << std::endl; @@ -1066,13 +1074,15 @@ bool uhd_device::set_freq(double freq, size_t chan, bool tx) */ if (treq.rf_freq_policy == uhd::tune_request_t::POLICY_MANUAL) { if (tx) { - treq = select_freq(tx_freqs[!chan], !chan, true); + treq = select_freq(tx_freqs[!chan].freq, !chan, true); tres = usrp_dev->set_tx_freq(treq, !chan); - tx_freqs[!chan] = usrp_dev->get_tx_freq(!chan); + tx_freqs[!chan].uhd = tres; + tx_freqs[!chan].freq = usrp_dev->get_tx_freq(!chan); } else { - treq = select_freq(rx_freqs[!chan], !chan, false); + treq = select_freq(rx_freqs[!chan].freq, !chan, false); tres = usrp_dev->set_rx_freq(treq, !chan); - rx_freqs[!chan] = usrp_dev->get_rx_freq(!chan); + rx_freqs[!chan].uhd = tres; + rx_freqs[!chan].freq = usrp_dev->get_rx_freq(!chan); } LOG(INFO) << "\n" << tres.to_pp_string() << std::endl; @@ -1091,6 +1101,20 @@ bool uhd_device::setTxFreq(double wFreq, size_t chan) return set_freq(wFreq, chan, true); } +bool uhd_device::setRxOffset(double wOffset, size_t chan) +{ + uhd::tune_result_t tres; + uhd::tune_request_t treq(rx_freqs[chan].freq - wOffset); + + treq.rf_freq_policy = uhd::tune_request_t::POLICY_MANUAL; + treq.rf_freq = rx_freqs[chan].uhd.actual_rf_freq; + + tres = usrp_dev->set_rx_freq(treq, chan); + rx_freqs[chan].freq = usrp_dev->get_rx_freq(chan); + + return true; +} + bool uhd_device::setRxFreq(double wFreq, size_t chan) { if (chan >= rx_freqs.size()) { @@ -1108,7 +1132,7 @@ double uhd_device::getTxFreq(size_t chan) return 0.0; } - return tx_freqs[chan]; + return tx_freqs[chan].freq; } double uhd_device::getRxFreq(size_t chan) @@ -1118,7 +1142,7 @@ double uhd_device::getRxFreq(size_t chan) return 0.0; } - return rx_freqs[chan]; + return rx_freqs[chan].freq; } bool uhd_device::recv_async_msg() diff --git a/Transceiver52M/radioDevice.h b/Transceiver52M/radioDevice.h index 6273bcc..c77869e 100644 --- a/Transceiver52M/radioDevice.h +++ b/Transceiver52M/radioDevice.h @@ -91,6 +91,9 @@ class RadioDevice { /** Set the receiver frequency */ virtual bool setRxFreq(double wFreq, size_t chan = 0) = 0; + /** Adjust the receiver offset */ + virtual bool setRxOffset(double wOffset, size_t chan = 0) = 0; + /** Returns the starting write Timestamp*/ virtual TIMESTAMP initialWriteTimestamp(void)=0; diff --git a/Transceiver52M/radioInterface.cpp b/Transceiver52M/radioInterface.cpp index 317d2b4..75266dd 100644 --- a/Transceiver52M/radioInterface.cpp +++ b/Transceiver52M/radioInterface.cpp @@ -172,6 +172,10 @@ bool RadioInterface::tuneRx(double freq, size_t chan) return mRadio->setRxFreq(freq, chan); } +bool RadioInterface::tuneRxOffset(double offset, size_t chan) +{ + return mRadio->setRxOffset(offset, chan); +} void RadioInterface::start() { diff --git a/Transceiver52M/radioInterface.h b/Transceiver52M/radioInterface.h index 7798e5c..ebf8f38 100644 --- a/Transceiver52M/radioInterface.h +++ b/Transceiver52M/radioInterface.h @@ -111,6 +111,9 @@ public: /** set receive frequency */ virtual bool tuneRx(double freq, size_t chan = 0); + /** set frequency correction */ + virtual bool tuneRxOffset(double offset, size_t chan = 0); + /** set receive gain */ double setRxGain(double dB, size_t chan = 0); diff --git a/Transceiver52M/radioVector.cpp b/Transceiver52M/radioVector.cpp index 2e3af9d..ea354b4 100644 --- a/Transceiver52M/radioVector.cpp +++ b/Transceiver52M/radioVector.cpp @@ -74,25 +74,31 @@ bool radioVector::setVector(signalVector *vector, size_t chan) return true; } -noiseVector::noiseVector(size_t size) - : std::vector<float>(size), itr(0) +avgVector::avgVector(size_t max) + : std::vector<float>(0), itr(0) { + this->max = max; } -float noiseVector::avg() const +float avgVector::avg() const { float val = 0.0; + if (!size()) + return 0.0f; + for (size_t i = 0; i < size(); i++) val += (*this)[i]; return val / (float) size(); } -bool noiseVector::insert(float val) +bool avgVector::insert(float val) { - if (!size()) - return false; + if (size() < max) { + push_back(val); + return true; + } if (itr >= this->size()) itr = 0; @@ -102,6 +108,16 @@ bool noiseVector::insert(float val) return true; } +bool avgVector::full() const +{ + return size() >= max; +} + +void avgVector::reset() +{ + resize(0); +} + GSM::Time VectorQueue::nextTime() const { GSM::Time retVal; diff --git a/Transceiver52M/radioVector.h b/Transceiver52M/radioVector.h index 0566123..7e236b6 100644 --- a/Transceiver52M/radioVector.h +++ b/Transceiver52M/radioVector.h @@ -46,14 +46,17 @@ private: GSM::Time mTime; }; -class noiseVector : std::vector<float> { +class avgVector : std::vector<float> { public: - noiseVector(size_t size = 0); + avgVector(size_t size = 0); bool insert(float val); + bool full() const; float avg() const; + void reset(); private: size_t itr; + size_t max; }; class VectorFIFO : public InterthreadQueue<radioVector> { }; diff --git a/Transceiver52M/sch.c b/Transceiver52M/sch.c index 3cc2232..67db259 100644 --- a/Transceiver52M/sch.c +++ b/Transceiver52M/sch.c @@ -62,6 +62,9 @@ const struct osmo_crc16gen_code gsm0503_sch_crc10 = { #define GSM_MAX_BURST_LEN 157 #define GSM_SYM_RATE (1625e3 / 6) +/* Pre-generated FCCH measurement tone */ +static complex float fcch_ref[GSM_MAX_BURST_LEN]; + int float_to_sbit(const float *in, sbit_t *out, float scale, int len) { int i; @@ -154,3 +157,63 @@ int gsm_sch_decode(uint8_t *info, sbit_t *data) return 0; } + +#define FCCH_TAIL_BITS_LEN 3 +#define FCCH_DATA_LEN 142 + +/* Compute FCCH frequency offset */ +double gsm_fcch_offset(float *burst, int len) +{ + int i, start, end; + float a, b, c, d, ang, avg = 0.0f; + double freq; + + if (len > GSM_MAX_BURST_LEN) + len = GSM_MAX_BURST_LEN; + + for (i = 0; i < len; i++) { + a = burst[2 * i + 0]; + b = burst[2 * i + 1]; + c = crealf(fcch_ref[i]); + d = cimagf(fcch_ref[i]); + + burst[2 * i + 0] = a * c - b * d; + burst[2 * i + 1] = a * d + b * c; + } + + start = FCCH_TAIL_BITS_LEN; + end = start + FCCH_DATA_LEN; + + for (i = start; i < end; i++) { + a = cargf(burst[2 * (i - 1) + 0] + + burst[2 * (i - 1) + 1] * I); + b = cargf(burst[2 * i + 0] + + burst[2 * i + 1] * I); + + ang = b - a; + + if (ang > M_PI) + ang -= 2 * M_PI; + else if (ang < -M_PI) + ang += 2 * M_PI; + + avg += ang; + } + + avg /= (float) (end - start); + freq = avg / (2 * M_PI) * GSM_SYM_RATE; + + return freq; +} + +/* Generate FCCH measurement tone */ +static __attribute__((constructor)) void init() +{ + int i; + double freq = 0.25; + + for (i = 0; i < GSM_MAX_BURST_LEN; i++) { + fcch_ref[i] = sin(2 * M_PI * freq * (double) i) + + cos(2 * M_PI * freq * (double) i) * I; + } +} diff --git a/Transceiver52M/sch.h b/Transceiver52M/sch.h index 1e31968..ec2d0e0 100644 --- a/Transceiver52M/sch.h +++ b/Transceiver52M/sch.h @@ -19,6 +19,8 @@ int gsm_sch_parse(const uint8_t *sb_info, struct sch_info *desc); int gsm_sch_to_fn(struct sch_info *sch); int gsm_sch_check_fn(int fn); +double gsm_fcch_offset(float *burst, int len); + int float_to_sbit(const float *in, sbit_t *out, float scale, int len); #endif /* _SCH_H_ */ |