aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThomas Tsou <tom@tsou.cc>2013-10-11 13:49:55 -0400
committerThomas Tsou <tom@tsou.cc>2013-10-18 13:10:17 -0400
commitc1f7c42a33a1125f8b39f53a1b6e1bae38376857 (patch)
treefd79543a262281b4cbf04bfb09f305b95a715dd4
parent2c282f5e1268146761413a145fd8ae2fb523fa4f (diff)
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 <tom@tsou.cc>
-rw-r--r--Transceiver52M/Transceiver.cpp35
-rw-r--r--Transceiver52M/Transceiver.h3
-rw-r--r--Transceiver52M/UHDDevice.cpp54
-rw-r--r--Transceiver52M/USRPDevice.cpp29
-rw-r--r--Transceiver52M/USRPDevice.h4
-rw-r--r--Transceiver52M/radioInterface.cpp34
-rw-r--r--Transceiver52M/radioInterface.h7
-rw-r--r--Transceiver52M/radioInterfaceResamp.cpp14
-rw-r--r--Transceiver52M/sigProcLib.cpp201
-rw-r--r--Transceiver52M/sigProcLib.h8
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,
&amplitude,
&TOA,
mMaxExpectedDelay,
@@ -398,11 +398,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
}
else {
// RACH burst
- success = detectRACHBurst(*vectorBurst,
- 6.0,
- mSPS,
- &amplitude,
- &TOA);
+ success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &amplitude, &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 <Logger.h>
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
@@ -142,14 +142,6 @@ signalVector *convolve(const signalVector *a,
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.
@param x The vector to-be-shifted.