Measure signal power / noise power (at least in 2.4MHz mode).

Switch signalLevel back to a power measurement, don't put SNR in there.
But make it a 0.0 - 1.0 double so we're not scaling everywhere.

Adjust for the amplitude offset when calculating power.

Adapt everything else to the new scheme.
This commit is contained in:
Oliver Jowett 2015-01-22 01:01:39 +00:00
parent 5beecb9f4f
commit 19082d92ea
9 changed files with 118 additions and 28 deletions

View file

@ -540,7 +540,7 @@ void demodulate2000(uint16_t *m, uint32_t mlen) {
&& (errors <= MODES_MSG_ENCODER_ERRS) ) { && (errors <= MODES_MSG_ENCODER_ERRS) ) {
// Set initial mm structure details // Set initial mm structure details
mm.timestampMsg = Modes.timestampBlk + (j*6); 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; mm.phase_corrected = use_correction;
// Decode the received message // Decode the received message

View file

@ -153,10 +153,15 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
struct modesMessage mm; struct modesMessage mm;
unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg; unsigned char msg1[MODES_LONG_MSG_BYTES], msg2[MODES_LONG_MSG_BYTES], *msg;
uint32_t j; uint32_t j;
uint32_t last_message_end = 0;
unsigned char *bestmsg; unsigned char *bestmsg;
int bestscore, bestphase; int bestscore, bestphase;
// noise floor:
uint32_t noise_power_count = 0;
uint64_t noise_power_sum = 0;
memset(&mm, 0, sizeof(mm)); memset(&mm, 0, sizeof(mm));
msg = msg1; msg = msg1;
@ -167,6 +172,17 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
int initial_phase, first_phase, last_phase, try_phase; int initial_phase, first_phase, last_phase, try_phase;
int msglen; 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 // Look for a message starting at around sample 0 with phase offset 3..7
// Ideal sample values for preambles with different phase // Ideal sample values for preambles with different phase
@ -403,6 +419,28 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
mm.score = bestscore; mm.score = bestscore;
mm.bFlags = mm.correctedbits = 0; 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 // Decode the received message
if (decodeModesMessage(&mm, bestmsg) < 0) if (decodeModesMessage(&mm, bestmsg) < 0)
continue; continue;
@ -426,10 +464,14 @@ void demodulate2400(uint16_t *m, uint32_t mlen) {
// where the preamble of the second message clobbered the last // where the preamble of the second message clobbered the last
// few bits of the first message, but the message bits didn't // few bits of the first message, but the message bits didn't
// overlap) // overlap)
last_message_end = j + (8 + msglen)*12/5;
j += (8 + msglen - 8)*12/5 - 1; j += (8 + msglen - 8)*12/5 - 1;
// Pass data to the next layer // Pass data to the next layer
useModesMessage(&mm); useModesMessage(&mm);
} }
Modes.stats_current.noise_power_sum += (noise_power_sum / MAX_POWER / noise_power_count);
Modes.stats_current.noise_power_count ++;
} }

View file

@ -209,6 +209,11 @@
#define MODES_NOTUSED(V) ((void) V) #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 subheaders after all the #defines are in place
#include "anet.h" #include "anet.h"
@ -235,7 +240,7 @@ struct client {
struct aircraft { struct aircraft {
uint32_t addr; // ICAO address uint32_t addr; // ICAO address
char flight[16]; // Flight number char flight[16]; // Flight number
unsigned char signalLevel[8]; // Last 8 Signal Amplitudes double signalLevel[8]; // Last 8 Signal Amplitudes
int altitude; // Altitude int altitude; // Altitude
int speed; // Velocity int speed; // Velocity
int track; // Angle of flight int track; // Angle of flight
@ -402,7 +407,7 @@ struct modesMessage {
int phase_corrected; // True if phase correction was applied int phase_corrected; // True if phase correction was applied
uint64_t timestampMsg; // Timestamp of the message uint64_t timestampMsg; // Timestamp of the message
int remote; // If set this message is from a remote station 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; int score;
// DF 11, DF 17 // DF 11, DF 17

View file

@ -68,15 +68,17 @@ static uint64_t mstime(void) {
// of aircraft // of aircraft
// //
struct aircraft *interactiveCreateAircraft(struct modesMessage *mm) { struct aircraft *interactiveCreateAircraft(struct modesMessage *mm) {
static struct aircraft zeroAircraft;
struct aircraft *a = (struct aircraft *) malloc(sizeof(*a)); struct aircraft *a = (struct aircraft *) malloc(sizeof(*a));
int i;
// Default everything to zero/NULL // Default everything to zero/NULL
memset(a, 0, sizeof(*a)); *a = zeroAircraft;
// Now initialise things that should not be 0/NULL to their defaults // Now initialise things that should not be 0/NULL to their defaults
a->addr = mm->addr; a->addr = mm->addr;
a->lat = a->lon = 0.0; for (i = 0; i < 8; ++i)
memset(a->signalLevel, mm->signalLevel, 8); // First time, initialise everything a->signalLevel[i] = mm->signalLevel; // First time, initialise everything
// to the first signal strength // to the first signal strength
// mm->msgtype 32 is used to represent Mode A/C. These values can never change, so // mm->msgtype 32 is used to represent Mode A/C. These values can never change, so
@ -521,7 +523,7 @@ void interactiveShowData(void) {
if (Modes.interactive_rtl1090 == 0) { if (Modes.interactive_rtl1090 == 0) {
printf ( 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 { } else {
printf ( printf (
"Hex Flight Alt V/S GS TT SSR G*456^ Msgs Seen %c\n", progress); "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 strMode[5] = " ";
char strLat[8] = " "; char strLat[8] = " ";
char strLon[9] = " "; char strLon[9] = " ";
unsigned char * pSig = a->signalLevel; double * pSig = a->signalLevel;
unsigned int signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] + double signalAverage = (pSig[0] + pSig[1] + pSig[2] + pSig[3] +
pSig[4] + pSig[5] + pSig[6] + pSig[7] + 3) >> 3; pSig[4] + pSig[5] + pSig[6] + pSig[7]) / 8.0;
if ((flags & MODEAC_MSG_FLAG) == 0) { if ((flags & MODEAC_MSG_FLAG) == 0) {
strMode[0] = 'S'; strMode[0] = 'S';
@ -599,9 +601,9 @@ void interactiveShowData(void) {
snprintf(strFl, 6, "%5d", altitude); snprintf(strFl, 6, "%5d", altitude);
} }
printf("%06X %-4s %-4s %-8s %5s %3s %3s %7s %8s %2d.%1d %5d %2d\n", printf("%06X %-4s %-4s %-8s %5s %3s %3s %7s %8s %5.1f %5d %2d\n",
a->addr, strMode, strSquawk, a->flight, strFl, strGs, strTt, a->addr, strMode, strSquawk, a->flight, strFl, strGs, strTt,
strLat, strLon, signalAverage/5, 2*(signalAverage%5), msgs, (int)(now - a->seen)); strLat, strLon, 10 * log10(signalAverage), msgs, (int)(now - a->seen));
} }
count++; count++;
} }

View file

@ -144,7 +144,6 @@ int detectModeA(uint16_t *m, struct modesMessage *mm)
int F1_sig, F1_noise; int F1_sig, F1_noise;
int F2_sig, F2_noise; int F2_sig, F2_noise;
int fSig, fNoise, fLevel, fLoLo; int fSig, fNoise, fLevel, fLoLo;
int snr;
// m[0] contains the energy from 0 -> 499 nS // m[0] contains the energy from 0 -> 499 nS
// m[1] contains the energy from 500 -> 999 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) ) if ((ModeABits < 3) || (ModeABits & 0xFFFF8808) || (ModeAErrs) )
{return (ModeABits = 0);} {return (ModeABits = 0);}
// snr = 5 * 20log10(fSig / (fSig+fNoise)) (in units of 0.2dB) mm->signalLevel = 1.0 * TRUE_AMPLITUDE(fSig + fNoise) * TRUE_AMPLITUDE(fSig + fNoise) / MAX_POWER;
// = 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);
return ModeABits; return ModeABits;
} }

View file

@ -1005,7 +1005,8 @@ void displayModesMessage(struct modesMessage *mm) {
if (mm->correctedbits != 0) if (mm->correctedbits != 0)
printf("No. of bit errors fixed: %d\n", mm->correctedbits); 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) if (mm->score)
printf("Score: %d\n", mm->score); printf("Score: %d\n", mm->score);

View file

@ -293,7 +293,7 @@ void modesSendBeastOutput(struct modesMessage *mm) {
if (0x1A == ch) {*p++ = ch; } if (0x1A == ch) {*p++ = ch; }
} }
*p++ = (ch = mm->signalLevel); *p++ = ch = (char) round(mm->signalLevel * 255);
if (0x1A == ch) {*p++ = ch; } if (0x1A == ch) {*p++ = ch; }
for (j = 0; j < msgLen; j++) { for (j = 0; j < msgLen; j++) {
@ -568,7 +568,8 @@ int decodeBinMessage(struct client *c, char *p) {
if (0x1A == ch) {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++;} if (0x1A == ch) {p++;}
for (j = 0; j < msgLen; j++) { // and the data 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 // 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 // pass them off as being received by this instance when forwarding them
mm.remote = 1; mm.remote = 1;
mm.signalLevel = 0xFF; mm.signalLevel = 0.0;
// Remove spaces on the left and on the right // Remove spaces on the left and on the right
while(l && isspace(hex[l-1])) { while(l && isspace(hex[l-1])) {
@ -644,7 +645,7 @@ int decodeHexMessage(struct client *c, char *hex) {
switch(hex[0]) { switch(hex[0]) {
case '<': { 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 ; hex += 15; l -= 16; // Skip <, timestamp and siglevel, and ;
break;} break;}

33
stats.c
View file

@ -110,6 +110,22 @@ void display_stats(struct stats *st) {
printf("%d phase enhancement attempts\n", st->out_of_phase); printf("%d phase enhancement attempts\n", st->out_of_phase);
display_demod_stats("phase enhanced ", &st->demod_phasecorrected); 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" 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: // total messages:
target->messages_total = st1->messages_total + st2->messages_total; 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: // CPR decoding:
target->cpr_global_ok = st1->cpr_global_ok + st2->cpr_global_ok; target->cpr_global_ok = st1->cpr_global_ok + st2->cpr_global_ok;
target->cpr_global_bad = st1->cpr_global_bad + st2->cpr_global_bad; target->cpr_global_bad = st1->cpr_global_bad + st2->cpr_global_bad;

14
stats.h
View file

@ -91,6 +91,20 @@ struct stats {
struct timespec cputime; 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: // remote messages:
unsigned int remote_accepted; unsigned int remote_accepted;
unsigned int remote_rejected; unsigned int remote_rejected;