int main(int argc, char *argv[]) { fsk_tx_state_t *caller_tx; fsk_rx_state_t *caller_rx; fsk_tx_state_t *answerer_tx; fsk_rx_state_t *answerer_rx; bert_state_t caller_bert; bert_state_t answerer_bert; bert_results_t bert_results; power_meter_t caller_meter; power_meter_t answerer_meter; int16_t caller_amp[BLOCK_LEN]; int16_t answerer_amp[BLOCK_LEN]; int16_t caller_model_amp[BLOCK_LEN]; int16_t answerer_model_amp[BLOCK_LEN]; int16_t out_amp[2*BLOCK_LEN]; AFfilehandle inhandle; AFfilehandle outhandle; int outframes; int i; int j; int samples; int test_bps; int noise_level; int noise_sweep; int bits_per_test; int line_model_no; int modem_under_test_1; int modem_under_test_2; int modems_set; int log_audio; int channel_codec; int rbs_pattern; int on_at; int off_at; tone_gen_descriptor_t tone_desc; tone_gen_state_t tone_tx; int opt; channel_codec = MUNGE_CODEC_NONE; rbs_pattern = 0; line_model_no = 0; decode_test_file = NULL; noise_sweep = FALSE; modem_under_test_1 = FSK_V21CH1; modem_under_test_2 = FSK_V21CH2; log_audio = FALSE; modems_set = 0; while ((opt = getopt(argc, argv, "c:dlm:nr:s:")) != -1) { switch (opt) { case 'c': channel_codec = atoi(optarg); break; case 'd': decode_test_file = optarg; break; case 'l': log_audio = TRUE; break; case 'm': line_model_no = atoi(optarg); break; case 'n': noise_sweep = TRUE; break; case 'r': rbs_pattern = atoi(optarg); break; case 's': switch (modems_set++) { case 0: modem_under_test_1 = atoi(optarg); break; case 1: modem_under_test_2 = atoi(optarg); break; } break; default: //usage(); exit(2); break; } } if (modem_under_test_1 >= 0) printf("Modem channel 1 is '%s'\n", preset_fsk_specs[modem_under_test_1].name); if (modem_under_test_2 >= 0) printf("Modem channel 2 is '%s'\n", preset_fsk_specs[modem_under_test_2].name); outhandle = AF_NULL_FILEHANDLE; if (log_audio) { if ((outhandle = afOpenFile_telephony_write(OUTPUT_FILE_NAME, 2)) == AF_NULL_FILEHANDLE) { fprintf(stderr, " Cannot create wave file '%s'\n", OUTPUT_FILE_NAME); exit(2); } } noise_level = -200; bits_per_test = 0; inhandle = NULL; memset(caller_amp, 0, sizeof(*caller_amp)); memset(answerer_amp, 0, sizeof(*answerer_amp)); memset(caller_model_amp, 0, sizeof(*caller_model_amp)); memset(answerer_model_amp, 0, sizeof(*answerer_model_amp)); power_meter_init(&caller_meter, 7); power_meter_init(&answerer_meter, 7); if (decode_test_file) { if ((inhandle = afOpenFile_telephony_read(decode_test_file, 1)) == AF_NULL_FILEHANDLE) { fprintf(stderr, " Cannot open wave file '%s'\n", decode_test_file); exit(2); } caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, put_bit, NULL); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; for (;;) { samples = afReadFrames(inhandle, AF_DEFAULT_TRACK, caller_model_amp, BLOCK_LEN); if (samples < BLOCK_LEN) break; for (i = 0; i < samples; i++) power_meter_update(&caller_meter, caller_model_amp[i]); fsk_rx(caller_rx, caller_model_amp, samples); } if (afCloseFile(inhandle) != 0) { fprintf(stderr, " Cannot close wave file '%s'\n", decode_test_file); exit(2); } } else { printf("Test cutoff level\n"); caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, cutoff_test_put_bit, NULL); fsk_rx_signal_cutoff(caller_rx, -30.0f); fsk_rx_set_modem_status_handler(caller_rx, cutoff_test_rx_status, (void *) &caller_rx); on_at = 0; for (i = -40; i < -25; i++) { make_tone_gen_descriptor(&tone_desc, 1500, i, 0, 0, 1, 0, 0, 0, TRUE); tone_gen_init(&tone_tx, &tone_desc); for (j = 0; j < 10; j++) { samples = tone_gen(&tone_tx, caller_model_amp, 160); fsk_rx(caller_rx, caller_model_amp, samples); } if (cutoff_test_carrier) break; } on_at = i; off_at = 0; for ( ; i > -40; i--) { make_tone_gen_descriptor(&tone_desc, 1500, i, 0, 0, 1, 0, 0, 0, TRUE); tone_gen_init(&tone_tx, &tone_desc); for (j = 0; j < 10; j++) { samples = tone_gen(&tone_tx, caller_model_amp, 160); fsk_rx(caller_rx, caller_model_amp, samples); } if (!cutoff_test_carrier) break; } off_at = i; printf("Carrier on at %d, off at %d\n", on_at, off_at); if (on_at < -29 || on_at > -26 || off_at < -35 || off_at > -31) { printf("Tests failed.\n"); exit(2); } printf("Test with BERT\n"); test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; if (modem_under_test_1 >= 0) { caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert); fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx); answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert); fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx); } if (modem_under_test_2 >= 0) { answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert); fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx); caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); } test_bps = preset_fsk_specs[modem_under_test_1].baud_rate; bits_per_test = 500000; noise_level = -24; bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1); bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2); if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, (float) noise_level, channel_codec, rbs_pattern)) == NULL) { fprintf(stderr, " Failed to create line model\n"); exit(2); } for (;;) { samples = fsk_tx(caller_tx, caller_amp, BLOCK_LEN); for (i = 0; i < samples; i++) power_meter_update(&caller_meter, caller_amp[i]); samples = fsk_tx(answerer_tx, answerer_amp, BLOCK_LEN); for (i = 0; i < samples; i++) power_meter_update(&answerer_meter, answerer_amp[i]); both_ways_line_model(model, caller_model_amp, caller_amp, answerer_model_amp, answerer_amp, samples); //printf("Powers %10.5fdBm0 %10.5fdBm0\n", power_meter_current_dbm0(&caller_meter), power_meter_current_dbm0(&answerer_meter)); fsk_rx(answerer_rx, caller_model_amp, samples); for (i = 0; i < samples; i++) out_amp[2*i] = caller_model_amp[i]; for ( ; i < BLOCK_LEN; i++) out_amp[2*i] = 0; fsk_rx(caller_rx, answerer_model_amp, samples); for (i = 0; i < samples; i++) out_amp[2*i + 1] = answerer_model_amp[i]; for ( ; i < BLOCK_LEN; i++) out_amp[2*i + 1] = 0; if (log_audio) { outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, out_amp, BLOCK_LEN); if (outframes != BLOCK_LEN) { fprintf(stderr, " Error writing wave file\n"); exit(2); } } if (samples < BLOCK_LEN) { bert_result(&caller_bert, &bert_results); fprintf(stderr, "%ddB AWGN, %d bits, %d bad bits, %d resyncs\n", noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); if (!noise_sweep) { if (bert_results.total_bits != bits_per_test - 43 || bert_results.bad_bits != 0 || bert_results.resyncs != 0) { printf("Tests failed.\n"); exit(2); } } bert_result(&answerer_bert, &bert_results); fprintf(stderr, "%ddB AWGN, %d bits, %d bad bits, %d resyncs\n", noise_level, bert_results.total_bits, bert_results.bad_bits, bert_results.resyncs); if (!noise_sweep) { if (bert_results.total_bits != bits_per_test - 43 || bert_results.bad_bits != 0 || bert_results.resyncs != 0) { printf("Tests failed.\n"); exit(2); } break; } /* Put a little silence between the chunks in the file. */ memset(out_amp, 0, sizeof(out_amp)); if (log_audio) { for (i = 0; i < 200; i++) { outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, out_amp, BLOCK_LEN); } } if (modem_under_test_1 >= 0) { caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert); fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx); answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert); fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx); } if (modem_under_test_2 >= 0) { answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert); fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx); caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert); fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx); } noise_level++; if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, noise_level, channel_codec, 0)) == NULL) { fprintf(stderr, " Failed to create line model\n"); exit(2); } bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1); bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20); bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2); } } printf("Tests passed.\n"); } if (log_audio) { if (afCloseFile(outhandle) != 0) { fprintf(stderr, " Cannot close wave file '%s'\n", OUTPUT_FILE_NAME); exit(2); } } return 0; }
SPAN_DECLARE(int) sig_tone_rx(sig_tone_rx_state_t *s, int16_t amp[], int len) { #if defined(SPANDSP_USE_FIXED_POINT) int16_t x; int32_t v; int16_t notched_signal[3]; int16_t bandpass_signal; int16_t signal; #else float x; float v; float notched_signal[3]; float bandpass_signal; float signal; #endif int i; int j; int k; int l; int m; int32_t notch_power[3]; int32_t flat_power; int immediate; l = s->desc->tones; if (l == 2) l = 3; notch_power[1] = notch_power[2] = INT32_MAX; for (i = 0; i < len; i++) { if (s->signalling_state_duration < INT_MAX) s->signalling_state_duration++; /*endif*/ signal = amp[i]; for (j = 0; j < l; j++) { k = coeff_sets[j]; /* The notch filter is two cascaded biquads. */ #if defined(SPANDSP_USE_FIXED_POINT) v = ((int32_t) signal*s->desc->notch[k]->a1[0]) + ((int32_t) s->tone[j].notch_z1[0]*s->desc->notch[k]->b1[1]) + ((int32_t) s->tone[j].notch_z1[1]*s->desc->notch[k]->b1[2]); x = v >> 15; v += ((int32_t) s->tone[j].notch_z1[0]*s->desc->notch[k]->a1[1]) + ((int32_t) s->tone[j].notch_z1[1]*s->desc->notch[k]->a1[2]); s->tone[j].notch_z1[1] = s->tone[j].notch_z1[0]; s->tone[j].notch_z1[0] = x; v += ((int32_t) s->tone[j].notch_z2[0]*s->desc->notch[k]->b2[1]) + ((int32_t) s->tone[j].notch_z2[1]*s->desc->notch[k]->b2[2]); x = v >> 15; v += ((int32_t) s->tone[j].notch_z2[0]*s->desc->notch[k]->a2[1]) + ((int32_t) s->tone[j].notch_z2[1]*s->desc->notch[k]->a2[2]); s->tone[j].notch_z2[1] = s->tone[j].notch_z2[0]; s->tone[j].notch_z2[0] = x; notched_signal[j] = v >> s->desc->notch[k]->postscale; #else v = signal*s->desc->notch[k]->a1[0] + s->tone[j].notch_z1[0]*s->desc->notch[k]->b1[1] + s->tone[j].notch_z1[1]*s->desc->notch[k]->b1[2]; x = v; v += s->tone[j].notch_z1[0]*s->desc->notch[k]->a1[1] + s->tone[j].notch_z1[1]*s->desc->notch[k]->a1[2]; s->tone[j].notch_z1[1] = s->tone[j].notch_z1[0]; s->tone[j].notch_z1[0] = x; v += s->tone[j].notch_z2[0]*s->desc->notch[k]->b2[1] + s->tone[j].notch_z2[1]*s->desc->notch[k]->b2[2]; x = v; v += s->tone[j].notch_z2[0]*s->desc->notch[k]->a2[1] + s->tone[j].notch_z2[1]*s->desc->notch[k]->a2[2]; s->tone[j].notch_z2[1] = s->tone[j].notch_z2[0]; s->tone[j].notch_z2[0] = x; notched_signal[j] = v; #endif /* Modulus and leaky integrate the notched data. The result of this isn't used in low tone detect mode, but we must keep the power measurement rolling along. */ notch_power[j] = power_meter_update(&s->tone[j].power, notched_signal[j]); if (j == 1) signal = notched_signal[j]; } if ((s->signalling_state & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT))) { if (s->flat_mode_timeout && --s->flat_mode_timeout == 0) s->flat_mode = TRUE; /*endif*/ } else { s->flat_mode_timeout = s->desc->sharp_flat_timeout; s->flat_mode = FALSE; } /*endif*/ immediate = -1; if (s->flat_mode) { //printf("Flat mode %d %d\n", s->flat_mode_timeout, s->desc->sharp_flat_timeout); /* Flat mode */ bandpass_signal = amp[i]; if (s->desc->flat) { /* The bandpass filter is a single bi-quad stage */ #if defined(SPANDSP_USE_FIXED_POINT) v = ((int32_t) amp[i]*s->desc->flat->a[0]) + ((int32_t) s->flat_z[0]*s->desc->flat->b[1]) + ((int32_t) s->flat_z[1]*s->desc->flat->b[2]); x = v >> 15; v += ((int32_t) s->flat_z[0]*s->desc->flat->a[1]) + ((int32_t) s->flat_z[1]*s->desc->flat->a[2]); s->flat_z[1] = s->flat_z[0]; s->flat_z[0] = x; bandpass_signal = v >> s->desc->flat->postscale; #else v = amp[i]*s->desc->flat->a[0] + s->flat_z[0]*s->desc->flat->b[1] + s->flat_z[1]*s->desc->flat->b[2]; x = v; v += s->flat_z[0]*s->desc->flat->a[1] + s->flat_z[1]*s->desc->flat->a[2]; s->flat_z[1] = s->flat_z[0]; s->flat_z[0] = x; bandpass_signal = v; #endif } flat_power = power_meter_update(&s->flat_power, bandpass_signal); /* For the flat receiver we use a simple power threshold! */ if ((s->signalling_state & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT))) { if (flat_power < s->flat_detection_threshold) { s->signalling_state &= ~tone_present_bits[0]; s->signalling_state |= tone_change_bits[0]; } /*endif*/ } else { if (flat_power > s->flat_detection_threshold) s->signalling_state |= (tone_present_bits[0] | tone_change_bits[0]); /*endif*/ } /*endif*/ /* Notch insertion logic */ /* tone_present and tone_on are equivalent in flat mode */ if ((s->signalling_state & (SIG_TONE_1_PRESENT | SIG_TONE_2_PRESENT))) { s->notch_insertion_timeout = s->desc->notch_lag_time; } else { if (s->notch_insertion_timeout) s->notch_insertion_timeout--; /*endif*/ } /*endif*/ }
static void compliance_tests(int log_audio) { SNDFILE *outhandle; power_meter_t power_meter; int outframes; int i; int block; int pre; int post; int post_post; int alaw_failures; int ulaw_failures; float worst_alaw; float worst_ulaw; float tmp; int len; g711_state_t *enc_state; g711_state_t *transcode; g711_state_t *dec_state; outhandle = NULL; if (log_audio) { if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL) { fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME); exit(2); } } printf("Conversion accuracy tests.\n"); alaw_failures = 0; ulaw_failures = 0; worst_alaw = 0.0; worst_ulaw = 0.0; for (block = 0; block < 1; block++) { for (i = 0; i < 65536; i++) { pre = i - 32768; post = alaw_to_linear(linear_to_alaw(pre)); if (abs(pre) > 140) { tmp = (float) abs(post - pre)/(float) abs(pre); if (tmp > 0.10) { printf("A-law: Excessive error at %d (%d)\n", pre, post); alaw_failures++; } if (tmp > worst_alaw) worst_alaw = tmp; } else { /* Small values need different handling for sensible measurement */ if (abs(post - pre) > 15) { printf("A-law: Excessive error at %d (%d)\n", pre, post); alaw_failures++; } } amp[i] = post; } if (log_audio) { outframes = sf_writef_short(outhandle, amp, 65536); if (outframes != 65536) { fprintf(stderr, " Error writing audio file\n"); exit(2); } } for (i = 0; i < 65536; i++) { pre = i - 32768; post = ulaw_to_linear(linear_to_ulaw(pre)); if (abs(pre) > 40) { tmp = (float) abs(post - pre)/(float) abs(pre); if (tmp > 0.10) { printf("u-law: Excessive error at %d (%d)\n", pre, post); ulaw_failures++; } if (tmp > worst_ulaw) worst_ulaw = tmp; } else { /* Small values need different handling for sensible measurement */ if (abs(post - pre) > 4) { printf("u-law: Excessive error at %d (%d)\n", pre, post); ulaw_failures++; } } amp[i] = post; } if (log_audio) { outframes = sf_writef_short(outhandle, amp, 65536); if (outframes != 65536) { fprintf(stderr, " Error writing audio file\n"); exit(2); } } } printf("Worst A-law error (ignoring small values) %f%%\n", worst_alaw*100.0); printf("Worst u-law error (ignoring small values) %f%%\n", worst_ulaw*100.0); if (alaw_failures || ulaw_failures) { printf("%d A-law values with excessive error\n", alaw_failures); printf("%d u-law values with excessive error\n", ulaw_failures); printf("Tests failed\n"); exit(2); } printf("Cyclic conversion repeatability tests.\n"); /* Find what happens to every possible linear value after a round trip. */ for (i = 0; i < 65536; i++) { pre = i - 32768; /* Make a round trip */ post = alaw_to_linear(linear_to_alaw(pre)); /* A second round trip should cause no further change */ post_post = alaw_to_linear(linear_to_alaw(post)); if (post_post != post) { printf("A-law second round trip mismatch - at %d, %d != %d\n", pre, post, post_post); printf("Tests failed\n"); exit(2); } /* Make a round trip */ post = ulaw_to_linear(linear_to_ulaw(pre)); /* A second round trip should cause no further change */ post_post = ulaw_to_linear(linear_to_ulaw(post)); if (post_post != post) { printf("u-law round trip mismatch - at %d, %d != %d\n", pre, post, post_post); printf("Tests failed\n"); exit(2); } } printf("Reference power level tests.\n"); power_meter_init(&power_meter, 7); for (i = 0; i < 8000; i++) { amp[i] = ulaw_to_linear(ulaw_1khz_sine[i & 7]); power_meter_update(&power_meter, amp[i]); } printf("Reference u-law 1kHz tone is %fdBm0\n", power_meter_current_dbm0(&power_meter)); if (log_audio) { outframes = sf_writef_short(outhandle, amp, 8000); if (outframes != 8000) { fprintf(stderr, " Error writing audio file\n"); exit(2); } } if (0.1f < fabs(power_meter_current_dbm0(&power_meter))) { printf("Test failed.\n"); exit(2); } for (i = 0; i < 8000; i++) { amp[i] = alaw_to_linear(alaw_1khz_sine[i & 7]); power_meter_update(&power_meter, amp[i]); } printf("Reference A-law 1kHz tone is %fdBm0\n", power_meter_current_dbm0(&power_meter)); if (log_audio) { outframes = sf_writef_short(outhandle, amp, 8000); if (outframes != 8000) { fprintf(stderr, " Error writing audio file\n"); exit(2); } } if (0.1f < fabs(power_meter_current_dbm0(&power_meter))) { printf("Test failed.\n"); exit(2); } /* Check the transcoding functions. */ printf("Testing transcoding A-law -> u-law -> A-law\n"); for (i = 0; i < 256; i++) { if (alaw_to_ulaw(ulaw_to_alaw(i)) != i) { if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1) { printf("u-law -> A-law -> u-law gave %d -> %d\n", i, alaw_to_ulaw(ulaw_to_alaw(i))); printf("Test failed\n"); exit(2); } } } printf("Testing transcoding u-law -> A-law -> u-law\n"); for (i = 0; i < 256; i++) { if (ulaw_to_alaw(alaw_to_ulaw(i)) != i) { if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1) { printf("A-law -> u-law -> A-law gave %d -> %d\n", i, ulaw_to_alaw(alaw_to_ulaw(i))); printf("Test failed\n"); exit(2); } } } enc_state = g711_init(NULL, G711_ALAW); transcode = g711_init(NULL, G711_ALAW); dec_state = g711_init(NULL, G711_ULAW); len = 65536; for (i = 0; i < len; i++) amp[i] = i - 32768; len = g711_encode(enc_state, alaw_data, amp, len); len = g711_transcode(transcode, ulaw_data, alaw_data, len); len = g711_decode(dec_state, amp, ulaw_data, len); if (len != 65536) { printf("Block coding gave the wrong length - %d instead of %d\n", len, 65536); printf("Test failed\n"); exit(2); } for (i = 0; i < len; i++) { pre = i - 32768; post = amp[i]; if (abs(pre) > 140) { tmp = (float) abs(post - pre)/(float) abs(pre); if (tmp > 0.10) { printf("Block: Excessive error at %d (%d)\n", pre, post); exit(2); } } else { /* Small values need different handling for sensible measurement */ if (abs(post - pre) > 15) { printf("Block: Excessive error at %d (%d)\n", pre, post); exit(2); } } } g711_release(enc_state); g711_release(transcode); g711_release(dec_state); if (log_audio) { if (sf_close_telephony(outhandle)) { fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME); exit(2); } } printf("Tests passed.\n"); }
static int power_meter_tests(void) { awgn_state_t noise_source; power_meter_t meter; tone_gen_descriptor_t tone_desc; tone_gen_state_t gen; int i; int idum = 1234567; int16_t amp[1000]; int len; int32_t level; power_meter_init(&meter, 7); printf("Testing with zero in the power register\n"); printf("Power: expected %fdBm0, got %fdBm0\n", -90.169f, power_meter_current_dbm0(&meter)); printf("Power: expected %fdBOv, got %fdBOv\n", -96.329f, power_meter_current_dbov(&meter)); printf("Testing with a square wave 10dB from maximum\n"); for (i = 0; i < 1000; i++) { amp[i] = (i & 1) ? 10362 : -10362; level = power_meter_update(&meter, amp[i]); //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter)); } printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level); printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter)); printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter)); if (level < power_meter_level_dbov(-10.0f)*0.99f || level > power_meter_level_dbov(-10.0f)*1.01f) { printf("Test failed (level)\n"); exit(2); } if (0.1f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER)) { printf("Test failed (dBm0)\n"); exit(2); } if (0.1f < fabsf(power_meter_current_dbov(&meter) + 10.0)) { printf("Test failed (dBOv)\n"); exit(2); } printf("Testing with a sine wave tone 10dB from maximum\n"); tone_gen_descriptor_init(&tone_desc, 1000, -4, 0, 1, 1, 0, 0, 0, true); tone_gen_init(&gen, &tone_desc); len = tone_gen(&gen, amp, 1000); for (i = 0; i < len; i++) { level = power_meter_update(&meter, amp[i]); //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter)); } printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level); printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter)); printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter)); if (level < power_meter_level_dbov(-10.0f)*0.95f || level > power_meter_level_dbov(-10.0f)*1.05f) { printf("Test failed (level)\n"); exit(2); } if (0.2f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER)) { printf("Test failed (dBm0)\n"); exit(2); } if (0.2f < fabsf(power_meter_current_dbov(&meter) + 10.0)) { printf("Test failed (dBOv)\n"); exit(2); } printf("Testing with AWGN 10dB from maximum\n"); awgn_init_dbov(&noise_source, idum, -10.0f); for (i = 0; i < 1000; i++) amp[i] = awgn(&noise_source); for (i = 0; i < 1000; i++) { level = power_meter_update(&meter, amp[i]); //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter)); } printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level); printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter)); printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter)); if (level < power_meter_level_dbov(-10.0f)*0.95f || level > power_meter_level_dbov(-10.0f)*1.05f) { printf("Test failed (level)\n"); exit(2); } if (0.2f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER)) { printf("Test failed (dBm0)\n"); exit(2); } if (0.2f < fabsf(power_meter_current_dbov(&meter) + 10.0f)) { printf("Test failed (dBOv)\n"); exit(2); } return 0; }
int main(int argc, char *argv[]) { AFfilehandle outhandle; AFfilesetup filesetup; power_meter_t power_meter; int outframes; int i; int block; int pre; int post; int alaw_failures; int ulaw_failures; float worst_alaw; float worst_ulaw; float tmp; if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP) { fprintf(stderr, " Failed to create file setup\n"); exit(2); } afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); afInitFileFormat(filesetup, AF_FILE_WAVE); afInitChannels(filesetup, AF_DEFAULT_TRACK, 1); if ((outhandle = afOpenFile(OUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE) { fprintf(stderr, " Cannot create wave file '%s'\n", OUT_FILE_NAME); exit(2); } printf("Conversion accuracy tests.\n"); alaw_failures = 0; ulaw_failures = 0; worst_alaw = 0.0; worst_ulaw = 0.0; for (block = 0; block < 1; block++) { for (i = 0; i < 65536; i++) { pre = i - 32768; post = alaw_to_linear(linear_to_alaw(pre)); if (abs(pre) > 140) { tmp = (float) abs(post - pre)/(float) abs(pre); if (tmp > 0.10) { printf("A-law: Excessive error at %d (%d)\n", pre, post); alaw_failures++; } if (tmp > worst_alaw) worst_alaw = tmp; } else { /* Small values need different handling for sensible measurement */ if (abs(post - pre) > 15) { printf("A-law: Excessive error at %d (%d)\n", pre, post); alaw_failures++; } } amp[i] = post; } outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, amp, 65536); if (outframes != 65536) { fprintf(stderr, " Error writing wave file\n"); exit(2); } for (i = 0; i < 65536; i++) { pre = i - 32768; post = ulaw_to_linear(linear_to_ulaw(pre)); if (abs(pre) > 40) { tmp = (float) abs(post - pre)/(float) abs(pre); if (tmp > 0.10) { printf("u-law: Excessive error at %d (%d)\n", pre, post); ulaw_failures++; } if (tmp > worst_ulaw) worst_ulaw = tmp; } else { /* Small values need different handling for sensible measurement */ if (abs(post - pre) > 4) { printf("u-law: Excessive error at %d (%d)\n", pre, post); ulaw_failures++; } } amp[i] = post; } outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, amp, 65536); if (outframes != 65536) { fprintf(stderr, " Error writing wave file\n"); exit(2); } } printf("Worst A-law error (ignoring small values) %f%%\n", worst_alaw*100.0); printf("Worst u-law error (ignoring small values) %f%%\n", worst_ulaw*100.0); if (alaw_failures || ulaw_failures) { printf("%d A-law values with excessive error\n", alaw_failures); printf("%d u-law values with excessive error\n", ulaw_failures); printf("Tests failed\n"); exit(2); } printf("Reference power level tests.\n"); power_meter_init(&power_meter, 7); for (i = 0; i < 8000; i++) { amp[i] = ulaw_to_linear(ulaw_1khz_sine[i & 7]); power_meter_update(&power_meter, amp[i]); } printf("Reference u-law 1kHz tone is %fdBm0\n", power_meter_dbm0(&power_meter)); outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, amp, 8000); if (outframes != 8000) { fprintf(stderr, " Error writing wave file\n"); exit(2); } if (0.1f < fabs(power_meter_dbm0(&power_meter))) { printf("Test failed.\n"); exit(2); } for (i = 0; i < 8000; i++) { amp[i] = alaw_to_linear(alaw_1khz_sine[i & 7]); power_meter_update(&power_meter, amp[i]); } printf("Reference A-law 1kHz tone is %fdBm0\n", power_meter_dbm0(&power_meter)); outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, amp, 8000); if (outframes != 8000) { fprintf(stderr, " Error writing wave file\n"); exit(2); } if (0.1f < fabs(power_meter_dbm0(&power_meter))) { printf("Test failed.\n"); exit(2); } /* Check the transcoding functions. */ printf("Testing transcoding A-law -> u-law -> A-law\n"); for (i = 0; i < 256; i++) { if (alaw_to_ulaw(ulaw_to_alaw(i)) != i) { if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1) { printf("u-law -> A-law -> u-law gave %d -> %d\n", i, alaw_to_ulaw(ulaw_to_alaw(i))); printf("Test failed\n"); exit(2); } } } printf("Testing transcoding u-law -> A-law -> u-law\n"); for (i = 0; i < 256; i++) { if (ulaw_to_alaw(alaw_to_ulaw(i)) != i) { if (abs(alaw_to_ulaw(ulaw_to_alaw(i)) - i) > 1) { printf("A-law -> u-law -> A-law gave %d -> %d\n", i, ulaw_to_alaw(alaw_to_ulaw(i))); printf("Test failed\n"); exit(2); } } } if (afCloseFile(outhandle)) { fprintf(stderr, " Cannot close wave file '%s'\n", OUT_FILE_NAME); exit(2); } afFreeFileSetup(filesetup); printf("Tests passed.\n"); return 0; }
int fsk_rx(fsk_rx_state_t *s, const int16_t *amp, int len) { int buf_ptr; int baudstate; int i; int j; int16_t x; int32_t dot; int32_t sum; int32_t power; complexi_t ph; buf_ptr = s->buf_ptr; for (i = 0; i < len; i++) { /* If there isn't much signal, don't demodulate - it will only produce useless junk results. */ /* There should be no DC in the signal, but sometimes there is. We need to measure the power with the DC blocked, but not using a slow to respond DC blocker. Use the most elementary HPF. */ x = amp[i] >> 1; power = power_meter_update(&(s->power), x - s->last_sample); s->last_sample = x; if (s->signal_present) { /* Look for power below turn-off threshold to turn the carrier off */ if (power < s->carrier_off_power) { if (--s->signal_present <= 0) { /* Count down a short delay, to ensure we push the last few bits through the filters before stopping. */ s->put_bit(s->user_data, PUTBIT_CARRIER_DOWN); continue; } } } else { /* Look for power exceeding turn-on threshold to turn the carrier on */ if (power < s->carrier_on_power) continue; s->signal_present = 1; s->put_bit(s->user_data, PUTBIT_CARRIER_UP); } /* Non-coherent FSK demodulation by correlation with the target tones over a one baud interval. The slow V.xx specs. are too open ended to allow anything fancier to be used. The dot products are calculated using a sliding window approach, so the compute load is not that great. */ /* The *totally* asynchronous character to character behaviour of these modems, when carrying async. data, seems to force a sample by sample approach. */ for (j = 0; j < 2; j++) { s->dot_i[j] -= s->window_i[j][buf_ptr]; s->dot_q[j] -= s->window_q[j][buf_ptr]; ph = dds_complexi(&(s->phase_acc[j]), s->phase_rate[j]); s->window_i[j][buf_ptr] = (ph.re*amp[i]) >> s->scaling_shift; s->window_q[j][buf_ptr] = (ph.im*amp[i]) >> s->scaling_shift; s->dot_i[j] += s->window_i[j][buf_ptr]; s->dot_q[j] += s->window_q[j][buf_ptr]; } dot = s->dot_i[0] >> 15; sum = dot*dot; dot = s->dot_q[0] >> 15; sum += dot*dot; dot = s->dot_i[1] >> 15; sum -= dot*dot; dot = s->dot_q[1] >> 15; sum -= dot*dot; baudstate = (sum < 0); if (s->lastbit != baudstate) { s->lastbit = baudstate; if (s->sync_mode) { /* For synchronous use (e.g. HDLC channels in FAX modems), nudge the baud phase gently, trying to keep it centred on the bauds. */ if (s->baud_pll < 0x8000) s->baud_pll += (s->baud_inc >> 3); else s->baud_pll -= (s->baud_inc >> 3); } else {