mirror of
https://github.com/RangeNetworks/openbts.git
synced 2025-10-23 07:42:01 +00:00
Transceiver52M: Update noise measurement calculation
Previous removal of the energy detector requirement broke the noise level calculation loop. The previous adaptive approach was finicky - noticably at high gain levels. Since we no longer use the energy threshold for primary burst gating, we can return to a simpler world. In the new approach, we compute a running average of energy levels and track them with a noise vector. A timeslot that passes the correlator threshold is a valid burst. These are not used in the noise calculation. Everything else is considered noise and used to compute the noise level with respect to full scale input level, which for almost all supported devices is 2^15. Signed-off-by: Thomas Tsou <tom@tsou.cc> git-svn-id: http://wush.net/svn/range/software/public/openbts/trunk@6755 19bc5d8c-e614-43d4-8b26-e1612bc8e597
This commit is contained in:
@@ -44,7 +44,8 @@
|
|||||||
# define USB_LATENCY_MIN 1,1
|
# define USB_LATENCY_MIN 1,1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INIT_ENERGY_THRSHD 5.0f
|
/* Number of running values use in noise average */
|
||||||
|
#define NOISE_CNT 20
|
||||||
|
|
||||||
Transceiver::Transceiver(int wBasePort,
|
Transceiver::Transceiver(int wBasePort,
|
||||||
const char *TRXAddress,
|
const char *TRXAddress,
|
||||||
@@ -54,7 +55,7 @@ Transceiver::Transceiver(int wBasePort,
|
|||||||
:mDataSocket(wBasePort+2,TRXAddress,wBasePort+102),
|
:mDataSocket(wBasePort+2,TRXAddress,wBasePort+102),
|
||||||
mControlSocket(wBasePort+1,TRXAddress,wBasePort+101),
|
mControlSocket(wBasePort+1,TRXAddress,wBasePort+101),
|
||||||
mClockSocket(wBasePort,TRXAddress,wBasePort+100),
|
mClockSocket(wBasePort,TRXAddress,wBasePort+100),
|
||||||
mSPSTx(wSPS), mSPSRx(1)
|
mSPSTx(wSPS), mSPSRx(1), mNoises(NOISE_CNT)
|
||||||
{
|
{
|
||||||
GSM::Time startTime(random() % gHyperframe,0);
|
GSM::Time startTime(random() % gHyperframe,0);
|
||||||
|
|
||||||
@@ -78,12 +79,9 @@ Transceiver::Transceiver(int wBasePort,
|
|||||||
mTxFreq = 0.0;
|
mTxFreq = 0.0;
|
||||||
mRxFreq = 0.0;
|
mRxFreq = 0.0;
|
||||||
mPower = -10;
|
mPower = -10;
|
||||||
mEnergyThreshold = INIT_ENERGY_THRSHD;
|
mNoiseLev = 0.0;
|
||||||
prevFalseDetectionTime = startTime;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Transceiver::~Transceiver()
|
Transceiver::~Transceiver()
|
||||||
{
|
{
|
||||||
sigProcLibDestroy();
|
sigProcLibDestroy();
|
||||||
@@ -324,19 +322,20 @@ Transceiver::CorrType Transceiver::expectedCorrType(GSM::Time currTime)
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
|
SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
|
||||||
int &RSSI,
|
int &RSSI,
|
||||||
int &timingOffset)
|
int &timingOffset)
|
||||||
{
|
{
|
||||||
bool needDFE = false;
|
bool needDFE = false;
|
||||||
|
bool success = false;
|
||||||
|
complex amplitude = 0.0;
|
||||||
|
float TOA = 0.0, avg = 0.0;
|
||||||
|
|
||||||
radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
|
radioVector *rxBurst = (radioVector *) mReceiveFIFO->get();
|
||||||
|
|
||||||
if (!rxBurst) return NULL;
|
if (!rxBurst) return NULL;
|
||||||
|
|
||||||
LOG(DEBUG) << "receiveFIFO: read radio vector at time: " << rxBurst->getTime() << ", new size: " << mReceiveFIFO->size();
|
|
||||||
|
|
||||||
int timeslot = rxBurst->getTime().TN();
|
int timeslot = rxBurst->getTime().TN();
|
||||||
|
|
||||||
CorrType corrType = expectedCorrType(rxBurst->getTime());
|
CorrType corrType = expectedCorrType(rxBurst->getTime());
|
||||||
@@ -345,30 +344,15 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
|
|||||||
delete rxBurst;
|
delete rxBurst;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check to see if received burst has sufficient
|
|
||||||
signalVector *vectorBurst = rxBurst;
|
|
||||||
complex amplitude = 0.0;
|
|
||||||
float TOA = 0.0;
|
|
||||||
float avgPwr = 0.0;
|
|
||||||
#ifdef ENERGY_DETECT
|
|
||||||
if (!energyDetect(*vectorBurst, 20 * mSPSRx, mEnergyThreshold, &avgPwr)) {
|
|
||||||
LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
|
|
||||||
double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
|
|
||||||
if (framesElapsed > 50) { // if we haven't had any false detections for a while, lower threshold
|
|
||||||
mEnergyThreshold -= 10.0/10.0;
|
|
||||||
if (mEnergyThreshold < 0.0)
|
|
||||||
mEnergyThreshold = 0.0;
|
|
||||||
|
|
||||||
prevFalseDetectionTime = rxBurst->getTime();
|
signalVector *vectorBurst = rxBurst;
|
||||||
}
|
|
||||||
delete rxBurst;
|
energyDetect(*vectorBurst, 20 * mSPSRx, 0.0, &avg);
|
||||||
return NULL;
|
|
||||||
}
|
// Update noise level
|
||||||
LOG(DEBUG) << "Estimated Energy: " << sqrt(avgPwr) << ", at time " << rxBurst->getTime();
|
mNoiseLev = mNoises.avg();
|
||||||
#endif
|
|
||||||
// run the proper correlator
|
// run the proper correlator
|
||||||
bool success = false;
|
|
||||||
if (corrType==TSC) {
|
if (corrType==TSC) {
|
||||||
LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
|
LOG(DEBUG) << "looking for TSC at time: " << rxBurst->getTime();
|
||||||
signalVector *channelResp;
|
signalVector *channelResp;
|
||||||
@@ -396,10 +380,7 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
|
|||||||
&channelResp,
|
&channelResp,
|
||||||
&chanOffset);
|
&chanOffset);
|
||||||
if (success) {
|
if (success) {
|
||||||
LOG(DEBUG) << "FOUND TSC!!!!!! " << amplitude << " " << TOA;
|
SNRestimate[timeslot] = amplitude.norm2()/(mNoiseLev*mNoiseLev+1.0); // this is not highly accurate
|
||||||
mEnergyThreshold -= 1.0F/10.0F;
|
|
||||||
if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
|
|
||||||
SNRestimate[timeslot] = amplitude.norm2()/(mEnergyThreshold*mEnergyThreshold+1.0); // this is not highly accurate
|
|
||||||
if (estimateChannel) {
|
if (estimateChannel) {
|
||||||
LOG(DEBUG) << "estimating channel...";
|
LOG(DEBUG) << "estimating channel...";
|
||||||
channelResponse[timeslot] = channelResp;
|
channelResponse[timeslot] = channelResp;
|
||||||
@@ -412,29 +393,17 @@ SoftVector *Transceiver::pullRadioVector(GSM::Time &wTime,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
|
|
||||||
LOG(DEBUG) << "wTime: " << rxBurst->getTime() << ", pTime: " << prevFalseDetectionTime << ", fElapsed: " << framesElapsed;
|
|
||||||
mEnergyThreshold += 10.0F/10.0F*exp(-framesElapsed);
|
|
||||||
prevFalseDetectionTime = rxBurst->getTime();
|
|
||||||
channelResponse[timeslot] = NULL;
|
channelResponse[timeslot] = NULL;
|
||||||
|
mNoises.insert(sqrt(avg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// RACH burst
|
// RACH burst
|
||||||
success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &litude, &TOA);
|
if (success = detectRACHBurst(*vectorBurst, 6.0, mSPSRx, &litude, &TOA))
|
||||||
if (success) {
|
channelResponse[timeslot] = NULL;
|
||||||
LOG(DEBUG) << "FOUND RACH!!!!!! " << amplitude << " " << TOA;
|
else
|
||||||
mEnergyThreshold -= (1.0F/10.0F);
|
mNoises.insert(sqrt(avg));
|
||||||
if (mEnergyThreshold < 0.0) mEnergyThreshold = 0.0;
|
|
||||||
channelResponse[timeslot] = NULL;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
double framesElapsed = rxBurst->getTime()-prevFalseDetectionTime;
|
|
||||||
mEnergyThreshold += (1.0F/10.0F)*exp(-framesElapsed);
|
|
||||||
prevFalseDetectionTime = rxBurst->getTime();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
LOG(DEBUG) << "energy Threshold = " << mEnergyThreshold;
|
|
||||||
|
|
||||||
// demodulate burst
|
// demodulate burst
|
||||||
SoftVector *burst = NULL;
|
SoftVector *burst = NULL;
|
||||||
@@ -542,13 +511,12 @@ void Transceiver::driveControl()
|
|||||||
int newGain;
|
int newGain;
|
||||||
sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
|
sscanf(buffer,"%3s %s %d",cmdcheck,command,&newGain);
|
||||||
newGain = mRadioInterface->setRxGain(newGain);
|
newGain = mRadioInterface->setRxGain(newGain);
|
||||||
mEnergyThreshold = INIT_ENERGY_THRSHD;
|
|
||||||
sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
|
sprintf(response,"RSP SETRXGAIN 0 %d",newGain);
|
||||||
}
|
}
|
||||||
else if (strcmp(command,"NOISELEV")==0) {
|
else if (strcmp(command,"NOISELEV")==0) {
|
||||||
if (mOn) {
|
if (mOn) {
|
||||||
sprintf(response,"RSP NOISELEV 0 %d",
|
sprintf(response,"RSP NOISELEV 0 %d",
|
||||||
(int) round(20.0*log10(rxFullScale/mEnergyThreshold)));
|
(int) round(20.0*log10(rxFullScale/mNoiseLev)));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sprintf(response,"RSP NOISELEV 1 0");
|
sprintf(response,"RSP NOISELEV 1 0");
|
||||||
|
@@ -92,6 +92,8 @@ private:
|
|||||||
IGPRS ///< GPRS channel, like I but static filler frames.
|
IGPRS ///< GPRS channel, like I but static filler frames.
|
||||||
} ChannelCombination;
|
} ChannelCombination;
|
||||||
|
|
||||||
|
float mNoiseLev; ///< Average noise level
|
||||||
|
noiseVector mNoises; ///< Vector holding running noise measurements
|
||||||
|
|
||||||
/** unmodulate a modulated burst */
|
/** unmodulate a modulated burst */
|
||||||
#ifdef TRANSMIT_LOGGING
|
#ifdef TRANSMIT_LOGGING
|
||||||
@@ -129,8 +131,6 @@ private:
|
|||||||
double mRxFreq; ///< the receive frequency
|
double mRxFreq; ///< the receive frequency
|
||||||
int mPower; ///< the transmit power in dB
|
int mPower; ///< the transmit power in dB
|
||||||
unsigned mTSC; ///< the midamble sequence code
|
unsigned mTSC; ///< the midamble sequence code
|
||||||
double mEnergyThreshold; ///< threshold to determine if received data is potentially a GSM burst
|
|
||||||
GSM::Time prevFalseDetectionTime; ///< last timestamp of a false energy detection
|
|
||||||
int fillerModulus[8]; ///< modulus values of all timeslots, in frames
|
int fillerModulus[8]; ///< modulus values of all timeslots, in frames
|
||||||
signalVector *fillerTable[102][8]; ///< table of modulated filler waveforms for all timeslots
|
signalVector *fillerTable[102][8]; ///< table of modulated filler waveforms for all timeslots
|
||||||
unsigned mMaxExpectedDelay; ///< maximum expected time-of-arrival offset in GSM symbols
|
unsigned mMaxExpectedDelay; ///< maximum expected time-of-arrival offset in GSM symbols
|
||||||
|
@@ -41,6 +41,35 @@ bool radioVector::operator>(const radioVector& other) const
|
|||||||
return mTime > other.mTime;
|
return mTime > other.mTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
noiseVector::noiseVector(size_t n)
|
||||||
|
{
|
||||||
|
this->resize(n);
|
||||||
|
it = this->begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
float noiseVector::avg()
|
||||||
|
{
|
||||||
|
float val = 0.0;
|
||||||
|
|
||||||
|
for (int i = 0; i < size(); i++)
|
||||||
|
val += (*this)[i];
|
||||||
|
|
||||||
|
return val / (float) size();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool noiseVector::insert(float val)
|
||||||
|
{
|
||||||
|
if (!size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (it == this->end())
|
||||||
|
it = this->begin();
|
||||||
|
|
||||||
|
*it++ = val;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
unsigned VectorFIFO::size()
|
unsigned VectorFIFO::size()
|
||||||
{
|
{
|
||||||
return mQ.size();
|
return mQ.size();
|
||||||
|
@@ -36,6 +36,16 @@ private:
|
|||||||
GSM::Time mTime;
|
GSM::Time mTime;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class noiseVector : std::vector<float> {
|
||||||
|
public:
|
||||||
|
noiseVector(size_t len = 0);
|
||||||
|
bool insert(float val);
|
||||||
|
float avg();
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<float>::iterator it;
|
||||||
|
};
|
||||||
|
|
||||||
class VectorFIFO {
|
class VectorFIFO {
|
||||||
public:
|
public:
|
||||||
unsigned size();
|
unsigned size();
|
||||||
|
Reference in New Issue
Block a user