AMPS: Improved level detection of bit decoder
This commit is contained in:
parent
3a3c1c258b
commit
052fe5d1de
|
@ -87,9 +87,12 @@ typedef struct amps {
|
||||||
/* the ex buffer holds the duration of one bit, and wrapps every
|
/* the ex buffer holds the duration of one bit, and wrapps every
|
||||||
* bit. */
|
* bit. */
|
||||||
double fsk_rx_bitcount; /* counts the bit. if it reaches or exceeds 1, the bit is complete and the next bit starts */
|
double fsk_rx_bitcount; /* counts the bit. if it reaches or exceeds 1, the bit is complete and the next bit starts */
|
||||||
int16_t *fsk_rx_buffer; /* rx buffer for one bit */
|
int16_t *fsk_rx_window; /* rx buffer for one bit */
|
||||||
int fsk_rx_buffer_length; /* length of rx buffer */
|
int fsk_rx_window_length; /* length of rx buffer */
|
||||||
int fsk_rx_buffer_pos; /* current position in buffer */
|
int fsk_rx_window_half; /* half of length of rx buffer */
|
||||||
|
int fsk_rx_window_begin; /* where to begin detecting level */
|
||||||
|
int fsk_rx_window_end; /* where to end detecting level */
|
||||||
|
int fsk_rx_window_pos; /* current position in buffer */
|
||||||
/* the rx bufffer received one frame until rx length */
|
/* the rx bufffer received one frame until rx length */
|
||||||
char fsk_rx_frame[FSK_MAX_BITS + 1]; /* +1 because 0-termination */
|
char fsk_rx_frame[FSK_MAX_BITS + 1]; /* +1 because 0-termination */
|
||||||
int fsk_rx_frame_length; /* length of expected frame */
|
int fsk_rx_frame_length; /* length of expected frame */
|
||||||
|
|
108
src/amps/dsp.c
108
src/amps/dsp.c
|
@ -43,6 +43,30 @@
|
||||||
* the average sample value of the right side. After the bit has been detected,
|
* the average sample value of the right side. After the bit has been detected,
|
||||||
* the samples for the next window will be received and detected.
|
* the samples for the next window will be received and detected.
|
||||||
*
|
*
|
||||||
|
* +-----+-----+-----+-----+
|
||||||
|
* | | | __|__ |
|
||||||
|
* | | | / | \ |
|
||||||
|
* | | | / | \ |
|
||||||
|
* | | |/ | \|
|
||||||
|
* +-----+-----+-----+-----+
|
||||||
|
* |\ | /| | |
|
||||||
|
* | \ | / | | |
|
||||||
|
* | \__|__/ | | |
|
||||||
|
* | | | | |
|
||||||
|
* +-----+-----+-----+-----+
|
||||||
|
* End Half Begin
|
||||||
|
*
|
||||||
|
* The Rx window is depiced above. In this example there is a raising edge.
|
||||||
|
* The window is analyzed in backward direction. The average level between
|
||||||
|
* 'Half' position and 'Begin' position is calculated, also the average level
|
||||||
|
* between 'End' position and 'Half' position. Because the right (second)
|
||||||
|
* side of the average level is higher than the left (first) side, a raising
|
||||||
|
* edge is detected.
|
||||||
|
*
|
||||||
|
* Tests showed that comparing half of the regions of the window will cause
|
||||||
|
* more errors than only quarter regions of the regions. Especially this is
|
||||||
|
* true with NBFM receivers that are normally not sufficient for AMPS signals.
|
||||||
|
*
|
||||||
* As soon as a sync pattern is detected, the polarity of the pattern is used
|
* As soon as a sync pattern is detected, the polarity of the pattern is used
|
||||||
* to decode the following frame bits with correct polarity. During reception
|
* to decode the following frame bits with correct polarity. During reception
|
||||||
* of the frame bits, no sync and no dotting sequnece is searched or detected.
|
* of the frame bits, no sync and no dotting sequnece is searched or detected.
|
||||||
|
@ -143,6 +167,7 @@ int dsp_init_sender(amps_t *amps, int high_pass)
|
||||||
int i;
|
int i;
|
||||||
int rc;
|
int rc;
|
||||||
double RC, dt;
|
double RC, dt;
|
||||||
|
int half;
|
||||||
|
|
||||||
/* attack (3ms) and recovery time (13.5ms) according to amps specs */
|
/* attack (3ms) and recovery time (13.5ms) according to amps specs */
|
||||||
init_compandor(&s->cstate, 8000, 3.0, 13.5, COMPANDOR_0DB);
|
init_compandor(&s->cstate, 8000, 3.0, 13.5, COMPANDOR_0DB);
|
||||||
|
@ -166,9 +191,16 @@ int dsp_init_sender(amps_t *amps, int high_pass)
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
amps->fsk_rx_buffer_length = ceil(amps->fsk_bitduration); /* buffer holds one bit (rounded up) */
|
amps->fsk_rx_window_length = ceil(amps->fsk_bitduration); /* buffer holds one bit (rounded up) */
|
||||||
amps->fsk_rx_buffer = calloc(sizeof(int16_t), amps->fsk_rx_buffer_length);
|
half = amps->fsk_rx_window_length >> 1;
|
||||||
if (!amps->fsk_rx_buffer) {
|
amps->fsk_rx_window_begin = half >> 1;
|
||||||
|
amps->fsk_rx_window_half = half;
|
||||||
|
amps->fsk_rx_window_end = amps->fsk_rx_window_length - (half >> 1);
|
||||||
|
PDEBUG(DDSP, DEBUG_DEBUG, "Bit window length: %d\n", amps->fsk_rx_window_length);
|
||||||
|
PDEBUG(DDSP, DEBUG_DEBUG, " -> Samples in window to analyse level left of edge: %d..%d\n", amps->fsk_rx_window_begin, amps->fsk_rx_window_half - 1);
|
||||||
|
PDEBUG(DDSP, DEBUG_DEBUG, " -> Samples in window to analyse level right of edge: %d..%d\n", amps->fsk_rx_window_half, amps->fsk_rx_window_end - 1);
|
||||||
|
amps->fsk_rx_window = calloc(sizeof(int16_t), amps->fsk_rx_window_length);
|
||||||
|
if (!amps->fsk_rx_window) {
|
||||||
PDEBUG(DDSP, DEBUG_DEBUG, "No memory!\n");
|
PDEBUG(DDSP, DEBUG_DEBUG, "No memory!\n");
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto error;
|
goto error;
|
||||||
|
@ -203,8 +235,8 @@ int dsp_init_sender(amps_t *amps, int high_pass)
|
||||||
/* use this filter to remove dc level for 0-crossing detection
|
/* use this filter to remove dc level for 0-crossing detection
|
||||||
* if we have de-emphasis, we don't need it, so high_pass is not set. */
|
* if we have de-emphasis, we don't need it, so high_pass is not set. */
|
||||||
if (high_pass) {
|
if (high_pass) {
|
||||||
RC = 1.0 / (CUT_OFF_HIGHPASS * 2.0 *3.14);
|
RC = 1.0 / (CUT_OFF_HIGHPASS * 2.0 *3.14);
|
||||||
dt = 1.0 / amps->sender.samplerate;
|
dt = 1.0 / amps->sender.samplerate;
|
||||||
amps->highpass_factor = RC / (RC + dt);
|
amps->highpass_factor = RC / (RC + dt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,8 +255,8 @@ void dsp_cleanup_sender(amps_t *amps)
|
||||||
|
|
||||||
if (amps->fsk_tx_buffer)
|
if (amps->fsk_tx_buffer)
|
||||||
free(amps->fsk_tx_buffer);
|
free(amps->fsk_tx_buffer);
|
||||||
if (amps->fsk_rx_buffer)
|
if (amps->fsk_rx_window)
|
||||||
free(amps->fsk_rx_buffer);
|
free(amps->fsk_rx_window);
|
||||||
if (amps->sat_filter_spl) {
|
if (amps->sat_filter_spl) {
|
||||||
free(amps->sat_filter_spl);
|
free(amps->sat_filter_spl);
|
||||||
amps->sat_filter_spl = NULL;
|
amps->sat_filter_spl = NULL;
|
||||||
|
@ -426,9 +458,9 @@ again:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fsk_rx_bit(amps_t *amps, int16_t *spl, int len, int pos)
|
static void fsk_rx_bit(amps_t *amps, int16_t *spl, int len, int pos, int begin, int half, int end)
|
||||||
{
|
{
|
||||||
int i, ii;
|
int i;
|
||||||
int32_t first, second;
|
int32_t first, second;
|
||||||
int bit;
|
int bit;
|
||||||
int32_t max = -32768, min = 32767;
|
int32_t max = -32768, min = 32767;
|
||||||
|
@ -436,11 +468,11 @@ static void fsk_rx_bit(amps_t *amps, int16_t *spl, int len, int pos)
|
||||||
/* decode one bit. substact the first half from the second half.
|
/* decode one bit. substact the first half from the second half.
|
||||||
* the result shows the direction of the bit change: 1 == positive.
|
* the result shows the direction of the bit change: 1 == positive.
|
||||||
*/
|
*/
|
||||||
ii = len >> 1;
|
pos -= begin; /* possible wrap is handled below */
|
||||||
second = first = 0;
|
second = first = 0;
|
||||||
for (i = 0; i < ii; i++) {
|
for (i = begin; i < half; i++) {
|
||||||
if (--pos < 0)
|
if (--pos < 0)
|
||||||
pos = len - 1;
|
pos += len;
|
||||||
//printf("second %d: %d\n", pos, spl[pos]);
|
//printf("second %d: %d\n", pos, spl[pos]);
|
||||||
second += spl[pos];
|
second += spl[pos];
|
||||||
if (spl[pos] > max)
|
if (spl[pos] > max)
|
||||||
|
@ -448,10 +480,10 @@ static void fsk_rx_bit(amps_t *amps, int16_t *spl, int len, int pos)
|
||||||
if (spl[pos] < min)
|
if (spl[pos] < min)
|
||||||
min = spl[pos];
|
min = spl[pos];
|
||||||
}
|
}
|
||||||
second /= ii;
|
second /= (half - begin);
|
||||||
for (i = 0; i < ii; i++) {
|
for (i = half; i < end; i++) {
|
||||||
if (--pos < 0)
|
if (--pos < 0)
|
||||||
pos = len - 1;
|
pos += len;
|
||||||
//printf("first %d: %d\n", pos, spl[pos]);
|
//printf("first %d: %d\n", pos, spl[pos]);
|
||||||
first += spl[pos];
|
first += spl[pos];
|
||||||
if (spl[pos] > max)
|
if (spl[pos] > max)
|
||||||
|
@ -459,7 +491,7 @@ static void fsk_rx_bit(amps_t *amps, int16_t *spl, int len, int pos)
|
||||||
if (spl[pos] < min)
|
if (spl[pos] < min)
|
||||||
min = spl[pos];
|
min = spl[pos];
|
||||||
}
|
}
|
||||||
first /= ii;
|
first /= (end - half);
|
||||||
//printf("first = %d second = %d\n", first, second);
|
//printf("first = %d second = %d\n", first, second);
|
||||||
/* get bit */
|
/* get bit */
|
||||||
if (second > first)
|
if (second > first)
|
||||||
|
@ -600,55 +632,47 @@ static void fsk_rx_dotting(amps_t *amps, double _elapsed)
|
||||||
/* decode frame */
|
/* decode frame */
|
||||||
static void sender_receive_frame(amps_t *amps, int16_t *samples, int length)
|
static void sender_receive_frame(amps_t *amps, int16_t *samples, int length)
|
||||||
{
|
{
|
||||||
int16_t *spl, last_sample;
|
|
||||||
int len, pos;
|
|
||||||
double bitstep, elapsed;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
bitstep = amps->fsk_bitstep;
|
|
||||||
spl = amps->fsk_rx_buffer;
|
|
||||||
pos = amps->fsk_rx_buffer_pos;
|
|
||||||
len = amps->fsk_rx_buffer_length;
|
|
||||||
last_sample = amps->fsk_rx_last_sample;
|
|
||||||
elapsed = amps->fsk_rx_elapsed;
|
|
||||||
|
|
||||||
for (i = 0; i < length; i++) {
|
for (i = 0; i < length; i++) {
|
||||||
#ifdef DEBUG_DECODER
|
#ifdef DEBUG_DECODER
|
||||||
puts(debug_amplitude((double)samples[i] / (double)FSK_DEVIATION));
|
puts(debug_amplitude((double)samples[i] / (double)FSK_DEVIATION));
|
||||||
#endif
|
#endif
|
||||||
/* push sample to detection window and shift */
|
/* push sample to detection window and shift */
|
||||||
spl[pos++] = samples[i];
|
amps->fsk_rx_window[amps->fsk_rx_window_pos++] = samples[i];
|
||||||
if (pos == len)
|
if (amps->fsk_rx_window_pos == amps->fsk_rx_window_length)
|
||||||
pos = 0;
|
amps->fsk_rx_window_pos = 0;
|
||||||
if (amps->fsk_rx_sync != FSK_SYNC_POSITIVE && amps->fsk_rx_sync != FSK_SYNC_NEGATIVE) {
|
if (amps->fsk_rx_sync != FSK_SYNC_POSITIVE && amps->fsk_rx_sync != FSK_SYNC_NEGATIVE) {
|
||||||
/* check for change in polarity */
|
/* check for change in polarity */
|
||||||
if (last_sample <= 0) {
|
if (amps->fsk_rx_last_sample <= 0) {
|
||||||
if (samples[i] > 0) {
|
if (samples[i] > 0) {
|
||||||
fsk_rx_dotting(amps, elapsed);
|
fsk_rx_dotting(amps, amps->fsk_rx_elapsed);
|
||||||
elapsed = 0.0;
|
amps->fsk_rx_elapsed = 0.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (samples[i] <= 0) {
|
if (samples[i] <= 0) {
|
||||||
fsk_rx_dotting(amps, elapsed);
|
fsk_rx_dotting(amps, amps->fsk_rx_elapsed);
|
||||||
elapsed = 0.0;
|
amps->fsk_rx_elapsed = 0.0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
last_sample = samples[i];
|
amps->fsk_rx_last_sample = samples[i];
|
||||||
elapsed += bitstep;
|
amps->fsk_rx_elapsed += amps->fsk_bitstep;
|
||||||
// printf("%.4f\n", bitcount);
|
// printf("%.4f\n", bitcount);
|
||||||
if (amps->fsk_rx_sync != FSK_SYNC_NONE) {
|
if (amps->fsk_rx_sync != FSK_SYNC_NONE) {
|
||||||
amps->fsk_rx_bitcount += bitstep;
|
amps->fsk_rx_bitcount += amps->fsk_bitstep;
|
||||||
if (amps->fsk_rx_bitcount >= 1.0) {
|
if (amps->fsk_rx_bitcount >= 1.0) {
|
||||||
amps->fsk_rx_bitcount -= 1.0;
|
amps->fsk_rx_bitcount -= 1.0;
|
||||||
fsk_rx_bit(amps, spl, len, pos);
|
fsk_rx_bit(amps,
|
||||||
|
amps->fsk_rx_window,
|
||||||
|
amps->fsk_rx_window_length,
|
||||||
|
amps->fsk_rx_window_pos,
|
||||||
|
amps->fsk_rx_window_begin,
|
||||||
|
amps->fsk_rx_window_half,
|
||||||
|
amps->fsk_rx_window_end);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
amps->fsk_rx_last_sample = last_sample;
|
|
||||||
amps->fsk_rx_elapsed = elapsed;
|
|
||||||
amps->fsk_rx_buffer_pos = pos;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue