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>
This commit is contained in:
Thomas Tsou 2013-10-11 13:49:55 -04:00
parent 2c282f5e12
commit c1f7c42a33
10 changed files with 229 additions and 162 deletions

View File

@ -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);
}
}

View File

@ -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

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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];

View File

@ -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;
}
}
bool sigProcLibSetup(int sps)
{
if ((sps != 1) && (sps != 4))
return false;
initTrigTables();
initGMSKRotationTables(sps);
generateGSMPulse(sps, 2);
if (!generateRACHSequence(sps)) {
sigProcLibDestroy();
return false;
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;
}
return true;
}
void GMSKRotate(signalVector &x) {
signalVector::iterator xPtr = x.begin();
signalVector::iterator rotPtr = GMSKRotation->begin();
static void GMSKRotate(signalVector &x, int sps)
{
signalVector::iterator rotPtr, xPtr = x.begin();
if (sps == 1)
rotPtr = GMSKRotation1->begin();
else
rotPtr = GMSKRotationN->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;
}

View File

@ -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.