fsk: expect_bits_string param, no start/stop bits required
fsk_find_frame() takes expect_bits_string (e.g. "10dddddddd1"), as a parameter supplied by the caller allowing for encodings which don't use any start/stop bits (e.g. just "dddddddd").
This commit is contained in:
parent
6bb683a90b
commit
501ee25c7d
52
src/fsk.c
52
src/fsk.c
|
@ -35,8 +35,7 @@ fsk_plan_new(
|
||||||
float sample_rate,
|
float sample_rate,
|
||||||
float f_mark,
|
float f_mark,
|
||||||
float f_space,
|
float f_space,
|
||||||
float filter_bw,
|
float filter_bw
|
||||||
unsigned int n_data_bits
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
fsk_plan *fskp = malloc(sizeof(fsk_plan));
|
fsk_plan *fskp = malloc(sizeof(fsk_plan));
|
||||||
|
@ -46,10 +45,6 @@ fsk_plan_new(
|
||||||
fskp->sample_rate = sample_rate;
|
fskp->sample_rate = sample_rate;
|
||||||
fskp->f_mark = f_mark;
|
fskp->f_mark = f_mark;
|
||||||
fskp->f_space = f_space;
|
fskp->f_space = f_space;
|
||||||
fskp->n_data_bits = n_data_bits;
|
|
||||||
|
|
||||||
/* 1 prev_stop + n_data_bits + 1 start + 1 stop == n_data_bits + 3 */
|
|
||||||
fskp->n_frame_bits = fskp->n_data_bits + 3;
|
|
||||||
|
|
||||||
#ifdef USE_FFT
|
#ifdef USE_FFT
|
||||||
fskp->band_width = filter_bw;
|
fskp->band_width = filter_bw;
|
||||||
|
@ -182,24 +177,9 @@ fsk_bit_analyze( fsk_plan *fskp, float *samples, unsigned int bit_nsamples,
|
||||||
/* returns confidence value [0.0 to 1.0] */
|
/* returns confidence value [0.0 to 1.0] */
|
||||||
static float
|
static float
|
||||||
fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
|
fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
|
||||||
|
int n_bits, const char *expect_bits_string,
|
||||||
unsigned int *bits_outp )
|
unsigned int *bits_outp )
|
||||||
{
|
{
|
||||||
int n_bits = fskp->n_frame_bits;
|
|
||||||
// char *expect_bit_string = "10dddddddd1";
|
|
||||||
char expect_bit_string[32];
|
|
||||||
memset(expect_bit_string, 'd', 32);
|
|
||||||
expect_bit_string[0] = '1';
|
|
||||||
expect_bit_string[1] = '0';
|
|
||||||
expect_bit_string[fskp->n_data_bits + 2] = '1';
|
|
||||||
|
|
||||||
// example...
|
|
||||||
// 0123456789A
|
|
||||||
// isddddddddp i == idle bit (a.k.a. prev_stop bit)
|
|
||||||
// s == start bit
|
|
||||||
// d == data bits
|
|
||||||
// p == stop bit
|
|
||||||
// MSddddddddM <-- expected mark/space framing pattern
|
|
||||||
|
|
||||||
unsigned int bit_nsamples = (float)(samples_per_bit + 0.5);
|
unsigned int bit_nsamples = (float)(samples_per_bit + 0.5);
|
||||||
|
|
||||||
unsigned int bit_values[32];
|
unsigned int bit_values[32];
|
||||||
|
@ -208,7 +188,7 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
|
||||||
unsigned int bit_begin_sample;
|
unsigned int bit_begin_sample;
|
||||||
int bitnum;
|
int bitnum;
|
||||||
|
|
||||||
char *expect_bits = expect_bit_string;
|
const char *expect_bits = expect_bits_string;
|
||||||
|
|
||||||
/* pass #1 - process and check only the "required" (1/0) expect_bits */
|
/* pass #1 - process and check only the "required" (1/0) expect_bits */
|
||||||
for ( bitnum=0; bitnum<n_bits; bitnum++ ) {
|
for ( bitnum=0; bitnum<n_bits; bitnum++ ) {
|
||||||
|
@ -242,12 +222,16 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
|
||||||
#define AVOID_TRANSIENTS 0.7
|
#define AVOID_TRANSIENTS 0.7
|
||||||
//
|
//
|
||||||
#ifdef AVOID_TRANSIENTS
|
#ifdef AVOID_TRANSIENTS
|
||||||
|
// FIXME: fsk_frame_analyze shouldn't care about start/stop bits,
|
||||||
|
// and this really is only correct for "10dd..dd1" format frames anyway:
|
||||||
|
// FIXME: this is totally defective, if the checked bits weren't
|
||||||
|
// even calculated in pass #1 (e.g. if there are no pass #1 expect bits).
|
||||||
/* Compare strength of stop bit and start bit, to avoid detecting
|
/* Compare strength of stop bit and start bit, to avoid detecting
|
||||||
* a transient as a start bit, as often results in a single false
|
* a transient as a start bit, as often results in a single false
|
||||||
* character when the mark "leader" tone begins. Require that the
|
* character when the mark "leader" tone begins. Require that the
|
||||||
* diff between start bit and stop bit strength not be "large". */
|
* diff between start bit and stop bit strength not be "large". */
|
||||||
float s_mag = bit_sig_mags[1];
|
float s_mag = bit_sig_mags[1]; // start bit
|
||||||
float p_mag = bit_sig_mags[fskp->n_data_bits + 2];
|
float p_mag = bit_sig_mags[n_bits-1]; // stop bit
|
||||||
if ( fabs(s_mag-p_mag) > (s_mag * AVOID_TRANSIENTS) ) {
|
if ( fabs(s_mag-p_mag) > (s_mag * AVOID_TRANSIENTS) ) {
|
||||||
debug_log(" avoid transient\n");
|
debug_log(" avoid transient\n");
|
||||||
return 0.0;
|
return 0.0;
|
||||||
|
@ -397,6 +381,8 @@ fsk_frame_analyze( fsk_plan *fskp, float *samples, float samples_per_bit,
|
||||||
#endif /* CONFIDENCE_ALGO */
|
#endif /* CONFIDENCE_ALGO */
|
||||||
|
|
||||||
|
|
||||||
|
// least significant bit first ... reverse the bits as we place them
|
||||||
|
// into the bits_outp word.
|
||||||
*bits_outp = 0;
|
*bits_outp = 0;
|
||||||
for ( bitnum=0; bitnum<n_bits; bitnum++ )
|
for ( bitnum=0; bitnum<n_bits; bitnum++ )
|
||||||
*bits_outp |= bit_values[bitnum] << bitnum;
|
*bits_outp |= bit_values[bitnum] << bitnum;
|
||||||
|
@ -413,11 +399,14 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
|
||||||
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,
|
float try_confidence_search_limit,
|
||||||
|
const char *expect_bits_string,
|
||||||
unsigned int *bits_outp,
|
unsigned int *bits_outp,
|
||||||
unsigned int *frame_start_outp
|
unsigned int *frame_start_outp
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
float samples_per_bit = (float)frame_nsamples / fskp->n_frame_bits;
|
int expect_n_bits = strlen(expect_bits_string);
|
||||||
|
|
||||||
|
float samples_per_bit = (float)frame_nsamples / expect_n_bits;
|
||||||
|
|
||||||
// try_step_nsamples = 1; // pedantic TEST
|
// try_step_nsamples = 1; // pedantic TEST
|
||||||
|
|
||||||
|
@ -441,7 +430,8 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
|
||||||
float c;
|
float c;
|
||||||
unsigned int bits_out = 0;
|
unsigned int bits_out = 0;
|
||||||
debug_log("try fsk_frame_analyze at t=%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,
|
||||||
|
expect_n_bits, expect_bits_string, &bits_out);
|
||||||
if ( best_c < c ) {
|
if ( best_c < c ) {
|
||||||
best_t = t;
|
best_t = t;
|
||||||
best_c = c;
|
best_c = c;
|
||||||
|
@ -463,8 +453,12 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
|
||||||
|
|
||||||
// FIXME? hardcoded chop off framing bits for debug
|
// FIXME? hardcoded chop off framing bits for debug
|
||||||
#ifdef FSK_DEBUG
|
#ifdef FSK_DEBUG
|
||||||
unsigned char bitchar = ( best_bits >> 2 ) & 0xFF;
|
unsigned char bitchar = ( *bits_outp >> 2 ) & 0xFF;
|
||||||
debug_log("FSK_FRAME datum='%c' (0x%02x) c=%f t=%d\n",
|
|
||||||
|
debug_log("FSK_FRAME bits='");
|
||||||
|
for ( j=0; j<expect_n_bits; j++ )
|
||||||
|
debug_log("%c", ( *bits_outp >> j ) & 1 ? '1' : '0' );
|
||||||
|
debug_log("' datum='%c' (0x%02x) c=%f t=%d\n",
|
||||||
isprint(bitchar)||isspace(bitchar) ? bitchar : '.',
|
isprint(bitchar)||isspace(bitchar) ? bitchar : '.',
|
||||||
bitchar,
|
bitchar,
|
||||||
confidence, best_t);
|
confidence, best_t);
|
||||||
|
|
|
@ -32,9 +32,7 @@ struct fsk_plan {
|
||||||
float f_mark;
|
float f_mark;
|
||||||
float f_space;
|
float f_space;
|
||||||
float filter_bw;
|
float filter_bw;
|
||||||
unsigned int n_data_bits;
|
|
||||||
|
|
||||||
unsigned int n_frame_bits;
|
|
||||||
#ifdef USE_FFT
|
#ifdef USE_FFT
|
||||||
int fftsize;
|
int fftsize;
|
||||||
unsigned int nbands;
|
unsigned int nbands;
|
||||||
|
@ -53,8 +51,7 @@ fsk_plan_new(
|
||||||
float sample_rate,
|
float sample_rate,
|
||||||
float f_mark,
|
float f_mark,
|
||||||
float f_space,
|
float f_space,
|
||||||
float filter_bw,
|
float filter_bw
|
||||||
unsigned int n_data_bits
|
|
||||||
);
|
);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -67,6 +64,7 @@ fsk_find_frame( fsk_plan *fskp, float *samples, unsigned int frame_nsamples,
|
||||||
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,
|
float try_confidence_search_limit,
|
||||||
|
const char *expect_bits_string,
|
||||||
unsigned int *bits_outp,
|
unsigned int *bits_outp,
|
||||||
unsigned int *frame_start_outp
|
unsigned int *frame_start_outp
|
||||||
);
|
);
|
||||||
|
|
|
@ -198,22 +198,23 @@ report_no_carrier( fsk_plan *fskp,
|
||||||
float bfsk_data_rate,
|
float bfsk_data_rate,
|
||||||
float nsamples_per_bit,
|
float nsamples_per_bit,
|
||||||
unsigned int nframes_decoded,
|
unsigned int nframes_decoded,
|
||||||
|
unsigned long long nbits_decoded,
|
||||||
size_t carrier_nsamples,
|
size_t carrier_nsamples,
|
||||||
float confidence_total )
|
float confidence_total )
|
||||||
{
|
{
|
||||||
unsigned long long nbits_total = nframes_decoded * (fskp->n_data_bits+2);
|
|
||||||
#if 0
|
#if 0
|
||||||
fprintf(stderr, "nframes_decoded=%u\n", nframes_decoded);
|
fprintf(stderr, "nframes_decoded=%u\n", nframes_decoded);
|
||||||
fprintf(stderr, "nbits_total=%llu\n", nbits_total);
|
fprintf(stderr, "nbits_decoded=%llu\n", nbits_decoded);
|
||||||
fprintf(stderr, "carrier_nsamples=%lu\n", carrier_nsamples);
|
fprintf(stderr, "carrier_nsamples=%lu\n", carrier_nsamples);
|
||||||
fprintf(stderr, "nsamples_per_bit=%f\n", nsamples_per_bit);
|
fprintf(stderr, "nsamples_per_bit=%f\n", nsamples_per_bit);
|
||||||
#endif
|
#endif
|
||||||
float throughput_rate = nbits_total * sample_rate / (float)carrier_nsamples;
|
float throughput_rate =
|
||||||
|
nbits_decoded * sample_rate / (float)carrier_nsamples;
|
||||||
fprintf(stderr, "### NOCARRIER ndata=%u confidence=%.3f throughput=%.2f",
|
fprintf(stderr, "### NOCARRIER ndata=%u confidence=%.3f throughput=%.2f",
|
||||||
nframes_decoded,
|
nframes_decoded,
|
||||||
confidence_total / nframes_decoded,
|
confidence_total / nframes_decoded,
|
||||||
throughput_rate);
|
throughput_rate);
|
||||||
if ( (size_t)(nbits_total * nsamples_per_bit + 0.5) == carrier_nsamples ) {
|
if ( (size_t)(nbits_decoded * nsamples_per_bit + 0.5) == carrier_nsamples ) {
|
||||||
fprintf(stderr, " (rate perfect) ###\n");
|
fprintf(stderr, " (rate perfect) ###\n");
|
||||||
} else {
|
} else {
|
||||||
float throughput_skew = (throughput_rate - bfsk_data_rate)
|
float throughput_skew = (throughput_rate - bfsk_data_rate)
|
||||||
|
@ -696,8 +697,7 @@ main( int argc, char*argv[] )
|
||||||
*/
|
*/
|
||||||
|
|
||||||
fsk_plan *fskp;
|
fsk_plan *fskp;
|
||||||
fskp = fsk_plan_new(sample_rate, bfsk_mark_f, bfsk_space_f,
|
fskp = fsk_plan_new(sample_rate, bfsk_mark_f, bfsk_space_f, band_width);
|
||||||
band_width, bfsk_n_data_bits);
|
|
||||||
if ( !fskp ) {
|
if ( !fskp ) {
|
||||||
fprintf(stderr, "fsk_plan_new() failed\n");
|
fprintf(stderr, "fsk_plan_new() failed\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -728,6 +728,7 @@ main( int argc, char*argv[] )
|
||||||
int carrier = 0;
|
int carrier = 0;
|
||||||
float confidence_total = 0;
|
float confidence_total = 0;
|
||||||
unsigned int nframes_decoded = 0;
|
unsigned int nframes_decoded = 0;
|
||||||
|
unsigned long long nbits_decoded = 0;
|
||||||
size_t carrier_nsamples = 0;
|
size_t carrier_nsamples = 0;
|
||||||
|
|
||||||
unsigned int noconfidence = 0;
|
unsigned int noconfidence = 0;
|
||||||
|
@ -839,9 +840,38 @@ main( int argc, char*argv[] )
|
||||||
|
|
||||||
debug_log( "--------------------------\n");
|
debug_log( "--------------------------\n");
|
||||||
|
|
||||||
unsigned int frame_nsamples = nsamples_per_bit * fskp->n_frame_bits;
|
// example expect_bits_string
|
||||||
|
// 0123456789A
|
||||||
|
// isddddddddp i == idle bit (a.k.a. prev_stop bit)
|
||||||
|
// s == start bit d == data bits p == stop bit
|
||||||
|
// ebs = "10dddddddd1" <-- expected mark/space framing pattern
|
||||||
|
//
|
||||||
|
// NOTE! expect_n_bits ends up being (frame_n_bits+1), because
|
||||||
|
// we expect the prev_stop bit in addition to this frame's own
|
||||||
|
// (start + n_data_bits + stop) bits. But for each decoded frame,
|
||||||
|
// we will advance just frame_n_bits worth of samples, leaving us
|
||||||
|
// pointing at our stop bit -- it becomes the next frame's prev_stop.
|
||||||
|
//
|
||||||
|
// prev_stop--v
|
||||||
|
// start--v v--stop
|
||||||
|
// char *expect_bits_string = "10dddddddd1";
|
||||||
|
//
|
||||||
|
char expect_bits_string[33] = "10dddddddddddddddddddddddddddddd";
|
||||||
|
expect_bits_string[bfsk_n_data_bits + 2] = '1';
|
||||||
|
expect_bits_string[bfsk_n_data_bits + 3] = 0;
|
||||||
|
unsigned int frame_n_bits = bfsk_n_data_bits + 2;
|
||||||
|
unsigned int frame_bits_shift = 2; // prev_stop + start
|
||||||
|
// FIXME - weird hardcode:
|
||||||
|
unsigned int frame_bits_mask = 0xFF;
|
||||||
|
if ( bfsk_n_data_bits == 5 )
|
||||||
|
frame_bits_mask = 0x1F;
|
||||||
|
|
||||||
if ( samples_nvalid < frame_nsamples )
|
unsigned int frame_nsamples = nsamples_per_bit * frame_n_bits;
|
||||||
|
|
||||||
|
unsigned int expect_n_bits = strlen(expect_bits_string);
|
||||||
|
unsigned int expect_nsamples = nsamples_per_bit * expect_n_bits;
|
||||||
|
|
||||||
|
if ( samples_nvalid < expect_nsamples )
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// try_max_nsamples = nsamples_per_bit + nsamples_overscan;
|
// try_max_nsamples = nsamples_per_bit + nsamples_overscan;
|
||||||
|
@ -877,20 +907,18 @@ main( int argc, char*argv[] )
|
||||||
try_confidence_search_limit = INFINITY;
|
try_confidence_search_limit = INFINITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
confidence = fsk_find_frame(fskp, samplebuf, frame_nsamples,
|
confidence = fsk_find_frame(fskp, samplebuf, expect_nsamples,
|
||||||
try_first_sample,
|
try_first_sample,
|
||||||
try_max_nsamples,
|
try_max_nsamples,
|
||||||
try_step_nsamples,
|
try_step_nsamples,
|
||||||
try_confidence_search_limit,
|
try_confidence_search_limit,
|
||||||
|
expect_bits_string,
|
||||||
&bits,
|
&bits,
|
||||||
&frame_start_sample
|
&frame_start_sample
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME: hardcoded chop off framing bits
|
// chop off framing bits
|
||||||
if ( fskp->n_data_bits == 5 )
|
bits = ( bits >> frame_bits_shift ) & frame_bits_mask;
|
||||||
bits = ( bits >> 2 ) & 0x1F;
|
|
||||||
else
|
|
||||||
bits = ( bits >> 2 ) & 0xFF;
|
|
||||||
|
|
||||||
#define FSK_MAX_NOCONFIDENCE_BITS 20
|
#define FSK_MAX_NOCONFIDENCE_BITS 20
|
||||||
|
|
||||||
|
@ -903,12 +931,13 @@ main( int argc, char*argv[] )
|
||||||
if ( carrier ) {
|
if ( carrier ) {
|
||||||
if ( !quiet_mode )
|
if ( !quiet_mode )
|
||||||
report_no_carrier(fskp, sample_rate, bfsk_data_rate,
|
report_no_carrier(fskp, sample_rate, bfsk_data_rate,
|
||||||
nsamples_per_bit, nframes_decoded,
|
nsamples_per_bit, nframes_decoded, nbits_decoded,
|
||||||
carrier_nsamples, confidence_total);
|
carrier_nsamples, confidence_total);
|
||||||
carrier = 0;
|
carrier = 0;
|
||||||
carrier_nsamples = 0;
|
carrier_nsamples = 0;
|
||||||
confidence_total = 0;
|
confidence_total = 0;
|
||||||
nframes_decoded = 0;
|
nframes_decoded = 0;
|
||||||
|
nbits_decoded = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -921,7 +950,7 @@ main( int argc, char*argv[] )
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add a frame's worth of samples to the sample count
|
// Add a frame's worth of samples to the sample count
|
||||||
carrier_nsamples += nsamples_per_bit * (fskp->n_data_bits + 2);
|
carrier_nsamples += frame_nsamples;
|
||||||
|
|
||||||
if ( carrier ) {
|
if ( carrier ) {
|
||||||
|
|
||||||
|
@ -944,27 +973,21 @@ main( int argc, char*argv[] )
|
||||||
bfsk_framebits_decode(0, 0, 0); /* reset the frame processor */
|
bfsk_framebits_decode(0, 0, 0); /* reset the frame processor */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
confidence_total += confidence;
|
confidence_total += confidence;
|
||||||
nframes_decoded++;
|
nframes_decoded++;
|
||||||
|
nbits_decoded += frame_n_bits;
|
||||||
noconfidence = 0;
|
noconfidence = 0;
|
||||||
|
|
||||||
/* Advance the sample stream forward past the decoded frame
|
// Advance the sample stream forward past the junk before the
|
||||||
* but not past the stop bit, since we want it to appear as
|
// frame starts (frame_start_sample), and then past decoded frame
|
||||||
* the prev_stop bit of the next frame, so ...
|
// (see also NOTE about frame_n_bits and expect_n_bits)...
|
||||||
*
|
// But actually advance just a bit less than that to allow
|
||||||
* advance = 1 prev_stop + 1 start + N data bits == n_data_bits+2
|
// for tracking slightly fast signals, hence - nsamples_overscan.
|
||||||
*
|
advance = frame_start_sample + frame_nsamples - nsamples_overscan;
|
||||||
* but actually advance just a bit less than that to allow
|
|
||||||
* for tracking slightly fast signals, hence - nsamples_overscan.
|
|
||||||
*/
|
|
||||||
advance = frame_start_sample
|
|
||||||
+ nsamples_per_bit * (float)(fskp->n_data_bits + 2)
|
|
||||||
- nsamples_overscan;
|
|
||||||
|
|
||||||
debug_log("@ nsamples_per_bit=%.3f n_data_bits=%u "
|
debug_log("@ nsamples_per_bit=%.3f n_data_bits=%u "
|
||||||
" frame_start=%u advance=%u\n",
|
" frame_start=%u advance=%u\n",
|
||||||
nsamples_per_bit, fskp->n_data_bits,
|
nsamples_per_bit, bfsk_n_data_bits,
|
||||||
frame_start_sample, advance);
|
frame_start_sample, advance);
|
||||||
|
|
||||||
|
|
||||||
|
@ -998,7 +1021,7 @@ main( int argc, char*argv[] )
|
||||||
if ( carrier ) {
|
if ( carrier ) {
|
||||||
if ( !quiet_mode )
|
if ( !quiet_mode )
|
||||||
report_no_carrier(fskp, sample_rate, bfsk_data_rate,
|
report_no_carrier(fskp, sample_rate, bfsk_data_rate,
|
||||||
nsamples_per_bit, nframes_decoded,
|
nsamples_per_bit, nframes_decoded, nbits_decoded,
|
||||||
carrier_nsamples, confidence_total);
|
carrier_nsamples, confidence_total);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue