Added brute force algorithm for phase/gain correction. Added more parameters for calibration.

git-svn-id: http://yate.null.ro/svn/yate/trunk@6005 acf43c95-373e-0410-b603-e72c3f656dc1
This commit is contained in:
marian 2015-07-16 14:53:56 +00:00
parent 837195edd4
commit 4a6b823a77
1 changed files with 203 additions and 123 deletions

View File

@ -1335,7 +1335,7 @@ private:
return status ? status : lmsWrite(addr,data | val,error);
}
// Read address from LMS, clear mask and write it back
inline unsigned int lmsReset(uint8_t addr, uint8_t clearMask, String* error) {
inline unsigned int lmsReset(uint8_t addr, uint8_t clearMask, String* error = 0) {
uint8_t data = 0;
unsigned int status = lmsRead(addr,data,error);
return status ? status : lmsWrite(addr,(data & ~clearMask),error);
@ -1472,9 +1472,12 @@ private:
unsigned int readComputeDcOffsetsCorr(int* corr, float* powerBalance, float* buf,
unsigned int samples, String* error, float& totalPower, float& rxDcOffset);
void calibrateBBStarting(const char* what);
unsigned int calibrateBBTxDc(int& dcI, int& dcQ, String* error);
unsigned int calibrateBBTxPhase(int& corr, String* error);
unsigned int calibrateBBTxGain(float& corr, String* error);
unsigned int calibrateBBTxDc(int& dcI, int& dcQ, float* buf, unsigned int samples,
String* error);
unsigned int calibrateBBTxPhase(bool bruteForce, int& corr, float* buf, unsigned int samples,
String* error);
unsigned int calibrateBBTxGain(bool bruteForce, float& corr, float* buf, unsigned int samples,
String* error);
unsigned int calibrateBB(String* error);
// Set error string or put a debug message
unsigned int showError(unsigned int code, const char* error, const char* prefix,
@ -5784,7 +5787,7 @@ unsigned int BrfLibUsbDevice::dummyRead(float* buf, unsigned int samples, String
m_rxIO.checkTs = 0;
unsigned int status = syncTxStatus(DevStatTs,0,error);
if (!status)
status = readBuffer(m_txIO.syncTs + 20 * samples,buf,samples,error);
status = readBuffer(m_txIO.syncTs + 3 * samples,buf,samples,error);
m_rxIO.checkTs = oldTsCheck;
return status;
}
@ -5814,13 +5817,10 @@ static inline void cxMult(const float i1, const float q1, const float i2, const
static void calculateDcOffsets(BrfLibUsbDevice* dev, float* input, unsigned samples,
float& totalPower, float& rxDcOffset, float* txDcOffset = 0)
{
if ((samples % 8) != 0)
Debug(dev->owner(),DebugFail,"Buffer samples (%u) should be multiple of 8 [%p]",
if ((samples % 4) != 0)
Debug(dev->owner(),DebugFail,"Buffer samples (%u) should be multiple of 4 [%p]",
samples,dev->owner());
// number of complex samples in the buffer
unsigned Ns = samples / 2;
// one cycle of a -pi/4 complex sinusoid
// note that is NOT the same as the test tone cycle array
static const float ci[4] = {+1,0,-1,0};
@ -5833,24 +5833,24 @@ static void calculateDcOffsets(BrfLibUsbDevice* dev, float* input, unsigned samp
float sumTxQ = 0.0F;
float* ip = input;
// note that i counts complex pairs, not floats
for (unsigned i = 0; i < Ns; i++) {
for (unsigned i = 0; i < samples; i++) {
const float vi = *ip++;
const float vq = *ip++;
sumE += vi * vi + vq * vq;
sumRxI += vi;
sumRxQ += vq;
float si, sq;
cxMult(vi,vq,ci[i%4],cq[i%4],si,sq);
cxMult(vi,vq,ci[i % 4],cq[i % 4],si,sq);
sumTxI += si;
sumTxQ += sq;
}
totalPower = sumE / Ns;
float meanRxI = sumRxI / Ns;
float meanRxQ = sumRxQ / Ns;
totalPower = sumE / samples;
float meanRxI = sumRxI / samples;
float meanRxQ = sumRxQ / samples;
rxDcOffset = meanRxI * meanRxI + meanRxQ * meanRxQ;
if (txDcOffset) {
float meanTxI = sumTxI / Ns;
float meanTxQ = sumTxQ / Ns;
float meanTxI = sumTxI / samples;
float meanTxQ = sumTxQ / samples;
*txDcOffset = meanTxI * meanTxI+meanTxQ * meanTxQ;
}
}
@ -5864,7 +5864,7 @@ unsigned int BrfLibUsbDevice::readComputeDcOffsets(uint8_t dcI, uint8_t dcQ,
m_txIO.syncStatus.dcOffsetI = decodeDCOffs(true,dcI);
m_txIO.syncStatus.dcOffsetQ = decodeDCOffs(true,dcQ);
BRF_FUNC_CALL_RET(syncTxStatus(DevStatTs | DevStatDc,0,error));
BRF_FUNC_CALL_RET(readBuffer(m_txIO.syncTs + 10 * samples,buf,samples,error));
BRF_FUNC_CALL_RET(readBuffer(m_txIO.syncTs + 3 * samples,buf,samples,error));
calculateDcOffsets(this,buf,samples,totalPower,rxDcOffset,&txDcOffset);
return 0;
}
@ -5886,7 +5886,7 @@ unsigned int BrfLibUsbDevice::readComputeDcOffsetsCorr(int* corr, float* powerBa
else
return showError(RadioInterface::OutOfRange,
"readComputeDcOffsetsCorr: invalid params",0,0,DebugFail);
BRF_FUNC_CALL_RET(readBuffer(m_txIO.syncTs + 10 * samples,buf,samples,error));
BRF_FUNC_CALL_RET(readBuffer(m_txIO.syncTs + 3 * samples,buf,samples,error));
calculateDcOffsets(this,buf,samples,totalPower,rxDcOffset);
return 0;
}
@ -5947,7 +5947,8 @@ struct BBDirChg
uint8_t dirNotChgMax;
};
unsigned int BrfLibUsbDevice::calibrateBBTxDc(int& dcI, int& dcQ, String* error)
unsigned int BrfLibUsbDevice::calibrateBBTxDc(int& dcI, int& dcQ, float* buf,
unsigned int samples, String* error)
{
//#define BRF_BB_TX_DC_TRACE
BrfDuration duration;
@ -5955,9 +5956,6 @@ unsigned int BrfLibUsbDevice::calibrateBBTxDc(int& dcI, int& dcQ, String* error)
calibrateBBStarting(oper);
dcI = 128;
dcQ = 128;
unsigned int samples = m_rxIO.bufSamples * m_rxIO.buffers;
DataBlock d(0,samplesf2bytes(samples));
float* buf = (float*)d.data(0);
int tmpDcI = 0;
int tmpDcQ = 0;
float power = 0;
@ -6036,7 +6034,8 @@ unsigned int BrfLibUsbDevice::calibrateBBTxDc(int& dcI, int& dcQ, String* error)
return showError(status,e,0,error);
}
unsigned int BrfLibUsbDevice::calibrateBBTxPhase(int& corr, String* error)
unsigned int BrfLibUsbDevice::calibrateBBTxPhase(bool bruteForce, int& corr, float* buf,
unsigned int samples, String* error)
{
//#define BRF_BB_PHASE_TRACE
BrfDuration duration;
@ -6044,68 +6043,92 @@ unsigned int BrfLibUsbDevice::calibrateBBTxPhase(int& corr, String* error)
calibrateBBStarting(oper);
m_txIO.showFpgaPhaseChange++;
corr = 0;
unsigned int samples = m_rxIO.bufSamples * m_rxIO.buffers;
DataBlock d(0,samplesf2bytes(samples));
float* buf = (float*)d.data(0);
float power = 0;
float rxDc = 0;
#if 0
unsigned int innerLoops[] = {BRF_FPGA_CORR_MAX,100,50,15};
unsigned int steps[] = {100,5,5,1};
uint8_t dirNotChgStop[] = {25,10,3,0};
#else
unsigned int innerLoops[] = {BRF_FPGA_CORR_MAX,99};
unsigned int steps[] = {100,1};
uint8_t dirNotChgStop[] = {25,25};
#endif
String e;
unsigned int status = dummyRead(buf,samples,&e);
if (!status)
status = readComputeDcOffsetsCorr(&corr,0,buf,samples,&e,power,rxDc);
float imagePower = power - rxDc;
float lastImage = imagePower;
if (bruteForce) {
float imagePower = (float)0xffffffffffffffff;
#ifdef BRF_BB_PHASE_TRACE
Output("Starting with power=%g rxDC=%g image=%g",power,rxDc,imagePower);
Output("Starting BRUTE FORCE image=%g",imagePower);
unsigned int n = 0;
#endif
for (unsigned int i = 0; !status && i < BRF_ARRAY_LEN(innerLoops); i++) {
int v = clampInt(corr + innerLoops[i],-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
int minV = clampInt(corr - innerLoops[i],-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
#ifdef BRF_BB_PHASE_TRACE
Output("Loop %u: best=%d interval=[%d..%d] step=%u",i,corr,minV,v,steps[i]);
#endif
BBDirChg dirChg(dirNotChgStop[i]);
unsigned int nMax = innerLoops[i] * 2 + 1;
for (unsigned int n = 0; n < nMax; n++) {
status = readComputeDcOffsetsCorr(&v,0,buf,samples,&e,power,rxDc);
int i = status ? (BRF_FPGA_CORR_MAX + 1) : -BRF_FPGA_CORR_MAX;
for (; i <= BRF_FPGA_CORR_MAX; i++) {
status = readComputeDcOffsetsCorr(&i,0,buf,samples,&e,power,rxDc);
if (status)
break;
float image = power - rxDc;
int8_t dir = 0;
updateBBResult(dir,lastImage,image,n == 0);
// First loop set dir to 'equal', avoid direction change in second loop
if (n == 1)
dirChg.lastDir = dir;
#ifdef BRF_BB_PHASE_TRACE
String dump;
dump.printf(" %-5d\tpower=%.6f\trxDC=%.6f\timage=%.6f\t%s",
v,power,rxDc,image,dirStr(dir));
if (imagePower > image)
dump << "\t" << corr << " -> " << v;
Output("%s",dump.c_str());
n++;
if (n < 10)
Output(" %-5d\tbest=%d\tpower=%.6f\trxDC=%.6f\timage=%.6f",i,corr,power,rxDc,image);
else if ((n % 500) == 0)
Output(" %-5d\tbest=%d",i,corr);
#endif
if (imagePower > image) {
imagePower = image;
corr = v;
if (imagePower <= image)
continue;
imagePower = image;
corr = i;
}
}
else {
if (!status)
status = readComputeDcOffsetsCorr(&corr,0,buf,samples,&e,power,rxDc);
float imagePower = power - rxDc;
float lastImage = imagePower;
#if 0
unsigned int innerLoops[] = {BRF_FPGA_CORR_MAX,200,10};
unsigned int steps[] = {200,10,1};
uint8_t dirNotChgStop[] = {20,0,0};
#else
unsigned int innerLoops[] = {BRF_FPGA_CORR_MAX,99};
unsigned int steps[] = {50,1};
uint8_t dirNotChgStop[] = {50,0};
#endif
#ifdef BRF_BB_PHASE_TRACE
Output("Starting with power=%g rxDC=%g image=%g",power,rxDc,imagePower);
#endif
for (unsigned int i = 0; !status && i < BRF_ARRAY_LEN(innerLoops); i++) {
int v = clampInt(corr + innerLoops[i],-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
int minV = clampInt(corr - innerLoops[i],-BRF_FPGA_CORR_MAX,BRF_FPGA_CORR_MAX);
#ifdef BRF_BB_PHASE_TRACE
Output("Loop %u: best=%d interval=[%d..%d] step=%u",i,corr,minV,v,steps[i]);
#endif
BBDirChg dirChg(dirNotChgStop[i]);
unsigned int nMax = innerLoops[i] * 2 + 1;
for (unsigned int n = 0; n < nMax; n++) {
status = readComputeDcOffsetsCorr(&v,0,buf,samples,&e,power,rxDc);
if (status)
break;
float image = power - rxDc;
int8_t dir = 0;
updateBBResult(dir,lastImage,image,n == 0);
// First loop set dir to 'equal', avoid direction change in second loop
if (n == 1)
dirChg.lastDir = dir;
#ifdef BRF_BB_PHASE_TRACE
String dump;
dump.printf(" %-5d\tpower=%.6f\trxDC=%.6f\timage=%.6f\t%s",
v,power,rxDc,image,dirStr(dir));
if (imagePower > image)
dump << "\t" << corr << " -> " << v;
Output("%s",dump.c_str());
#endif
if (imagePower > image) {
imagePower = image;
corr = v;
}
if (!dirChg.update(dir))
break;
int tmp = v - steps[i];
if (tmp >= minV)
v = tmp;
else if ((minV - tmp) < (int)steps[i])
v = minV;
else
break;
}
if (!dirChg.update(dir))
break;
int tmp = v - steps[i];
if (tmp >= minV)
v = tmp;
else if ((minV - tmp) < (int)steps[i])
v = minV;
else
break;
}
}
duration.stop();
@ -6119,7 +6142,8 @@ unsigned int BrfLibUsbDevice::calibrateBBTxPhase(int& corr, String* error)
return showError(status,e,0,error);
}
unsigned int BrfLibUsbDevice::calibrateBBTxGain(float& corr, String* error)
unsigned int BrfLibUsbDevice::calibrateBBTxGain(bool bruteForce, float& corr, float* buf,
unsigned int samples, String* error)
{
//#define BRF_BB_GAIN_TRACE
BrfDuration duration;
@ -6127,55 +6151,83 @@ unsigned int BrfLibUsbDevice::calibrateBBTxGain(float& corr, String* error)
calibrateBBStarting(oper);
m_txIO.showPowerBalanceChange++;
corr = 1;
unsigned int samples = m_rxIO.bufSamples * m_rxIO.buffers;
DataBlock d(0,samplesf2bytes(samples));
float* buf = (float*)d.data(0);
float power = 0;
float rxDc = 0;
#if 0
float innerBounds[] = {1,0.5,0.2,0.1,0.05};
float innerIntervals[] = {10,20,20,20,100};
#else
float innerBounds[] = {0.1,0.01,0.001};
float innerIntervals[] = {10,100,100};
#endif
String e;
unsigned int status = dummyRead(buf,samples,&e);
if (!status)
status = readComputeDcOffsetsCorr(0,&corr,buf,samples,&e,power,rxDc);
float imagePower = power - rxDc;
float lastImage = imagePower;
if (bruteForce) {
// Brute force
float imagePower = (float)0xffffffffffffffff;
float crt = 0.9;
float step = 0.0005;
#ifdef BRF_BB_GAIN_TRACE
Output("Starting with power=%g rxDC=%g image=%g",power,rxDc,imagePower);
Output("Starting BRUTE FORCE start=%g step=%g image=%g",crt,step,imagePower);
unsigned int n = 0;
#endif
for (unsigned int i = 0; !status && i < BRF_ARRAY_LEN(innerBounds); i++) {
float crt = corr + innerBounds[i];
if (crt >= 2)
crt = 1.999999;
unsigned int intervals = innerIntervals[i] + 1;
float step = innerBounds[i] * 2 / intervals;
#ifdef BRF_BB_GAIN_TRACE
Output("Loop %u: best=%g corrStart=%g intervals=%u step=%g",i,corr,crt,intervals,step);
#endif
BBDirChg dirChg(0);
for (unsigned int n = 0; n < intervals && crt > 0; n++, crt -= step) {
if (status)
crt = 3;
for (; crt < 1.1; crt += step) {
status = readComputeDcOffsetsCorr(0,&crt,buf,samples,&e,power,rxDc);
if (status)
break;
float image = power - rxDc;
int8_t dir = 0;
updateBBResult(dir,lastImage,image,n == 0);
#ifdef BRF_BB_GAIN_TRACE
String dump;
dump.printf(" %.6f\tpower=%.6f\trxDC=%.6f\timage=%.6f\t%s",
crt,power,rxDc,image,dirStr(dir));
if (imagePower > image)
dump << "\t" << corr << " -> " << crt;
Output("%s",dump.c_str());
n++;
if (n < 10)
Output(" %g\t\tbest=%g\tpower=%.6f\trxDC=%.6f\timage=%.6f",crt,corr,power,rxDc,image);
else if ((n % 30) == 0)
Output(" %g\tbest=%g",crt,corr);
#endif
if (imagePower > image) {
imagePower = image;
corr = crt;
if (imagePower <= image)
continue;
imagePower = image;
corr = crt;
}
}
else {
if (!status)
status = readComputeDcOffsetsCorr(0,&corr,buf,samples,&e,power,rxDc);
float imagePower = power - rxDc;
float lastImage = imagePower;
#if 0
float innerBounds[] = {1,0.5,0.2,0.1,0.05};
unsigned int innerIntervals[] = {10,20,20,20,100};
#else
float innerBounds[] = {0.1,0.01};
unsigned int innerIntervals[] = {500,100};
#endif
#ifdef BRF_BB_GAIN_TRACE
Output("Starting with power=%g rxDC=%g image=%g",power,rxDc,imagePower);
#endif
for (unsigned int i = 0; !status && i < BRF_ARRAY_LEN(innerBounds); i++) {
float crt = corr + innerBounds[i];
if (crt >= 2)
crt = 1.999999;
unsigned int intervals = innerIntervals[i] + 1;
float step = innerBounds[i] * 2 / intervals;
#ifdef BRF_BB_GAIN_TRACE
Output("Loop %u: best=%g corrStart=%g intervals=%u step=%.5f",i,corr,crt,intervals,step);
#endif
BBDirChg dirChg(0);
for (unsigned int n = 0; n < intervals && crt > 0; n++, crt -= step) {
status = readComputeDcOffsetsCorr(0,&crt,buf,samples,&e,power,rxDc);
if (status)
break;
float image = power - rxDc;
int8_t dir = 0;
updateBBResult(dir,lastImage,image,n == 0);
#ifdef BRF_BB_GAIN_TRACE
String dump;
dump.printf(" %.6f\tpower=%.6f\trxDC=%.6f\timage=%.6f\t%s",
crt,power,rxDc,image,dirStr(dir));
if (imagePower > image)
dump << "\t" << corr << " -> " << crt;
Output("%s",dump.c_str());
#endif
if (imagePower > image) {
imagePower = image;
corr = crt;
}
}
}
}
@ -6207,13 +6259,23 @@ unsigned int BrfLibUsbDevice::calibrateBB(String* error)
bool lowBand = brfIsLowBand(txOld.frequency);
int lp = lowBand ? LoopRfLna1 : LoopRfLna2;
const char* pattern = "circle";
const char* lmsWr = 0;
bool twice = true;
bool bruteForce = true;
unsigned int samples = m_rxIO.bufSamples * m_rxIO.buffers;
NamedList p("calibrate-bb");
loadCfg(false,&p);
if (p.c_str()) {
lp = lookup(p["loopback"],s_loopback,lp);
paOn = p.getBoolValue("transmit");
pattern = p.getValue("txpattern",pattern);
lmsWr = p.getValue("lms-write");
twice = p.getBoolValue("phase-gain-twice",true);
bruteForce = p.getBoolValue("phase-gain-bruteforce",true);
samples = p.getIntValue("samples",samples,512);
}
if ((samples % 4) != 0)
samples = 4 * (samples + 3) / 4;
BRF_FUNC_CALL_BREAK(internalSetLoopback(lp,&e));
// Set VGA
BRF_FUNC_CALL_BREAK(internalSetVga(true,-14,true,&e));
@ -6226,8 +6288,13 @@ unsigned int BrfLibUsbDevice::calibrateBB(String* error)
if (paOn)
BRF_FUNC_CALL_BREAK(selectPaLna(true,lowBand,&e));
setTxPattern(pattern);
// dumpLoopbackStatus();
// dumpLmsModulesStatus();
if (lmsWr)
lmsWrite(lmsWr);
//dumpLoopbackStatus();
//dumpLmsModulesStatus();
//internalDumpPeripheral(UartDevLMS,0,128,0,16);
// Start sending thread
m_sendThread = (new BrfThread(this))->start();
if (!m_sendThread) {
@ -6235,33 +6302,46 @@ unsigned int BrfLibUsbDevice::calibrateBB(String* error)
e << "Failed to start send data thread";
break;
}
unsigned int Fc = 850000000;
m_calibration.assign("");
m_calibration.clearParams();
DataBlock d(0,samplesf2bytes(samples));
float* buf = (float*)d.data(0);
int dcI = 0;
int dcQ = 0;
int phase = 0;
float corrBalance = 0;
Debug(m_owner,DebugAll,"BB calibration: samples=%u Fc=%u samplerate=%u [%p]",
samples,Fc,m_txIO.sampleRate,m_owner);
// Calibrate TX DC
m_txIO.syncStatus.frequency = Fc + m_txIO.sampleRate / 4;
m_rxIO.syncStatus.frequency = Fc;
BRF_FUNC_CALL_BREAK(syncTxStatus(DevStatFreq,DevStatFreq,&e));
int dcI = 0;
int dcQ = 0;
BRF_FUNC_CALL_BREAK(calibrateBBTxDc(dcI,dcQ,&e));
BRF_FUNC_CALL_BREAK(calibrateBBTxDc(dcI,dcQ,buf,samples,&e));
BRF_FUNC_CALL_BREAK(internalSetCorrectionIQ(true,dcI,dcQ,&e));
// Calibrate TX FPGA PHASE
m_txIO.syncStatus.frequency = Fc;
m_rxIO.syncStatus.frequency = Fc - m_txIO.sampleRate / 2;
BRF_FUNC_CALL_BREAK(syncTxStatus(DevStatFreq,DevStatFreq,&e));
int phase = 0;
BRF_FUNC_CALL_BREAK(calibrateBBTxPhase(phase,&e));
BRF_FUNC_CALL_BREAK(calibrateBBTxPhase(bruteForce,phase,buf,samples,&e));
BRF_FUNC_CALL_BREAK(internalSetFpgaCorr(true,CorrFpgaPhase,phase,&e));
// Calibrate TX power balance
float corrBalance = 0;
BRF_FUNC_CALL_BREAK(calibrateBBTxGain(corrBalance,&e));
BRF_FUNC_CALL_BREAK(calibrateBBTxGain(bruteForce,corrBalance,buf,samples,&e));
BRF_FUNC_CALL_BREAK(internalSetTxIQBalance(false,corrBalance));
//
if (twice) {
BRF_FUNC_CALL_BREAK(calibrateBBTxPhase(bruteForce,phase,buf,samples,&e));
BRF_FUNC_CALL_BREAK(internalSetFpgaCorr(true,CorrFpgaPhase,phase,&e));
// Calibrate TX power balance
BRF_FUNC_CALL_BREAK(calibrateBBTxGain(bruteForce,corrBalance,buf,samples,&e));
BRF_FUNC_CALL_BREAK(internalSetTxIQBalance(false,corrBalance));
}
m_calibration.assign(String(Fc));
m_calibration.addParam("tx_dc_i",String(dcI));
m_calibration.addParam("tx_dc_q",String(dcQ));
m_calibration.addParam("tx_phase",String(phase));
m_calibration.addParam("tx_fpga_corr_phase",String(phase));
m_calibration.addParam("tx_powerbalance",String(corrBalance));
break;
}