mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
synced 2025-11-02 21:23:16 +00:00
transceiver: Remove remainings of the equalizer, restructure driveReceiveFIFO() for better modularity.
Equalizer has never worked properly and was always disabled. Now is a good time to remove it completely to make the code cleaner.
This commit is contained in:
@@ -50,9 +50,6 @@ TransceiverState::TransceiverState()
|
||||
for (int i = 0; i < 8; i++) {
|
||||
chanType[i] = Transceiver::NONE;
|
||||
fillerModulus[i] = 26;
|
||||
chanResponse[i] = NULL;
|
||||
DFEForward[i] = NULL;
|
||||
DFEFeedback[i] = NULL;
|
||||
|
||||
for (int n = 0; n < 102; n++)
|
||||
fillerTable[n][i] = NULL;
|
||||
@@ -62,10 +59,6 @@ TransceiverState::TransceiverState()
|
||||
TransceiverState::~TransceiverState()
|
||||
{
|
||||
for (int i = 0; i < 8; i++) {
|
||||
delete chanResponse[i];
|
||||
delete DFEForward[i];
|
||||
delete DFEFeedback[i];
|
||||
|
||||
for (int n = 0; n < 102; n++)
|
||||
delete fillerTable[n][i];
|
||||
}
|
||||
@@ -141,6 +134,12 @@ bool TransceiverState::init(int filler, size_t sps, float scale, size_t rtsc)
|
||||
return false;
|
||||
}
|
||||
|
||||
void Transceiver::reset()
|
||||
{
|
||||
for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
|
||||
mTxPriorityQueues[i].clear();
|
||||
}
|
||||
|
||||
Transceiver::Transceiver(int wBasePort,
|
||||
const char *wTRXAddress,
|
||||
size_t wSPS, size_t wChans,
|
||||
@@ -556,11 +555,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.
|
||||
* Detect RACH synchronization sequence within a burst.
|
||||
*/
|
||||
int Transceiver::detectRACH(TransceiverState *state,
|
||||
signalVector &burst,
|
||||
int Transceiver::detectRACH(signalVector &burst,
|
||||
complex &, float &toa)
|
||||
{
|
||||
float threshold = 6.0;
|
||||
@@ -569,76 +566,16 @@ int Transceiver::detectRACH(TransceiverState *state,
|
||||
}
|
||||
|
||||
/*
|
||||
* Detect normal burst training sequence midamble. Update equalization
|
||||
* state information and channel estimate if necessary. Equalization
|
||||
* is currently disabled.
|
||||
* Detect normal burst training sequence midamble.
|
||||
*/
|
||||
int Transceiver::detectTSC(TransceiverState *state, signalVector &burst,
|
||||
complex &, float &toa, GSM::Time &time)
|
||||
int Transceiver::detectTSC(signalVector &burst,
|
||||
complex &, float &toa)
|
||||
{
|
||||
int success;
|
||||
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;
|
||||
}
|
||||
float threshold = 5.0;
|
||||
|
||||
/* Detect normal burst midambles */
|
||||
success = analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
|
||||
toa, mMaxExpectedDelay, estimateChan,
|
||||
&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);
|
||||
return analyzeTrafficBurst(burst, mTSC, threshold, mSPSRx, amp,
|
||||
toa, mMaxExpectedDelay);
|
||||
}
|
||||
|
||||
void writeToFile(radioVector *radio_burst, size_t chan)
|
||||
@@ -655,42 +592,47 @@ void writeToFile(radioVector *radio_burst, size_t chan)
|
||||
* 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, double &RSSI, bool &isRssiValid,
|
||||
double &timingOffset, double &noise,
|
||||
size_t chan)
|
||||
SoftVector *Transceiver::demodSignalVector(signalVector *burst,
|
||||
CorrType type,
|
||||
double &timingOffset)
|
||||
{
|
||||
int success;
|
||||
bool equalize = false;
|
||||
complex amp;
|
||||
float toa, pow, max = -1.0, avg = 0.0;
|
||||
int max_i = -1;
|
||||
signalVector *burst;
|
||||
float toa;
|
||||
SoftVector *bits = NULL;
|
||||
TransceiverState *state = &mStates[chan];
|
||||
isRssiValid = false;
|
||||
|
||||
/* Blocking FIFO read */
|
||||
radioVector *radio_burst = mReceiveFIFO[chan]->read();
|
||||
if (!radio_burst)
|
||||
return NULL;
|
||||
/* Detect normal or RACH bursts */
|
||||
if (type == TSC)
|
||||
success = detectTSC(*burst, amp, toa);
|
||||
else
|
||||
success = detectRACH(*burst, amp, toa);
|
||||
|
||||
/* Set time and determine correlation type */
|
||||
GSM::Time time = radio_burst->getTime();
|
||||
CorrType type = expectedCorrType(time, chan);
|
||||
/* 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";
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
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 */
|
||||
for (size_t i = 0; i < radio_burst->chans(); i++) {
|
||||
energyDetect(*radio_burst->getVector(i), 20 * mSPSRx, 0.0, &pow);
|
||||
@@ -703,7 +645,6 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &i
|
||||
|
||||
if (max_i < 0) {
|
||||
LOG(ALERT) << "Received empty burst";
|
||||
delete radio_burst;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -711,62 +652,16 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime, double &RSSI, bool &i
|
||||
burst = radio_burst->getVector(max_i);
|
||||
avg = sqrt(avg / radio_burst->chans());
|
||||
|
||||
wTime = time;
|
||||
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;
|
||||
return burst;
|
||||
}
|
||||
|
||||
void Transceiver::reset()
|
||||
void TransceiverState::updateNoiseEstimates(double avg)
|
||||
{
|
||||
for (size_t i = 0; i < mTxPriorityQueues.size(); i++)
|
||||
mTxPriorityQueues[i].clear();
|
||||
/* Update noise levels */
|
||||
mNoises.insert(avg);
|
||||
mNoiseLev = mNoises.avg();
|
||||
}
|
||||
|
||||
|
||||
void Transceiver::driveControl(size_t chan)
|
||||
{
|
||||
int MAX_PACKET_LENGTH = 100;
|
||||
@@ -841,9 +736,8 @@ void Transceiver::driveControl(size_t chan)
|
||||
}
|
||||
else if (strcmp(command,"NOISELEV")==0) {
|
||||
if (mOn) {
|
||||
float lev = mStates[chan].mNoiseLev;
|
||||
sprintf(response,"RSP NOISELEV 0 %d",
|
||||
(int) round(20.0 * log10(rxFullScale / lev)));
|
||||
(int) round(dB2(rxFullScale / mStates[chan].mNoiseLev)));
|
||||
}
|
||||
else {
|
||||
sprintf(response,"RSP NOISELEV 1 0");
|
||||
@@ -980,45 +874,94 @@ void Transceiver::driveReceiveRadio()
|
||||
|
||||
void Transceiver::driveReceiveFIFO(size_t chan)
|
||||
{
|
||||
radioVector *radio_burst = NULL;
|
||||
signalVector *burst = NULL;
|
||||
SoftVector *rxBurst = NULL;
|
||||
double burst_power; // sqr(amp)
|
||||
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;
|
||||
bool isRssiValid; // are RSSI, noise and burstTime valid
|
||||
CorrType burstType;
|
||||
|
||||
rxBurst = pullRadioVector(burstTime, RSSI, isRssiValid, TOA, noise, chan);
|
||||
/* Blocking FIFO read */
|
||||
radio_burst = mReceiveFIFO[chan]->read();
|
||||
if (!radio_burst)
|
||||
return;
|
||||
|
||||
if (rxBurst) {
|
||||
dBm = RSSI+rssiOffset;
|
||||
TOAint = (int) (TOA * 256.0 + 0.5); // round to closest integer
|
||||
/* Set time and determine correlation type */
|
||||
burstTime = radio_burst->getTime();
|
||||
burstType = expectedCorrType(burstTime, chan);
|
||||
|
||||
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;
|
||||
/* 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);
|
||||
|
||||
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] = (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;
|
||||
|
||||
mDataSockets[chan]->write(burstString,gSlotLen+10);
|
||||
/* No processing if the timeslot is off. */
|
||||
if (burstType == OFF) {
|
||||
delete radio_burst;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Choose a diversity channel to use */
|
||||
burst = chooseDiversityPath(radio_burst, burst_power);
|
||||
delete radio_burst;
|
||||
if (!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;
|
||||
|
||||
/* Pre-process and demodulate radio vector */
|
||||
rxBurst = demodSignalVector(burst, burstType, TOA);
|
||||
if (!rxBurst)
|
||||
return;
|
||||
|
||||
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;
|
||||
|
||||
char burstString[gSlotLen+10];
|
||||
formatDemodPacket(burstTime, dBm, TOA, rxBurst, burstString);
|
||||
delete rxBurst;
|
||||
|
||||
mDataSockets[chan]->write(burstString,gSlotLen+10);
|
||||
}
|
||||
|
||||
void Transceiver::formatDemodPacket(GSM::Time burstTime, double dBm, double TOA,
|
||||
SoftVector *rxBurst, 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;
|
||||
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';
|
||||
}
|
||||
|
||||
void Transceiver::driveTxFIFO()
|
||||
|
||||
@@ -55,29 +55,15 @@ struct TransceiverState {
|
||||
|
||||
/* Initialize a multiframe slot in the filler table */
|
||||
bool init(int filler, size_t sps, float scale, size_t rtsc);
|
||||
void updateNoiseEstimates(double avg);
|
||||
|
||||
int chanType[8];
|
||||
|
||||
/* Last timestamp of each timeslot's channel estimate */
|
||||
GSM::Time chanEstimateTime[8];
|
||||
|
||||
/* The filler table */
|
||||
signalVector *fillerTable[102][8];
|
||||
int fillerModulus[8];
|
||||
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 */
|
||||
float mNoiseLev;
|
||||
noiseVector mNoises;
|
||||
@@ -195,9 +181,15 @@ private:
|
||||
void pushRadioVector(GSM::Time &nowTime);
|
||||
|
||||
/** Pull and demodulate a burst from the receive FIFO */
|
||||
SoftVector *pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
|
||||
double &timingOffset, double &noise,
|
||||
size_t chan = 0);
|
||||
SoftVector *demodSignalVector(signalVector *burst,
|
||||
CorrType type,
|
||||
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 */
|
||||
void setModulus(size_t timeslot, size_t chan);
|
||||
@@ -209,19 +201,12 @@ private:
|
||||
void writeClockInterface(void);
|
||||
|
||||
/** Detect RACH bursts */
|
||||
int detectRACH(TransceiverState *state,
|
||||
signalVector &burst,
|
||||
int detectRACH(signalVector &burst,
|
||||
complex &, float &toa);
|
||||
|
||||
/** Detect normal bursts */
|
||||
int detectTSC(TransceiverState *state,
|
||||
signalVector &burst,
|
||||
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 detectTSC(signalVector &burst,
|
||||
complex &, float &toa);
|
||||
|
||||
int mSPSTx; ///< number of samples per Tx symbol
|
||||
int mSPSRx; ///< number of samples per Rx symbol
|
||||
@@ -251,6 +236,10 @@ protected:
|
||||
/** drive demodulation of GSM bursts */
|
||||
void driveReceiveFIFO(size_t chan);
|
||||
|
||||
/** format a packet of soft-bits to be sent over the network */
|
||||
void formatDemodPacket(GSM::Time burstTime, double dBm, double TOA,
|
||||
SoftVector *rxBurst, char *burstString);
|
||||
|
||||
/** drive transmission of GSM bursts */
|
||||
void driveTxFIFO();
|
||||
|
||||
|
||||
@@ -147,64 +147,8 @@ void sigProcLibDestroy()
|
||||
GSMPulse1 = NULL;
|
||||
}
|
||||
|
||||
// dB relative to 1.0.
|
||||
// if > 1.0, then return 0 dB
|
||||
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;
|
||||
|
||||
double dB2(double x) {
|
||||
return 20.0 * log10(x);
|
||||
}
|
||||
|
||||
float vectorNorm2(const signalVector &x)
|
||||
@@ -1478,8 +1422,7 @@ int detectRACHBurst(signalVector &rxBurst,
|
||||
* tail: Search 4 symbols + maximum expected delay
|
||||
*/
|
||||
int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
|
||||
int sps, complex &, float &toa, unsigned max_toa,
|
||||
bool chan_req, signalVector **chan, float *chan_offset)
|
||||
int sps, complex &, float &toa, unsigned max_toa)
|
||||
{
|
||||
int rc, target, head, tail;
|
||||
CorrelationSequence *sync;
|
||||
@@ -1495,14 +1438,6 @@ int analyzeTrafficBurst(signalVector &rxBurst, unsigned tsc, float thresh,
|
||||
rc = detectGeneralBurst(rxBurst, thresh, sps, amp, toa,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1559,166 +1494,6 @@ SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
|
||||
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)
|
||||
{
|
||||
if ((sps != 1) && (sps != 4))
|
||||
|
||||
@@ -36,8 +36,8 @@ enum signalError {
|
||||
SIGERR_INTERNAL,
|
||||
};
|
||||
|
||||
/** Convert a linear number to a dB value */
|
||||
float dB(float x);
|
||||
/** Convert a power value to a dB value */
|
||||
double dB2(double x);
|
||||
|
||||
/** Convert a dB value into a linear value */
|
||||
float dBinv(float x);
|
||||
@@ -204,9 +204,6 @@ int detectRACHBurst(signalVector &rxBurst,
|
||||
@param amplitude The estimated amplitude of received TSC burst.
|
||||
@param TOA The estimate time-of-arrival of received TSC burst.
|
||||
@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
|
||||
*/
|
||||
int analyzeTrafficBurst(signalVector &rxBurst,
|
||||
@@ -215,10 +212,7 @@ int analyzeTrafficBurst(signalVector &rxBurst,
|
||||
int sps,
|
||||
complex &litude,
|
||||
float &TOA,
|
||||
unsigned maxTOA,
|
||||
bool requestChannel = false,
|
||||
signalVector** channelResponse = NULL,
|
||||
float *channelResponseOffset = NULL);
|
||||
unsigned maxTOA);
|
||||
|
||||
/**
|
||||
Decimate a vector.
|
||||
@@ -240,34 +234,4 @@ signalVector *decimateVector(signalVector &wVector, size_t factor);
|
||||
SoftVector *demodulateBurst(signalVector &rxBurst, int sps,
|
||||
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 */
|
||||
|
||||
Reference in New Issue
Block a user