ADS-B: reworked correlation threshold. Added RSSI. Corrected latitude negative shift. Implements #696

This commit is contained in:
f4exb 2020-11-09 07:28:43 +01:00
parent fffac68b7f
commit 9024d3f6fa
8 changed files with 89 additions and 46 deletions

View File

@ -70,6 +70,7 @@
#define ADSB_COL_TIME 20 #define ADSB_COL_TIME 20
#define ADSB_COL_FRAMECOUNT 21 #define ADSB_COL_FRAMECOUNT 21
#define ADSB_COL_CORRELATION 22 #define ADSB_COL_CORRELATION 22
#define ADSB_COL_RSSI 23
const char *Aircraft::m_speedTypeNames[] = { const char *Aircraft::m_speedTypeNames[] = {
"GS", "TAS", "IAS" "GS", "TAS", "IAS"
@ -529,7 +530,11 @@ QIcon *ADSBDemodGUI::getFlagIcon(const QString &country)
} }
} }
void ADSBDemodGUI::handleADSB(const QByteArray data, const QDateTime dateTime, float correlation) void ADSBDemodGUI::handleADSB(
const QByteArray data,
const QDateTime dateTime,
float correlation,
float correlationOnes)
{ {
const char idMap[] = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ????? ???????????????0123456789??????"; const char idMap[] = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ????? ???????????????0123456789??????";
const QString categorySetA[] = { const QString categorySetA[] = {
@ -621,6 +626,7 @@ void ADSBDemodGUI::handleADSB(const QByteArray data, const QDateTime dateTime, f
ui->adsbData->setItem(row, ADSB_COL_TIME, aircraft->m_timeItem); ui->adsbData->setItem(row, ADSB_COL_TIME, aircraft->m_timeItem);
ui->adsbData->setItem(row, ADSB_COL_FRAMECOUNT, aircraft->m_adsbFrameCountItem); ui->adsbData->setItem(row, ADSB_COL_FRAMECOUNT, aircraft->m_adsbFrameCountItem);
ui->adsbData->setItem(row, ADSB_COL_CORRELATION, aircraft->m_correlationItem); ui->adsbData->setItem(row, ADSB_COL_CORRELATION, aircraft->m_correlationItem);
ui->adsbData->setItem(row, ADSB_COL_RSSI, aircraft->m_rssiItem);
// Look aircraft up in database // Look aircraft up in database
if (m_aircraftInfo != nullptr) if (m_aircraftInfo != nullptr)
{ {
@ -709,7 +715,9 @@ void ADSBDemodGUI::handleADSB(const QByteArray data, const QDateTime dateTime, f
.arg(CalcDb::dbPower(aircraft->m_minCorrelation), 3, 'f', 1) .arg(CalcDb::dbPower(aircraft->m_minCorrelation), 3, 'f', 1)
.arg(CalcDb::dbPower(aircraft->m_correlation), 3, 'f', 1) .arg(CalcDb::dbPower(aircraft->m_correlation), 3, 'f', 1)
.arg(CalcDb::dbPower(aircraft->m_maxCorrelation), 3, 'f', 1)); .arg(CalcDb::dbPower(aircraft->m_maxCorrelation), 3, 'f', 1));
m_correlationOnesAvg(correlationOnes);
aircraft->m_rssiItem->setText(QString("%1")
.arg(CalcDb::dbPower(m_correlationOnesAvg.instantAverage()), 3, 'f', 1));
// ADS-B, non-transponder ADS-B or TIS-B rebroadcast of ADS-B (ADS-R) // ADS-B, non-transponder ADS-B or TIS-B rebroadcast of ADS-B (ADS-R)
if ((df == 17) || ((df == 18) && ((ca == 0) || (ca == 1) || (ca == 6)))) if ((df == 17) || ((df == 18) && ((ca == 0) || (ca == 1) || (ca == 6))))
{ {
@ -796,9 +804,13 @@ void ADSBDemodGUI::handleADSB(const QByteArray data, const QDateTime dateTime, f
latEven = dLatEven * ((j % 60) + aircraft->m_cprLat[0]); latEven = dLatEven * ((j % 60) + aircraft->m_cprLat[0]);
if (latEven >= 270.0f) if (latEven >= 270.0f)
latEven -= 360.0f; latEven -= 360.0f;
else if (latEven <= -270.0f)
latEven += 360.0f;
latOdd = dLatOdd * ((j % 59) + aircraft->m_cprLat[1]); latOdd = dLatOdd * ((j % 59) + aircraft->m_cprLat[1]);
if (latOdd >= 270.0f) if (latOdd >= 270.0f)
latOdd -= 360.0f; latOdd -= 360.0f;
else if (latOdd <= -270.0f)
latOdd += 360.0f;
if (aircraft->m_cprTime[0] >= aircraft->m_cprTime[1]) if (aircraft->m_cprTime[0] >= aircraft->m_cprTime[1])
latitude = latEven; latitude = latEven;
else else
@ -980,8 +992,10 @@ bool ADSBDemodGUI::handleMessage(const Message& message)
{ {
ADSBDemodReport::MsgReportADSB& report = (ADSBDemodReport::MsgReportADSB&) message; ADSBDemodReport::MsgReportADSB& report = (ADSBDemodReport::MsgReportADSB&) message;
handleADSB( handleADSB(
report.getData(), report.getDateTime(), report.getData(),
report.getPreambleCorrelation()); report.getDateTime(),
report.getPreambleCorrelation(),
report.getCorrelationOnes());
return true; return true;
} }
else if (ADSBDemodReport::MsgReportDemodStats::match(message)) else if (ADSBDemodReport::MsgReportDemodStats::match(message))
@ -1867,6 +1881,7 @@ void ADSBDemodGUI::resizeTable()
ui->adsbData->setItem(row, ADSB_COL_TIME, new QTableWidgetItem("99:99:99")); ui->adsbData->setItem(row, ADSB_COL_TIME, new QTableWidgetItem("99:99:99"));
ui->adsbData->setItem(row, ADSB_COL_FRAMECOUNT, new QTableWidgetItem("Frames")); ui->adsbData->setItem(row, ADSB_COL_FRAMECOUNT, new QTableWidgetItem("Frames"));
ui->adsbData->setItem(row, ADSB_COL_CORRELATION, new QTableWidgetItem("0.001/0.001/0.001")); ui->adsbData->setItem(row, ADSB_COL_CORRELATION, new QTableWidgetItem("0.001/0.001/0.001"));
ui->adsbData->setItem(row, ADSB_COL_RSSI, new QTableWidgetItem("-100.0"));
ui->adsbData->resizeColumnsToContents(); ui->adsbData->resizeColumnsToContents();
ui->adsbData->removeCellWidget(row, ADSB_COL_ICAO); ui->adsbData->removeCellWidget(row, ADSB_COL_ICAO);
ui->adsbData->removeCellWidget(row, ADSB_COL_FLIGHT); ui->adsbData->removeCellWidget(row, ADSB_COL_FLIGHT);
@ -1891,5 +1906,6 @@ void ADSBDemodGUI::resizeTable()
ui->adsbData->removeCellWidget(row, ADSB_COL_TIME); ui->adsbData->removeCellWidget(row, ADSB_COL_TIME);
ui->adsbData->removeCellWidget(row, ADSB_COL_FRAMECOUNT); ui->adsbData->removeCellWidget(row, ADSB_COL_FRAMECOUNT);
ui->adsbData->removeCellWidget(row, ADSB_COL_CORRELATION); ui->adsbData->removeCellWidget(row, ADSB_COL_CORRELATION);
ui->adsbData->removeCellWidget(row, ADSB_COL_RSSI);
ui->adsbData->setRowCount(row); ui->adsbData->setRowCount(row);
} }

View File

@ -147,6 +147,7 @@ struct Aircraft {
QTableWidgetItem *m_timeItem; QTableWidgetItem *m_timeItem;
QTableWidgetItem *m_adsbFrameCountItem; QTableWidgetItem *m_adsbFrameCountItem;
QTableWidgetItem *m_correlationItem; QTableWidgetItem *m_correlationItem;
QTableWidgetItem *m_rssiItem;
Aircraft(ADSBDemodGUI *gui) : Aircraft(ADSBDemodGUI *gui) :
m_icao(0), m_icao(0),
@ -201,6 +202,7 @@ struct Aircraft {
m_timeItem = new QTableWidgetItem(); m_timeItem = new QTableWidgetItem();
m_adsbFrameCountItem = new QTableWidgetItem(); m_adsbFrameCountItem = new QTableWidgetItem();
m_correlationItem = new QTableWidgetItem(); m_correlationItem = new QTableWidgetItem();
m_rssiItem = new QTableWidgetItem();
} }
}; };
@ -458,6 +460,7 @@ private:
AzEl m_azEl; // Position of station AzEl m_azEl; // Position of station
Aircraft *m_trackAircraft; // Aircraft we want to track in Channel Report Aircraft *m_trackAircraft; // Aircraft we want to track in Channel Report
MovingAverageUtil<float, double, 10> m_correlationAvg; MovingAverageUtil<float, double, 10> m_correlationAvg;
MovingAverageUtil<float, double, 10> m_correlationOnesAvg;
Aircraft *m_highlightAircraft; // Aircraft we want to highlight, when selected in table Aircraft *m_highlightAircraft; // Aircraft we want to highlight, when selected in table
float m_currentAirportRange; // Current settings, so we only update if changed float m_currentAirportRange; // Current settings, so we only update if changed
@ -479,7 +482,11 @@ private:
void displayStreamIndex(); void displayStreamIndex();
bool handleMessage(const Message& message); bool handleMessage(const Message& message);
void updatePosition(Aircraft *aircraft); void updatePosition(Aircraft *aircraft);
void handleADSB(const QByteArray data, const QDateTime dateTime, float correlation); void handleADSB(
const QByteArray data,
const QDateTime dateTime,
float correlation,
float correlationOnes);
void resizeTable(); void resizeTable();
QString getDataDir(); QString getDataDir();
QString getAirportDBFilename(); QString getAirportDBFilename();

View File

@ -6,7 +6,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>350</width> <width>384</width>
<height>1046</height> <height>1046</height>
</rect> </rect>
</property> </property>
@ -36,7 +36,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>340</width> <width>381</width>
<height>141</height> <height>141</height>
</rect> </rect>
</property> </property>
@ -327,7 +327,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QToolButton" name="demodModeS"> <widget class="ButtonSwitch" name="demodModeS">
<property name="toolTip"> <property name="toolTip">
<string>Demodulate all Mode-S frames, not just ADS-B</string> <string>Demodulate all Mode-S frames, not just ADS-B</string>
</property> </property>
@ -347,7 +347,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QToolButton" name="correlateFullPreamble"> <widget class="ButtonSwitch" name="correlateFullPreamble">
<property name="toolTip"> <property name="toolTip">
<string>Correlate against full preamble.</string> <string>Correlate against full preamble.</string>
</property> </property>
@ -378,16 +378,16 @@
<string>Correlation threshold in dB. Lower values will increase the number of frames that can be received, but require more processing and possibly result in invalid frames.</string> <string>Correlation threshold in dB. Lower values will increase the number of frames that can be received, but require more processing and possibly result in invalid frames.</string>
</property> </property>
<property name="minimum"> <property name="minimum">
<number>-450</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>0</number> <number>200</number>
</property> </property>
<property name="pageStep"> <property name="pageStep">
<number>1</number> <number>1</number>
</property> </property>
<property name="value"> <property name="value">
<number>0</number> <number>100</number>
</property> </property>
</widget> </widget>
</item> </item>
@ -400,7 +400,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>-15.0</string> <string>20.0</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -451,7 +451,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QToolButton" name="flightPaths"> <widget class="ButtonSwitch" name="flightPaths">
<property name="toolTip"> <property name="toolTip">
<string>Display flight paths</string> <string>Display flight paths</string>
</property> </property>
@ -471,7 +471,7 @@
</widget> </widget>
</item> </item>
<item> <item>
<widget class="QToolButton" name="feed"> <widget class="ButtonSwitch" name="feed">
<property name="toolTip"> <property name="toolTip">
<string>Enable feeding of received ADS-B messages to the specifed server. Right click for settings.</string> <string>Enable feeding of received ADS-B messages to the specifed server. Right click for settings.</string>
</property> </property>
@ -547,7 +547,7 @@
<rect> <rect>
<x>0</x> <x>0</x>
<y>140</y> <y>140</y>
<width>341</width> <width>381</width>
<height>291</height> <height>291</height>
</rect> </rect>
</property> </property>
@ -765,6 +765,11 @@
<string>Correlation values for received frames. min/avg/max</string> <string>Correlation values for received frames. min/avg/max</string>
</property> </property>
</column> </column>
<column>
<property name="text">
<string>RSSI</string>
</property>
</column>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -774,7 +779,7 @@
<rect> <rect>
<x>10</x> <x>10</x>
<y>450</y> <y>450</y>
<width>331</width> <width>361</width>
<height>581</height> <height>581</height>
</rect> </rect>
</property> </property>
@ -857,6 +862,11 @@
<header>gui/valuedialz.h</header> <header>gui/valuedialz.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>ButtonSwitch</class>
<extends>QToolButton</extends>
<header>gui/buttonswitch.h</header>
</customwidget>
</customwidgets> </customwidgets>
<tabstops> <tabstops>
<tabstop>deltaFrequency</tabstop> <tabstop>deltaFrequency</tabstop>

View File

@ -38,21 +38,32 @@ public:
QByteArray getData() const { return m_data; } QByteArray getData() const { return m_data; }
QDateTime getDateTime() const { return m_dateTime; } QDateTime getDateTime() const { return m_dateTime; }
float getPreambleCorrelation() const { return m_preambleCorrelation; } float getPreambleCorrelation() const { return m_preambleCorrelation; }
float getCorrelationOnes() const { return m_correlationOnes; }
static MsgReportADSB* create(QByteArray data, float preambleCorrelation) static MsgReportADSB* create(
QByteArray data,
float preambleCorrelation,
float correlationOnes
)
{ {
return new MsgReportADSB(data, preambleCorrelation); return new MsgReportADSB(data, preambleCorrelation, correlationOnes);
} }
private: private:
QByteArray m_data; QByteArray m_data;
QDateTime m_dateTime; QDateTime m_dateTime;
float m_preambleCorrelation; float m_preambleCorrelation;
float m_correlationOnes;
MsgReportADSB(QByteArray data, float preambleCorrelation) : MsgReportADSB(
QByteArray data,
float preambleCorrelation,
float correlationOnes
) :
Message(), Message(),
m_data(data), m_data(data),
m_preambleCorrelation(preambleCorrelation) m_preambleCorrelation(preambleCorrelation),
m_correlationOnes(correlationOnes)
{ {
m_dateTime = QDateTime::currentDateTime(); m_dateTime = QDateTime::currentDateTime();
} }

View File

@ -34,7 +34,7 @@ void ADSBDemodSettings::resetToDefaults()
{ {
m_inputFrequencyOffset = 0; m_inputFrequencyOffset = 0;
m_rfBandwidth = 2*1300000; m_rfBandwidth = 2*1300000;
m_correlationThreshold = -20.0f; m_correlationThreshold = 10.0f; //<! ones/zero powers correlation threshold in dB
m_samplesPerBit = 4; m_samplesPerBit = 4;
m_removeTimeout = 60; m_removeTimeout = 60;
m_feedEnabled = false; m_feedEnabled = false;

View File

@ -57,7 +57,7 @@ void ADSBDemodSinkWorker::run()
<< " samplesPerChip: " << samplesPerChip << " samplesPerChip: " << samplesPerChip
<< " samplesPerBit: " << samplesPerBit << " samplesPerBit: " << samplesPerBit
<< " correlateFullPreamble: " << m_settings.m_correlateFullPreamble << " correlateFullPreamble: " << m_settings.m_correlateFullPreamble
<< " correlationZerosScale: " << m_correlationZerosScale << " correlationScale: " << m_correlationScale
<< " correlationThreshold: " << m_settings.m_correlationThreshold; << " correlationThreshold: " << m_settings.m_correlationThreshold;
int readIdx = m_sink->m_samplesPerFrame - 1; int readIdx = m_sink->m_samplesPerFrame - 1;
@ -127,7 +127,7 @@ void ADSBDemodSinkWorker::run()
} }
} }
// Use the difference rather than absolute value, as we don't care how powerful the signal // Use the ratio of ones power over zeros power, as we don't care how powerful the signal
// is, just whether there is a good correlation with the preamble. The absolute value varies // is, just whether there is a good correlation with the preamble. The absolute value varies
// too much with different radios, AGC settings and and the noise floor is not constant // too much with different radios, AGC settings and and the noise floor is not constant
// (E.g: it's quite possible to receive multiple frames simultaneously, so we don't // (E.g: it's quite possible to receive multiple frames simultaneously, so we don't
@ -135,11 +135,11 @@ void ADSBDemodSinkWorker::run()
// a stronger signals 0 chip position. Similarly a strong signal in an adjacent // a stronger signals 0 chip position. Similarly a strong signal in an adjacent
// channel may casue AGC to reduce gain, reducing the ampltiude of an otherwise // channel may casue AGC to reduce gain, reducing the ampltiude of an otherwise
// strong signal, as well as the noise floor) // strong signal, as well as the noise floor)
// The scale factors account for different values of samplesPerBit and the different // The threshold accounts for the different number of zeros and ones in the preamble
// number of zeros and ones in the preamble
// If the sum of ones is exactly 0, it's probably no signal // If the sum of ones is exactly 0, it's probably no signal
Real preambleCorrelation = (preambleCorrelationOnes * m_correlationZerosScale)
- (preambleCorrelationZeros * m_correlationOnesScale); Real preambleCorrelation = preambleCorrelationOnes/preambleCorrelationZeros; // without one/zero ratio correction
if ((preambleCorrelation > m_correlationThresholdLinear) && (preambleCorrelationOnes != 0.0f)) if ((preambleCorrelation > m_correlationThresholdLinear) && (preambleCorrelationOnes != 0.0f))
{ {
m_demodStats.m_correlatorMatches++; m_demodStats.m_correlatorMatches++;
@ -203,7 +203,8 @@ void ADSBDemodSinkWorker::run()
{ {
ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create( ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create(
QByteArray((char*)data, sizeof(data)), QByteArray((char*)data, sizeof(data)),
preambleCorrelation); preambleCorrelation * m_correlationScale,
preambleCorrelationOnes / samplesPerChip);
m_sink->getMessageQueueToGUI()->push(msg); m_sink->getMessageQueueToGUI()->push(msg);
} }
// Pass to worker to feed to other servers // Pass to worker to feed to other servers
@ -211,7 +212,8 @@ void ADSBDemodSinkWorker::run()
{ {
ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create( ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create(
QByteArray((char*)data, sizeof(data)), QByteArray((char*)data, sizeof(data)),
preambleCorrelation); preambleCorrelation * m_correlationScale,
preambleCorrelationOnes / samplesPerChip);
m_sink->getMessageQueueToWorker()->push(msg); m_sink->getMessageQueueToWorker()->push(msg);
} }
} }
@ -244,7 +246,8 @@ void ADSBDemodSinkWorker::run()
{ {
ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create( ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create(
QByteArray((char*)data, sizeof(data)), QByteArray((char*)data, sizeof(data)),
preambleCorrelation); preambleCorrelation * m_correlationScale,
preambleCorrelationOnes / samplesPerChip);
m_sink->getMessageQueueToWorker()->push(msg); m_sink->getMessageQueueToWorker()->push(msg);
} }
} }
@ -325,23 +328,19 @@ void ADSBDemodSinkWorker::handleInputMessages()
ADSBDemodSettings settings = cfg->getSettings(); ADSBDemodSettings settings = cfg->getSettings();
bool force = cfg->getForce(); bool force = cfg->getForce();
if (settings.m_correlateFullPreamble) {
m_correlationScale = 3.0;
} else {
m_correlationScale = 2.0;
}
if ((m_settings.m_correlationThreshold != settings.m_correlationThreshold) || force) if ((m_settings.m_correlationThreshold != settings.m_correlationThreshold) || force)
{ {
m_correlationThresholdLinear = CalcDb::powerFromdB(settings.m_correlationThreshold); m_correlationThresholdLinear = CalcDb::powerFromdB(settings.m_correlationThreshold);
m_correlationThresholdLinear /= m_correlationScale;
qDebug() << "m_correlationThresholdLinear: " << m_correlationThresholdLinear; qDebug() << "m_correlationThresholdLinear: " << m_correlationThresholdLinear;
} }
if (settings.m_correlateFullPreamble)
{
m_correlationOnesScale = 1.0f / settings.m_samplesPerBit;
m_correlationZerosScale = 2.0 * 1.0f / settings.m_samplesPerBit; // As 2x more 0s than 1s
}
else
{
m_correlationOnesScale = 1.0f / settings.m_samplesPerBit;
m_correlationZerosScale = 3.0 * 1.0f / settings.m_samplesPerBit; // As 3x more 0s than 1s
}
m_settings = settings; m_settings = settings;
delete message; delete message;
} }

View File

@ -74,8 +74,7 @@ private:
ADSBDemodSink *m_sink; ADSBDemodSink *m_sink;
ADSBDemodStats m_demodStats; ADSBDemodStats m_demodStats;
Real m_correlationThresholdLinear; Real m_correlationThresholdLinear;
Real m_correlationZerosScale; Real m_correlationScale;
Real m_correlationOnesScale;
crcadsb m_crc; //!< Have as member to avoid recomputing LUT crcadsb m_crc; //!< Have as member to avoid recomputing LUT
}; };

View File

@ -116,7 +116,8 @@ The table displays the decoded ADS-B data for each aircraft along side data avai
* Owner - The owner of the aircraft. (DB) * Owner - The owner of the aircraft. (DB)
* Updated - The local time at which the last ADS-B message was received. * Updated - The local time at which the last ADS-B message was received.
* RX Frames - A count of the number of ADS-B frames received from this aircraft. * RX Frames - A count of the number of ADS-B frames received from this aircraft.
* Correlation - Displays the minimun, average and maximum of the preamable correlation in dB for each recevied frame. These values can be used to help select a threshold setting. * Correlation - Displays the minimun, average and maximum of the preamable correlation in dB for each recevied frame. These values can be used to help select a threshold setting. This correlation value is the ratio between the presence and absence of the signal corresponding to the "ones" and the "zeros" of the sync word adjusted by the bits ratio. It can be interpreted as a SNR estimation.
* RSSI - This Received Signal Strength Indicator is based on the signal power during correlation estimation. This is the power sum during the expected presence of the signal i.e. the "ones" of the sync word.
If an ADS-B frame has not been received from an aircraft for 60 seconds, the aircraft is removed from the table and map. This timeout can be adjusted in the Display Settings dialog. If an ADS-B frame has not been received from an aircraft for 60 seconds, the aircraft is removed from the table and map. This timeout can be adjusted in the Display Settings dialog.