diff --git a/demod_2400.c b/demod_2400.c index 7ed1a299..01b51674 100644 --- a/demod_2400.c +++ b/demod_2400.c @@ -287,6 +287,16 @@ void demodulate2400(struct mag_buf *mag) { uint16_t *pa = m; uint16_t *stop = m + mlen; + uint16_t *statsProgress = m; + + const uint32_t statsWindow = MODES_SHORT_MSG_SAMPLES / 2; // half a short message + uint32_t loudSamples = 0; + uint32_t quietSamples = 0; + uint32_t quiet2Samples = 0; + uint32_t loudThreshold = 55000 * statsWindow; // max 65536 + uint32_t quietThreshold = 800 * statsWindow; + uint32_t quiet2Threshold = 2 * quietThreshold; + for (; pa < stop; pa++) { int32_t pa_mag, base_noise, ref_level; int msglen; @@ -308,6 +318,18 @@ void demodulate2400(struct mag_buf *mag) { // due to plenty room in the message buffer for decoding // we can with pa go beyond stop without a buffer overrun ... + if (Modes.autoGain && pa >= statsProgress) { + uint32_t magSum = 0; + for (uint32_t i = 0; i < statsWindow; i++) { + magSum += pa[i]; + } + loudSamples += statsWindow * (magSum > loudThreshold); + quietSamples += statsWindow * (magSum < quietThreshold); + quiet2Samples += statsWindow * (magSum < quiet2Threshold); + + statsProgress = pa + statsWindow; + } + if (pa[1] > pa[7] && pa[12] > pa[14] && pa[12] > pa[15]) { goto after_pre; } pa++; if (pa[1] > pa[7] && pa[12] > pa[14] && pa[12] > pa[15]) { goto after_pre; } pa++; if (pa[1] > pa[7] && pa[12] > pa[14] && pa[12] > pa[15]) { goto after_pre; } @@ -471,6 +493,10 @@ void demodulate2400(struct mag_buf *mag) { netUseMessage(mm); } + mag->loudSamples = loudSamples; + mag->quietSamples = quietSamples; + mag->quiet2Samples = quiet2Samples; + /* update noise power */ { double sum_signal_power = sum_scaled_signal_power / 65535.0 / 65535.0; diff --git a/readsb.c b/readsb.c index 10f38f26..69b1a22f 100644 --- a/readsb.c +++ b/readsb.c @@ -751,6 +751,65 @@ static void *globeBinEntryPoint(void *arg) { return NULL; } +static void gainStatistics(struct mag_buf *buf) { + static uint64_t loudSamples; + static uint64_t quietSamples; + static uint64_t quiet2Samples; + static uint64_t totalSamples; + static int slowRise; + static int lastGain; + + loudSamples += buf->loudSamples; + quietSamples += buf->quietSamples; + quiet2Samples += buf->quiet2Samples; + totalSamples += buf->length; + + if (totalSamples < 2 * Modes.sample_rate) { + return; + } + + double loudPercent = loudSamples / (double) totalSamples * 100.0; + double quietPercent = quietSamples / (double) totalSamples * 100.0; + double quiet2Percent = quiet2Samples / (double) totalSamples * 100.0; + + // reset + loudSamples = 0; + quietSamples = 0; + quiet2Samples = 0; + totalSamples = 0; + + if (!Modes.autoGain) { + // don't adjust anything + return; + } + + if (loudPercent > 0.05 || quiet2Percent < 0.05) { + Modes.lowerGain = 1; + } else if ( + quietPercent > 10.0 + ) { + if (getUptime() < 1 * MINUTES || slowRise > 10) { + slowRise = 0; + Modes.increaseGain = 1; + } else { + slowRise++; + } + } + if (Modes.increaseGain || Modes.lowerGain) { + if (getUptime() < 1 * MINUTES) { + Modes.lowerGain *= 2; + Modes.increaseGain *= 2; + } + if (Modes.gain != lastGain) { + lastGain = Modes.gain; + fprintf(stderr, "loud: %8.4f %% quiet: %8.4f %% quiet2 %8.4f %%\n", loudPercent, quietPercent, quiet2Percent); + } + sdrSetGain(); + } + +} + + static void timingStatistics(struct mag_buf *buf) { static int64_t last_ts; @@ -873,6 +932,10 @@ static void *decodeEntryPoint(void *arg) { demodulate2400AC(buf); } + gainStatistics(buf); + timingStatistics(buf); + + Modes.stats_current.samples_lost += Modes.sdr_buf_samples - buf->length; Modes.stats_current.samples_processed += buf->length; Modes.stats_current.samples_dropped += buf->dropped; end_cpu_timing(&start_time, &Modes.stats_current.demod_cpu); @@ -883,10 +946,6 @@ static void *decodeEntryPoint(void *arg) { pthread_cond_signal(&Threads.reader.cond); unlockReader(); - Modes.stats_current.samples_lost += Modes.sdr_buf_samples - buf->length; - - timingStatistics(buf); - watchdogCounter = 100; // roughly 10 seconds } else { // Nothing to process this time around. @@ -1446,7 +1505,12 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) { Modes.dev_name = strdup(arg); break; case OptGain: - Modes.gain = (int) (atof(arg)*10); // Gain is in tens of DBs + if (strcmp(arg, "auto") == 0) { + Modes.autoGain = 1; + Modes.gain = 439; + } else { + Modes.gain = (int) (atof(arg)*10); // Gain is in tens of DBs + } break; case OptFreq: Modes.freq = (int) strtoll(arg, NULL, 10); diff --git a/readsb.h b/readsb.h index 77a7ae22..a02e894a 100644 --- a/readsb.h +++ b/readsb.h @@ -456,6 +456,10 @@ struct mag_buf unsigned length; // Number of valid samples _after_ overlap. Total buffer length is buf->length + Modes.trailing_samples. int64_t sysTimestamp; // Estimated system time at start of block int64_t sysMicroseconds; // sysTimestamp in microseconds + uint32_t loudSamples; + uint32_t quietSamples; + uint32_t quiet2Samples; + uint32_t padding2; uint16_t *data; // Magnitude data. Starts with Modes.trailing_samples worth of overlap from the previous block #if defined(__arm__) /*padding 4 bytes*/ @@ -529,6 +533,9 @@ struct _Modes pthread_mutex_t sdrControlMutex; int8_t sdrInitialized; int8_t sdrOpenFailed; + int8_t increaseGain; + int8_t lowerGain; + int8_t autoGain; int gain; int dc_filter; // should we apply a DC filter? int enable_agc; diff --git a/sdr_rtlsdr.c b/sdr_rtlsdr.c index 587ac332..5123a583 100644 --- a/sdr_rtlsdr.c +++ b/sdr_rtlsdr.c @@ -91,7 +91,47 @@ void rtlsdrInitConfig() { RTLSDR.tunerAgcEnabled = 0; } +static int getClosestGainIndex(int target) { + target = (target == MODES_MAX_GAIN ? 9999 : target); + int closest = 0; + + for (int i = 0; i < RTLSDR.numgains; ++i) { + if (abs(RTLSDR.gains[i] - target) < abs(RTLSDR.gains[closest] - target)) { + closest = i; + } + } + return closest; +} + void rtlsdrSetGain() { + if (Modes.increaseGain || Modes.lowerGain) { + int closest = getClosestGainIndex(Modes.gain); + if (Modes.increaseGain) { + closest += Modes.increaseGain; + } else if (Modes.lowerGain) { + closest -= Modes.lowerGain; + } + if (closest >= RTLSDR.numgains) { + closest = RTLSDR.numgains - 1; + } + if (closest < 0) { + closest = 0; + } + Modes.increaseGain = 0; + Modes.lowerGain = 0; + + if (Modes.gain == RTLSDR.gains[closest]) { + // same gain, nothing to do + return; + } + + // change gain + Modes.gain = RTLSDR.gains[closest]; + } + + if (Modes.gain < 0) { + Modes.gain = 0; + } if (Modes.gain == MODES_AUTO_GAIN || Modes.gain >= 520) { Modes.gain = 590; @@ -104,13 +144,7 @@ void rtlsdrSetGain() { } } else { - int target = (Modes.gain == MODES_MAX_GAIN ? 9999 : Modes.gain); - int closest = -1; - - for (int i = 0; i < RTLSDR.numgains; ++i) { - if (closest == -1 || abs(RTLSDR.gains[i] - target) < abs(RTLSDR.gains[closest] - target)) - closest = i; - } + int closest = getClosestGainIndex(Modes.gain); int newGain = RTLSDR.gains[closest]; if (RTLSDR.tunerAgcEnabled) {