mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
synced 2025-11-02 05:03:18 +00:00
Compare commits
6 Commits
2023q1
...
fairwaves/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2518186b45 | ||
|
|
6512812e43 | ||
|
|
ded68da44f | ||
|
|
37bbfa2125 | ||
|
|
fdbf914584 | ||
|
|
bbef7e4d70 |
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 &, float &toa)
|
||||
int Transceiver::detectRACH(TransceiverState *state,
|
||||
signalVector &burst,
|
||||
complex &, 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 &, float &toa, GSM::Time &time)
|
||||
int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
|
||||
complex &, 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, &,
|
||||
&toa, mMaxExpectedDelay, estimateChan,
|
||||
&chanResp, &chanOffset)) {
|
||||
return false;
|
||||
success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, &,
|
||||
&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++) {
|
||||
|
||||
@@ -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 &, float &toa);
|
||||
int detectRACH(TransceiverState *state,
|
||||
signalVector &burst,
|
||||
complex &, float &toa);
|
||||
|
||||
/** Detect normal bursts */
|
||||
bool detectTSC(TransceiverState *state,
|
||||
signalVector &burst,
|
||||
complex &, float &toa, GSM::Time &time);
|
||||
int detectTSC(TransceiverState *state,
|
||||
signalVector &burst,
|
||||
complex &, float &toa, GSM::Time &time);
|
||||
|
||||
/** Demodulat burst and output soft bits */
|
||||
SoftVector *demodulate(TransceiverState *state,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user