diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.cpp b/plugins/channelrx/demodadsb/adsbdemodgui.cpp index d035cf6d4..738b5229d 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodgui.cpp @@ -264,7 +264,7 @@ void ADSBDemodGUI::updatePosition(Aircraft *aircraft) m_adsbDemod->setTarget(aircraft->m_azimuth, aircraft->m_elevation); } -void ADSBDemodGUI::handleADSB(const QByteArray data, const QDateTime dateTime, float correlation) +void ADSBDemodGUI::handleADSB(const QByteArray data, const QDateTime dateTime, float correlationOnes, float correlationZeros) { const char idMap[] = "?ABCDEFGHIJKLMNOPQRSTUVWXYZ????? ???????????????0123456789??????"; const QString categorySetA[] = { @@ -350,12 +350,14 @@ void ADSBDemodGUI::handleADSB(const QByteArray data, const QDateTime dateTime, f aircraft->m_adsbFrameCount++; aircraft->m_adsbFrameCountItem->setText(QString("%1").arg(aircraft->m_adsbFrameCount)); - if (correlation < aircraft->m_minCorrelation) - aircraft->m_minCorrelation = correlation; - if (correlation > aircraft->m_maxCorrelation) - aircraft->m_maxCorrelation = correlation; - aircraft->m_sumCorrelation += correlation; - aircraft->m_correlationItem->setText(QString("%1/%2/%3").arg(aircraft->m_minCorrelation, 3, 'f', 1).arg(aircraft->m_sumCorrelation / aircraft->m_adsbFrameCount, 3, 'f', 1).arg(aircraft->m_maxCorrelation, 3, 'f', 1)); + aircraft->m_minCorrelation = correlationZeros; + if (correlationOnes > aircraft->m_maxCorrelation) + aircraft->m_maxCorrelation = correlationOnes; + aircraft->m_correlation = correlationOnes; + aircraft->m_correlationItem->setText(QString("%1/%2/%3") + .arg(CalcDb::dbPower(aircraft->m_minCorrelation), 3, 'f', 1) + .arg(CalcDb::dbPower(aircraft->m_correlation), 3, 'f', 1) + .arg(CalcDb::dbPower(aircraft->m_maxCorrelation), 3, 'f', 1)); if ((tc >= 1) && ((tc <= 4))) @@ -607,7 +609,10 @@ bool ADSBDemodGUI::handleMessage(const Message& message) if (ADSBDemodReport::MsgReportADSB::match(message)) { ADSBDemodReport::MsgReportADSB& report = (ADSBDemodReport::MsgReportADSB&) message; - handleADSB(report.getData(), report.getDateTime(), report.getPreambleCorrelation()); + handleADSB( + report.getData(), report.getDateTime(), + report.getPreambleCorrelationOnes(), + report.getPreambleCorrelationZeros()); return true; } else if (ADSBDemod::MsgConfigureADSBDemod::match(message)) @@ -667,9 +672,9 @@ void ADSBDemodGUI::on_rfBW_valueChanged(int value) void ADSBDemodGUI::on_threshold_valueChanged(int value) { - Real threshold = ((Real)value)/10.0f; - ui->thresholdText->setText(QString("%1").arg(threshold, 0, 'f', 1)); - m_settings.m_correlationThreshold = threshold; + Real thresholddB = ((Real)value)/10.0f; + ui->thresholdText->setText(QString("%1").arg(thresholddB, 0, 'f', 1)); + m_settings.m_correlationThreshold = thresholddB; applySettings(); } @@ -856,7 +861,7 @@ ADSBDemodGUI::ADSBDemodGUI(PluginAPI* pluginAPI, DeviceUISet *deviceUISet, Baseb connect(getInputMessageQueue(), SIGNAL(messageEnqueued()), this, SLOT(handleInputMessages())); - ui->adsbData->resizeColumnsToContents(); + resizeTable(); // Get station position Real stationLatitude = MainCore::instance()->getSettings().getLatitude(); @@ -1022,3 +1027,41 @@ void ADSBDemodGUI::tick() } } } + +void ADSBDemodGUI::resizeTable() +{ + int row = ui->adsbData->rowCount(); + ui->adsbData->setRowCount(row + 1); + ui->adsbData->setItem(row, ADSB_COL_ICAO, new QTableWidgetItem("ICAO ID")); + ui->adsbData->setItem(row, ADSB_COL_FLIGHT, new QTableWidgetItem("Flight No")); + ui->adsbData->setItem(row, ADSB_COL_LATITUDE, new QTableWidgetItem("-90.00000 L")); + ui->adsbData->setItem(row, ADSB_COL_LONGITUDE, new QTableWidgetItem("-180.00000 L")); + ui->adsbData->setItem(row, ADSB_COL_ALTITUDE, new QTableWidgetItem("Alt (ft)")); + ui->adsbData->setItem(row, ADSB_COL_SPEED, new QTableWidgetItem("Sp (kn)")); + ui->adsbData->setItem(row, ADSB_COL_HEADING, new QTableWidgetItem("Hd (o)")); + ui->adsbData->setItem(row, ADSB_COL_VERTICALRATE, new QTableWidgetItem("Climb")); + ui->adsbData->setItem(row, ADSB_COL_CATEGORY, new QTableWidgetItem("Category")); + ui->adsbData->setItem(row, ADSB_COL_STATUS, new QTableWidgetItem("No emergency")); + ui->adsbData->setItem(row, ADSB_COL_RANGE, new QTableWidgetItem("D (km)")); + ui->adsbData->setItem(row, ADSB_COL_AZEL, new QTableWidgetItem("Az/El (o)")); + 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_CORRELATION, new QTableWidgetItem("-99.9/-99.9/=99.9")); + ui->adsbData->resizeColumnsToContents(); + ui->adsbData->removeCellWidget(row, ADSB_COL_ICAO); + ui->adsbData->removeCellWidget(row, ADSB_COL_FLIGHT); + ui->adsbData->removeCellWidget(row, ADSB_COL_LATITUDE); + ui->adsbData->removeCellWidget(row, ADSB_COL_LONGITUDE); + ui->adsbData->removeCellWidget(row, ADSB_COL_ALTITUDE); + ui->adsbData->removeCellWidget(row, ADSB_COL_SPEED); + ui->adsbData->removeCellWidget(row, ADSB_COL_HEADING); + ui->adsbData->removeCellWidget(row, ADSB_COL_VERTICALRATE); + ui->adsbData->removeCellWidget(row, ADSB_COL_CATEGORY); + ui->adsbData->removeCellWidget(row, ADSB_COL_STATUS); + ui->adsbData->removeCellWidget(row, ADSB_COL_RANGE); + ui->adsbData->removeCellWidget(row, ADSB_COL_AZEL); + ui->adsbData->removeCellWidget(row, ADSB_COL_TIME); + ui->adsbData->removeCellWidget(row, ADSB_COL_FRAMECOUNT); + ui->adsbData->removeCellWidget(row, ADSB_COL_CORRELATION); + ui->adsbData->setRowCount(row); +} diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.h b/plugins/channelrx/demodadsb/adsbdemodgui.h index 68c8e2511..4680330c0 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.h +++ b/plugins/channelrx/demodadsb/adsbdemodgui.h @@ -79,7 +79,7 @@ struct Aircraft { int m_adsbFrameCount; // Number of ADS-B frames for this aircraft float m_minCorrelation; float m_maxCorrelation; - float m_sumCorrelation; + float m_correlation; bool m_isBeingTracked; // Are we tracking this aircraft // GUI table items for above data @@ -117,7 +117,7 @@ struct Aircraft { m_adsbFrameCount(0), m_minCorrelation(INFINITY), m_maxCorrelation(-INFINITY), - m_sumCorrelation(0.0f), + m_correlation(0.0f), m_isBeingTracked(false) { for (int i = 0; i < 2; i++) @@ -247,7 +247,8 @@ private: void displayStreamIndex(); bool handleMessage(const Message& message); void updatePosition(Aircraft *aircraft); - void handleADSB(const QByteArray data, const QDateTime dateTime, float correlation); + void handleADSB(const QByteArray data, const QDateTime dateTime, float correlationOnes, float correlationZeros); + void resizeTable(); void leaveEvent(QEvent*); void enterEvent(QEvent*); diff --git a/plugins/channelrx/demodadsb/adsbdemodgui.ui b/plugins/channelrx/demodadsb/adsbdemodgui.ui index a0ffdff16..55cb28bba 100644 --- a/plugins/channelrx/demodadsb/adsbdemodgui.ui +++ b/plugins/channelrx/demodadsb/adsbdemodgui.ui @@ -337,16 +337,19 @@ - Correlation threshold. Lower values will increase the number of frames that can be received, but require more processing. + Correlation threshold in dB. Lower values will increase the number of frames that can be received, but require more processing. - -100 + -990 - 20 + 0 + + + 1 - 0 + -500 @@ -442,6 +445,11 @@ 0 + + + Liberation Mono + + ADS-B Data @@ -465,8 +473,7 @@ - Segoe UI - 9 + Liberation Mono @@ -477,84 +484,120 @@ ICAO ID - + International Civil Aviation Organization identifier. Links to www.planespotters.net Flight No. + + Commercial flight number. Links to www.flightradar24.com + - Latitude (°) + Lat (°) - + Latitude in degrees postive towards the North - Longitude (°) + Lon (°) - + Longitude in degrees. Positive towards the East - Altitude (ft) + Alt (ft) + + + Altitude in feet - Speed (kn) + Sp (kn) + + + Speed in knots - Heading (°) + Hd (°) + + + Aircraft heading in degrees - Climb (ft/min) + Climb + + + Climbing rate in feet per minute Category + + Aircraft standard category + Status + + Aircraft standard status + - Range (km) + D (km) + + + Range or distance of aircraft to home location Az/El (°) + + Aircraft azimuth and elevation from home point in degrees + Updated + + Last time updated + - RX Frames + Frames + + + Number of frames received Correlation + + Correlation power min/avg/max in dB + diff --git a/plugins/channelrx/demodadsb/adsbdemodreport.h b/plugins/channelrx/demodadsb/adsbdemodreport.h index 3ee354896..11ff4c690 100644 --- a/plugins/channelrx/demodadsb/adsbdemodreport.h +++ b/plugins/channelrx/demodadsb/adsbdemodreport.h @@ -36,22 +36,25 @@ public: public: QByteArray getData() const { return m_data; } QDateTime getDateTime() const { return m_dateTime; } - float getPreambleCorrelation() const { return m_premableCorrelation; } + float getPreambleCorrelationOnes() const { return m_premableCorrelationOnes; } + float getPreambleCorrelationZeros() const { return m_premableCorrelationZeros; } - static MsgReportADSB* create(QByteArray data, float premableCorrelation) + static MsgReportADSB* create(QByteArray data, float premableCorrelationOnes, float premableCorrelationZeros) { - return new MsgReportADSB(data, premableCorrelation); + return new MsgReportADSB(data, premableCorrelationOnes, premableCorrelationZeros); } private: QByteArray m_data; QDateTime m_dateTime; - float m_premableCorrelation; + float m_premableCorrelationOnes; + float m_premableCorrelationZeros; - MsgReportADSB(QByteArray data, float premableCorrelation) : + MsgReportADSB(QByteArray data, float premableCorrelationOnes, float premableCorrelationZeros) : Message(), m_data(data), - m_premableCorrelation(premableCorrelation) + m_premableCorrelationOnes(premableCorrelationOnes), + m_premableCorrelationZeros(premableCorrelationZeros) { m_dateTime = QDateTime::currentDateTime(); } diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp index f24621a48..e46082241 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.cpp @@ -34,7 +34,7 @@ void ADSBDemodSettings::resetToDefaults() { m_inputFrequencyOffset = 0; m_rfBandwidth = 2*1300000; - m_correlationThreshold = 0.0f; + m_correlationThreshold = -50.0f; m_samplesPerBit = 6; m_removeTimeout = 60; m_beastEnabled = false; @@ -102,7 +102,7 @@ bool ADSBDemodSettings::deserialize(const QByteArray& data) d.readS32(1, &tmp, 0); m_inputFrequencyOffset = tmp; d.readReal(2, &m_rfBandwidth, 2*1300000); - d.readReal(3, &m_correlationThreshold, 1.0f); + d.readReal(3, &m_correlationThreshold, -50.0f); d.readS32(4, &m_samplesPerBit, 6); d.readS32(5, &m_removeTimeout, 60); d.readBool(6, &m_beastEnabled, false); diff --git a/plugins/channelrx/demodadsb/adsbdemodsettings.h b/plugins/channelrx/demodadsb/adsbdemodsettings.h index 9b02d1b51..a9674a592 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsettings.h +++ b/plugins/channelrx/demodadsb/adsbdemodsettings.h @@ -30,9 +30,9 @@ struct ADSBDemodSettings { int32_t m_inputFrequencyOffset; Real m_rfBandwidth; - Real m_correlationThreshold; + Real m_correlationThreshold; //!< Correlation power threshold in dB int m_samplesPerBit; - int m_removeTimeout; // Time in seconds before removing an aircraft, unless a new frame is received + int m_removeTimeout; //!< Time in seconds before removing an aircraft, unless a new frame is received bool m_beastEnabled; QString m_beastHost; uint16_t m_beastPort; diff --git a/plugins/channelrx/demodadsb/adsbdemodsink.cpp b/plugins/channelrx/demodadsb/adsbdemodsink.cpp index 9d9903109..6ca06755e 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsink.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodsink.cpp @@ -42,13 +42,13 @@ ADSBDemodSink::ADSBDemodSink() : m_sampleIdx(0), m_sampleCount(0), m_skipCount(0), + m_correlationThresholdLinear(0.0), m_magsq(0.0f), m_magsqSum(0.0f), m_magsqPeak(0.0f), m_magsqCount(0), m_messageQueueToGUI(nullptr), - m_sampleBuffer(nullptr), - m_preamble(nullptr) + m_sampleBuffer(nullptr) { applySettings(m_settings, true); applyChannelSettings(m_channelSampleRate, m_channelFrequencyOffset, true); @@ -57,7 +57,6 @@ ADSBDemodSink::ADSBDemodSink() : ADSBDemodSink::~ADSBDemodSink() { delete m_sampleBuffer; - delete m_preamble; } void ADSBDemodSink::feed(const SampleVector::const_iterator& begin, const SampleVector::const_iterator& end) @@ -108,7 +107,7 @@ void ADSBDemodSink::processOneSample(Complex &ci) } m_magsqCount++; - sample = sqrtf(magsq); + sample = magsq; m_sampleBuffer[m_sampleCount] = sample; m_sampleCount++; @@ -118,12 +117,37 @@ void ADSBDemodSink::processOneSample(Complex &ci) int startIdx = m_sampleCount - m_totalSamples; // Correlate received signal with expected preamble - Real preambleCorrelation = 0.0f; - for (int i = 0; i < ADS_B_PREAMBLE_CHIPS*m_samplesPerChip; i++) - preambleCorrelation += m_preamble[i] * m_sampleBuffer[startIdx+i]; + // chip+ indexes are 0, 2, 7, 9 + // we correlate only over 6 symbols so that the number of zero chips is twice the + // number of one chips - empirically this is enough to get good correlation + Real premableCorrelationOnes = 0.0; + Real preambleCorrelationZeros = 0.0; + + for (int i = 0; i < m_samplesPerChip; i++) + { + premableCorrelationOnes += m_sampleBuffer[startIdx + 0*m_samplesPerChip + i]; + preambleCorrelationZeros += m_sampleBuffer[startIdx + 1*m_samplesPerChip + i]; + + premableCorrelationOnes += m_sampleBuffer[startIdx + 2*m_samplesPerChip + i]; + preambleCorrelationZeros += m_sampleBuffer[startIdx + 3*m_samplesPerChip + i]; + + preambleCorrelationZeros += m_sampleBuffer[startIdx + 4*m_samplesPerChip + i]; + preambleCorrelationZeros += m_sampleBuffer[startIdx + 5*m_samplesPerChip + i]; + + preambleCorrelationZeros += m_sampleBuffer[startIdx + 6*m_samplesPerChip + i]; + premableCorrelationOnes += m_sampleBuffer[startIdx + 7*m_samplesPerChip + i]; + + preambleCorrelationZeros += m_sampleBuffer[startIdx + 8*m_samplesPerChip + i]; + premableCorrelationOnes += m_sampleBuffer[startIdx + 9*m_samplesPerChip + i]; + + preambleCorrelationZeros += m_sampleBuffer[startIdx + 10*m_samplesPerChip + i]; + preambleCorrelationZeros += m_sampleBuffer[startIdx + 11*m_samplesPerChip + i]; + } // If the correlation is exactly 0, it's probably no signal - if ((preambleCorrelation > m_settings.m_correlationThreshold) && (preambleCorrelation != 0.0f)) + if ((premableCorrelationOnes > m_correlationThresholdLinear) && + (preambleCorrelationZeros < 2.0*m_correlationThresholdLinear) && + (premableCorrelationOnes != 0.0f)) { // Skip over preamble startIdx += m_settings.m_samplesPerBit*ADS_B_PREAMBLE_BITS; @@ -183,13 +207,19 @@ void ADSBDemodSink::processOneSample(Complex &ci) // Pass to GUI if (getMessageQueueToGUI()) { - ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create(QByteArray((char*)data, sizeof(data)), preambleCorrelation); + ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create( + QByteArray((char*)data, sizeof(data)), + premableCorrelationOnes, + preambleCorrelationZeros/2.0); getMessageQueueToGUI()->push(msg); } // Pass to worker if (getMessageQueueToWorker()) { - ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create(QByteArray((char*)data, sizeof(data)), preambleCorrelation); + ADSBDemodReport::MsgReportADSB *msg = ADSBDemodReport::MsgReportADSB::create( + QByteArray((char*)data, sizeof(data)), + premableCorrelationOnes, + preambleCorrelationZeros/2.0); getMessageQueueToWorker()->push(msg); } } @@ -212,23 +242,11 @@ void ADSBDemodSink::init(int samplesPerBit) { if (m_sampleBuffer) delete m_sampleBuffer; - if (m_preamble) - delete m_preamble; m_totalSamples = samplesPerBit*(ADS_B_PREAMBLE_BITS+ADS_B_ES_BITS); m_samplesPerChip = samplesPerBit/ADS_B_CHIPS_PER_BIT; m_sampleBuffer = new Real[2*m_totalSamples]; - m_preamble = new Real[ADS_B_PREAMBLE_CHIPS*m_samplesPerChip]; - // Possibly don't look for first chip - const int preambleChips[] = {1, -1, 1, -1, -1, -1, -1, 1, -1, 1, -1, -1, -1, -1, -1, -1}; - for (int i = 0; i < ADS_B_PREAMBLE_CHIPS; i++) - { - for (int j = 0; j < m_samplesPerChip; j++) - { - m_preamble[i*m_samplesPerChip+j] = preambleChips[i]; - } - } } void ADSBDemodSink::applyChannelSettings(int channelSampleRate, int channelFrequencyOffset, bool force) @@ -270,10 +288,15 @@ void ADSBDemodSink::applySettings(const ADSBDemodSettings& settings, bool force) m_interpolatorDistanceRemain = 0; m_interpolatorDistance = (Real) m_channelSampleRate / (Real) (ADS_B_BITS_PER_SECOND * settings.m_samplesPerBit); } + if ((settings.m_samplesPerBit != m_settings.m_samplesPerBit) || force) { init(settings.m_samplesPerBit); } + if ((settings.m_correlationThreshold != m_settings.m_correlationThreshold) || force) { + m_correlationThresholdLinear = CalcDb::powerFromdB(m_settings.m_correlationThreshold); + } + m_settings = settings; } diff --git a/plugins/channelrx/demodadsb/adsbdemodsink.h b/plugins/channelrx/demodadsb/adsbdemodsink.h index b57970c7b..d68a1403e 100644 --- a/plugins/channelrx/demodadsb/adsbdemodsink.h +++ b/plugins/channelrx/demodadsb/adsbdemodsink.h @@ -82,10 +82,10 @@ private: int m_sampleCount; int m_skipCount; // Samples to skip, because we've already received a frame Real *m_sampleBuffer; - Real *m_preamble; int m_totalSamples; // These two values are derived from samplesPerBit int m_samplesPerChip; + double m_correlationThresholdLinear; //!< settings m_correlationThreshold is in dB. Linear value is calculated once. double m_magsq; //!< displayed averaged value double m_magsqSum; diff --git a/plugins/channelrx/demodadsb/adsbdemodworker.cpp b/plugins/channelrx/demodadsb/adsbdemodworker.cpp index c254f4bbc..f2a1289a2 100644 --- a/plugins/channelrx/demodadsb/adsbdemodworker.cpp +++ b/plugins/channelrx/demodadsb/adsbdemodworker.cpp @@ -88,7 +88,7 @@ bool ADSBDemodWorker::handleMessage(const Message& message) else if (ADSBDemodReport::MsgReportADSB::match(message)) { ADSBDemodReport::MsgReportADSB& report = (ADSBDemodReport::MsgReportADSB&) message; - handleADSB(report.getData(), report.getDateTime(), report.getPreambleCorrelation()); + handleADSB(report.getData(), report.getDateTime(), report.getPreambleCorrelationOnes()); return true; } else diff --git a/plugins/channelrx/demodadsb/readme.md b/plugins/channelrx/demodadsb/readme.md index f01148706..3beb65eec 100644 --- a/plugins/channelrx/demodadsb/readme.md +++ b/plugins/channelrx/demodadsb/readme.md @@ -34,7 +34,11 @@ Higher channel sample rates may help decode more frames, but will require more p

6: Threshold

-This sets the correlation threshold between the received signal and expected 1090ES preamble, that is required to be exceeded before the demodulator will try to decode a frame. Lower values should decode more frames, but will require more processing power. +This sets the correlation power threshold in dB between the received signal and expected 1090ES preamble, that is required to be exceeded before the demodulator will try to decode a frame. Thus it acts as a kind of squelch. Lower values should decode more frames amd will require more processing power but more often just to process garbage. It is a compromise and setting it correctly is kind of subtle. You may start at ~12 dB over the noise shown in channel power (2). You may also look at correlation values obtained with reliable signals in the "Correlation" column of the data table. + +In detail this threshold is used to test two conditions are met: + - the correlation on the "ones" chips is above threshold + - the correlation of the "zeros" chips is below threshold. As zeros chips are two times the ones chips in the correlation (done over 6 first symbols of preamble) the raw value of zeros correlation sum is halved before comparison.

7: Feed

@@ -59,7 +63,7 @@ The table displays the decoded ADS-B data for each aircraft. The data is not all * Az/El - The azimuth and elevation angles to the aircraft from the receiving antenna in degrees. These values can be sent to a rotator controller to track the aircraft. * 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. -* Correlation - Displays the minimum, average and maximum of the preamable correlation for each recevied frame. These values can be used to help select a threshold setting. +* Correlation - Displays the zeros chip correlation, average of current ones chip corelation and maximum of the preamable correlation power in dB for each recevied frame. These values can be used to help select a threshold setting. A suffix of L in the latitude and longitude columns, indicates the position is based on a local decode, using a single received frame and the position of the radio station. No suffix will be added for a global decode, which is based upon receving and odd and even frame. If an ADS-B frame has not been received from an aircraft for 60 seconds, the aircraft is removed from the table and map.