diff --git a/include/am_analyze.h b/include/am_analyze.h index 6a972b50..17c34330 100644 --- a/include/am_analyze.h +++ b/include/am_analyze.h @@ -18,7 +18,7 @@ #define PULSE_DATA_SIZE 4000 /* maximum number of pulses */ typedef struct am_analyze { - int32_t *level_limit; + int level_limit; int override_short; int override_long; uint32_t *frequency; diff --git a/include/baseband.h b/include/baseband.h index 27a2f956..c89aa78d 100644 --- a/include/baseband.h +++ b/include/baseband.h @@ -14,6 +14,7 @@ #define INCLUDE_BASEBAND_H_ #include <stdint.h> +#include <math.h> /** This will give a noisy envelope of OOK/ASK signals. @@ -31,6 +32,18 @@ void magnitude_true_cu8(uint8_t const *iq_buf, uint16_t *y_buf, uint32_t len); void magnitude_est_cs16(int16_t const *iq_buf, uint16_t *y_buf, uint32_t len); void magnitude_true_cs16(int16_t const *iq_buf, uint16_t *y_buf, uint32_t len); +#define AMP_TO_DB(x) (10.0f * ((x) > 0 ? log10f(x) : 0) - 42.1442f) // 10*log10f(16384.0f) +#define MAG_TO_DB(x) (20.0f * ((x) > 0 ? log10f(x) : 0) - 84.2884f) // 20*log10f(16384.0f) +#ifdef __exp10f +#define _exp10f(x) __exp10f(x) +#else +#define _exp10f(x) powf(10, x) +#endif +#define DB_TO_AMP(x) ((int)(_exp10f(((x) + 42.1442f) / 10.0f))) // 10*log10f(16384.0f) +#define DB_TO_MAG(x) ((int)(_exp10f(((x) + 84.2884f) / 20.0f))) // 20*log10f(16384.0f) +#define DB_TO_AMP_F(x) ((int)(0.5 + _exp10f((x) / 10.0f))) +#define DB_TO_MAG_F(x) ((int)(0.5 + _exp10f((x) / 20.0f))) + #define FILTER_ORDER 1 /// Filter state buffer. diff --git a/include/pulse_detect.h b/include/pulse_detect.h index 0c7059d2..580c902e 100644 --- a/include/pulse_detect.h +++ b/include/pulse_detect.h @@ -14,7 +14,6 @@ #include <stdint.h> #include <stdio.h> -#include "r_util.h" #define PD_MAX_PULSES 1200 // Maximum number of pulses before forcing End Of Package #define PD_MIN_PULSES 16 // Minimum number of pulses before declaring a proper package @@ -101,6 +100,14 @@ pulse_detect_t *pulse_detect_create(void); void pulse_detect_free(pulse_detect_t *pulse_detect); +/// Set pulse detector level values. +/// +/// @param pulse_detect The pulse_detect instance +/// @param fixed_high_level Manual high level override, default is 0 (auto) +/// @param min_high_level Minimum high level, default is -12 dB +/// @param high_low_ratio Minimum signal noise ratio, default is 9 dB +void pulse_detect_set_levels(pulse_detect_t *pulse_detect, float fixed_high_level, float min_high_level, float high_low_ratio); + /// Demodulate On/Off Keying (OOK) and Frequency Shift Keying (FSK) from an envelope signal. /// /// Function is stateful and can be called with chunks of input data. @@ -109,7 +116,6 @@ void pulse_detect_free(pulse_detect_t *pulse_detect); /// @param envelope_data Samples with amplitude envelope of carrier /// @param fm_data Samples with frequency offset from center frequency /// @param len Number of samples in input buffers -/// @param level_limit Manual level override /// @param samp_rate Sample rate in samples per second /// @param sample_offset Offset tracking for ringbuffer /// @param[in,out] pulses Will return a pulse_data_t structure @@ -118,7 +124,7 @@ void pulse_detect_free(pulse_detect_t *pulse_detect); /// @return 0 if all input sample data is processed /// @return 1 if OOK package is detected (but all sample data is still not completely processed) /// @return 2 if FSK package is detected (but all sample data is still not completely processed) -int pulse_detect_package(pulse_detect_t *pulse_detect, int16_t const *envelope_data, int16_t const *fm_data, int len, int16_t level_limit, uint32_t samp_rate, uint64_t sample_offset, pulse_data_t *pulses, pulse_data_t *fsk_pulses, unsigned fpdm); +int pulse_detect_package(pulse_detect_t *pulse_detect, int16_t const *envelope_data, int16_t const *fm_data, int len, uint32_t samp_rate, uint64_t sample_offset, pulse_data_t *pulses, pulse_data_t *fsk_pulses, unsigned fpdm); /// Analyze and print result. void pulse_analyzer(pulse_data_t *data, int package_type); diff --git a/include/r_private.h b/include/r_private.h index 2ec30a7b..aaf3a8ae 100644 --- a/include/r_private.h +++ b/include/r_private.h @@ -17,7 +17,7 @@ #include "compat_time.h" struct dm_state { - int32_t level_limit; + float level_limit; int16_t am_buf[MAXIMAL_BUF_LENGTH]; // AM demodulated signal (for OOK decoding) union { // These buffers aren't used at the same time, so let's use a union to save some memory diff --git a/include/rtl_433.h b/include/rtl_433.h index c41331e1..9fd927aa 100644 --- a/include/rtl_433.h +++ b/include/rtl_433.h @@ -15,12 +15,6 @@ #define DEFAULT_ASYNC_BUF_NUMBER 0 // Force use of default value (librtlsdr default: 15) #define DEFAULT_BUF_LENGTH (16 * 32 * 512) // librtlsdr default #define FSK_PULSE_DETECTOR_LIMIT 800000000 -/* - * Theoretical high level at I/Q saturation is 128x128 = 16384 (above is ripple) - * 0 = automatic adaptive level limit, else fixed level limit - * 8000 = previous fixed default - */ -#define DEFAULT_LEVEL_LIMIT 0 #define MINIMAL_BUF_LENGTH 512 #define MAXIMAL_BUF_LENGTH (256 * 16384) diff --git a/src/am_analyze.c b/src/am_analyze.c index 08432a2a..d7e2d787 100644 --- a/src/am_analyze.c +++ b/src/am_analyze.c @@ -45,7 +45,7 @@ void am_analyze_skip(am_analyze_t *a, unsigned n_samples) void am_analyze(am_analyze_t *a, int16_t *am_buf, unsigned n_samples, int debug_output, samp_grab_t *g) { unsigned int i; - int32_t threshold = (*a->level_limit ? *a->level_limit : 8000); // Does not support auto level. Use old default instead. + int threshold = (a->level_limit ? a->level_limit : 8000); // Does not support auto level. Use old default instead. for (i = 0; i < n_samples; i++) { if (am_buf[i] > threshold) { diff --git a/src/pulse_detect.c b/src/pulse_detect.c index f6e76789..49137938 100644 --- a/src/pulse_detect.c +++ b/src/pulse_detect.c @@ -12,8 +12,10 @@ #include "pulse_detect.h" #include "pulse_demod.h" #include "pulse_detect_fsk.h" +#include "baseband.h" #include "util.h" -#include "decoder.h" +#include "r_device.h" +#include "r_util.h" #include "fatal.h" #include <limits.h> #include <stdio.h> @@ -183,15 +185,17 @@ void pulse_data_dump(FILE *file, pulse_data_t *data) } // OOK adaptive level estimator constants -#define OOK_HIGH_LOW_RATIO 8 // Default ratio between high and low (noise) level -#define OOK_MIN_HIGH_LEVEL 1000 // Minimum estimate of high level -#define OOK_MAX_HIGH_LEVEL (128*128) // Maximum estimate for high level (A unit phasor is 128, anything above is overdrive) -#define OOK_MAX_LOW_LEVEL (OOK_MAX_HIGH_LEVEL/2) // Maximum estimate for low level +#define OOK_MAX_HIGH_LEVEL DB_TO_AMP(0) // Maximum estimate for high level (-0 dB) +#define OOK_MAX_LOW_LEVEL DB_TO_AMP(-15) // Maximum estimate for low level #define OOK_EST_HIGH_RATIO 64 // Constant for slowness of OOK high level estimator #define OOK_EST_LOW_RATIO 1024 // Constant for slowness of OOK low level (noise) estimator (very slow) /// Internal state data for pulse_pulse_package() struct pulse_detect { + int ook_fixed_high_level; ///< Manual detection level override, 0 = auto. + int ook_min_high_level; ///< Minimum estimate of high level (-12 dB: 1000 amp, 4000 mag). + int ook_high_low_ratio; ///< Default ratio between high and low (noise) level (9 dB: x8 amp, 11 dB: x3.6 mag). + enum { PD_OOK_STATE_IDLE = 0, PD_OOK_STATE_PULSE = 1, @@ -213,8 +217,13 @@ struct pulse_detect { pulse_detect_t *pulse_detect_create() { pulse_detect_t *pulse_detect = calloc(1, sizeof(pulse_detect_t)); - if (!pulse_detect) + if (!pulse_detect) { WARN_CALLOC("pulse_detect_create()"); + return NULL; + } + + pulse_detect_set_levels(pulse_detect, 0.0, -12.1442, 9.0); + return pulse_detect; } @@ -223,12 +232,24 @@ void pulse_detect_free(pulse_detect_t *pulse_detect) free(pulse_detect); } +void pulse_detect_set_levels(pulse_detect_t *pulse_detect, float fixed_high_level, float min_high_level, float high_low_ratio) +{ + pulse_detect->ook_fixed_high_level = fixed_high_level < 0.0 ? DB_TO_AMP(fixed_high_level) : 0; + pulse_detect->ook_min_high_level = DB_TO_AMP(min_high_level); + pulse_detect->ook_high_low_ratio = DB_TO_AMP_F(high_low_ratio); + + //fprintf(stderr, "fixed_high_level %.1f (%d), min_high_level %.1f (%d), high_low_ratio %.1f (%d)\n", + // fixed_high_level, pulse_detect->ook_fixed_high_level, + // min_high_level, pulse_detect->ook_min_high_level, + // high_low_ratio, pulse_detect->ook_high_low_ratio); +} + /// Demodulate On/Off Keying (OOK) and Frequency Shift Keying (FSK) from an envelope signal -int pulse_detect_package(pulse_detect_t *pulse_detect, int16_t const *envelope_data, int16_t const *fm_data, int len, int16_t level_limit, uint32_t samp_rate, uint64_t sample_offset, pulse_data_t *pulses, pulse_data_t *fsk_pulses, unsigned fpdm) +int pulse_detect_package(pulse_detect_t *pulse_detect, int16_t const *envelope_data, int16_t const *fm_data, int len, uint32_t samp_rate, uint64_t sample_offset, pulse_data_t *pulses, pulse_data_t *fsk_pulses, unsigned fpdm) { int const samples_per_ms = samp_rate / 1000; pulse_detect_t *s = pulse_detect; - s->ook_high_estimate = MAX(s->ook_high_estimate, OOK_MIN_HIGH_LEVEL); // Be sure to set initial minimum level + s->ook_high_estimate = MAX(s->ook_high_estimate, pulse_detect->ook_min_high_level); // Be sure to set initial minimum level if (s->data_counter == 0) { // age the pulse_data if this is a fresh buffer @@ -240,9 +261,9 @@ int pulse_detect_package(pulse_detect_t *pulse_detect, int16_t const *envelope_d while (s->data_counter < len) { // Calculate OOK detection threshold and hysteresis int16_t const am_n = envelope_data[s->data_counter]; - int16_t ook_threshold = s->ook_low_estimate + (s->ook_high_estimate - s->ook_low_estimate) / 2; - if (level_limit != 0) - ook_threshold = level_limit; // Manual override + int16_t ook_threshold = (s->ook_low_estimate + s->ook_high_estimate) / 2; + if (pulse_detect->ook_fixed_high_level != 0) + ook_threshold = pulse_detect->ook_fixed_high_level; // Manual override int16_t const ook_hysteresis = ook_threshold / 8; // ±12% // OOK State machine @@ -273,8 +294,8 @@ int pulse_detect_package(pulse_detect_t *pulse_detect, int16_t const *envelope_d s->ook_low_estimate += ook_low_delta / OOK_EST_LOW_RATIO; s->ook_low_estimate += ((ook_low_delta > 0) ? 1 : -1); // Hack to compensate for lack of fixed-point scaling // Calculate default OOK high level estimate - s->ook_high_estimate = OOK_HIGH_LOW_RATIO * s->ook_low_estimate; // Default is a ratio of low level - s->ook_high_estimate = MAX(s->ook_high_estimate, OOK_MIN_HIGH_LEVEL); + s->ook_high_estimate = pulse_detect->ook_high_low_ratio * s->ook_low_estimate; // Default is a ratio of low level + s->ook_high_estimate = MAX(s->ook_high_estimate, pulse_detect->ook_min_high_level); s->ook_high_estimate = MIN(s->ook_high_estimate, OOK_MAX_HIGH_LEVEL); if (s->lead_in_counter <= OOK_EST_LOW_RATIO) s->lead_in_counter++; // Allow initial estimate to settle } @@ -299,7 +320,7 @@ int pulse_detect_package(pulse_detect_t *pulse_detect, int16_t const *envelope_d else { // Calculate OOK high level estimate s->ook_high_estimate += am_n / OOK_EST_HIGH_RATIO - s->ook_high_estimate / OOK_EST_HIGH_RATIO; - s->ook_high_estimate = MAX(s->ook_high_estimate, OOK_MIN_HIGH_LEVEL); + s->ook_high_estimate = MAX(s->ook_high_estimate, pulse_detect->ook_min_high_level); s->ook_high_estimate = MIN(s->ook_high_estimate, OOK_MAX_HIGH_LEVEL); // Estimate pulse carrier frequency pulses->fsk_f1_est += fm_data[s->data_counter] / OOK_EST_HIGH_RATIO - pulses->fsk_f1_est / OOK_EST_HIGH_RATIO; diff --git a/src/r_api.c b/src/r_api.c index 7c3da2b3..0ff0b366 100644 --- a/src/r_api.c +++ b/src/r_api.c @@ -17,6 +17,7 @@ #include <math.h> #include "r_api.h" +#include "r_util.h" #include "rtl_433.h" #include "r_private.h" #include "r_device.h" @@ -89,7 +90,7 @@ void r_init_cfg(r_cfg_t *cfg) if (!cfg->demod) FATAL_CALLOC("r_init_cfg()"); - cfg->demod->level_limit = DEFAULT_LEVEL_LIMIT; + cfg->demod->level_limit = 0.0; list_ensure_size(&cfg->demod->r_devs, 100); list_ensure_size(&cfg->demod->dumper, 32); diff --git a/src/rtl_433.c b/src/rtl_433.c index 7d6e680f..922ce352 100644 --- a/src/rtl_433.c +++ b/src/rtl_433.c @@ -99,7 +99,7 @@ static void usage(int exit_code) " Specify a negative number to disable a device decoding protocol (can be used multiple times)\n" " [-G] Enable blacklisted device decoding protocols, for testing only.\n" " [-X <spec> | help] Add a general purpose decoder (prepend -R 0 to disable all decoders)\n" - " [-l <level>] Change detection level used to determine pulses (0-16384) (0=auto) (default: %i)\n" + " [-l <dB level>] Manual detection level used to determine pulses (-1.0 to -30.0) (0=auto)\n" " [-z <value>] Override short value in data decoder\n" " [-x <value>] Override long value in data decoder\n" " [-n <value>] Specify number of samples to take (each sample is 2 bytes: 1 each of I & Q)\n" @@ -126,7 +126,7 @@ static void usage(int exit_code) " [-E hop | quit] Hop/Quit after outputting successful event(s)\n" " [-h] Output this usage help and exit\n" " Use -d, -g, -R, -X, -F, -M, -r, -w, or -W without argument for more help\n\n", - DEFAULT_FREQUENCY, DEFAULT_HOP_TIME, DEFAULT_SAMPLE_RATE, DEFAULT_LEVEL_LIMIT); + DEFAULT_FREQUENCY, DEFAULT_HOP_TIME, DEFAULT_SAMPLE_RATE); exit(exit_code); } @@ -366,7 +366,7 @@ static void sdr_callback(unsigned char *iq_buf, uint32_t len, void *ctx) } while (package_type) { int p_events = 0; // Sensor events successfully detected per package - package_type = pulse_detect_package(demod->pulse_detect, demod->am_buf, demod->buf.fm, n_samples, demod->level_limit, cfg->samp_rate, cfg->input_pos, &demod->pulse_data, &demod->fsk_pulse_data, fpdm); + package_type = pulse_detect_package(demod->pulse_detect, demod->am_buf, demod->buf.fm, n_samples, cfg->samp_rate, cfg->input_pos, &demod->pulse_data, &demod->fsk_pulse_data, fpdm); if (package_type) { // new package: set a first frame start if we are not tracking one already if (!demod->frame_start_ago) @@ -784,7 +784,17 @@ static void parse_conf_option(r_cfg_t *cfg, int opt, char *arg) cfg->out_block_size = atouint32_metric(arg, "-b: "); break; case 'l': - cfg->demod->level_limit = atouint32_metric(arg, "-l: "); + if (!arg) + usage(1); + cfg->demod->level_limit = atof(arg); + if (cfg->demod->level_limit > 0.0) { + fprintf(stderr, "\n\tLevel limit has changed to dB, %.0f is %.1f dB.\n\n", + cfg->demod->level_limit, AMP_TO_DB(cfg->demod->level_limit)); + exit(1); + } + if (cfg->demod->am_analyze) { + cfg->demod->am_analyze->level_limit = DB_TO_AMP(cfg->demod->level_limit); + } break; case 'n': cfg->bytes_to_read = atouint32_metric(arg, "-n: ") * 2; @@ -1184,8 +1194,9 @@ int main(int argc, char **argv) { add_infile(cfg, argv[optind++]); } + pulse_detect_set_levels(demod->pulse_detect, demod->level_limit, -12.1442, 9.0); + if (demod->am_analyze) { - demod->am_analyze->level_limit = &demod->level_limit; demod->am_analyze->frequency = &cfg->center_frequency; demod->am_analyze->samp_rate = &cfg->samp_rate; demod->am_analyze->sample_size = &demod->sample_size; @@ -1502,8 +1513,8 @@ int main(int argc, char **argv) { /* Set the sample rate */ r = sdr_set_sample_rate(cfg->dev, cfg->samp_rate, 1); // always verbose - if (cfg->verbosity || demod->level_limit) - fprintf(stderr, "Bit detection level set to %d%s.\n", demod->level_limit, (demod->level_limit ? "" : " (Auto)")); + if (cfg->verbosity || demod->level_limit < 0.0) + fprintf(stderr, "Bit detection level set to %.1f%s.\n", demod->level_limit, (demod->level_limit < 0.0 ? "" : " (Auto)")); r = sdr_apply_settings(cfg->dev, cfg->settings_str, 1); // always verbose for soapy