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