ExpressLRS开源之基本调试数据含义
ExpressLRS开源之基本调试数据含义
- 1. 源由
- 2. 代码
- 2.1 debugRcvrLinkstats
- 2.2 debugRcvrSignalStats
- 3. 含义解释
- 3.1 ID(packetCounter),Antenna,RSSI(dBm),LQ,SNR,PWR,FHSS,TimingOffset
- 3.2 IRQ_CNT,RSSI_AVE,SNR_AVE,SNV_MAX,TELEM_CNT,FAIL_CNT
- 4. 总结
- 5. 参考资料
1. 源由
基于ExpressLRS开源代码对基本调试验证数据进行详细的研读理解,以期望更深入的理解相关数据的实际含义。
ID(packetCounter),Antenna,RSSI(dBm),LQ,SNR,PWR,FHSS,TimingOffset
IRQ_CNT,RSSI_AVE,SNR_AVE,SNV_MAX,TELEM_CNT,FAIL_CNT
2. 代码
2.1 debugRcvrLinkstats
static void debugRcvrLinkstats()
{
#if defined(DEBUG_RCVR_LINKSTATS)if (debugRcvrLinkstatsPending){debugRcvrLinkstatsPending = false;// Copy the data out of the ISR-updating bits ASAP// While YOLOing (const void *) away the volatilecrsfLinkStatistics_t ls = *(crsfLinkStatistics_t *)((const void *)&CRSF::LinkStatistics);uint32_t packetCounter = debugRcvrLinkstatsPacketId;uint8_t fhss = debugRcvrLinkstatsFhssIdx;// actually the previous packet's offset since the update happens in tick, and this will// fire right after packet reception (a little before tock)int32_t pfd = PfdPrevRawOffset;// Use serial instead of DBG() because do not necessarily want all the debug in our logschar buf[50];snprintf(buf, sizeof(buf), "%u,%u,-%u,%u,%d,%u,%u,%d\r\n",packetCounter, ls.active_antenna,ls.active_antenna ? ls.uplink_RSSI_2 : ls.uplink_RSSI_1,ls.uplink_Link_quality, ls.uplink_SNR,ls.uplink_TX_Power, fhss, pfd);Serial.write(buf);}
#endif
}
2.2 debugRcvrSignalStats
static void debugRcvrSignalStats(uint32_t now)
{
#if defined(DEBUG_RCVR_SIGNAL_STATS)static uint32_t lastReport = 0;// log column header: cnt1, rssi1, snr1, snr1_max, telem1, fail1, cnt2, rssi2, snr2, snr2_max, telem2, fail2, or, bothif(now - lastReport >= 1000 && connectionState == connected){for (int i = 0 ; i < (isDualRadio()?2:1) ; i++){DBG("%d\t%f\t%f\t%f\t%d\t%d\t",Radio.rxSignalStats[i].irq_count,(Radio.rxSignalStats[i].irq_count==0) ? 0 : double(Radio.rxSignalStats[i].rssi_sum)/Radio.rxSignalStats[i].irq_count,(Radio.rxSignalStats[i].irq_count==0) ? 0 : double(Radio.rxSignalStats[i].snr_sum)/Radio.rxSignalStats[i].irq_count/RADIO_SNR_SCALE,float(Radio.rxSignalStats[i].snr_max)/RADIO_SNR_SCALE,Radio.rxSignalStats[i].telem_count,Radio.rxSignalStats[i].fail_count);Radio.rxSignalStats[i].irq_count = 0;Radio.rxSignalStats[i].snr_sum = 0;Radio.rxSignalStats[i].rssi_sum = 0;Radio.rxSignalStats[i].snr_max = INT8_MIN;Radio.rxSignalStats[i].telem_count = 0;Radio.rxSignalStats[i].fail_count = 0;}if (isDualRadio()){DBGLN("%d\t%d", Radio.irq_count_or, Radio.irq_count_both);}else{DBGLN("");}Radio.irq_count_or = 0;Radio.irq_count_both = 0;lastReport = now;}
#endif
}
3. 含义解释
对于debug给出参数含义解释,有助于理解性能测试结果。
ID(packetCounter),Antenna,RSSI(dBm),LQ,SNR,PWR,FHSS,TimingOffset
IRQ_CNT,RSSI_AVE,SNR_AVE,SNV_MAX,TELEM_CNT,FAIL_CNT
3.1 ID(packetCounter),Antenna,RSSI(dBm),LQ,SNR,PWR,FHSS,TimingOffset
- ID(packetCounter):报文ID(递增,需打开Tx发射端DEBUG_RCVR_LINKSTATS)
报文ID是在发射机发射信号是递增,接收机解析报文是获取ID信息的。
//接收机
OtaUpdateSerializers├──> UnpackChannelDataHybridSwitch8/UnpackChannelDataHybridWide│ └──> UnpackChannelDataHybridCommon - ota4->dbg_linkstats.packetNum│ └──> debugRcvrLinkstatsPacketId│ └──> packetCounter└──> UnpackChannelData8ch - ota8->dbg_linkstats.packetNum└──> debugRcvrLinkstatsPacketId└──> packetCounter//发射机
OtaUpdateSerializers└──> GenerateChannelData8ch/GenerateChannelData12ch└──> GenerateChannelData8ch12ch└──> <DEBUG_RCVR_LINKSTATS> ota8->dbg_linkstats.packetNum = packetCnt++
- Antenna:天线编号(0或1)
目前,天线配置方面有以下几种工作模式:
- Basic:一根天线
- Antenna Diversity:两根天线,其中一根天线接收信号
- True Diversity:两根天线,同时接收信号
- Gemini:两根天线,同时接收信号,并且工作在两个不同的频点。
- RSSI(dBm):信号强度,单位dBm
分贝毫瓦简写为dBm或dBmW,是一个表示绝对功率的量。
uplink_RSSI_1/uplink_RSSI_2└──> rssiDBM└──> LastPacketRSSI└──> GetLastPacketRSSI/GetLastPacketStats└──> readRegister(SX127X_REG_PKT_RSSI_VALUE)/ReadCommand(SX1280_RADIO_GET_PACKETSTATUS)
- LQ(Link Quality):链路质量
链路接收到数据包与预期数据包的百分比,表示信号中丢包的概率。
uplink_Link_quality└──> uplinkLQ└──> LQCalc.getLQ()/LQCalcDVDA.getLQ()
- SNR(Signal-to-noise ratio):信噪比
信号与干扰加噪声比 (Signal to Interference plus Noise Ratio)是指接收到的有用信号的强度与接收到的干扰信号(噪声和干扰)的强度的比值。
uplink_SNR└──> LastPacketSNRRaw└──> GetLastPacketSNRRaw/GetLastPacketStats└──> readRegister(SX127X_REG_PKT_SNR_VALUE)/ReadCommand(SX1280_RADIO_GET_PACKETSTATUS)
- PWR(Power):功率
发射机工作时的发射功率。
RX::uplink_TX_Power└──> RX::UnpackChannelData8ch/UnpackChannelDataHybridWide└──> TX::GenerateChannelDataHybridWide/GenerateChannelData8ch12ch└──> TX::CurrentPower└──> TX::decPower/incPower└──> TX::DynamicPower_Update└──> TX::loop
其对应输出数值与功率之间的对应关系。
uint8_t powerToCrsfPower(PowerLevels_e Power)
{// Crossfire's power levels as defined in opentx:radio/src/telemetry/crossfire.cpp//static const int32_t power_values[] = { 0, 10, 25, 100, 500, 1000, 2000, 250, 50 };switch (Power){case PWR_10mW: return 1;case PWR_25mW: return 2;case PWR_50mW: return 8;case PWR_100mW: return 3;case PWR_250mW: return 7;case PWR_500mW: return 4;case PWR_1000mW: return 5;case PWR_2000mW: return 6;default:return 0;}
}
- FHSS(Frequency-hopping spread spectrum):跳频频率
FHSS,跳频技术 (Frequency-Hopping Spread Spectrum)在同步、且同时的情况下,接受两端以特定型式的窄频载波来传送讯号,对于一个非特定的接受器,FHSS所产生的跳动讯号对它而言,也只算是脉冲噪声。FHSS所展开的讯号可依特别设计来规避噪声或One-to-Many的非重复的频道,并且这些跳频讯号必须遵守要求。
debugRcvrLinkstatsFhssIdx└──> getRFlinkInfo└──> ProcessRFPacket└──> RXdoneISR└──> setupRadio└──> setup
注:关于跳频方面的设置,详见FHSSrandomiseFHSSsequence
和FHSSgetNextFreq
。
- TimingOffset
这里的时间差是指HWtimerCallbackTock
调用到ProcessRFPacket
报文开始处理的时间差。
PfdPrevRawOffset└──> PFDloop.calcResult() = PFDloop.intEvent(HWtimerCallbackTock) - PFDloop.extEvent(ProcessRFPacket)└──> updatePhaseLock└──> HWtimerCallbackTick└──> setup
3.2 IRQ_CNT,RSSI_AVE,SNR_AVE,SNV_MAX,TELEM_CNT,FAIL_CNT
- IRQ_CNT
接收机收到RF芯片中断的数量。
setup└──> setupRadio└──> RXdoneISR└──> ProcessRFPacket└──> GetLastPacketStats└──> instance->rxSignalStats[i].irq_count++
- RSSI_AVE
接收机平均RSSI信号强度。
double(Radio.rxSignalStats[i].rssi_sum)/Radio.rxSignalStats[i].irq_count
- SNR_AVE
接收机平均SNR信号强度。
double(Radio.rxSignalStats[i].snr_sum)/Radio.rxSignalStats[i].irq_count/RADIO_SNR_SCALE
- SNV_MAX
接收机最大SNR信号强度。
float(Radio.rxSignalStats[i].snr_max)/RADIO_SNR_SCALE
- TELEM_CNT
接收机发送报文数量。
setup└──> HWtimerCallbackTock└──> HandleSendTelemetryResponse└──> TXnb└──> telem_count++
- FAIL_CNT
判断双天线是否第二根天线受到同样的报文,如果没有收到则fail++。
setup└──> setupRadio└──> RXdoneISR└──> ProcessRFPacket└──> GetLastPacketStats└──> fail_count++
4. 总结
通过对上面调试参数含义的分析,在对单/双天线模块配置下:
可以根据以下表格内容进行可选择性的分析比对,详细比对方法请见:
【1】ExpressLRS开源之RC链路性能测试
【2】ExpressLRS开源之接收机固件编译烧录步骤
ID(packetCounter) | Antenna | RSSI(dBm) | LQ | SNR | PWR | FHSS | TimingOffset |
---|---|---|---|---|---|---|---|
报文ID | 天线编号 | 信号强度 | 信号质量 | 信噪比 | 发射功率 | 跳频频率 | 中断时延 |
单、双 | 双 | 单、双 | 单、双 | 单、双 | 单、双 | 单、双 | 单、双 |
IRQ_CNT | RSSI_AVE | SNR_AVE | SNV_MAX | TELEM_CNT | FAIL_CNT |
---|---|---|---|---|---|
中断数量 | 平均信号强度 | 平均信噪比 | 最大信噪比 | 发送报文数量 | 报文缺失次数 |
单、双 | 单、双 | 单、双 | 单、双 | 单、双 | 双 |
,
5. 参考资料
【1】ExpressLRS开源之RC链路性能测试
【2】ExpressLRS开源之接收机固件编译烧录步骤
【3】High-performance Open Source Radio Control Link