comparison spandsp-0.0.6pre17/tests/fsk_tests.c @ 4:26cd8f1ef0b1

import spandsp-0.0.6pre17
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 15:50:58 +0200
parents
children
comparison
equal deleted inserted replaced
3:c6c5a16ce2f2 4:26cd8f1ef0b1
1 /*
2 * SpanDSP - a series of DSP components for telephony
3 *
4 * fsk_tests.c - Tests for the low speed FSK modem code (V.21, V.23, etc.).
5 *
6 * Written by Steve Underwood <steveu@coppice.org>
7 *
8 * Copyright (C) 2003 Steve Underwood
9 *
10 * All rights reserved.
11 *
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2, as
14 * published by the Free Software Foundation.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 *
25 * $Id: fsk_tests.c,v 1.59 2009/11/02 13:25:20 steveu Exp $
26 */
27
28 /*! \page fsk_tests_page FSK modem tests
29 \section fsk_tests_page_sec_1 What does it do?
30 These tests allow either:
31
32 - An FSK transmit modem to feed an FSK receive modem, of the same type,
33 through a telephone line model. BER testing is then used to evaluate
34 performance under various line conditions. This is effective for testing
35 the basic performance of the receive modem. It is also the only test mode
36 provided for evaluating the transmit modem.
37
38 - An FSK receive modem is used to decode FSK audio, stored in a file.
39 This is good way to evaluate performance with audio recorded from other
40 models of modem, and with real world problematic telephone lines.
41
42 \section fsk_tests_page_sec_2 How does it work?
43 */
44
45 #if defined(HAVE_CONFIG_H)
46 #include "config.h"
47 #endif
48
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <unistd.h>
52 #include <string.h>
53 #include <assert.h>
54 #include <sndfile.h>
55
56 //#if defined(WITH_SPANDSP_INTERNALS)
57 #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
58 //#endif
59
60 #include "spandsp.h"
61 #include "spandsp-sim.h"
62
63 #define BLOCK_LEN 160
64
65 #define OUTPUT_FILE_NAME "fsk.wav"
66
67 char *decode_test_file = NULL;
68 both_ways_line_model_state_t *model;
69 int rx_bits = 0;
70 int cutoff_test_carrier = FALSE;
71
72 static void rx_status(void *user_data, int status)
73 {
74 printf("FSK rx status is %s (%d)\n", signal_status_to_str(status), status);
75 }
76 /*- End of function --------------------------------------------------------*/
77
78 static void tx_status(void *user_data, int status)
79 {
80 printf("FSK tx status is %s (%d)\n", signal_status_to_str(status), status);
81 }
82 /*- End of function --------------------------------------------------------*/
83
84 static void put_bit(void *user_data, int bit)
85 {
86 if (bit < 0)
87 {
88 rx_status(user_data, bit);
89 return;
90 }
91
92 printf("Rx bit %d - %d\n", rx_bits++, bit);
93 }
94 /*- End of function --------------------------------------------------------*/
95
96 static void cutoff_test_rx_status(void *user_data, int status)
97 {
98 printf("FSK rx status is %s (%d)\n", signal_status_to_str(status), status);
99 switch (status)
100 {
101 case SIG_STATUS_CARRIER_UP:
102 cutoff_test_carrier = TRUE;
103 break;
104 case SIG_STATUS_CARRIER_DOWN:
105 cutoff_test_carrier = FALSE;
106 break;
107 }
108 }
109 /*- End of function --------------------------------------------------------*/
110
111 static void cutoff_test_put_bit(void *user_data, int bit)
112 {
113 if (bit < 0)
114 {
115 cutoff_test_rx_status(user_data, bit);
116 return;
117 }
118 }
119 /*- End of function --------------------------------------------------------*/
120
121 static void reporter(void *user_data, int reason, bert_results_t *results)
122 {
123 int channel;
124
125 channel = (int) (intptr_t) user_data;
126 switch (reason)
127 {
128 case BERT_REPORT_SYNCED:
129 fprintf(stderr, "%d: BERT report synced\n", channel);
130 break;
131 case BERT_REPORT_UNSYNCED:
132 fprintf(stderr, "%d: BERT report unsync'ed\n", channel);
133 break;
134 case BERT_REPORT_REGULAR:
135 fprintf(stderr, "%d: BERT report regular - %d bits, %d bad bits, %d resyncs\n", channel, results->total_bits, results->bad_bits, results->resyncs);
136 break;
137 case BERT_REPORT_GT_10_2:
138 fprintf(stderr, "%d: BERT report > 1 in 10^2\n", channel);
139 break;
140 case BERT_REPORT_LT_10_2:
141 fprintf(stderr, "%d: BERT report < 1 in 10^2\n", channel);
142 break;
143 case BERT_REPORT_LT_10_3:
144 fprintf(stderr, "%d: BERT report < 1 in 10^3\n", channel);
145 break;
146 case BERT_REPORT_LT_10_4:
147 fprintf(stderr, "%d: BERT report < 1 in 10^4\n", channel);
148 break;
149 case BERT_REPORT_LT_10_5:
150 fprintf(stderr, "%d: BERT report < 1 in 10^5\n", channel);
151 break;
152 case BERT_REPORT_LT_10_6:
153 fprintf(stderr, "%d: BERT report < 1 in 10^6\n", channel);
154 break;
155 case BERT_REPORT_LT_10_7:
156 fprintf(stderr, "%d: BERT report < 1 in 10^7\n", channel);
157 break;
158 default:
159 fprintf(stderr, "%d: BERT report reason %d\n", channel, reason);
160 break;
161 }
162 }
163 /*- End of function --------------------------------------------------------*/
164
165 int main(int argc, char *argv[])
166 {
167 fsk_tx_state_t *caller_tx;
168 fsk_rx_state_t *caller_rx;
169 fsk_tx_state_t *answerer_tx;
170 fsk_rx_state_t *answerer_rx;
171 bert_state_t caller_bert;
172 bert_state_t answerer_bert;
173 bert_results_t bert_results;
174 power_meter_t caller_meter;
175 power_meter_t answerer_meter;
176 int16_t caller_amp[BLOCK_LEN];
177 int16_t answerer_amp[BLOCK_LEN];
178 int16_t caller_model_amp[BLOCK_LEN];
179 int16_t answerer_model_amp[BLOCK_LEN];
180 int16_t out_amp[2*BLOCK_LEN];
181 SNDFILE *inhandle;
182 SNDFILE *outhandle;
183 int outframes;
184 int i;
185 int j;
186 int samples;
187 int test_bps;
188 int noise_level;
189 int noise_sweep;
190 int bits_per_test;
191 int line_model_no;
192 int modem_under_test_1;
193 int modem_under_test_2;
194 int modems_set;
195 int log_audio;
196 int channel_codec;
197 int rbs_pattern;
198 int on_at;
199 int off_at;
200 tone_gen_descriptor_t tone_desc;
201 tone_gen_state_t tone_tx;
202 int opt;
203
204 channel_codec = MUNGE_CODEC_NONE;
205 rbs_pattern = 0;
206 line_model_no = 0;
207 decode_test_file = NULL;
208 noise_sweep = FALSE;
209 modem_under_test_1 = FSK_V21CH1;
210 modem_under_test_2 = FSK_V21CH2;
211 log_audio = FALSE;
212 modems_set = 0;
213 while ((opt = getopt(argc, argv, "c:dlm:nr:s:")) != -1)
214 {
215 switch (opt)
216 {
217 case 'c':
218 channel_codec = atoi(optarg);
219 break;
220 case 'd':
221 decode_test_file = optarg;
222 break;
223 case 'l':
224 log_audio = TRUE;
225 break;
226 case 'm':
227 line_model_no = atoi(optarg);
228 break;
229 case 'n':
230 noise_sweep = TRUE;
231 break;
232 case 'r':
233 rbs_pattern = atoi(optarg);
234 break;
235 case 's':
236 switch (modems_set++)
237 {
238 case 0:
239 modem_under_test_1 = atoi(optarg);
240 break;
241 case 1:
242 modem_under_test_2 = atoi(optarg);
243 break;
244 }
245 break;
246 default:
247 //usage();
248 exit(2);
249 break;
250 }
251 }
252
253 if (modem_under_test_1 >= 0)
254 printf("Modem channel 1 is '%s'\n", preset_fsk_specs[modem_under_test_1].name);
255 if (modem_under_test_2 >= 0)
256 printf("Modem channel 2 is '%s'\n", preset_fsk_specs[modem_under_test_2].name);
257
258 outhandle = NULL;
259
260 if (log_audio)
261 {
262 if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 2)) == NULL)
263 {
264 fprintf(stderr, " Cannot create audio file '%s'\n", OUTPUT_FILE_NAME);
265 exit(2);
266 }
267 }
268 noise_level = -200;
269 bits_per_test = 0;
270 inhandle = NULL;
271
272 memset(caller_amp, 0, sizeof(*caller_amp));
273 memset(answerer_amp, 0, sizeof(*answerer_amp));
274 memset(caller_model_amp, 0, sizeof(*caller_model_amp));
275 memset(answerer_model_amp, 0, sizeof(*answerer_model_amp));
276 power_meter_init(&caller_meter, 7);
277 power_meter_init(&answerer_meter, 7);
278
279 if (decode_test_file)
280 {
281 if ((inhandle = sf_open_telephony_read(decode_test_file, 1)) == NULL)
282 {
283 fprintf(stderr, " Cannot open audio file '%s'\n", decode_test_file);
284 exit(2);
285 }
286 caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, put_bit, NULL);
287 fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx);
288 test_bps = preset_fsk_specs[modem_under_test_1].baud_rate;
289
290 for (;;)
291 {
292 samples = sf_readf_short(inhandle, caller_model_amp, BLOCK_LEN);
293 if (samples < BLOCK_LEN)
294 break;
295 for (i = 0; i < samples; i++)
296 power_meter_update(&caller_meter, caller_model_amp[i]);
297 fsk_rx(caller_rx, caller_model_amp, samples);
298 }
299
300 if (sf_close(inhandle) != 0)
301 {
302 fprintf(stderr, " Cannot close audio file '%s'\n", decode_test_file);
303 exit(2);
304 }
305 }
306 else
307 {
308 printf("Test cutoff level\n");
309 caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, cutoff_test_put_bit, NULL);
310 fsk_rx_signal_cutoff(caller_rx, -30.0f);
311 fsk_rx_set_modem_status_handler(caller_rx, cutoff_test_rx_status, (void *) &caller_rx);
312 on_at = 0;
313 for (i = -40; i < -25; i++)
314 {
315 make_tone_gen_descriptor(&tone_desc,
316 1500,
317 i,
318 0,
319 0,
320 1,
321 0,
322 0,
323 0,
324 TRUE);
325 tone_gen_init(&tone_tx, &tone_desc);
326 for (j = 0; j < 10; j++)
327 {
328 samples = tone_gen(&tone_tx, caller_model_amp, 160);
329 fsk_rx(caller_rx, caller_model_amp, samples);
330 }
331 if (cutoff_test_carrier)
332 break;
333 }
334 on_at = i;
335 off_at = 0;
336 for ( ; i > -40; i--)
337 {
338 make_tone_gen_descriptor(&tone_desc,
339 1500,
340 i,
341 0,
342 0,
343 1,
344 0,
345 0,
346 0,
347 TRUE);
348 tone_gen_init(&tone_tx, &tone_desc);
349 for (j = 0; j < 10; j++)
350 {
351 samples = tone_gen(&tone_tx, caller_model_amp, 160);
352 fsk_rx(caller_rx, caller_model_amp, samples);
353 }
354 if (!cutoff_test_carrier)
355 break;
356 }
357 off_at = i;
358 printf("Carrier on at %d, off at %d\n", on_at, off_at);
359 if (on_at < -29 || on_at > -26
360 ||
361 off_at < -35 || off_at > -31)
362 {
363 printf("Tests failed.\n");
364 exit(2);
365 }
366
367 printf("Test with BERT\n");
368 test_bps = preset_fsk_specs[modem_under_test_1].baud_rate;
369 if (modem_under_test_1 >= 0)
370 {
371 caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert);
372 fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx);
373 answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &answerer_bert);
374 fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx);
375 }
376 if (modem_under_test_2 >= 0)
377 {
378 answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert);
379 fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx);
380 caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &caller_bert);
381 fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx);
382 }
383 test_bps = preset_fsk_specs[modem_under_test_1].baud_rate;
384
385 bits_per_test = 500000;
386 noise_level = -24;
387
388 bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
389 bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1);
390 bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
391 bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2);
392 if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, (float) noise_level, channel_codec, rbs_pattern)) == NULL)
393 {
394 fprintf(stderr, " Failed to create line model\n");
395 exit(2);
396 }
397
398 for (;;)
399 {
400 samples = fsk_tx(caller_tx, caller_amp, BLOCK_LEN);
401 for (i = 0; i < samples; i++)
402 power_meter_update(&caller_meter, caller_amp[i]);
403 samples = fsk_tx(answerer_tx, answerer_amp, BLOCK_LEN);
404 for (i = 0; i < samples; i++)
405 power_meter_update(&answerer_meter, answerer_amp[i]);
406 both_ways_line_model(model,
407 caller_model_amp,
408 caller_amp,
409 answerer_model_amp,
410 answerer_amp,
411 samples);
412
413 //printf("Powers %10.5fdBm0 %10.5fdBm0\n", power_meter_current_dbm0(&caller_meter), power_meter_current_dbm0(&answerer_meter));
414
415 fsk_rx(answerer_rx, caller_model_amp, samples);
416 for (i = 0; i < samples; i++)
417 out_amp[2*i] = caller_model_amp[i];
418 for ( ; i < BLOCK_LEN; i++)
419 out_amp[2*i] = 0;
420
421 fsk_rx(caller_rx, answerer_model_amp, samples);
422 for (i = 0; i < samples; i++)
423 out_amp[2*i + 1] = answerer_model_amp[i];
424 for ( ; i < BLOCK_LEN; i++)
425 out_amp[2*i + 1] = 0;
426
427 if (log_audio)
428 {
429 outframes = sf_writef_short(outhandle, out_amp, BLOCK_LEN);
430 if (outframes != BLOCK_LEN)
431 {
432 fprintf(stderr, " Error writing audio file\n");
433 exit(2);
434 }
435 }
436
437 if (samples < BLOCK_LEN)
438 {
439 bert_result(&caller_bert, &bert_results);
440 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);
441 if (!noise_sweep)
442 {
443 if (bert_results.total_bits != bits_per_test - 43
444 ||
445 bert_results.bad_bits != 0
446 ||
447 bert_results.resyncs != 0)
448 {
449 printf("Tests failed.\n");
450 exit(2);
451 }
452 }
453 bert_result(&answerer_bert, &bert_results);
454 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);
455 if (!noise_sweep)
456 {
457 if (bert_results.total_bits != bits_per_test - 43
458 ||
459 bert_results.bad_bits != 0
460 ||
461 bert_results.resyncs != 0)
462 {
463 printf("Tests failed.\n");
464 exit(2);
465 }
466 break;
467 }
468
469 /* Put a little silence between the chunks in the file. */
470 memset(out_amp, 0, sizeof(out_amp));
471 if (log_audio)
472 {
473 for (i = 0; i < 200; i++)
474 outframes = sf_writef_short(outhandle, out_amp, BLOCK_LEN);
475 }
476 if (modem_under_test_1 >= 0)
477 {
478 caller_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert);
479 fsk_tx_set_modem_status_handler(caller_tx, tx_status, (void *) &caller_tx);
480 answerer_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_1], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &answerer_bert);
481 fsk_rx_set_modem_status_handler(answerer_rx, rx_status, (void *) &answerer_rx);
482 }
483 if (modem_under_test_2 >= 0)
484 {
485 answerer_tx = fsk_tx_init(NULL, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert);
486 fsk_tx_set_modem_status_handler(answerer_tx, tx_status, (void *) &answerer_tx);
487 caller_rx = fsk_rx_init(NULL, &preset_fsk_specs[modem_under_test_2], FSK_FRAME_MODE_SYNC, (put_bit_func_t) bert_put_bit, &caller_bert);
488 fsk_rx_set_modem_status_handler(caller_rx, rx_status, (void *) &caller_rx);
489 }
490 noise_level++;
491 if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, noise_level, channel_codec, 0)) == NULL)
492 {
493 fprintf(stderr, " Failed to create line model\n");
494 exit(2);
495 }
496 bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
497 bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1);
498 bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
499 bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2);
500 }
501 }
502 printf("Tests passed.\n");
503 }
504 if (log_audio)
505 {
506 if (sf_close(outhandle) != 0)
507 {
508 fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME);
509 exit(2);
510 }
511 }
512 return 0;
513 }
514 /*- End of function --------------------------------------------------------*/
515 /*- End of file ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.