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.
This commit is contained in:
Kamal Mostafa 2012-08-18 21:24:01 -07:00
parent e1b055cf4f
commit f81f069d95
4 changed files with 77 additions and 16 deletions

View File

@ -409,8 +409,10 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
/* returns confidence value [0.0 to 1.0] */ /* returns confidence value [0.0 to 1.0] */
float float
fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples, 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_max_nsamples,
unsigned int try_step_nsamples, unsigned int try_step_nsamples,
float try_confidence_search_limit,
unsigned int *bits_outp, unsigned int *bits_outp,
unsigned int *frame_start_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 // try_step_nsamples = 1; // pedantic TEST
unsigned int t;
unsigned int best_t = 0; unsigned int best_t = 0;
float best_c = 0.0; float best_c = 0.0;
unsigned int best_bits = 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; float c;
unsigned int bits_out = 0; 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); c = fsk_frame_analyze(fskp, samples+t, samples_per_bit, &bits_out);
if ( best_c < c ) { if ( best_c < c ) {
best_t = t; best_t = t;
best_c = c; best_c = c;
best_bits = bits_out; best_bits = bits_out;
// TEST // If we find a frame with confidence > try_confidence_search_limit
// if ( best_c > 100.0f ) // quit searching.
// break; if ( best_c >= try_confidence_search_limit )
// if we find a perfect frame, stop scanning for a better one
if ( best_c == INFINITY )
break; break;
} }
} }

View File

@ -63,8 +63,10 @@ fsk_plan_destroy( fsk_plan *fskp );
/* returns confidence value [0.0 to 1.0] */ /* returns confidence value [0.0 to 1.0] */
float float
fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples, 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_max_nsamples,
unsigned int try_step_nsamples, unsigned int try_step_nsamples,
float try_confidence_search_limit,
unsigned int *bits_outp, unsigned int *bits_outp,
unsigned int *frame_start_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?: // FIXME move this?:
//#define FSK_DEBUG // #define FSK_DEBUG
#ifdef FSK_DEBUG #ifdef FSK_DEBUG
# define debug_log(format, args...) fprintf(stderr, format, ## args) # define debug_log(format, args...) fprintf(stderr, format, ## args)
#else #else

View File

@ -2,7 +2,7 @@
.\" First parameter, NAME, should be all caps .\" First parameter, NAME, should be all caps
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
.\" other parameters are allowed: see man(7), man(1) .\" 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. .\" Please adjust this date whenever revising the manpage.
.\" .\"
.\" Some roff macros, for reference: .\" Some roff macros, for reference:
@ -48,8 +48,19 @@ receive mode: decode audio tones
.B \-a, \-\-auto-carrier .B \-a, \-\-auto-carrier
automatically detect mark and space frequences from carrier automatically detect mark and space frequences from carrier
.TP .TP
.B \-c, \-\-confidence threshold .B \-c, \-\-confidence min-snr-threshold
set receive confidence (minimum SNR) threshold (default 2.0) 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 .TP
.B \-8, \-\-ascii .B \-8, \-\-ascii
ASCII 8\-N\-1 ASCII 8\-N\-1
@ -143,7 +154,7 @@ The latest version is available at <http://www.whence.com/minimodem>.
.B minimodem .B minimodem
was written by Kamal Mostafa <kamal@whence.com>. was written by Kamal Mostafa <kamal@whence.com>.
.SH COPYRIGHT .SH COPYRIGHT
Copyright \(co 2011 by Kamal Mostafa <kamal@whence.com>. Copyright \(co 2011-2012 by Kamal Mostafa <kamal@whence.com>.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
.br .br
This is free software: you are free to change and redistribute it. This is free software: you are free to change and redistribute it.

View File

@ -322,6 +322,7 @@ usage()
" [options]\n" " [options]\n"
" -a, --auto-carrier\n" " -a, --auto-carrier\n"
" -c, --confidence {min-snr-threshold}\n" " -c, --confidence {min-snr-threshold}\n"
" -l, --limit {max-snr-search-limit}\n"
" -8, --ascii ASCII 8-N-1\n" " -8, --ascii ASCII 8-N-1\n"
" -5, --baudot Baudot 5-N-1\n" " -5, --baudot Baudot 5-N-1\n"
" -f, --file {filename.flac}\n" " -f, --file {filename.flac}\n"
@ -360,7 +361,20 @@ main( int argc, char*argv[] )
char *filename = NULL; char *filename = NULL;
float carrier_autodetect_threshold = 0.0; 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_backend_t sa_backend = SA_BACKEND_SYSDEFAULT;
sa_format_t sample_format = SA_SAMPLE_FORMAT_S16; sa_format_t sample_format = SA_SAMPLE_FORMAT_S16;
@ -403,6 +417,7 @@ main( int argc, char*argv[] )
{ "receive", 0, 0, 'r' }, { "receive", 0, 0, 'r' },
{ "read", 0, 0, 'r' }, { "read", 0, 0, 'r' },
{ "confidence", 1, 0, 'c' }, { "confidence", 1, 0, 'c' },
{ "limit", 1, 0, 'l' },
{ "auto-carrier", 0, 0, 'a' }, { "auto-carrier", 0, 0, 'a' },
{ "ascii", 0, 0, '8' }, { "ascii", 0, 0, '8' },
{ "baudot", 0, 0, '5' }, { "baudot", 0, 0, '5' },
@ -438,7 +453,10 @@ main( int argc, char*argv[] )
TX_mode = 0; TX_mode = 0;
break; break;
case 'c': case 'c':
bfsk_confidence_threshold = atof(optarg); fsk_confidence_threshold = atof(optarg);
break;
case 'l':
fsk_confidence_search_limit = atof(optarg);
break; break;
case 'a': case 'a':
carrier_autodetect_threshold = 0.001; carrier_autodetect_threshold = 0.001;
@ -607,6 +625,9 @@ main( int argc, char*argv[] )
if ( band_width > bfsk_data_rate ) if ( band_width > bfsk_data_rate )
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;; char *stream_name = NULL;;
@ -842,9 +863,25 @@ main( int argc, char*argv[] )
* prev_stop bit begins (since the "frame" includes the prev_stop). */ * prev_stop bit begins (since the "frame" includes the prev_stop). */
unsigned int frame_start_sample = 0; 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, confidence = fsk_find_frame(fskp, samplebuf, frame_nsamples,
try_first_sample,
try_max_nsamples, try_max_nsamples,
try_step_nsamples, try_step_nsamples,
try_confidence_search_limit,
&bits, &bits,
&frame_start_sample &frame_start_sample
); );
@ -857,7 +894,7 @@ main( int argc, char*argv[] )
#define FSK_MAX_NOCONFIDENCE_BITS 20 #define FSK_MAX_NOCONFIDENCE_BITS 20
if ( confidence <= bfsk_confidence_threshold ) { if ( confidence <= fsk_confidence_threshold ) {
// FIXME: explain // FIXME: explain
if ( ++noconfidence > FSK_MAX_NOCONFIDENCE_BITS ) if ( ++noconfidence > FSK_MAX_NOCONFIDENCE_BITS )