From f81f069d95009bb3a8d4f5110e842b2543ea5f33 Mon Sep 17 00:00:00 2001 From: Kamal Mostafa Date: Sat, 18 Aug 2012 21:24:01 -0700 Subject: [PATCH] minimodem: --limit (2.3) sets fsk_confidence_search_limit Significant performance enhancements from fsk_confidence_search_limit: runs far fewer FFT's when --limit (default 2.3) is less than INFINITY. --- src/fsk.c | 27 +++++++++++++++++++-------- src/fsk.h | 4 +++- src/minimodem.1.in | 19 +++++++++++++++---- src/minimodem.c | 43 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 77 insertions(+), 16 deletions(-) diff --git a/src/fsk.c b/src/fsk.c index 082bbac..0967b41 100644 --- a/src/fsk.c +++ b/src/fsk.c @@ -409,8 +409,10 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit, /* returns confidence value [0.0 to 1.0] */ float fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples, + unsigned int try_first_sample, unsigned int try_max_nsamples, unsigned int try_step_nsamples, + float try_confidence_search_limit, unsigned int *bits_outp, unsigned int *frame_start_outp ) @@ -419,25 +421,34 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples, // try_step_nsamples = 1; // pedantic TEST - unsigned int t; unsigned int best_t = 0; float best_c = 0.0; unsigned int best_bits = 0; - for ( t=0; t+try_step_nsamples<=try_max_nsamples; t+=try_step_nsamples ) + + // Scan the frame positions starting with the one try_first_sample, + // alternating between a step above that, a step below that, above, below, + // and so on, until we've scanned the whole try_max_nsamples range. + int j; + for ( j=0; ; j++ ) { + int up = j%2 ? 1 : -1; + int t = try_first_sample + up*((j+1)/2)*try_step_nsamples; + if ( t >= (int)try_max_nsamples ) + break; + if ( t < 0 ) + continue; + float c; unsigned int bits_out = 0; - debug_log("try fsk_frame_analyze(skip=%+d)\n", t); + debug_log("try fsk_frame_analyze at t=%d\n", t); c = fsk_frame_analyze(fskp, samples+t, samples_per_bit, &bits_out); if ( best_c < c ) { best_t = t; best_c = c; best_bits = bits_out; - // TEST -// if ( best_c > 100.0f ) -// break; - // if we find a perfect frame, stop scanning for a better one - if ( best_c == INFINITY ) + // If we find a frame with confidence > try_confidence_search_limit + // quit searching. + if ( best_c >= try_confidence_search_limit ) break; } } diff --git a/src/fsk.h b/src/fsk.h index b75b09d..6e26ddd 100644 --- a/src/fsk.h +++ b/src/fsk.h @@ -63,8 +63,10 @@ fsk_plan_destroy( fsk_plan *fskp ); /* returns confidence value [0.0 to 1.0] */ float fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples, + unsigned int try_first_sample, unsigned int try_max_nsamples, unsigned int try_step_nsamples, + float try_confidence_search_limit, unsigned int *bits_outp, unsigned int *frame_start_outp ); @@ -78,7 +80,7 @@ fsk_set_tones_by_bandshift( fsk_plan *fskp, unsigned int b_mark, int b_shift ); // FIXME move this?: -//#define FSK_DEBUG +// #define FSK_DEBUG #ifdef FSK_DEBUG # define debug_log(format, args...) fprintf(stderr, format, ## args) #else diff --git a/src/minimodem.1.in b/src/minimodem.1.in index d57e2df..cb49296 100644 --- a/src/minimodem.1.in +++ b/src/minimodem.1.in @@ -2,7 +2,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) -.TH MINIMODEM 1 "August 12, 2011" +.TH MINIMODEM 1 "August 19, 2012" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: @@ -48,8 +48,19 @@ receive mode: decode audio tones .B \-a, \-\-auto-carrier automatically detect mark and space frequences from carrier .TP -.B \-c, \-\-confidence threshold -set receive confidence (minimum SNR) threshold (default 2.0) +.B \-c, \-\-confidence min-snr-threshold +Set receive confidence minimum SNR threshold (default 2.0). +This value acts as an FSK decoder "squelch" control. +Increase to accept only very clean signals (up to INFINITY, but +a value around 5.0 is more practical). Decrease to accept partial +decoding of noisy signals (down to 1.0). +.TP +.B \-l, \-\-limit max-snr-search-limit +Set receive confidence maximum SNR search limit (default 2.3). +This value acts as a performance vs. analysis quality control. +Increase (up to INFINITY) for a more pedantic analysis +and higher CPU usage. Decrease (down to the min-snr-threshold) +for a sloppier analysis, with lower CPU usage. .TP .B \-8, \-\-ascii ASCII 8\-N\-1 @@ -143,7 +154,7 @@ The latest version is available at . .B minimodem was written by Kamal Mostafa . .SH COPYRIGHT -Copyright \(co 2011 by Kamal Mostafa . +Copyright \(co 2011-2012 by Kamal Mostafa . License GPLv3+: GNU GPL version 3 or later . .br This is free software: you are free to change and redistribute it. diff --git a/src/minimodem.c b/src/minimodem.c index 3217bf1..400db38 100644 --- a/src/minimodem.c +++ b/src/minimodem.c @@ -322,6 +322,7 @@ usage() " [options]\n" " -a, --auto-carrier\n" " -c, --confidence {min-snr-threshold}\n" + " -l, --limit {max-snr-search-limit}\n" " -8, --ascii ASCII 8-N-1\n" " -5, --baudot Baudot 5-N-1\n" " -f, --file {filename.flac}\n" @@ -360,7 +361,20 @@ main( int argc, char*argv[] ) char *filename = NULL; float carrier_autodetect_threshold = 0.0; - float bfsk_confidence_threshold = 2.0; + + // fsk_confidence_threshold : signal-to-noise squelch control + // + // The minimum SNR confidence level seen as "a signal". + float fsk_confidence_threshold = 2.0; + + // fsk_confidence_search_limit : performance vs. quality + // + // If we find a frame with SNR confidence > confidence_search_limit, + // quit searching for a better frame. confidence_search_limit has a + // dramatic effect on peformance (high value yields low performance, but + // higher decode quality, for noisy or hard-to-discern signals (Bell 103). + float fsk_confidence_search_limit = 2.3f; + // float fsk_confidence_search_limit = INFINITY; /* for test */ sa_backend_t sa_backend = SA_BACKEND_SYSDEFAULT; sa_format_t sample_format = SA_SAMPLE_FORMAT_S16; @@ -403,6 +417,7 @@ main( int argc, char*argv[] ) { "receive", 0, 0, 'r' }, { "read", 0, 0, 'r' }, { "confidence", 1, 0, 'c' }, + { "limit", 1, 0, 'l' }, { "auto-carrier", 0, 0, 'a' }, { "ascii", 0, 0, '8' }, { "baudot", 0, 0, '5' }, @@ -438,7 +453,10 @@ main( int argc, char*argv[] ) TX_mode = 0; break; case 'c': - bfsk_confidence_threshold = atof(optarg); + fsk_confidence_threshold = atof(optarg); + break; + case 'l': + fsk_confidence_search_limit = atof(optarg); break; case 'a': carrier_autodetect_threshold = 0.001; @@ -607,6 +625,9 @@ main( int argc, char*argv[] ) if ( band_width > bfsk_data_rate ) band_width = bfsk_data_rate; + // sanitize confidence search limit + if ( fsk_confidence_search_limit < fsk_confidence_threshold ) + fsk_confidence_search_limit = fsk_confidence_threshold; char *stream_name = NULL;; @@ -842,9 +863,25 @@ main( int argc, char*argv[] ) * prev_stop bit begins (since the "frame" includes the prev_stop). */ unsigned int frame_start_sample = 0; + // If we don't have carrier, then set this try_confidence_search_limit + // to infinity (search for best possible frame) so to get the decoder + // into phase with the signal, so the next try_first_sample will match + // up with where the next frame should be. + unsigned int try_first_sample; + float try_confidence_search_limit; + if ( carrier ) { + try_first_sample = nsamples_overscan; + try_confidence_search_limit = fsk_confidence_search_limit; + } else { + try_first_sample = 0; + try_confidence_search_limit = INFINITY; + } + confidence = fsk_find_frame(fskp, samplebuf, frame_nsamples, + try_first_sample, try_max_nsamples, try_step_nsamples, + try_confidence_search_limit, &bits, &frame_start_sample ); @@ -857,7 +894,7 @@ main( int argc, char*argv[] ) #define FSK_MAX_NOCONFIDENCE_BITS 20 - if ( confidence <= bfsk_confidence_threshold ) { + if ( confidence <= fsk_confidence_threshold ) { // FIXME: explain if ( ++noconfidence > FSK_MAX_NOCONFIDENCE_BITS )