int main(int argc, char *argv[]) { int duration; int i; int j; int len; int sample; const char *s; char digit[2]; char buf[MAX_BELL_MF_DIGITS + 1]; int actual; int nplus; int nminus; float rrb; float rcfo; time_t now; bell_mf_rx_state_t *mf_state; awgn_state_t noise_source; time(&now); mf_state = bell_mf_rx_init(NULL, NULL, NULL); /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step, which has no meaning here. */ printf("Test 1: Calibration\n"); printf(" Passed\n"); /* Test 2: Decode check This is a sanity check, that all digits are reliably detected under ideal conditions. Each possible digit is repeated 10 times, with 68ms bursts. The level of each tone is about 6dB down from clip */ printf("Test 2: Decode check\n"); my_mf_gen_init(0.0, -3, 0.0, -3, 68, 68); s = ALL_POSSIBLE_DIGITS; digit[1] = '\0'; while (*s) { digit[0] = *s++; for (i = 0; i < 10; i++) { len = my_mf_generate(amp, digit); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); actual = bell_mf_rx_get(mf_state, buf, 128); if (actual != 1 || buf[0] != digit[0]) { printf(" Sent '%s'\n", digit); printf(" Received '%s' [%d]\n", buf, actual); printf(" Failed\n"); exit(2); } } } printf(" Passed\n"); /* Test 3: Recognition bandwidth and channel centre frequency check. Use all digits. Each digit types requires four tests to complete the check. Each section contains 40 pulses of 68ms duration, with an amplitude of -20dB from clip per frequency. Four sections covering the tests for one tone (1 digit) are: a. H frequency at 0% deviation from center, L frequency at +0.1%. L frequency is then increments in +01.% steps up to +4%. The number of tone bursts is noted and designated N+. b. H frequency at 0% deviation, L frequency at -0.1%. L frequency is then incremental in -0.1% steps, up to -4%. The number of tone bursts is noted and designated N-. c. The test in (a) is repeated with the L frequency at 0% and the H frequency varied up to +4%. d. The test in (b) is repeated with the L frequency and 0% and the H frequency varied to -4%. Receiver Recognition Bandwidth (RRB) is calculated as follows: RRB% = (N+ + N-)/10 Receiver Center Frequency Offset (RCFO) is calculated as follows: RCFO% = X + (N+ - N-)/20 Note that this test doesn't test what it says it is testing at all, and the results are quite inaccurate, if not a downright lie! However, it follows the Mitel procedure, so how can it be bad? :) The spec calls for +-1.5% +-10Hz of bandwidth. */ printf("Test 3: Recognition bandwidth and channel centre frequency check\n"); s = ALL_POSSIBLE_DIGITS; digit[1] = '\0'; j = 0; while (*s) { digit[0] = *s++; for (nplus = 0, i = 1; i <= 60; i++) { my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, 68); len = my_mf_generate(amp, digit); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); nplus += bell_mf_rx_get(mf_state, buf, 128); } for (nminus = 0, i = -1; i >= -60; i--) { my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, 68); len = my_mf_generate(amp, digit); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); nminus += bell_mf_rx_get(mf_state, buf, 128); } rrb = (float) (nplus + nminus)/10.0; rcfo = (float) (nplus - nminus)/10.0; printf(" %c (low) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", digit[0], rrb, rcfo, (float) nminus/10.0, (float) nplus/10.0); if (rrb < 3.0 + rcfo + (2.0*100.0*10.0/bell_mf_tones[j].f1) || rrb >= 15.0 + rcfo) { printf(" Failed\n"); exit(2); } for (nplus = 0, i = 1; i <= 60; i++) { my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, 68); len = my_mf_generate(amp, digit); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); nplus += bell_mf_rx_get(mf_state, buf, 128); } for (nminus = 0, i = -1; i >= -60; i--) { my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, 68); len = my_mf_generate(amp, digit); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); nminus += bell_mf_rx_get(mf_state, buf, 128); } rrb = (float) (nplus + nminus)/10.0; rcfo = (float) (nplus - nminus)/10.0; printf(" %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", digit[0], rrb, rcfo, (float) nminus/10.0, (float) nplus/10.0); if (rrb < 3.0 + rcfo + (2.0*100.0*10.0/bell_mf_tones[j].f2) || rrb >= 15.0 + rcfo) { printf(" Failed\n"); exit(2); } j++; } printf(" Passed\n"); /* Test 4: Acceptable amplitude ratio (twist). Twist all digits in both directions, and check the maximum twist we can accept. The way this is done is styled after the Mitel DTMF test, and has good and bad points. */ printf("Test 4: Acceptable amplitude ratio (twist)\n"); s = ALL_POSSIBLE_DIGITS; digit[1] = '\0'; while (*s) { digit[0] = *s++; for (nplus = 0, i = -50; i >= -250; i--) { my_mf_gen_init(0.0, -5, 0.0, i/10, 68, 68); len = my_mf_generate(amp, digit); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); nplus += bell_mf_rx_get(mf_state, buf, 128); } printf(" %c normal twist = %.2fdB\n", digit[0], (float) nplus/10.0); if (nplus < 60) { printf(" Failed\n"); exit(2); } for (nminus = 0, i = -50; i >= -250; i--) { my_mf_gen_init(0.0, i/10, 0.0, -5, 68, 68); len = my_mf_generate(amp, digit); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); nminus += bell_mf_rx_get(mf_state, buf, 128); } printf(" %c reverse twist = %.2fdB\n", digit[0], (float) nminus/10.0); if (nminus < 60) { printf(" Failed\n"); exit(2); } } printf(" Passed\n"); /* Test 5: Dynamic range This test sends all possible digits, with gradually increasing amplitude. We determine the span over which we achieve reliable detection. The spec says we should detect between -14dBm and 0dBm, but the tones clip above -3dBm, so this cannot really work. */ printf("Test 5: Dynamic range\n"); for (nplus = nminus = -1000, i = -50; i <= 3; i++) { my_mf_gen_init(0.0, i, 0.0, i, 68, 68); for (j = 0; j < 100; j++) { len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); if (bell_mf_rx_get(mf_state, buf, 128) != 15) break; if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0) break; } if (j == 100) { if (nplus == -1000) nplus = i; } else { if (nplus != -1000 && nminus == -1000) nminus = i; } } printf(" Dynamic range = %ddB to %ddB\n", nplus, nminus - 1); if (nplus > -22 || nminus <= -3) { printf(" Failed\n"); exit(2); } printf(" Passed\n"); /* Test 6: Guard time This test sends all possible digits, with a gradually reducing duration. The spec defines a narrow range of tone duration times we can expect, so as long as we detect reliably at the specified minimum we should be OK. However, the spec also says we should detect on a minimum of 55ms of KP, or 30ms of other digits. */ printf("Test 6: Guard time\n"); for (i = 30; i < 62; i++) { my_mf_gen_init(0.0, -5, 0.0, -3, i, 68); for (j = 0; j < 500; j++) { len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); if (bell_mf_rx_get(mf_state, buf, 128) != 15) break; if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0) break; } if (j == 500) break; } printf(" Guard time = %dms\n", i); if (i > 61) { printf(" Failed\n"); exit(2); } printf(" Passed\n"); /* Test 7: Acceptable signal to noise ratio We send all possible digits at -6dBm from clip, mixed with AWGN. We gradually reduce the noise until we get clean detection. */ printf("Test 7: Acceptable signal to noise ratio\n"); my_mf_gen_init(0.0, -3, 0.0, -3, 68, 68); for (i = -10; i > -50; i--) { awgn_init_dbm0(&noise_source, 1234567, (float) i); for (j = 0; j < 500; j++) { len = my_mf_generate(amp, ALL_POSSIBLE_DIGITS); for (sample = 0; sample < len; sample++) amp[sample] = saturate(amp[sample] + awgn(&noise_source)); codec_munge(amp, len); bell_mf_rx(mf_state, amp, len); if (bell_mf_rx_get(mf_state, buf, 128) != 15) break; if (strcmp(buf, ALL_POSSIBLE_DIGITS) != 0) break; } if (j == 500) break; } printf(" Acceptable S/N ratio is %ddB\n", -3 - i); if (-3 - i > 26) { printf(" Failed\n"); exit(2); } bell_mf_rx_free(mf_state); printf(" Passed\n"); /* The remainder of the Mitel tape is the talk-off test. This is meaningless for Bell MF. However the decoder's tolerance of out of band noise is significant. */ /* TODO: add a OOB tolerance test. */ /* Test the callback mode for delivering detected digits */ printf("Test: Callback digit delivery mode.\n"); callback_ok = false; callback_roll = 0; mf_state = bell_mf_rx_init(NULL, digit_delivery, (void *) 0x12345678); my_mf_gen_init(0.0, -10, 0.0, -10, 68, 68); for (i = 1; i < 10; i++) { len = 0; for (j = 0; j < i; j++) len += my_mf_generate(amp + len, ALL_POSSIBLE_DIGITS); bell_mf_rx(mf_state, amp, len); if (!callback_ok) break; } if (!callback_ok) { printf(" Failed\n"); exit(2); } bell_mf_rx_free(mf_state); printf(" Passed\n"); duration = time (NULL) - now; printf("Tests passed in %ds\n", duration); return 0; }
static int test_a_tone_set(int fwd) { int i; int j; int len; int sample; const char *s; char digit; int actual; int nplus; int nminus; float rrb; float rcfo; int16_t amp[100000]; r2_mf_rx_state_t mf_state; awgn_state_t noise_source; const mf_digit_tones_t *tone; if (fwd) tone = &r2_mf_fwd_tones[0]; else tone = &r2_mf_back_tones[0]; r2_mf_rx_init(&mf_state, fwd); /* Test 1: Mitel's test 1 isn't really a test. Its a calibration step, which has no meaning here. */ printf ("Test 1: Calibration\n"); printf (" Passed\n"); /* Test 2: Decode check This is a sanity check, that all digits are reliably detected under ideal conditions. Each possible digit is repeated 10 times, with 68ms bursts. The level of each tone is about 6dB down from clip */ printf ("Test 2: Decode check\n"); my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd); s = r2_mf_tone_codes; while (*s) { digit = *s++; for (i = 0; i < 10; i++) { len = my_mf_generate(amp, digit); codec_munge (amp, len); actual = r2_mf_rx(&mf_state, amp, len); if (actual != digit) { printf (" Sent '%c'\n", digit); printf (" Received 0x%X\n", actual); printf (" Failed\n"); exit (2); } } } printf (" Passed\n"); /* Test 3: Recognition bandwidth and channel centre frequency check. Use all digits. Each digit types requires four tests to complete the check. Each section contains 40 pulses of 68ms duration, with an amplitude of -20dB from clip per frequency. Four sections covering the tests for one tone (1 digit) are: a. H frequency at 0% deviation from center, L frequency at +0.1%. L frequency is then increments in +01.% steps up to +4%. The number of tone bursts is noted and designated N+. b. H frequency at 0% deviation, L frequency at -0.1%. L frequency is then incremental in -0.1% steps, up to -4%. The number of tone bursts is noted and designated N-. c. The test in (a) is repeated with the L frequency at 0% and the H frequency varied up to +4%. d. The test in (b) is repeated with the L frequency and 0% and the H frequency varied to -4%. Receiver Recognition Bandwidth (RRB) is calculated as follows: RRB% = (N+ + N-)/10 Receiver Center Frequency Offset (RCFO) is calculated as follows: RCFO% = X + (N+ - N-)/20 Note that this test doesn't test what it says it is testing at all, and the results are quite inaccurate, if not a downright lie! However, it follows the Mitel procedure, so how can it be bad? :) The spec calls for +-4 +-10Hz (ie +-14Hz) of bandwidth. */ printf ("Test 3: Recognition bandwidth and channel centre frequency check\n"); s = r2_mf_tone_codes; j = 0; while (*s) { digit = *s++; for (nplus = 0, i = 1; i <= 60; i++) { my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, fwd); len = my_mf_generate(amp, digit); codec_munge(amp, len); if (r2_mf_rx(&mf_state, amp, len) == digit) nplus++; } for (nminus = 0, i = -1; i >= -60; i--) { my_mf_gen_init((float) i/1000.0, -17, 0.0, -17, 68, fwd); len = my_mf_generate(amp, digit); codec_munge(amp, len); if (r2_mf_rx(&mf_state, amp, len) == digit) nminus++; } rrb = (float) (nplus + nminus)/10.0; rcfo = (float) (nplus - nminus)/10.0; printf (" %c (low) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", digit, rrb, rcfo, (float) nminus/10.0, (float) nplus/10.0); if (rrb < rcfo + (2.0*100.0*14.0/r2_mf_fwd_tones[j].f1) || rrb >= 15.0 + rcfo) { printf (" Failed\n"); exit (2); } for (nplus = 0, i = 1; i <= 60; i++) { my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, fwd); len = my_mf_generate(amp, digit); codec_munge(amp, len); if (r2_mf_rx(&mf_state, amp, len) == digit) nplus++; } for (nminus = 0, i = -1; i >= -60; i--) { my_mf_gen_init(0.0, -17, (float) i/1000.0, -17, 68, fwd); len = my_mf_generate(amp, digit); codec_munge(amp, len); if (r2_mf_rx(&mf_state, amp, len) == digit) nminus++; } rrb = (float) (nplus + nminus)/10.0; rcfo = (float) (nplus - nminus)/10.0; printf (" %c (high) rrb = %5.2f%%, rcfo = %5.2f%%, max -ve = %5.2f, max +ve = %5.2f\n", digit, rrb, rcfo, (float) nminus/10.0, (float) nplus/10.0); if (rrb < rcfo + (2.0*100.0*14.0/r2_mf_fwd_tones[j].f2) || rrb >= 15.0 + rcfo) { printf (" Failed\n"); exit (2); } j++; } printf (" Passed\n"); /* Test 4: Acceptable amplitude ratio (twist). Twist all digits in both directions, and check the maximum twist we can accept. The way this is done is styled after the Mitel DTMF test, and has good and bad points. */ printf ("Test 4: Acceptable amplitude ratio (twist)\n"); s = r2_mf_tone_codes; while (*s) { digit = *s++; for (nplus = 0, i = -50; i >= -250; i--) { my_mf_gen_init(0.0, -5, 0.0, i/10, 68, fwd); len = my_mf_generate(amp, digit); codec_munge (amp, len); if (r2_mf_rx(&mf_state, amp, len) == digit) nplus++; } printf (" %c normal twist = %.2fdB\n", digit, (float) nplus/10.0); if (nplus < 70) { printf (" Failed\n"); exit (2); } for (nminus = 0, i = -50; i >= -250; i--) { my_mf_gen_init(0.0, i/10, 0.0, -5, 68, fwd); len = my_mf_generate(amp, digit); codec_munge(amp, len); if (r2_mf_rx(&mf_state, amp, len) == digit) nminus++; } printf (" %c reverse twist = %.2fdB\n", digit, (float) nminus/10.0); if (nminus < 70) { printf (" Failed\n"); exit (2); } } printf (" Passed\n"); /* Test 5: Dynamic range This test sends all possible digits, with gradually increasing amplitude. We determine the span over which we achieve reliable detection. */ printf ("Test 5: Dynamic range\n"); for (nplus = nminus = -1000, i = -50; i <= 3; i++) { s = r2_mf_tone_codes; while (*s) { digit = *s++; my_mf_gen_init(0.0, i, 0.0, i, 68, fwd); for (j = 0; j < 100; j++) { len = my_mf_generate(amp, digit); codec_munge(amp, len); if (r2_mf_rx(&mf_state, amp, len) != digit) break; } if (j < 100) break; } if (j == 100) { if (nplus == -1000) nplus = i; } else { if (nplus != -1000 && nminus == -1000) nminus = i; } } printf (" Dynamic range = %ddB to %ddB\n", nplus, nminus - 1); if (nplus > -35 || nminus <= -5) { printf(" Failed\n"); exit(2); } printf (" Passed\n"); /* Test 6: Guard time This test sends all possible digits, with a gradually reducing duration. */ printf ("Test 6: Guard time\n"); for (i = 30; i < 62; i++) { s = r2_mf_tone_codes; j = 0; while (*s) { digit = *s++; my_mf_gen_init(0.0, -5, 0.0, -3, i, fwd); for (j = 0; j < 500; j++) { len = my_mf_generate(amp, digit); codec_munge(amp, len); if (r2_mf_rx(&mf_state, amp, len) != digit) break; } if (j < 500) break; } if (j == 500) break; } printf (" Guard time = %dms\n", i); if (i > 61) { printf(" Failed\n"); exit(2); } printf (" Passed\n"); /* Test 7: Acceptable signal to noise ratio We send all possible digits at -6dBm from clip, mixed with AWGN. We gradually reduce the noise until we get clean detection. */ printf ("Test 7: Acceptable signal to noise ratio\n"); my_mf_gen_init(0.0, -3, 0.0, -3, 68, fwd); for (i = -3; i > -50; i--) { s = r2_mf_tone_codes; while (*s) { digit = *s++; awgn_init_dbm0(&noise_source, 1234567, (float) i); for (j = 0; j < 500; j++) { len = my_mf_generate(amp, digit); for (sample = 0; sample < len; sample++) amp[sample] = saturate(amp[sample] + awgn(&noise_source)); codec_munge(amp, len); if (r2_mf_rx(&mf_state, amp, len) != digit) break; } if (j < 500) break; } if (j == 500) break; } printf(" Acceptable S/N ratio is %ddB\n", -3 - i); if (-3 - i > 26) { printf(" Failed\n"); exit(2); } printf(" Passed\n"); /* The remainder of the Mitel tape is the talk-off test. This is meaningless for R2 MF. However the decoder's tolerance of out of band noise is significant. */ /* TODO: add a OOB tolerance test. */ return 0; }