diff --git a/demod_2000.c b/demod_2000.c index c093b55..e433138 100644 --- a/demod_2000.c +++ b/demod_2000.c @@ -540,7 +540,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) { && (errors <= MODES_MSG_ENCODER_ERRS) ) { // Set initial mm structure details mm.timestampMsg = Modes.timestampBlk + (j*6); - mm.signalLevel = (snr > 255 ? 255 : (uint8_t)snr); + mm.signalLevel = (365.0*60 + sigLevel + noiseLevel) * (365.0*60 + sigLevel + noiseLevel) / MAX_POWER / 60 / 60; mm.phase_corrected = use_correction; // Decode the received message diff --git a/demod_2400.c b/demod_2400.c index 8ba35e7..1a73df8 100644 --- a/demod_2400.c +++ b/demod_2400.c @@ -153,10 +153,15 @@ void demodulate2400(uint16_t *m, uint32_t mlen) { struct modesMessage mm; unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg; uint32_t j; + uint32_t last_message_end = 0; unsigned char *bestmsg; int bestscore, bestphase; + // noise floor: + uint32_t noise_power_count = 0; + uint64_t noise_power_sum = 0; + memset(&mm, 0, sizeof(mm)); msg = msg1; @@ -167,6 +172,17 @@ void demodulate2400(uint16_t *m, uint32_t mlen) { int initial_phase, first_phase, last_phase, try_phase; int msglen; + // update noise for all samples that aren't part of a message + // (we don't know if m[j] is or not, yet, so work one sample + // in arrears) + if (j > last_message_end+1) { + // There seems to be a weird compiler bug I'm hitting here.. + // if you compute the square directly, it occasionally gets mangled. + uint64_t s = TRUE_AMPLITUDE(m[j-1]); + noise_power_sum += s * s; + noise_power_count++; + } + // Look for a message starting at around sample 0 with phase offset 3..7 // Ideal sample values for preambles with different phase @@ -403,6 +419,28 @@ void demodulate2400(uint16_t *m, uint32_t mlen) { mm.score = bestscore; mm.bFlags = mm.correctedbits = 0; + // measure signal power + { + uint64_t signal_power_sum = 0; + double signal_power; + int signal_len = msglen*12/5 + 1; + int k; + + for (k = 0; k < signal_len; ++k) { + uint64_t s = TRUE_AMPLITUDE(m[j+19+k]); + signal_power_sum += s * s; + } + + mm.signalLevel = signal_power = signal_power_sum / MAX_POWER / signal_len; + Modes.stats_current.signal_power_sum += signal_power; + Modes.stats_current.signal_power_count ++; + + if (signal_power > Modes.stats_current.peak_signal_power) + Modes.stats_current.peak_signal_power = signal_power; + if (signal_power > 0.50119) + Modes.stats_current.strong_signal_count++; // signal power above -3dBFS + } + // Decode the received message if (decodeModesMessage(&mm, bestmsg) < 0) continue; @@ -426,10 +464,14 @@ void demodulate2400(uint16_t *m, uint32_t mlen) { // where the preamble of the second message clobbered the last // few bits of the first message, but the message bits didn't // overlap) + last_message_end = j + (8 + msglen)*12/5; j += (8 + msglen - 8)*12/5 - 1; // Pass data to the next layer useModesMessage(&mm); } + + Modes.stats_current.noise_power_sum += (noise_power_sum / MAX_POWER / noise_power_count); + Modes.stats_current.noise_power_count ++; } diff --git a/dump1090.h b/dump1090.h index 13218c1..979570e 100644 --- a/dump1090.h +++ b/dump1090.h @@ -209,6 +209,11 @@ #define MODES_NOTUSED(V) ((void) V) +// adjust for zero offset of amplitude values +#define TRUE_AMPLITUDE(x) ((x) + 365) +#define MAX_AMPLITUDE TRUE_AMPLITUDE(65535) +#define MAX_POWER (1.0 * MAX_AMPLITUDE * MAX_AMPLITUDE) + // Include subheaders after all the #defines are in place #include "anet.h" @@ -235,7 +240,7 @@ struct client { struct aircraft { uint32_t addr; // ICAO address char flight[16]; // Flight number - unsigned char signalLevel[8]; // Last 8 Signal Amplitudes + double signalLevel[8]; // Last 8 Signal Amplitudes int altitude; // Altitude int speed; // Velocity int track; // Angle of flight @@ -402,7 +407,7 @@ struct modesMessage { int phase_corrected; // True if phase correction was applied uint64_t timestampMsg; // Timestamp of the message int remote; // If set this message is from a remote station - unsigned char signalLevel; // Signal Amplitude + double signalLevel; // RSSI, in the range [0..1], as a fraction of full-scale power int score; // DF 11, DF 17 diff --git a/interactive.c b/interactive.c index 66e3411..eee61f5 100644 --- a/interactive.c +++ b/interactive.c @@ -68,16 +68,18 @@ static uint64_t mstime(void) { // of aircraft // struct aircraft *interactiveCreateAircraft(struct modesMessage *mm) { + static struct aircraft zeroAircraft; struct aircraft *a = (struct aircraft *) malloc(sizeof(*a)); + int i; // Default everything to zero/NULL - memset(a, 0, sizeof(*a)); + *a = zeroAircraft; // Now initialise things that should not be 0/NULL to their defaults a->addr = mm->addr; - a->lat = a->lon = 0.0; - memset(a->signalLevel, mm->signalLevel, 8); // First time, initialise everything - // to the first signal strength + for (i = 0; i < 8; ++i) + a->signalLevel[i] = mm->signalLevel; // First time, initialise everything + // to the first signal strength // mm->msgtype 32 is used to represent Mode A/C. These values can never change, so // set them once here during initialisation, and don't bother to set them every @@ -521,7 +523,7 @@ void interactiveShowData(void) { if (Modes.interactive_rtl1090 == 0) { printf ( -"Hex Mode Sqwk Flight Alt Spd Hdg Lat Long Sig Msgs Ti%c\n", progress); +"Hex Mode Sqwk Flight Alt Spd Hdg Lat Long RSSI Msgs Ti%c\n", progress); } else { printf ( "Hex Flight Alt V/S GS TT SSR G*456^ Msgs Seen %c\n", progress); @@ -576,9 +578,9 @@ void interactiveShowData(void) { char strMode[5] = " "; char strLat[8] = " "; char strLon[9] = " "; - unsigned char * pSig = a->signalLevel; - unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] + - pSig[4] + pSig[5] + pSig[6] + pSig[7] + 3) >> 3; + double * pSig = a->signalLevel; + double signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] + + pSig[4] + pSig[5] + pSig[6] + pSig[7]) / 8.0; if ((flags & MODEAC_MSG_FLAG) == 0) { strMode[0] = 'S'; @@ -599,9 +601,9 @@ void interactiveShowData(void) { snprintf(strFl, 6, "%5d", altitude); } - printf("%06X %-4s %-4s %-8s %5s %3s %3s %7s %8s %2d.%1d %5d %2d\n", - a->addr, strMode, strSquawk, a->flight, strFl, strGs, strTt, - strLat, strLon, signalAverage/5, 2*(signalAverage%5), msgs, (int)(now - a->seen)); + printf("%06X %-4s %-4s %-8s %5s %3s %3s %7s %8s %5.1f %5d %2d\n", + a->addr, strMode, strSquawk, a->flight, strFl, strGs, strTt, + strLat, strLon, 10 * log10(signalAverage), msgs, (int)(now - a->seen)); } count++; } diff --git a/mode_ac.c b/mode_ac.c index 1c17f05..b168e37 100644 --- a/mode_ac.c +++ b/mode_ac.c @@ -144,7 +144,6 @@ int detectModeA(uint16_t *m, struct modesMessage *mm) int F1_sig, F1_noise; int F2_sig, F2_noise; int fSig, fNoise, fLevel, fLoLo; - int snr; // m[0] contains the energy from 0 -> 499 nS // m[1] contains the energy from 500 -> 999 nS @@ -307,14 +306,7 @@ int detectModeA(uint16_t *m, struct modesMessage *mm) if ((ModeABits < 3) || (ModeABits & 0xFFFF8808) || (ModeAErrs) ) {return (ModeABits = 0);} - // snr = 5 * 20log10(fSig / (fSig+fNoise)) (in units of 0.2dB) - // = 100log10(fSig) - 100log10(fSig+fNoise) - while (fSig > 65535 || (fSig + fNoise) > 65535) { - fSig >>= 1; - fNoise >>= 1; - } - snr = Modes.log10lut[fSig] - Modes.log10lut[fSig + fNoise]; - mm->signalLevel = ((snr < 255) ? (uint8_t)snr : 255); + mm->signalLevel = 1.0 * TRUE_AMPLITUDE(fSig + fNoise) * TRUE_AMPLITUDE(fSig + fNoise) / MAX_POWER; return ModeABits; } diff --git a/mode_s.c b/mode_s.c index 96f565a..3f2b9e6 100644 --- a/mode_s.c +++ b/mode_s.c @@ -1005,7 +1005,8 @@ void displayModesMessage(struct modesMessage *mm) { if (mm->correctedbits != 0) printf("No. of bit errors fixed: %d\n", mm->correctedbits); - printf("SNR: %d.%d dB\n", mm->signalLevel/5, 2*(mm->signalLevel%5)); + if (mm->signalLevel > 0) + printf("RSSI: %.1f dBFS\n", 10 * log10(mm->signalLevel)); if (mm->score) printf("Score: %d\n", mm->score); diff --git a/net_io.c b/net_io.c index 2d5cb9e..9e5ac5b 100644 --- a/net_io.c +++ b/net_io.c @@ -293,7 +293,7 @@ void modesSendBeastOutput(struct modesMessage *mm) { if (0x1A == ch) {*p++ = ch; } } - *p++ = (ch = mm->signalLevel); + *p++ = ch = (char) round(mm->signalLevel * 255); if (0x1A == ch) {*p++ = ch; } for (j = 0; j < msgLen; j++) { @@ -568,7 +568,8 @@ int decodeBinMessage(struct client *c, char *p) { if (0x1A == ch) {p++;} } - mm.signalLevel = ch = *p++; // Grab the signal level + ch = *p++; // Grab the signal level + mm.signalLevel = ((unsigned)ch / 255.0); if (0x1A == ch) {p++;} for (j = 0; j < msgLen; j++) { // and the data @@ -627,7 +628,7 @@ int decodeHexMessage(struct client *c, char *hex) { // Mark messages received over the internet as remote so that we don't try to // pass them off as being received by this instance when forwarding them mm.remote = 1; - mm.signalLevel = 0xFF; + mm.signalLevel = 0.0; // Remove spaces on the left and on the right while(l && isspace(hex[l-1])) { @@ -644,7 +645,7 @@ int decodeHexMessage(struct client *c, char *hex) { switch(hex[0]) { case '<': { - mm.signalLevel = (hexDigitVal(hex[13])<<4) | hexDigitVal(hex[14]); + mm.signalLevel = ((hexDigitVal(hex[13])<<4) | hexDigitVal(hex[14])) / 255.0; hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ; break;} diff --git a/stats.c b/stats.c index cdf3598..e5a915b 100644 --- a/stats.c +++ b/stats.c @@ -110,6 +110,22 @@ void display_stats(struct stats *st) { printf("%d phase enhancement attempts\n", st->out_of_phase); display_demod_stats("phase enhanced ", &st->demod_phasecorrected); } + + if (st->noise_power_count) { + printf("%.1f dBFS noise floor\n", + 10 * log10(st->noise_power_sum / st->noise_power_count)); + } + + if (st->signal_power_count) { + printf("%.1f dBFS mean signal power\n", + 10 * log10(st->signal_power_sum / st->signal_power_count)); + } + + printf("%.1f dBFS peak signal power\n", + 10 * log10(st->peak_signal_power)); + + printf("%u messages with signal power above -3dBFS\n", + st->strong_signal_count); } printf("%d remote messages accepted\n" @@ -206,6 +222,23 @@ void add_stats(const struct stats *st1, const struct stats *st2, struct stats *t // total messages: target->messages_total = st1->messages_total + st2->messages_total; + // noise floor: + target->noise_power_sum = st1->noise_power_sum + st2->noise_power_sum; + target->noise_power_count = st1->noise_power_count + st2->noise_power_count; + + // mean signal power: + target->signal_power_sum = st1->signal_power_sum + st2->signal_power_sum; + target->signal_power_count = st1->signal_power_count + st2->signal_power_count; + + // peak signal power seen + if (st1->peak_signal_power > st2->peak_signal_power) + target->peak_signal_power = st1->peak_signal_power; + else + target->peak_signal_power = st2->peak_signal_power; + + // strong signals + target->strong_signal_count = st1->strong_signal_count + st2->strong_signal_count; + // CPR decoding: target->cpr_global_ok = st1->cpr_global_ok + st2->cpr_global_ok; target->cpr_global_bad = st1->cpr_global_bad + st2->cpr_global_bad; diff --git a/stats.h b/stats.h index 46d65b2..4f19391 100644 --- a/stats.h +++ b/stats.h @@ -91,6 +91,20 @@ struct stats { struct timespec cputime; + // noise floor: + double noise_power_sum; + uint32_t noise_power_count; + + // mean signal power: + double signal_power_sum; + uint32_t signal_power_count; + + // peak signal power seen + double peak_signal_power; + + // number of signals with power > -3dBFS + uint32_t strong_signal_count; + // remote messages: unsigned int remote_accepted; unsigned int remote_rejected;