Compare commits

...

6 Commits

Author SHA1 Message Date
Tom Tsou
2518186b45 sigproc: Setup downlink bursts at 156.25 duration with 4 SPS
Instead of extending 156/157 symbol sized bursts to 624/628 when 4
samples-per-symbol are used, use a fixed size of 625 samples, or
625.25 us.

This is a breaking timing change.
2015-06-05 23:40:27 -04:00
Alexander Chemeris
6512812e43 sigProcLib: Check for bogus TOA before using it. 2015-06-05 23:40:27 -04:00
Alexander Chemeris
ded68da44f Transceiver: Fix clipping detection.
There are two primary changes in this commit:

1) Return values of detect functions changed form bool to int to actually pass
the return value from the inner function and notify higher levels about clipping.
Previously the information was lost due to conversion to bool.

2) Clipping level is not the final verdict now. We still try to demod a burst
and mark it as clipped only if the level is above the clipping level AND we can't
demod it. The reasoning for this is that in real life we want to do as much as
possible to demod the burst, because we want to get as much from our dynamic
range as possible. So a little bit of clipping is fine and is expected. We just
don't want too much of it to break our demod.
2015-06-05 23:32:41 -04:00
Alexander Chemeris
37bbfa2125 Transceiver: Print noise level for each burst in debug mode. 2015-06-05 23:25:22 -04:00
Alexander Chemeris
fdbf914584 osmo-trx: Add a command line option for the dBFS to dBm offset. 2015-06-04 19:13:48 -04:00
Alexander Chemeris
bbef7e4d70 Common: Use a scoped lock in the Logger to avoid deadlock on thread cancel. 2015-06-04 19:13:48 -04:00
5 changed files with 119 additions and 81 deletions

View File

@@ -206,7 +206,7 @@ Log::~Log()
if (gLogToConsole||gLogToFile) {
int mlen = mStream.str().size();
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
gLogToLock.lock();
ScopedLock lock(gLogToLock);
if (gLogToConsole) {
// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
// so just use std::cout.
@@ -218,7 +218,6 @@ Log::~Log()
if (neednl) {fputc('\n',gLogToFile);}
fflush(gLogToFile);
}
gLogToLock.unlock();
}
}

View File

@@ -22,6 +22,7 @@
*/
#include <stdio.h>
#include <iomanip> // std::setprecision
#include "Transceiver.h"
#include <Logger.h>
@@ -140,13 +141,15 @@ bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
}
Transceiver::Transceiver(int wBasePort,
const char *wTRXAddress,
size_t wSPS, size_t wChans,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface)
const char *wTRXAddress,
size_t wSPS, size_t wChans,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface,
double wRssiOffset)
: mBasePort(wBasePort), mAddr(wTRXAddress),
mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
rssiOffset(wRssiOffset),
mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0)
{
@@ -531,9 +534,9 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
* Detect RACH synchronization sequence within a burst. No equalization
* is used or available on the RACH channel.
*/
bool Transceiver::detectRACH(TransceiverState *state,
signalVector &burst,
complex &amp, float &toa)
int Transceiver::detectRACH(TransceiverState *state,
signalVector &burst,
complex &amp, float &toa)
{
float threshold = 6.0;
@@ -545,9 +548,10 @@ bool Transceiver::detectRACH(TransceiverState *state,
* state information and channel estimate if necessary. Equalization
* is currently disabled.
*/
bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
complex &amp, float &toa, GSM::Time &time)
int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
complex &amp, float &toa, GSM::Time &time)
{
int success;
int tn = time.TN();
float chanOffset, threshold = 5.0;
bool noise, needDFE = false, estimateChan = false;
@@ -565,10 +569,11 @@ bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
}
/* Detect normal burst midambles */
if (!analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
&toa, mMaxExpectedDelay, estimateChan,
&chanResp, &chanOffset)) {
return false;
success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &amp,
&toa, mMaxExpectedDelay, estimateChan,
&chanResp, &chanOffset);
if (success <= 0) {
return success;
}
noise = state->mNoiseLev;
@@ -588,7 +593,7 @@ bool Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
state->chanEstimateTime[tn] = time;
}
return true;;
return 1;
}
/*
@@ -615,10 +620,12 @@ SoftVector *Transceiver::demodulate(TransceiverState *state,
* Pull bursts from the FIFO and handle according to the slot
* and burst correlation type. Equalzation is currently disabled.
*/
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
int &timingOffset, size_t chan)
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI,
double &timingOffset, double &noise,
size_t chan)
{
bool success, equalize = false;
int success;
bool equalize = false;
complex amp;
float toa, pow, max = -1.0, avg = 0.0;
int max_i = -1;
@@ -669,12 +676,12 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
/* Update noise average if no bust detected or alert on error */
if (success <= 0) {
if (!success) {
if (success == SIGERR_NONE) {
state->mNoises.insert(avg);
} else if (success == -SIGERR_CLIP) {
LOG(ALERT) << "Clipping detected on RACH input";
} else if (success < 0) {
LOG(ALERT) << "Unhandled RACH error";
LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
} else {
LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
}
delete radio_burst;
@@ -689,8 +696,9 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, int &RSSI,
bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
wTime = time;
RSSI = (int) floor(20.0 * log10(rxFullScale / avg));
timingOffset = (int) round(toa * 256.0 / mSPSRx);
RSSI = 20.0 * log10(rxFullScale / avg);
timingOffset = toa / mSPSRx;
noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
delete radio_burst;
@@ -892,27 +900,33 @@ void Transceiver::driveReceiveRadio()
void Transceiver::driveReceiveFIFO(size_t chan)
{
SoftVector *rxBurst = NULL;
int RSSI;
int TOA; // in 1/256 of a symbol
double RSSI; // in dBFS
double dBm; // in dBm
double TOA; // in symbols
int TOAint; // in 1/256 symbols
double noise; // noise level in dBFS
GSM::Time burstTime;
rxBurst = pullRadioVector(burstTime, RSSI, TOA, chan);
rxBurst = pullRadioVector(burstTime, RSSI, TOA, noise, chan);
if (rxBurst) {
dBm = RSSI+rssiOffset;
TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
LOG(DEBUG) << std::fixed << std::right
<< " time: " << burstTime
<< " RSSI: " << std::setw(5) << std::setprecision(1) << RSSI << "dBFS/" << std::setw(6) << -dBm << "dBm"
<< " noise: " << std::setw(5) << std::setprecision(1) << noise << "dBFS/" << std::setw(6) << -(noise+rssiOffset) << "dBm"
<< " TOA: " << std::setw(5) << std::setprecision(2) << TOA
<< " bits: " << *rxBurst;
LOG(DEBUG) << "burst parameters: "
<< " time: " << burstTime
<< " RSSI: " << RSSI
<< " TOA: " << TOA
<< " bits: " << *rxBurst;
char burstString[gSlotLen+10];
burstString[0] = burstTime.TN();
for (int i = 0; i < 4; i++)
burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
burstString[5] = RSSI;
burstString[6] = (TOA >> 8) & 0x0ff;
burstString[7] = TOA & 0x0ff;
burstString[5] = (int)dBm;
burstString[6] = (TOAint >> 8) & 0x0ff;
burstString[7] = TOAint & 0x0ff;
SoftVector::iterator burstItr = rxBurst->begin();
for (unsigned int i = 0; i < gSlotLen; i++) {

View File

@@ -97,10 +97,11 @@ public:
@param radioInterface associated radioInterface object
*/
Transceiver(int wBasePort,
const char *TRXAddress,
size_t wSPS, size_t chans,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface);
const char *TRXAddress,
size_t wSPS, size_t chans,
GSM::Time wTransmitLatency,
RadioInterface *wRadioInterface,
double wRssiOffset);
/** Destructor */
~Transceiver();
@@ -181,6 +182,8 @@ private:
double txFullScale; ///< full scale input to radio
double rxFullScale; ///< full scale output to radio
double rssiOffset; ///< RSSI to dBm conversion offset
/** modulate and add a burst to the transmit queue */
void addRadioVector(size_t chan, BitVector &bits,
int RSSI, GSM::Time &wTime);
@@ -192,8 +195,9 @@ private:
void pushRadioVector(GSM::Time &nowTime);
/** Pull and demodulate a burst from the receive FIFO */
SoftVector *pullRadioVector(GSM::Time &wTime, int &RSSI,
int &timingOffset, size_t chan = 0);
SoftVector *pullRadioVector(GSM::Time &wTime, double &RSSI,
double &timingOffset, double &noise,
size_t chan = 0);
/** Set modulus for specific timeslot */
void setModulus(size_t timeslot, size_t chan);
@@ -205,14 +209,14 @@ private:
void writeClockInterface(void);
/** Detect RACH bursts */
bool detectRACH(TransceiverState *state,
signalVector &burst,
complex &amp, float &toa);
int detectRACH(TransceiverState *state,
signalVector &burst,
complex &amp, float &toa);
/** Detect normal bursts */
bool detectTSC(TransceiverState *state,
signalVector &burst,
complex &amp, float &toa, GSM::Time &time);
int detectTSC(TransceiverState *state,
signalVector &burst,
complex &amp, float &toa, GSM::Time &time);
/** Demodulat burst and output soft bits */
SoftVector *demodulate(TransceiverState *state,

View File

@@ -70,6 +70,7 @@ struct trx_config {
Transceiver::FillerType filler;
bool diversity;
double offset;
double rssi_offset;
};
ConfigurationTable gConfig;
@@ -185,6 +186,7 @@ bool trx_setup_config(struct trx_config *config)
ost << " C0 Filler Table......... " << fillstr << std::endl;
ost << " Diversity............... " << divstr << std::endl;
ost << " Tuning offset........... " << config->offset << std::endl;
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
std::cout << ost << std::endl;
return true;
@@ -240,7 +242,7 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio)
VectorFIFO *fifo;
trx = new Transceiver(config->port, config->addr.c_str(), config->sps,
config->chans, GSM::Time(3,0), radio);
config->chans, GSM::Time(3,0), radio, config->rssi_offset);
if (!trx->init(config->filler, config->rtsc)) {
LOG(ALERT) << "Failed to initialize transceiver";
delete trx;
@@ -292,7 +294,8 @@ static void print_help()
" -c Number of ARFCN channels (default=1)\n"
" -f Enable C0 filler table\n"
" -o Set baseband frequency offset (default=auto)\n"
" -r Random burst test mode with TSC\n",
" -r Random burst test mode with TSC\n"
" -R RSSI to dBm offset in dB (default=0)\n",
"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
}
@@ -308,8 +311,9 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
config->filler = Transceiver::FILLER_ZERO;
config->diversity = false;
config->offset = 0.0;
config->rssi_offset = 0.0;
while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:")) != -1) {
while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:R:")) != -1) {
switch (option) {
case 'h':
print_help();
@@ -349,6 +353,9 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
config->rtsc = atoi(optarg);
config->filler = Transceiver::FILLER_RAND;
break;
case 'R':
config->rssi_offset = atof(optarg);
break;
default:
print_help();
exit(0);

View File

@@ -28,6 +28,7 @@
#include "sigProcLib.h"
#include "GSMCommon.h"
#include "Logger.h"
extern "C" {
#include "convolve.h"
@@ -43,6 +44,9 @@ using namespace GSM;
/* Clipping detection threshold */
#define CLIP_THRESH 30000.0f
/* GSM 4 sps burst length */
#define GSM_BURST_LEN_4SPS 625
/** Lookup tables for trigonometric approximation */
float cosTable[TABLESIZE+1]; // add 1 element for wrap around
float sinTable[TABLESIZE+1];
@@ -696,27 +700,22 @@ static signalVector *rotateBurst(const BitVector &wBurst,
return shaped;
}
static signalVector *modulateBurstLaurent(const BitVector &bits,
int guard_len, int sps)
/*
* Laurent decomposition based GMSK modulator - 4 SPS only
*/
static signalVector *modulateBurstLaurent(const BitVector &bits)
{
int burst_len;
const int burst_len = GSM_BURST_LEN_4SPS;
const int sps = 4;
float phase;
signalVector *c0_pulse, *c1_pulse, *c0_burst;
signalVector *c1_burst, *c0_shaped, *c1_shaped;
signalVector::iterator c0_itr, c1_itr;
/*
* Apply before and after bits to reduce phase error at burst edges.
* Make sure there is enough room in the burst to accomodate all bits.
*/
if (guard_len < 4)
guard_len = 4;
c0_pulse = GSMPulse->c0;
c1_pulse = GSMPulse->c1;
burst_len = sps * (bits.size() + guard_len);
c0_burst = new signalVector(burst_len, c0_pulse->size());
c0_burst->isReal(true);
c0_itr = c0_burst->begin();
@@ -825,7 +824,7 @@ signalVector *modulateBurst(const BitVector &wBurst, int guardPeriodLength,
if (emptyPulse)
return rotateBurst(wBurst, guardPeriodLength, sps);
else if (sps == 4)
return modulateBurstLaurent(wBurst, guardPeriodLength, sps);
return modulateBurstLaurent(wBurst);
else
return modulateBurstBasic(wBurst, guardPeriodLength, sps);
}
@@ -1284,12 +1283,12 @@ static float computePeakRatio(signalVector *corr,
complex *peak;
float rms, avg = 0.0;
peak = corr->begin() + (int) rint(toa);
/* Check for bogus results */
if ((toa < 0.0) || (toa > corr->size()))
return 0.0;
peak = corr->begin() + (int) rint(toa);
for (int i = 2 * sps; i <= 5 * sps; i++) {
if (peak - i >= corr->begin()) {
avg += (peak - i)->norm2();
@@ -1372,16 +1371,17 @@ static int detectBurst(signalVector &burst,
return 1;
}
static int detectClipping(signalVector &burst, float thresh)
static float maxAmplitude(signalVector &burst)
{
for (size_t i = 0; i < burst.size(); i++) {
if (fabs(burst[i].real()) > thresh)
return 1;
if (fabs(burst[i].imag()) > thresh)
return 1;
}
float max = 0.0;
for (size_t i = 0; i < burst.size(); i++) {
if (fabs(burst[i].real()) > max)
max = fabs(burst[i].real());
if (fabs(burst[i].imag()) > max)
max = fabs(burst[i].imag());
}
return 0;
return max;
}
/*
@@ -1399,6 +1399,7 @@ int detectRACHBurst(signalVector &rxBurst,
float *toa)
{
int rc, start, target, head, tail, len;
bool clipping = false;
float _toa;
complex _amp;
signalVector *corr;
@@ -1407,8 +1408,14 @@ int detectRACHBurst(signalVector &rxBurst,
if ((sps != 1) && (sps != 4))
return -SIGERR_UNSUPPORTED;
if (detectClipping(rxBurst, CLIP_THRESH))
return -SIGERR_CLIP;
// Detect potential clipping
// We still may be able to demod the burst, so we'll give it a try
// and only report clipping if we can't demod.
float maxAmpl = maxAmplitude(rxBurst);
if (maxAmpl > CLIP_THRESH) {
LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
clipping = true;
}
target = 8 + 40;
head = 4;
@@ -1430,7 +1437,7 @@ int detectRACHBurst(signalVector &rxBurst,
*amp = 0.0f;
if (toa)
*toa = 0.0f;
return 0;
return clipping?-SIGERR_CLIP:SIGERR_NONE;
}
/* Subtract forward search bits from delay */
@@ -1455,6 +1462,7 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
bool chan_req, signalVector **chan, float *chan_offset)
{
int rc, start, target, head, tail, len;
bool clipping = false;
complex _amp;
float _toa;
signalVector *corr;
@@ -1463,8 +1471,14 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
if ((tsc < 0) || (tsc > 7) || ((sps != 1) && (sps != 4)))
return -SIGERR_UNSUPPORTED;
if (detectClipping(rxBurst, CLIP_THRESH))
return -SIGERR_CLIP;
// Detect potential clipping
// We still may be able to demod the burst, so we'll give it a try
// and only report clipping if we can't demod.
float maxAmpl = maxAmplitude(rxBurst);
if (maxAmpl > CLIP_THRESH) {
LOG(DEBUG) << "max burst amplitude: " << maxAmpl << " is above the clipping threshold: " << CLIP_THRESH << std::endl;
clipping = true;
}
target = 3 + 58 + 16 + 5;
head = 4;
@@ -1486,7 +1500,7 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
*amp = 0.0f;
if (toa)
*toa = 0.0f;
return 0;
return clipping?-SIGERR_CLIP:SIGERR_NONE;
}
/* Subtract forward search bits from delay */