mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
synced 2025-11-03 05:33:16 +00:00
Compare commits
20 Commits
Hoernchen/
...
fairwaves/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f8f000cca1 | ||
|
|
f1c1379e97 | ||
|
|
bb7b057ec3 | ||
|
|
9155d8da94 | ||
|
|
8b8e7ecf8a | ||
|
|
e587cdb213 | ||
|
|
5d1eaaffcc | ||
|
|
511a662394 | ||
|
|
7d2866164b | ||
|
|
a0f8ed8ecb | ||
|
|
c579c071f4 | ||
|
|
2337e8f8aa | ||
|
|
afa28be3ef | ||
|
|
cab15655f3 | ||
|
|
f8e8e57568 | ||
|
|
441dd35a6f | ||
|
|
bf7ed547ac | ||
|
|
ab31d70678 | ||
|
|
341869feb1 | ||
|
|
31862c5e4c |
@@ -35,7 +35,7 @@
|
|||||||
#ifdef DEBUG_CONFIG
|
#ifdef DEBUG_CONFIG
|
||||||
#define debugLogEarly gLogEarly
|
#define debugLogEarly gLogEarly
|
||||||
#else
|
#else
|
||||||
#define debugLogEarly
|
#define debugLogEarly(x,y,z)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,14 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
// Switches to enable/disable logging targets
|
||||||
|
// MUST BE DEFINED BEFORE gConfig FOR gLogEarly() TO WORK CORRECTLY
|
||||||
|
bool gLogToConsole = true;
|
||||||
|
bool gLogToSyslog = false;
|
||||||
|
FILE *gLogToFile = NULL;
|
||||||
|
Mutex gLogToLock;
|
||||||
|
|
||||||
|
|
||||||
// Reference to a global config table, used all over the system.
|
// Reference to a global config table, used all over the system.
|
||||||
extern ConfigurationTable gConfig;
|
extern ConfigurationTable gConfig;
|
||||||
|
|
||||||
@@ -67,10 +75,6 @@ const char *levelNames[] = {
|
|||||||
"EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
|
"EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
|
||||||
};
|
};
|
||||||
int numLevels = 8;
|
int numLevels = 8;
|
||||||
bool gLogToConsole = true;
|
|
||||||
bool gLogToSyslog = false;
|
|
||||||
FILE *gLogToFile = NULL;
|
|
||||||
Mutex gLogToLock;
|
|
||||||
|
|
||||||
|
|
||||||
int levelStringToInt(const string& name)
|
int levelStringToInt(const string& name)
|
||||||
@@ -269,9 +273,32 @@ void gLogInit(const char* name, const char* level, int facility)
|
|||||||
void gLogEarly(int level, const char *fmt, ...)
|
void gLogEarly(int level, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
va_list args;
|
va_list args;
|
||||||
|
|
||||||
va_start(args, fmt);
|
va_start(args, fmt);
|
||||||
vsyslog(level | LOG_USER, fmt, args);
|
|
||||||
|
if (gLogToSyslog) {
|
||||||
|
va_list args_copy;
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
vsyslog(level | LOG_USER, fmt, args_copy);
|
||||||
|
va_end(args_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gLogToConsole) {
|
||||||
|
va_list args_copy;
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
vprintf(fmt, args_copy);
|
||||||
|
printf("\n");
|
||||||
|
va_end(args_copy);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gLogToFile) {
|
||||||
|
va_list args_copy;
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
vfprintf(gLogToFile, fmt, args_copy);
|
||||||
|
fprintf(gLogToFile, "\n");
|
||||||
|
va_end(args_copy);
|
||||||
|
}
|
||||||
|
|
||||||
va_end(args);
|
va_end(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -50,9 +50,6 @@ TransceiverState::TransceiverState()
|
|||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
chanType[i] = Transceiver::NONE;
|
chanType[i] = Transceiver::NONE;
|
||||||
fillerModulus[i] = 26;
|
fillerModulus[i] = 26;
|
||||||
chanResponse[i] = NULL;
|
|
||||||
DFEForward[i] = NULL;
|
|
||||||
DFEFeedback[i] = NULL;
|
|
||||||
|
|
||||||
for (int n = 0; n < 102; n++)
|
for (int n = 0; n < 102; n++)
|
||||||
fillerTable[n][i] = NULL;
|
fillerTable[n][i] = NULL;
|
||||||
@@ -62,10 +59,6 @@ TransceiverState::TransceiverState()
|
|||||||
TransceiverState::~TransceiverState()
|
TransceiverState::~TransceiverState()
|
||||||
{
|
{
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
delete chanResponse[i];
|
|
||||||
delete DFEForward[i];
|
|
||||||
delete DFEFeedback[i];
|
|
||||||
|
|
||||||
for (int n = 0; n < 102; n++)
|
for (int n = 0; n < 102; n++)
|
||||||
delete fillerTable[n][i];
|
delete fillerTable[n][i];
|
||||||
}
|
}
|
||||||
@@ -141,16 +134,24 @@ bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Transceiver::reset()
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
|
||||||
|
mTxPriorityQueues[i].clear();
|
||||||
|
}
|
||||||
|
|
||||||
Transceiver::Transceiver(int wBasePort,
|
Transceiver::Transceiver(int wBasePort,
|
||||||
const char *wTRXAddress,
|
const char *wTRXAddress,
|
||||||
size_t wSPS, size_t wChans,
|
size_t wSPS, size_t wChans,
|
||||||
GSM::Time wTransmitLatency,
|
GSM::Time wTransmitLatency,
|
||||||
RadioInterface *wRadioInterface,
|
RadioInterface *wRadioInterface,
|
||||||
double wRssiOffset)
|
double wRssiOffset,
|
||||||
|
bool wExternalDemod)
|
||||||
: mBasePort(wBasePort), mAddr(wTRXAddress),
|
: mBasePort(wBasePort), mAddr(wTRXAddress),
|
||||||
mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
|
mClockSocket(wBasePort, wTRXAddress, mBasePort + 100),
|
||||||
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
|
mTransmitLatency(wTransmitLatency), mRadioInterface(wRadioInterface),
|
||||||
rssiOffset(wRssiOffset),
|
rssiOffset(wRssiOffset),
|
||||||
|
mExternalDemod(wExternalDemod),
|
||||||
mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
|
mSPSTx(wSPS), mSPSRx(1), mChans(wChans), mOn(false),
|
||||||
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
|
mTxFreq(0.0), mRxFreq(0.0), mTSC(0), mMaxExpectedDelay(0), mWriteBurstToDiskMask(0)
|
||||||
{
|
{
|
||||||
@@ -222,7 +223,7 @@ bool Transceiver::init(int filler, size_t rtsc)
|
|||||||
c_srcport = mBasePort + 2 * i + 1;
|
c_srcport = mBasePort + 2 * i + 1;
|
||||||
c_dstport = mBasePort + 2 * i + 101;
|
c_dstport = mBasePort + 2 * i + 101;
|
||||||
d_srcport = mBasePort + 2 * i + 2;
|
d_srcport = mBasePort + 2 * i + 2;
|
||||||
d_dstport = mBasePort + 2 * i + 102;
|
d_dstport = mBasePort + 2 * i + (mExternalDemod?202:102);
|
||||||
|
|
||||||
mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
|
mCtrlSockets[i] = new UDPSocket(c_srcport, mAddr.c_str(), c_dstport);
|
||||||
mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
|
mDataSockets[i] = new UDPSocket(d_srcport, mAddr.c_str(), d_dstport);
|
||||||
@@ -556,11 +557,9 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Detect RACH synchronization sequence within a burst. No equalization
|
* Detect RACH synchronization sequence within a burst.
|
||||||
* is used or available on the RACH channel.
|
|
||||||
*/
|
*/
|
||||||
int Transceiver::detectRACH(TransceiverState *state,
|
int Transceiver::detectRACH(signalVector &burst,
|
||||||
signalVector &burst,
|
|
||||||
complex &, float &toa)
|
complex &, float &toa)
|
||||||
{
|
{
|
||||||
float threshold = 6.0;
|
float threshold = 6.0;
|
||||||
@@ -569,76 +568,16 @@ int Transceiver::detectRACH(TransceiverState *state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Detect normal burst training sequence midamble. Update equalization
|
* Detect normal burst training sequence midamble.
|
||||||
* state information and channel estimate if necessary. Equalization
|
|
||||||
* is currently disabled.
|
|
||||||
*/
|
*/
|
||||||
int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
|
int Transceiver::detectTSC(signalVector &burst,
|
||||||
complex &, float &toa, GSM::Time &time)
|
complex &, float &toa)
|
||||||
{
|
{
|
||||||
int success;
|
float threshold = 5.0;
|
||||||
int tn = time.TN();
|
|
||||||
float chanOffset, threshold = 5.0;
|
|
||||||
bool needDFE = false, estimateChan = false;
|
|
||||||
double elapsed = time - state->chanEstimateTime[tn];
|
|
||||||
signalVector *chanResp;
|
|
||||||
|
|
||||||
/* Check equalization update state */
|
|
||||||
if (needDFE && ((elapsed > 50) || (!state->chanResponse[tn]))) {
|
|
||||||
delete state->DFEForward[tn];
|
|
||||||
delete state->DFEFeedback[tn];
|
|
||||||
state->DFEForward[tn] = NULL;
|
|
||||||
state->DFEFeedback[tn] = NULL;
|
|
||||||
|
|
||||||
estimateChan = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detect normal burst midambles */
|
/* Detect normal burst midambles */
|
||||||
success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
|
return analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
|
||||||
toa, mMaxExpectedDelay, estimateChan,
|
toa, mMaxExpectedDelay);
|
||||||
&chanResp, &chanOffset);
|
|
||||||
if (success <= 0) {
|
|
||||||
return success;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Set equalizer if unabled */
|
|
||||||
if (needDFE && estimateChan) {
|
|
||||||
float noise = state->mNoiseLev;
|
|
||||||
state->SNRestimate[tn] = amp.norm2() / (noise * noise + 1.0);
|
|
||||||
|
|
||||||
state->chanResponse[tn] = chanResp;
|
|
||||||
state->chanRespOffset[tn] = chanOffset;
|
|
||||||
state->chanRespAmplitude[tn] = amp;
|
|
||||||
|
|
||||||
scaleVector(*chanResp, complex(1.0, 0.0) / amp);
|
|
||||||
|
|
||||||
designDFE(*chanResp, state->SNRestimate[tn],
|
|
||||||
7, &state->DFEForward[tn], &state->DFEFeedback[tn]);
|
|
||||||
|
|
||||||
state->chanEstimateTime[tn] = time;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Demodulate GMSK burst using equalization if requested. Otherwise
|
|
||||||
* demodulate by direct rotation and soft slicing.
|
|
||||||
*/
|
|
||||||
SoftVector *Transceiver::demodulate(TransceiverState *state,
|
|
||||||
signalVector &burst, complex amp,
|
|
||||||
float toa, size_t tn, bool equalize)
|
|
||||||
{
|
|
||||||
if (equalize) {
|
|
||||||
scaleVector(burst, complex(1.0, 0.0) / amp);
|
|
||||||
return equalizeBurst(burst,
|
|
||||||
toa - state->chanRespOffset[tn],
|
|
||||||
mSPSRx,
|
|
||||||
*state->DFEForward[tn],
|
|
||||||
*state->DFEFeedback[tn]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return demodulateBurst(burst, mSPSRx, amp, toa);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void writeToFile(radioVector *radio_burst, size_t chan)
|
void writeToFile(radioVector *radio_burst, size_t chan)
|
||||||
@@ -655,42 +594,47 @@ void writeToFile(radioVector *radio_burst, size_t chan)
|
|||||||
* Pull bursts from the FIFO and handle according to the slot
|
* Pull bursts from the FIFO and handle according to the slot
|
||||||
* and burst correlation type. Equalzation is currently disabled.
|
* and burst correlation type. Equalzation is currently disabled.
|
||||||
*/
|
*/
|
||||||
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
|
SoftVector *Transceiver::demodSignalVector(signalVector *burst,
|
||||||
double &timingOffset, double &noise,
|
CorrType type,
|
||||||
size_t chan)
|
double &timingOffset)
|
||||||
{
|
{
|
||||||
int success;
|
int success;
|
||||||
bool equalize = false;
|
|
||||||
complex amp;
|
complex amp;
|
||||||
float toa, pow, max = -1.0, avg = 0.0;
|
float toa;
|
||||||
int max_i = -1;
|
|
||||||
signalVector *burst;
|
|
||||||
SoftVector *bits = NULL;
|
SoftVector *bits = NULL;
|
||||||
TransceiverState *state = &mStates[chan];
|
|
||||||
isRssiValid = false;
|
|
||||||
|
|
||||||
/* Blocking FIFO read */
|
/* Detect normal or RACH bursts */
|
||||||
radioVector *radio_burst = mReceiveFIFO[chan]->read();
|
if (type == TSC)
|
||||||
if (!radio_burst)
|
success = detectTSC(*burst, amp, toa);
|
||||||
return NULL;
|
else
|
||||||
|
success = detectRACH(*burst, amp, toa);
|
||||||
|
|
||||||
/* Set time and determine correlation type */
|
/* Alert an error and exit */
|
||||||
GSM::Time time = radio_burst->getTime();
|
if (success <= 0) {
|
||||||
CorrType type = expectedCorrType(time, chan);
|
if (success == -SIGERR_CLIP) {
|
||||||
|
LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
|
||||||
|
} else if (success != SIGERR_NONE) {
|
||||||
|
LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
|
||||||
|
}
|
||||||
|
|
||||||
/* Debug: dump bursts to disk */
|
|
||||||
/* bits 0-7 - chan 0 timeslots
|
|
||||||
* bits 8-15 - chan 1 timeslots */
|
|
||||||
if (mWriteBurstToDiskMask & ((1<<time.TN()) << (8*chan)))
|
|
||||||
writeToFile(radio_burst, chan);
|
|
||||||
|
|
||||||
/* No processing if the timeslot is off.
|
|
||||||
* Not even power level or noise calculation. */
|
|
||||||
if (type == OFF) {
|
|
||||||
delete radio_burst;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
timingOffset = toa / mSPSRx;
|
||||||
|
|
||||||
|
bits = demodulateBurst(*burst, mSPSRx, amp, toa);
|
||||||
|
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
|
|
||||||
|
signalVector *Transceiver::chooseDiversityPath(radioVector *radio_burst, double &avg)
|
||||||
|
{
|
||||||
|
signalVector *burst;
|
||||||
|
int max_i = -1;
|
||||||
|
float pow, max = -1.0;
|
||||||
|
|
||||||
|
avg = 0.0;
|
||||||
|
|
||||||
/* Select the diversity channel with highest energy */
|
/* Select the diversity channel with highest energy */
|
||||||
for (size_t i = 0; i < radio_burst->chans(); i++) {
|
for (size_t i = 0; i < radio_burst->chans(); i++) {
|
||||||
energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
|
energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
|
||||||
@@ -703,7 +647,6 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &i
|
|||||||
|
|
||||||
if (max_i < 0) {
|
if (max_i < 0) {
|
||||||
LOG(ALERT) << "Received empty burst";
|
LOG(ALERT) << "Received empty burst";
|
||||||
delete radio_burst;
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,62 +654,16 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &i
|
|||||||
burst = radio_burst->getVector(max_i);
|
burst = radio_burst->getVector(max_i);
|
||||||
avg = sqrt(avg / radio_burst->chans());
|
avg = sqrt(avg / radio_burst->chans());
|
||||||
|
|
||||||
wTime = time;
|
return burst;
|
||||||
RSSI = 20.0 * log10(rxFullScale / avg);
|
|
||||||
|
|
||||||
/* RSSI estimation are valid */
|
|
||||||
isRssiValid = true;
|
|
||||||
|
|
||||||
if (type == IDLE) {
|
|
||||||
/* Update noise levels */
|
|
||||||
state->mNoises.insert(avg);
|
|
||||||
state->mNoiseLev = state->mNoises.avg();
|
|
||||||
noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
|
|
||||||
|
|
||||||
delete radio_burst;
|
|
||||||
return NULL;
|
|
||||||
} else {
|
|
||||||
/* Do not update noise levels */
|
|
||||||
noise = 20.0 * log10(rxFullScale / state->mNoiseLev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Detect normal or RACH bursts */
|
|
||||||
if (type == TSC)
|
|
||||||
success = detectTSC(state, *burst, amp, toa, time);
|
|
||||||
else
|
|
||||||
success = detectRACH(state, *burst, amp, toa);
|
|
||||||
|
|
||||||
/* Alert an error and exit */
|
|
||||||
if (success <= 0) {
|
|
||||||
if (success == -SIGERR_CLIP) {
|
|
||||||
LOG(WARNING) << "Clipping detected on received RACH or Normal Burst";
|
|
||||||
} else if (success != SIGERR_NONE) {
|
|
||||||
LOG(WARNING) << "Unhandled RACH or Normal Burst detection error";
|
|
||||||
}
|
|
||||||
|
|
||||||
delete radio_burst;
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
timingOffset = toa / mSPSRx;
|
|
||||||
|
|
||||||
/* Demodulate and set output info */
|
|
||||||
if (equalize && (type != TSC))
|
|
||||||
equalize = false;
|
|
||||||
|
|
||||||
bits = demodulate(state, *burst, amp, toa, time.TN(), equalize);
|
|
||||||
|
|
||||||
delete radio_burst;
|
|
||||||
return bits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transceiver::reset()
|
void TransceiverState::updateNoiseEstimates(double avg)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
|
/* Update noise levels */
|
||||||
mTxPriorityQueues[i].clear();
|
mNoises.insert(avg);
|
||||||
|
mNoiseLev = mNoises.avg();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Transceiver::driveControl(size_t chan)
|
void Transceiver::driveControl(size_t chan)
|
||||||
{
|
{
|
||||||
int MAX_PACKET_LENGTH = 100;
|
int MAX_PACKET_LENGTH = 100;
|
||||||
@@ -841,9 +738,8 @@ void Transceiver::driveControl(size_t chan)
|
|||||||
}
|
}
|
||||||
else if (strcmp(command,"NOISELEV")==0) {
|
else if (strcmp(command,"NOISELEV")==0) {
|
||||||
if (mOn) {
|
if (mOn) {
|
||||||
float lev = mStates[chan].mNoiseLev;
|
|
||||||
sprintf(response,"RSP NOISELEV 0 %d",
|
sprintf(response,"RSP NOISELEV 0 %d",
|
||||||
(int) round(20.0 * log10(rxFullScale / lev)));
|
(int) round(dB2(rxFullScale / mStates[chan].mNoiseLev)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sprintf(response,"RSP NOISELEV 1 0");
|
sprintf(response,"RSP NOISELEV 1 0");
|
||||||
@@ -980,20 +876,64 @@ void Transceiver::driveReceiveRadio()
|
|||||||
|
|
||||||
void Transceiver::driveReceiveFIFO(size_t chan)
|
void Transceiver::driveReceiveFIFO(size_t chan)
|
||||||
{
|
{
|
||||||
SoftVector *rxBurst = NULL;
|
radioVector *radio_burst = NULL;
|
||||||
|
signalVector *burst = NULL;
|
||||||
|
double burst_power; // sqr(amp)
|
||||||
double RSSI; // in dBFS
|
double RSSI; // in dBFS
|
||||||
double dBm; // in dBm
|
double dBm; // in dBm
|
||||||
double TOA; // in symbols
|
double TOA; // in symbols
|
||||||
int TOAint; // in 1/256 symbols
|
|
||||||
double noise; // noise level in dBFS
|
double noise; // noise level in dBFS
|
||||||
GSM::Time burstTime;
|
GSM::Time burstTime;
|
||||||
bool isRssiValid; // are RSSI, noise and burstTime valid
|
CorrType burstType;
|
||||||
|
char burstString[3000];
|
||||||
|
int pktLen;
|
||||||
|
|
||||||
rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
|
/* Blocking FIFO read */
|
||||||
|
radio_burst = mReceiveFIFO[chan]->read();
|
||||||
|
if (!radio_burst)
|
||||||
|
return;
|
||||||
|
|
||||||
if (rxBurst) {
|
/* Set time and determine correlation type */
|
||||||
dBm = RSSI+rssiOffset;
|
burstTime = radio_burst->getTime();
|
||||||
TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
|
burstType = expectedCorrType(burstTime, chan);
|
||||||
|
|
||||||
|
/* Debug: dump bursts to disk */
|
||||||
|
/* bits 0-7 - chan 0 timeslots
|
||||||
|
* bits 8-15 - chan 1 timeslots */
|
||||||
|
if (mWriteBurstToDiskMask & ((1<<burstTime.TN()) << (8*chan)))
|
||||||
|
writeToFile(radio_burst, chan);
|
||||||
|
|
||||||
|
/* No processing if the timeslot is off. */
|
||||||
|
if (burstType == OFF) {
|
||||||
|
delete radio_burst;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Choose a diversity channel to use */
|
||||||
|
/* Returned value is a pointer to the radio_burst internal structure */
|
||||||
|
burst = chooseDiversityPath(radio_burst, burst_power);
|
||||||
|
if (!burst) {
|
||||||
|
delete radio_burst;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We use idle timeslots to calculate noise levels for informational purposes.
|
||||||
|
* Otherwise we ignore them. */
|
||||||
|
if (burstType == IDLE) {
|
||||||
|
mStates[chan].updateNoiseEstimates(burst_power);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update/calculate burst info */
|
||||||
|
noise = dB2(rxFullScale / mStates[chan].mNoiseLev);
|
||||||
|
RSSI = dB2(rxFullScale / burst_power);
|
||||||
|
dBm = RSSI+rssiOffset;
|
||||||
|
|
||||||
|
if (!mExternalDemod) {
|
||||||
|
/* Pre-process and demodulate radio vector */
|
||||||
|
SoftVector *rxBurst = demodSignalVector(burst, burstType, TOA);
|
||||||
|
if (!rxBurst)
|
||||||
|
return;
|
||||||
|
|
||||||
LOG(DEBUG) << std::fixed << std::right
|
LOG(DEBUG) << std::fixed << std::right
|
||||||
<< " time: " << burstTime
|
<< " time: " << burstTime
|
||||||
@@ -1002,23 +942,67 @@ void Transceiver::driveReceiveFIFO(size_t chan)
|
|||||||
<< " TOA: " << std::setw(5) << std::setprecision(2) << TOA
|
<< " TOA: " << std::setw(5) << std::setprecision(2) << TOA
|
||||||
<< " bits: " << *rxBurst;
|
<< " bits: " << *rxBurst;
|
||||||
|
|
||||||
char burstString[gSlotLen+10];
|
pktLen = formatDemodPacket(burstTime, dBm, TOA, rxBurst, burstString);
|
||||||
burstString[0] = burstTime.TN();
|
|
||||||
for (int i = 0; i < 4; i++)
|
|
||||||
burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 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++) {
|
|
||||||
burstString[8+i] =(char) round((*burstItr++)*255.0);
|
|
||||||
}
|
|
||||||
burstString[gSlotLen+9] = '\0';
|
|
||||||
delete rxBurst;
|
delete rxBurst;
|
||||||
|
} else {
|
||||||
mDataSockets[chan]->write(burstString,gSlotLen+10);
|
/* Send radio vector as is */
|
||||||
|
pktLen = formatRawPacket(burstTime, dBm, TOA, burstType, mTSC, burst, burstString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mDataSockets[chan]->write(burstString, pktLen);
|
||||||
|
|
||||||
|
delete radio_burst;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Transceiver::formatCommonPacketHeader(GSM::Time burstTime, double dBm, double TOA,
|
||||||
|
char *burstString)
|
||||||
|
{
|
||||||
|
int TOAint; // in 1/256 symbols
|
||||||
|
TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
|
||||||
|
|
||||||
|
burstString[0] = burstTime.TN();
|
||||||
|
for (int i = 0; i < 4; i++)
|
||||||
|
burstString[1+i] = (burstTime.FN() >> ((3-i)*8)) & 0x0ff;
|
||||||
|
burstString[5] = (int)dBm;
|
||||||
|
burstString[6] = (TOAint >> 8) & 0x0ff;
|
||||||
|
burstString[7] = TOAint & 0x0ff;
|
||||||
|
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Transceiver::formatDemodPacket(GSM::Time burstTime, double dBm, double TOA,
|
||||||
|
SoftVector *rxBurst, char *burstString)
|
||||||
|
{
|
||||||
|
int headerSize = formatCommonPacketHeader(burstTime, dBm, TOA, burstString);
|
||||||
|
SoftVector::iterator burstItr = rxBurst->begin();
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < gSlotLen; i++) {
|
||||||
|
burstString[headerSize+i] =(char) round((*burstItr++)*255.0);
|
||||||
|
}
|
||||||
|
burstString[gSlotLen+headerSize+1] = '\0';
|
||||||
|
|
||||||
|
return gSlotLen+headerSize+2;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Transceiver::formatRawPacket(GSM::Time burstTime, double dBm, double TOA,
|
||||||
|
CorrType burstType, unsigned tsc,
|
||||||
|
signalVector *rxBurst, char *burstString)
|
||||||
|
{
|
||||||
|
int headerSize = formatCommonPacketHeader(burstTime, dBm, TOA, burstString);
|
||||||
|
burstString[headerSize++] = burstType;
|
||||||
|
burstString[headerSize++] = tsc;
|
||||||
|
burstString[headerSize++] = 0; // alignment
|
||||||
|
burstString[headerSize++] = 0; // alignment
|
||||||
|
|
||||||
|
signalVector::iterator burstItr = rxBurst->begin();
|
||||||
|
float *signalItr = (float*)(&burstString[headerSize]);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < gSlotLen; i++, burstItr++) {
|
||||||
|
signalItr[2*i] = (*burstItr).real();
|
||||||
|
signalItr[2*i+1] = (*burstItr).imag();
|
||||||
|
}
|
||||||
|
|
||||||
|
return headerSize + 2*gSlotLen*sizeof(float);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Transceiver::driveTxFIFO()
|
void Transceiver::driveTxFIFO()
|
||||||
|
|||||||
@@ -55,29 +55,15 @@ struct TransceiverState {
|
|||||||
|
|
||||||
/* Initialize a multiframe slot in the filler table */
|
/* Initialize a multiframe slot in the filler table */
|
||||||
bool init(int filler, size_t sps, float scale, size_t rtsc);
|
bool init(int filler, size_t sps, float scale, size_t rtsc);
|
||||||
|
void updateNoiseEstimates(double avg);
|
||||||
|
|
||||||
int chanType[8];
|
int chanType[8];
|
||||||
|
|
||||||
/* Last timestamp of each timeslot's channel estimate */
|
|
||||||
GSM::Time chanEstimateTime[8];
|
|
||||||
|
|
||||||
/* The filler table */
|
/* The filler table */
|
||||||
signalVector *fillerTable[102][8];
|
signalVector *fillerTable[102][8];
|
||||||
int fillerModulus[8];
|
int fillerModulus[8];
|
||||||
bool mRetrans;
|
bool mRetrans;
|
||||||
|
|
||||||
/* Most recent channel estimate of all timeslots */
|
|
||||||
signalVector *chanResponse[8];
|
|
||||||
|
|
||||||
/* Most recent DFE feedback filter of all timeslots */
|
|
||||||
signalVector *DFEForward[8];
|
|
||||||
signalVector *DFEFeedback[8];
|
|
||||||
|
|
||||||
/* Most recent SNR, timing, and channel amplitude estimates */
|
|
||||||
float SNRestimate[8];
|
|
||||||
float chanRespOffset[8];
|
|
||||||
complex chanRespAmplitude[8];
|
|
||||||
|
|
||||||
/* Received noise energy levels */
|
/* Received noise energy levels */
|
||||||
float mNoiseLev;
|
float mNoiseLev;
|
||||||
noiseVector mNoises;
|
noiseVector mNoises;
|
||||||
@@ -101,7 +87,8 @@ public:
|
|||||||
size_t wSPS, size_t chans,
|
size_t wSPS, size_t chans,
|
||||||
GSM::Time wTransmitLatency,
|
GSM::Time wTransmitLatency,
|
||||||
RadioInterface *wRadioInterface,
|
RadioInterface *wRadioInterface,
|
||||||
double wRssiOffset);
|
double wRssiOffset,
|
||||||
|
bool wExternalDemod);
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~Transceiver();
|
~Transceiver();
|
||||||
@@ -184,6 +171,8 @@ private:
|
|||||||
|
|
||||||
double rssiOffset; ///< RSSI to dBm conversion offset
|
double rssiOffset; ///< RSSI to dBm conversion offset
|
||||||
|
|
||||||
|
bool mExternalDemod; ///< Should we internal or external demod
|
||||||
|
|
||||||
/** modulate and add a burst to the transmit queue */
|
/** modulate and add a burst to the transmit queue */
|
||||||
void addRadioVector(size_t chan, BitVector &bits,
|
void addRadioVector(size_t chan, BitVector &bits,
|
||||||
int RSSI, GSM::Time &wTime);
|
int RSSI, GSM::Time &wTime);
|
||||||
@@ -195,9 +184,15 @@ private:
|
|||||||
void pushRadioVector(GSM::Time &nowTime);
|
void pushRadioVector(GSM::Time &nowTime);
|
||||||
|
|
||||||
/** Pull and demodulate a burst from the receive FIFO */
|
/** Pull and demodulate a burst from the receive FIFO */
|
||||||
SoftVector *pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
|
SoftVector *demodSignalVector(signalVector *burst,
|
||||||
double &timingOffset, double &noise,
|
CorrType type,
|
||||||
size_t chan = 0);
|
double &timingOffset);
|
||||||
|
|
||||||
|
/** choose the channel to use */
|
||||||
|
signalVector *chooseDiversityPath(radioVector *radio_burst, double &avg);
|
||||||
|
|
||||||
|
/** update noise estimate */
|
||||||
|
double updateNoiseEstimates(TransceiverState *state, double avg);
|
||||||
|
|
||||||
/** Set modulus for specific timeslot */
|
/** Set modulus for specific timeslot */
|
||||||
void setModulus(size_t timeslot, size_t chan);
|
void setModulus(size_t timeslot, size_t chan);
|
||||||
@@ -209,19 +204,12 @@ private:
|
|||||||
void writeClockInterface(void);
|
void writeClockInterface(void);
|
||||||
|
|
||||||
/** Detect RACH bursts */
|
/** Detect RACH bursts */
|
||||||
int detectRACH(TransceiverState *state,
|
int detectRACH(signalVector &burst,
|
||||||
signalVector &burst,
|
|
||||||
complex &, float &toa);
|
complex &, float &toa);
|
||||||
|
|
||||||
/** Detect normal bursts */
|
/** Detect normal bursts */
|
||||||
int detectTSC(TransceiverState *state,
|
int detectTSC(signalVector &burst,
|
||||||
signalVector &burst,
|
complex &, float &toa);
|
||||||
complex &, float &toa, GSM::Time &time);
|
|
||||||
|
|
||||||
/** Demodulat burst and output soft bits */
|
|
||||||
SoftVector *demodulate(TransceiverState *state,
|
|
||||||
signalVector &burst, complex amp,
|
|
||||||
float toa, size_t tn, bool equalize);
|
|
||||||
|
|
||||||
int mSPSTx; ///< number of samples per Tx symbol
|
int mSPSTx; ///< number of samples per Tx symbol
|
||||||
int mSPSRx; ///< number of samples per Rx symbol
|
int mSPSRx; ///< number of samples per Rx symbol
|
||||||
@@ -251,6 +239,19 @@ protected:
|
|||||||
/** drive demodulation of GSM bursts */
|
/** drive demodulation of GSM bursts */
|
||||||
void driveReceiveFIFO(size_t chan);
|
void driveReceiveFIFO(size_t chan);
|
||||||
|
|
||||||
|
/** format a common header for packets with sent over the network */
|
||||||
|
int formatCommonPacketHeader(GSM::Time burstTime, double dBm, double TOA,
|
||||||
|
char *burstString);
|
||||||
|
|
||||||
|
/** format a packet of soft-bits to be sent over the network */
|
||||||
|
int formatDemodPacket(GSM::Time burstTime, double dBm, double TOA,
|
||||||
|
SoftVector *rxBurst, char *burstString);
|
||||||
|
|
||||||
|
/** format a packet of raw samples to be sent over the network */
|
||||||
|
int formatRawPacket(GSM::Time burstTime, double dBm, double TOA,
|
||||||
|
CorrType burstType, unsigned tsc,
|
||||||
|
signalVector *rxBurst, char *burstString);
|
||||||
|
|
||||||
/** drive transmission of GSM bursts */
|
/** drive transmission of GSM bursts */
|
||||||
void driveTxFIFO();
|
void driveTxFIFO();
|
||||||
|
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ struct trx_config {
|
|||||||
double offset;
|
double offset;
|
||||||
double rssi_offset;
|
double rssi_offset;
|
||||||
bool swap_channels;
|
bool swap_channels;
|
||||||
|
bool external_demod;
|
||||||
};
|
};
|
||||||
|
|
||||||
ConfigurationTable gConfig;
|
ConfigurationTable gConfig;
|
||||||
@@ -189,6 +190,7 @@ bool trx_setup_config(struct trx_config *config)
|
|||||||
ost << " Tuning offset........... " << config->offset << std::endl;
|
ost << " Tuning offset........... " << config->offset << std::endl;
|
||||||
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
|
ost << " RSSI to dBm offset...... " << config->rssi_offset << std::endl;
|
||||||
ost << " Swap channels........... " << config->swap_channels << std::endl;
|
ost << " Swap channels........... " << config->swap_channels << std::endl;
|
||||||
|
ost << " External demodulator.... " << config->external_demod << std::endl;
|
||||||
std::cout << ost << std::endl;
|
std::cout << ost << std::endl;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -244,7 +246,7 @@ Transceiver *makeTransceiver(struct trx_config *config, RadioInterface *radio)
|
|||||||
VectorFIFO *fifo;
|
VectorFIFO *fifo;
|
||||||
|
|
||||||
trx = new Transceiver(config->port, config->addr.c_str(), config->sps,
|
trx = new Transceiver(config->port, config->addr.c_str(), config->sps,
|
||||||
config->chans, GSM::Time(3,0), radio, config->rssi_offset);
|
config->chans, GSM::Time(3,0), radio, config->rssi_offset, config->external_demod);
|
||||||
if (!trx->init(config->filler, config->rtsc)) {
|
if (!trx->init(config->filler, config->rtsc)) {
|
||||||
LOG(ALERT) << "Failed to initialize transceiver";
|
LOG(ALERT) << "Failed to initialize transceiver";
|
||||||
delete trx;
|
delete trx;
|
||||||
@@ -298,8 +300,9 @@ static void print_help()
|
|||||||
" -o Set baseband frequency offset (default=auto)\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"
|
" -R RSSI to dBm offset in dB (default=0)\n"
|
||||||
" -S Swap channels (UmTRX only)\n",
|
" -S Swap channels (UmTRX only)\n"
|
||||||
"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
|
" -e External demodulator - stream raw samples instead of soft bits (default=internal)\n",
|
||||||
|
"EMERG, ALERT, CRT, ERR, WARNING, NOTICE, INFO, DEBUG");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_options(int argc, char **argv, struct trx_config *config)
|
static void handle_options(int argc, char **argv, struct trx_config *config)
|
||||||
@@ -316,8 +319,9 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
|
|||||||
config->offset = 0.0;
|
config->offset = 0.0;
|
||||||
config->rssi_offset = 0.0;
|
config->rssi_offset = 0.0;
|
||||||
config->swap_channels = false;
|
config->swap_channels = false;
|
||||||
|
config->external_demod = false;
|
||||||
|
|
||||||
while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:R:S")) != -1) {
|
while ((option = getopt(argc, argv, "ha:l:i:p:c:dxfo:s:r:R:Se")) != -1) {
|
||||||
switch (option) {
|
switch (option) {
|
||||||
case 'h':
|
case 'h':
|
||||||
print_help();
|
print_help();
|
||||||
@@ -363,6 +367,9 @@ static void handle_options(int argc, char **argv, struct trx_config *config)
|
|||||||
case 'S':
|
case 'S':
|
||||||
config->swap_channels = true;
|
config->swap_channels = true;
|
||||||
break;
|
break;
|
||||||
|
case 'e':
|
||||||
|
config->external_demod = true;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
print_help();
|
print_help();
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|||||||
@@ -147,64 +147,8 @@ void sigProcLibDestroy()
|
|||||||
GSMPulse1 = NULL;
|
GSMPulse1 = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// dB relative to 1.0.
|
double dB2(double x) {
|
||||||
// if > 1.0, then return 0 dB
|
return 20.0 * log10(x);
|
||||||
float dB(float x) {
|
|
||||||
|
|
||||||
float arg = 1.0F;
|
|
||||||
float dB = 0.0F;
|
|
||||||
|
|
||||||
if (x >= 1.0F) return 0.0F;
|
|
||||||
if (x <= 0.0F) return -200.0F;
|
|
||||||
|
|
||||||
float prevArg = arg;
|
|
||||||
float prevdB = dB;
|
|
||||||
float stepSize = 16.0F;
|
|
||||||
float dBstepSize = 12.0F;
|
|
||||||
while (stepSize > 1.0F) {
|
|
||||||
do {
|
|
||||||
prevArg = arg;
|
|
||||||
prevdB = dB;
|
|
||||||
arg /= stepSize;
|
|
||||||
dB -= dBstepSize;
|
|
||||||
} while (arg > x);
|
|
||||||
arg = prevArg;
|
|
||||||
dB = prevdB;
|
|
||||||
stepSize *= 0.5F;
|
|
||||||
dBstepSize -= 3.0F;
|
|
||||||
}
|
|
||||||
return ((arg-x)*(dB-3.0F) + (x-arg*0.5F)*dB)/(arg - arg*0.5F);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 10^(-dB/10), inverse of dB func.
|
|
||||||
float dBinv(float x) {
|
|
||||||
|
|
||||||
float arg = 1.0F;
|
|
||||||
float dB = 0.0F;
|
|
||||||
|
|
||||||
if (x >= 0.0F) return 1.0F;
|
|
||||||
if (x <= -200.0F) return 0.0F;
|
|
||||||
|
|
||||||
float prevArg = arg;
|
|
||||||
float prevdB = dB;
|
|
||||||
float stepSize = 16.0F;
|
|
||||||
float dBstepSize = 12.0F;
|
|
||||||
while (stepSize > 1.0F) {
|
|
||||||
do {
|
|
||||||
prevArg = arg;
|
|
||||||
prevdB = dB;
|
|
||||||
arg /= stepSize;
|
|
||||||
dB -= dBstepSize;
|
|
||||||
} while (dB > x);
|
|
||||||
arg = prevArg;
|
|
||||||
dB = prevdB;
|
|
||||||
stepSize *= 0.5F;
|
|
||||||
dBstepSize -= 3.0F;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((dB-x)*(arg*0.5F)+(x-(dB-3.0F))*(arg))/3.0F;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float vectorNorm2(const signalVector &x)
|
float vectorNorm2(const signalVector &x)
|
||||||
@@ -1478,8 +1422,7 @@ int detectRACHBurst(signalVector &rxBurst,
|
|||||||
* tail: Search 4 symbols + maximum expected delay
|
* tail: Search 4 symbols + maximum expected delay
|
||||||
*/
|
*/
|
||||||
int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
|
int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
|
||||||
int sps, complex &, float &toa, unsigned max_toa,
|
int sps, complex &, float &toa, unsigned max_toa)
|
||||||
bool chan_req, signalVector **chan, float *chan_offset)
|
|
||||||
{
|
{
|
||||||
int rc, target, head, tail;
|
int rc, target, head, tail;
|
||||||
CorrelationSequence *sync;
|
CorrelationSequence *sync;
|
||||||
@@ -1495,14 +1438,6 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
|
|||||||
rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa,
|
rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa,
|
||||||
target, head, tail, sync);
|
target, head, tail, sync);
|
||||||
|
|
||||||
/* Equalization not currently supported */
|
|
||||||
if (rc > 0 && chan_req) {
|
|
||||||
*chan = new signalVector(6 * sps);
|
|
||||||
|
|
||||||
if (chan_offset)
|
|
||||||
*chan_offset = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1559,166 +1494,6 @@ SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
|
|||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumes symbol-spaced sampling!!!
|
|
||||||
// Based upon paper by Al-Dhahir and Cioffi
|
|
||||||
bool designDFE(signalVector &channelResponse,
|
|
||||||
float SNRestimate,
|
|
||||||
int Nf,
|
|
||||||
signalVector **feedForwardFilter,
|
|
||||||
signalVector **feedbackFilter)
|
|
||||||
{
|
|
||||||
|
|
||||||
signalVector G0(Nf);
|
|
||||||
signalVector G1(Nf);
|
|
||||||
signalVector::iterator G0ptr = G0.begin();
|
|
||||||
signalVector::iterator G1ptr = G1.begin();
|
|
||||||
signalVector::iterator chanPtr = channelResponse.begin();
|
|
||||||
|
|
||||||
int nu = channelResponse.size()-1;
|
|
||||||
|
|
||||||
*G0ptr = 1.0/sqrtf(SNRestimate);
|
|
||||||
for(int j = 0; j <= nu; j++) {
|
|
||||||
*G1ptr = chanPtr->conj();
|
|
||||||
G1ptr++; chanPtr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
signalVector *L[Nf];
|
|
||||||
signalVector::iterator Lptr;
|
|
||||||
float d = 1.0;
|
|
||||||
for(int i = 0; i < Nf; i++) {
|
|
||||||
d = G0.begin()->norm2() + G1.begin()->norm2();
|
|
||||||
L[i] = new signalVector(Nf+nu);
|
|
||||||
Lptr = L[i]->begin()+i;
|
|
||||||
G0ptr = G0.begin(); G1ptr = G1.begin();
|
|
||||||
while ((G0ptr < G0.end()) && (Lptr < L[i]->end())) {
|
|
||||||
*Lptr = (*G0ptr*(G0.begin()->conj()) + *G1ptr*(G1.begin()->conj()) )/d;
|
|
||||||
Lptr++;
|
|
||||||
G0ptr++;
|
|
||||||
G1ptr++;
|
|
||||||
}
|
|
||||||
complex k = (*G1.begin())/(*G0.begin());
|
|
||||||
|
|
||||||
if (i != Nf-1) {
|
|
||||||
signalVector G0new = G1;
|
|
||||||
scaleVector(G0new,k.conj());
|
|
||||||
addVector(G0new,G0);
|
|
||||||
|
|
||||||
signalVector G1new = G0;
|
|
||||||
scaleVector(G1new,k*(-1.0));
|
|
||||||
addVector(G1new,G1);
|
|
||||||
delayVector(&G1new, &G1new, -1.0);
|
|
||||||
|
|
||||||
scaleVector(G0new,1.0/sqrtf(1.0+k.norm2()));
|
|
||||||
scaleVector(G1new,1.0/sqrtf(1.0+k.norm2()));
|
|
||||||
G0 = G0new;
|
|
||||||
G1 = G1new;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*feedbackFilter = new signalVector(nu);
|
|
||||||
L[Nf-1]->segmentCopyTo(**feedbackFilter,Nf,nu);
|
|
||||||
scaleVector(**feedbackFilter,(complex) -1.0);
|
|
||||||
conjugateVector(**feedbackFilter);
|
|
||||||
|
|
||||||
signalVector v(Nf);
|
|
||||||
signalVector::iterator vStart = v.begin();
|
|
||||||
signalVector::iterator vPtr;
|
|
||||||
*(vStart+Nf-1) = (complex) 1.0;
|
|
||||||
for(int k = Nf-2; k >= 0; k--) {
|
|
||||||
Lptr = L[k]->begin()+k+1;
|
|
||||||
vPtr = vStart + k+1;
|
|
||||||
complex v_k = 0.0;
|
|
||||||
for (int j = k+1; j < Nf; j++) {
|
|
||||||
v_k -= (*vPtr)*(*Lptr);
|
|
||||||
vPtr++; Lptr++;
|
|
||||||
}
|
|
||||||
*(vStart + k) = v_k;
|
|
||||||
}
|
|
||||||
|
|
||||||
*feedForwardFilter = new signalVector(Nf);
|
|
||||||
signalVector::iterator w = (*feedForwardFilter)->end();
|
|
||||||
for (int i = 0; i < Nf; i++) {
|
|
||||||
delete L[i];
|
|
||||||
complex w_i = 0.0;
|
|
||||||
int endPt = ( nu < (Nf-1-i) ) ? nu : (Nf-1-i);
|
|
||||||
vPtr = vStart+i;
|
|
||||||
chanPtr = channelResponse.begin();
|
|
||||||
for (int k = 0; k < endPt+1; k++) {
|
|
||||||
w_i += (*vPtr)*(chanPtr->conj());
|
|
||||||
vPtr++; chanPtr++;
|
|
||||||
}
|
|
||||||
*--w = w_i/d;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Assumes symbol-rate sampling!!!!
|
|
||||||
SoftVector *equalizeBurst(signalVector &rxBurst,
|
|
||||||
float TOA,
|
|
||||||
int sps,
|
|
||||||
signalVector &w, // feedforward filter
|
|
||||||
signalVector &b) // feedback filter
|
|
||||||
{
|
|
||||||
signalVector *postForwardFull;
|
|
||||||
|
|
||||||
if (!delayVector(&rxBurst, &rxBurst, -TOA))
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
postForwardFull = convolve(&rxBurst, &w, NULL,
|
|
||||||
CUSTOM, 0, rxBurst.size() + w.size() - 1);
|
|
||||||
if (!postForwardFull)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
signalVector* postForward = new signalVector(rxBurst.size());
|
|
||||||
postForwardFull->segmentCopyTo(*postForward,w.size()-1,rxBurst.size());
|
|
||||||
delete postForwardFull;
|
|
||||||
|
|
||||||
signalVector::iterator dPtr = postForward->begin();
|
|
||||||
signalVector::iterator dBackPtr;
|
|
||||||
signalVector::iterator rotPtr = GMSKRotationN->begin();
|
|
||||||
signalVector::iterator revRotPtr = GMSKReverseRotationN->begin();
|
|
||||||
|
|
||||||
signalVector *DFEoutput = new signalVector(postForward->size());
|
|
||||||
signalVector::iterator DFEItr = DFEoutput->begin();
|
|
||||||
|
|
||||||
// NOTE: can insert the midamble and/or use midamble to estimate BER
|
|
||||||
for (; dPtr < postForward->end(); dPtr++) {
|
|
||||||
dBackPtr = dPtr-1;
|
|
||||||
signalVector::iterator bPtr = b.begin();
|
|
||||||
while ( (bPtr < b.end()) && (dBackPtr >= postForward->begin()) ) {
|
|
||||||
*dPtr = *dPtr + (*bPtr)*(*dBackPtr);
|
|
||||||
bPtr++;
|
|
||||||
dBackPtr--;
|
|
||||||
}
|
|
||||||
*dPtr = *dPtr * (*revRotPtr);
|
|
||||||
*DFEItr = *dPtr;
|
|
||||||
// make decision on symbol
|
|
||||||
*dPtr = (dPtr->real() > 0.0) ? 1.0 : -1.0;
|
|
||||||
//*DFEItr = *dPtr;
|
|
||||||
*dPtr = *dPtr * (*rotPtr);
|
|
||||||
DFEItr++;
|
|
||||||
rotPtr++;
|
|
||||||
revRotPtr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
vectorSlicer(DFEoutput);
|
|
||||||
|
|
||||||
SoftVector *burstBits = new SoftVector(postForward->size());
|
|
||||||
SoftVector::iterator burstItr = burstBits->begin();
|
|
||||||
DFEItr = DFEoutput->begin();
|
|
||||||
for (; DFEItr < DFEoutput->end(); DFEItr++)
|
|
||||||
*burstItr++ = DFEItr->real();
|
|
||||||
|
|
||||||
delete postForward;
|
|
||||||
|
|
||||||
delete DFEoutput;
|
|
||||||
|
|
||||||
return burstBits;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sigProcLibSetup(int sps)
|
bool sigProcLibSetup(int sps)
|
||||||
{
|
{
|
||||||
if ((sps != 1) && (sps != 4))
|
if ((sps != 1) && (sps != 4))
|
||||||
|
|||||||
@@ -36,8 +36,8 @@ enum signalError {
|
|||||||
SIGERR_INTERNAL,
|
SIGERR_INTERNAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Convert a linear number to a dB value */
|
/** Convert a power value to a dB value */
|
||||||
float dB(float x);
|
double dB2(double x);
|
||||||
|
|
||||||
/** Convert a dB value into a linear value */
|
/** Convert a dB value into a linear value */
|
||||||
float dBinv(float x);
|
float dBinv(float x);
|
||||||
@@ -204,9 +204,6 @@ int detectRACHBurst(signalVector &rxBurst,
|
|||||||
@param amplitude The estimated amplitude of received TSC burst.
|
@param amplitude The estimated amplitude of received TSC burst.
|
||||||
@param TOA The estimate time-of-arrival of received TSC burst.
|
@param TOA The estimate time-of-arrival of received TSC burst.
|
||||||
@param maxTOA The maximum expected time-of-arrival
|
@param maxTOA The maximum expected time-of-arrival
|
||||||
@param requestChannel Set to true if channel estimation is desired.
|
|
||||||
@param channelResponse The estimated channel.
|
|
||||||
@param channelResponseOffset The time offset b/w the first sample of the channel response and the reported TOA.
|
|
||||||
@return positive if threshold value is reached, negative on error, zero otherwise
|
@return positive if threshold value is reached, negative on error, zero otherwise
|
||||||
*/
|
*/
|
||||||
int analyzeTrafficBurst(signalVector &rxBurst,
|
int analyzeTrafficBurst(signalVector &rxBurst,
|
||||||
@@ -215,10 +212,7 @@ int analyzeTrafficBurst(signalVector &rxBurst,
|
|||||||
int sps,
|
int sps,
|
||||||
complex &litude,
|
complex &litude,
|
||||||
float &TOA,
|
float &TOA,
|
||||||
unsigned maxTOA,
|
unsigned maxTOA);
|
||||||
bool requestChannel = false,
|
|
||||||
signalVector** channelResponse = NULL,
|
|
||||||
float *channelResponseOffset = NULL);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Decimate a vector.
|
Decimate a vector.
|
||||||
@@ -240,34 +234,4 @@ signalVector *decimateVector(signalVector &wVector, size_t factor);
|
|||||||
SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
|
SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
|
||||||
complex channel, float TOA);
|
complex channel, float TOA);
|
||||||
|
|
||||||
/**
|
|
||||||
Design the necessary filters for a decision-feedback equalizer.
|
|
||||||
@param channelResponse The multipath channel that we're mitigating.
|
|
||||||
@param SNRestimate The signal-to-noise estimate of the channel, a linear value
|
|
||||||
@param Nf The number of taps in the feedforward filter.
|
|
||||||
@param feedForwardFilter The designed feed forward filter.
|
|
||||||
@param feedbackFilter The designed feedback filter.
|
|
||||||
@return True if DFE can be designed.
|
|
||||||
*/
|
|
||||||
bool designDFE(signalVector &channelResponse,
|
|
||||||
float SNRestimate,
|
|
||||||
int Nf,
|
|
||||||
signalVector **feedForwardFilter,
|
|
||||||
signalVector **feedbackFilter);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Equalize/demodulate a received burst via a decision-feedback equalizer.
|
|
||||||
@param rxBurst The received burst to be demodulated.
|
|
||||||
@param TOA The time-of-arrival of the received burst.
|
|
||||||
@param sps The number of samples per GSM symbol.
|
|
||||||
@param w The feed forward filter of the DFE.
|
|
||||||
@param b The feedback filter of the DFE.
|
|
||||||
@return The demodulated bit sequence.
|
|
||||||
*/
|
|
||||||
SoftVector *equalizeBurst(signalVector &rxBurst,
|
|
||||||
float TOA,
|
|
||||||
int sps,
|
|
||||||
signalVector &w,
|
|
||||||
signalVector &b);
|
|
||||||
|
|
||||||
#endif /* SIGPROCLIB_H */
|
#endif /* SIGPROCLIB_H */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
if !ARCH_ARM
|
if !ARCH_ARM
|
||||||
AM_CFLAGS = -Wall -std=gnu99 -march=native -I../common
|
AM_CFLAGS = -Wall -std=gnu99 -I../common
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libarch.la
|
noinst_LTLIBRARIES = libarch.la
|
||||||
|
|
||||||
|
|||||||
19
debian/changelog
vendored
Normal file
19
debian/changelog
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
osmo-trx (0.1.9~1) trusty; urgency=medium
|
||||||
|
|
||||||
|
* minor debian changes
|
||||||
|
* correct atom cross-compilation
|
||||||
|
* corrected build-time and run-time dependencies
|
||||||
|
|
||||||
|
-- Kirill Zakharenko <earwin@gmail.com> Thu, 23 Jul 2015 00:01:07 +0000
|
||||||
|
|
||||||
|
osmo-trx (0.1.9) trusty; urgency=medium
|
||||||
|
|
||||||
|
* Ask Ivan, really
|
||||||
|
|
||||||
|
-- Kirill Zakharenko <earwin@gmail.com> Thu, 16 Jul 2015 12:13:46 +0000
|
||||||
|
|
||||||
|
osmo-trx (0.1.8) precise; urgency=low
|
||||||
|
|
||||||
|
* Initial release (Closes: #nnnn) <nnnn is the bug number of your ITP
|
||||||
|
|
||||||
|
-- Ivan Klyuchnikov <Ivan.Kluchnikov@fairwaves.ru> Sun, 9 Mar 2014 14:10:10 +0400
|
||||||
1
debian/compat
vendored
Normal file
1
debian/compat
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
9
|
||||||
24
debian/control
vendored
Normal file
24
debian/control
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
Source: osmo-trx
|
||||||
|
Maintainer: Ivan Klyuchnikov <ivan.kluchnikov@fairwaves.ru>
|
||||||
|
Section: net
|
||||||
|
Priority: optional
|
||||||
|
Standards-Version: 3.9.3
|
||||||
|
Build-Depends: debhelper (>= 9), autotools-dev, libdbd-sqlite3, pkg-config, dh-autoreconf, libuhd-dev, libusb-1.0-0-dev, libboost-all-dev, hardening-wrapper
|
||||||
|
Homepage: http://openbsc.osmocom.org/trac/wiki/OsmoTRX
|
||||||
|
Vcs-Git: git://git.osmocom.org/osmo-trx
|
||||||
|
Vcs-Browser: http://cgit.osmocom.org/osmo-trx
|
||||||
|
|
||||||
|
Package: osmo-trx
|
||||||
|
Architecture: any
|
||||||
|
Depends: ${shlibs:Depends}, ${misc:Depends}, libdbd-sqlite3
|
||||||
|
Description: OsmoTRX is a software-defined radio transceiver that implements the Layer 1 physical layer of a BTS
|
||||||
|
|
||||||
|
Package: osmo-trx-dbg
|
||||||
|
Architecture: any
|
||||||
|
Section: debug
|
||||||
|
Priority: extra
|
||||||
|
Depends: osmo-trx (= ${binary:Version}), ${misc:Depends}
|
||||||
|
Description: Debug symbols for the osmo-trx
|
||||||
|
Make debugging possible
|
||||||
|
|
||||||
|
|
||||||
25
debian/copyright
vendored
Normal file
25
debian/copyright
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
The Debian packaging is:
|
||||||
|
|
||||||
|
Copyright (C) 2014 Max <max.suraev@fairwaves.ru>
|
||||||
|
|
||||||
|
It was downloaded from:
|
||||||
|
|
||||||
|
git://git.osmocom.org/osmo-trx
|
||||||
|
|
||||||
|
Upstream Authors:
|
||||||
|
|
||||||
|
Thomas Tsou <tom@tsou.cc>
|
||||||
|
David A. Burgess <dburgess@kestrelsp.com>
|
||||||
|
Harvind S. Samra <hssamra@kestrelsp.com>
|
||||||
|
Raffi Sevlian <raffisev@gmail.com>
|
||||||
|
|
||||||
|
Copyright:
|
||||||
|
|
||||||
|
Copyright (C) 2012-2013 Thomas Tsou <tom@tsou.cc>
|
||||||
|
Copyright (C) 2011 Range Networks, Inc.
|
||||||
|
Copyright (C) 2008-2011 Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
License:
|
||||||
|
|
||||||
|
GNU Affero General Public License, Version 3
|
||||||
|
|
||||||
1
debian/osmo-trx.install
vendored
Normal file
1
debian/osmo-trx.install
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/usr/bin/osmo-trx
|
||||||
15
debian/rules
vendored
Executable file
15
debian/rules
vendored
Executable file
@@ -0,0 +1,15 @@
|
|||||||
|
#!/usr/bin/make -f
|
||||||
|
|
||||||
|
DEB_BUILD_HARDENING=1
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --with autoreconf
|
||||||
|
|
||||||
|
override_dh_auto_configure:
|
||||||
|
dh_auto_configure -- --without-sse CFLAGS="-DHAVE_SSE3 -march=atom -mtune=atom -O2" CXXFLAGS="-DHAVE_SSE3 -march=atom -mtune=atom -O2"
|
||||||
|
|
||||||
|
override_dh_shlibdeps:
|
||||||
|
dh_shlibdeps --dpkg-shlibdeps-params=--ignore-missing-info
|
||||||
|
|
||||||
|
override_dh_strip:
|
||||||
|
dh_strip --dbg-package=osmo-trx-dbg
|
||||||
1
debian/source/format
vendored
Normal file
1
debian/source/format
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
3.0 (native)
|
||||||
Reference in New Issue
Block a user