comparison spandsp-0.0.3/spandsp-0.0.3/tests/fsk_tests.c @ 5:f762bf195c4b

import spandsp-0.0.3
author Peter Meerwald <pmeerw@cosy.sbg.ac.at>
date Fri, 25 Jun 2010 16:00:21 +0200
parents
children
comparison
equal deleted inserted replaced
4:26cd8f1ef0b1 5:f762bf195c4b
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.30 2006/11/19 14:07:27 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 wave 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 #ifdef HAVE_CONFIG_H
46 #include "config.h"
47 #endif
48
49 #include <inttypes.h>
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <string.h>
53 #if defined(HAVE_TGMATH_H)
54 #include <tgmath.h>
55 #endif
56 #if defined(HAVE_MATH_H)
57 #include <math.h>
58 #endif
59 #include <assert.h>
60 #include <audiofile.h>
61 #include <tiffio.h>
62
63 #include "spandsp.h"
64 #include "test_utils.h"
65 #include "line_model.h"
66
67 #define BLOCK_LEN 160
68
69 #define OUTPUT_FILE_NAME "fsk.wav"
70
71 char *decode_test_file = NULL;
72 both_ways_line_model_state_t *model;
73 int rx_bits = 0;
74
75 static void put_bit(void *user_data, int bit)
76 {
77 if (bit < 0)
78 {
79 /* Special conditions */
80 switch (bit)
81 {
82 case PUTBIT_TRAINING_FAILED:
83 printf("Training failed\n");
84 break;
85 case PUTBIT_TRAINING_SUCCEEDED:
86 printf("Training succeeded\n");
87 break;
88 case PUTBIT_CARRIER_UP:
89 printf("Carrier up\n");
90 break;
91 case PUTBIT_CARRIER_DOWN:
92 printf("Carrier down\n");
93 break;
94 default:
95 printf("Eh!\n");
96 break;
97 }
98 return;
99 }
100
101 printf("Rx bit %d - %d\n", rx_bits++, bit);
102 }
103 /*- End of function --------------------------------------------------------*/
104
105 static void reporter(void *user_data, int reason, bert_results_t *results)
106 {
107 int channel;
108
109 channel = (int) (intptr_t) user_data;
110 switch (reason)
111 {
112 case BERT_REPORT_SYNCED:
113 printf("%d: BERT report synced\n", channel);
114 break;
115 case BERT_REPORT_UNSYNCED:
116 printf("%d: BERT report unsync'ed\n", channel);
117 break;
118 case BERT_REPORT_REGULAR:
119 printf("%d: BERT report regular - %d bits, %d bad bits, %d resyncs\n", channel, results->total_bits, results->bad_bits, results->resyncs);
120 break;
121 case BERT_REPORT_GT_10_2:
122 printf("%d: BERT report > 1 in 10^2\n", channel);
123 break;
124 case BERT_REPORT_LT_10_2:
125 printf("%d: BERT report < 1 in 10^2\n", channel);
126 break;
127 case BERT_REPORT_LT_10_3:
128 printf("%d: BERT report < 1 in 10^3\n", channel);
129 break;
130 case BERT_REPORT_LT_10_4:
131 printf("%d: BERT report < 1 in 10^4\n", channel);
132 break;
133 case BERT_REPORT_LT_10_5:
134 printf("%d: BERT report < 1 in 10^5\n", channel);
135 break;
136 case BERT_REPORT_LT_10_6:
137 printf("%d: BERT report < 1 in 10^6\n", channel);
138 break;
139 case BERT_REPORT_LT_10_7:
140 printf("%d: BERT report < 1 in 10^7\n", channel);
141 break;
142 default:
143 printf("%d: BERT report reason %d\n", channel, reason);
144 break;
145 }
146 }
147 /*- End of function --------------------------------------------------------*/
148
149 int main(int argc, char *argv[])
150 {
151 fsk_tx_state_t caller_tx;
152 fsk_rx_state_t caller_rx;
153 fsk_tx_state_t answerer_tx;
154 fsk_rx_state_t answerer_rx;
155 bert_state_t caller_bert;
156 bert_state_t answerer_bert;
157 bert_results_t bert_results;
158 power_meter_t caller_meter;
159 power_meter_t answerer_meter;
160 int16_t caller_amp[BLOCK_LEN];
161 int16_t answerer_amp[BLOCK_LEN];
162 int16_t caller_model_amp[BLOCK_LEN];
163 int16_t answerer_model_amp[BLOCK_LEN];
164 int16_t out_amp[2*BLOCK_LEN];
165 AFfilehandle inhandle;
166 AFfilehandle outhandle;
167 AFfilesetup filesetup;
168 int outframes;
169 int i;
170 int samples;
171 int test_bps;
172 int noise_level;
173 int noise_sweep;
174 int bits_per_test;
175 int line_model_no;
176 int modem_under_test_1;
177 int modem_under_test_2;
178 int log_audio;
179 int channel_codec;
180
181 channel_codec = MUNGE_CODEC_NONE;
182 line_model_no = 0;
183 decode_test_file = NULL;
184 noise_sweep = FALSE;
185 modem_under_test_1 = FSK_V21CH1;
186 modem_under_test_2 = FSK_V21CH2;
187 log_audio = FALSE;
188 for (i = 1; i < argc; i++)
189 {
190 if (strcmp(argv[i], "-c") == 0)
191 {
192 channel_codec = atoi(argv[++i]);
193 continue;
194 }
195 if (strcmp(argv[i], "-d") == 0)
196 {
197 i++;
198 decode_test_file = argv[i];
199 continue;
200 }
201 if (strcmp(argv[i], "-m") == 0)
202 {
203 i++;
204 line_model_no = atoi(argv[i]);
205 continue;
206 }
207 if (strcmp(argv[i], "-s") == 0)
208 {
209 i++;
210 modem_under_test_1 = atoi(argv[i]);
211 i++;
212 modem_under_test_2 = atoi(argv[i]);
213 continue;
214 }
215 if (strcmp(argv[i], "-n") == 0)
216 {
217 noise_sweep = TRUE;
218 continue;
219 }
220 if (strcmp(argv[i], "-l") == 0)
221 {
222 log_audio = TRUE;
223 continue;
224 }
225 }
226
227 filesetup = AF_NULL_FILESETUP;
228 outhandle = AF_NULL_FILEHANDLE;
229
230 if (log_audio)
231 {
232 if ((filesetup = afNewFileSetup()) == AF_NULL_FILESETUP)
233 {
234 fprintf(stderr, " Failed to create file setup\n");
235 exit(2);
236 }
237 afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
238 afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE);
239 afInitFileFormat(filesetup, AF_FILE_WAVE);
240 afInitChannels(filesetup, AF_DEFAULT_TRACK, 2);
241 }
242 noise_level = -200;
243 bits_per_test = 0;
244 inhandle = NULL;
245 if (decode_test_file)
246 {
247 if ((inhandle = afOpenFile(decode_test_file, "r", NULL)) == AF_NULL_FILEHANDLE)
248 {
249 fprintf(stderr, " Cannot open wave file '%s'\n", decode_test_file);
250 exit(2);
251 }
252 fsk_rx_init(&caller_rx, &preset_fsk_specs[modem_under_test_1], TRUE, put_bit, NULL);
253 test_bps = preset_fsk_specs[modem_under_test_1].baud_rate;
254 }
255 else
256 {
257 printf("Test with BERT\n");
258 if (modem_under_test_1 >= 0)
259 {
260 fsk_tx_init(&caller_tx, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert);
261 fsk_rx_init(&answerer_rx, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert);
262 }
263 if (modem_under_test_2 >= 0)
264 {
265 fsk_tx_init(&answerer_tx, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert);
266 fsk_rx_init(&caller_rx, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert);
267 }
268 test_bps = preset_fsk_specs[modem_under_test_1].baud_rate;
269
270 bits_per_test = 500000;
271 noise_level = -24;
272
273 bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
274 bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1);
275 bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
276 bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2);
277 if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, noise_level, channel_codec)) == NULL)
278 {
279 fprintf(stderr, " Failed to create line model\n");
280 exit(2);
281 }
282 }
283 if (log_audio)
284 {
285 if ((outhandle = afOpenFile(OUTPUT_FILE_NAME, "w", filesetup)) == AF_NULL_FILEHANDLE)
286 {
287 fprintf(stderr, " Cannot create wave file '%s'\n", OUTPUT_FILE_NAME);
288 exit(2);
289 }
290 }
291
292 if (modem_under_test_1 >= 0)
293 printf("Modem channel 1 is '%s'\n", preset_fsk_specs[modem_under_test_1].name);
294 if (modem_under_test_2 >= 0)
295 printf("Modem channel 2 is '%s'\n", preset_fsk_specs[modem_under_test_2].name);
296 memset(caller_amp, 0, sizeof(*caller_amp));
297 memset(answerer_amp, 0, sizeof(*answerer_amp));
298 memset(caller_model_amp, 0, sizeof(*caller_model_amp));
299 memset(answerer_model_amp, 0, sizeof(*answerer_model_amp));
300 power_meter_init(&caller_meter, 7);
301 power_meter_init(&answerer_meter, 7);
302 for (;;)
303 {
304 if (decode_test_file)
305 {
306 samples = afReadFrames(inhandle,
307 AF_DEFAULT_TRACK,
308 caller_model_amp,
309 BLOCK_LEN);
310 if (samples < BLOCK_LEN)
311 break;
312 for (i = 0; i < samples; i++)
313 power_meter_update(&caller_meter, caller_model_amp[i]);
314 }
315 else
316 {
317 samples = fsk_tx(&caller_tx, caller_amp, BLOCK_LEN);
318 for (i = 0; i < samples; i++)
319 power_meter_update(&caller_meter, caller_amp[i]);
320 samples = fsk_tx(&answerer_tx, answerer_amp, BLOCK_LEN);
321 for (i = 0; i < samples; i++)
322 power_meter_update(&answerer_meter, answerer_amp[i]);
323 both_ways_line_model(model,
324 caller_model_amp,
325 caller_amp,
326 answerer_model_amp,
327 answerer_amp,
328 samples);
329 }
330 //printf("Powers %10.5fdBm0 %10.5fdBm0\n", power_meter_dbm0(&caller_meter), power_meter_dbm0(&answerer_meter));
331
332 fsk_rx(&answerer_rx, caller_model_amp, samples);
333 for (i = 0; i < samples; i++)
334 out_amp[2*i] = caller_model_amp[i];
335 for ( ; i < BLOCK_LEN; i++)
336 out_amp[2*i] = 0;
337
338 fsk_rx(&caller_rx, answerer_model_amp, samples);
339 for (i = 0; i < samples; i++)
340 out_amp[2*i + 1] = answerer_model_amp[i];
341 for ( ; i < BLOCK_LEN; i++)
342 out_amp[2*i + 1] = 0;
343
344 if (log_audio)
345 {
346 outframes = afWriteFrames(outhandle,
347 AF_DEFAULT_TRACK,
348 out_amp,
349 BLOCK_LEN);
350 if (outframes != BLOCK_LEN)
351 {
352 fprintf(stderr, " Error writing wave file\n");
353 exit(2);
354 }
355 }
356
357 if (samples < BLOCK_LEN)
358 {
359 bert_result(&caller_bert, &bert_results);
360 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);
361 if (!noise_sweep)
362 {
363 if (bert_results.total_bits != bits_per_test - 43
364 ||
365 bert_results.bad_bits != 0
366 ||
367 bert_results.resyncs != 0)
368 {
369 printf("Tests failed.\n");
370 exit(2);
371 }
372 }
373 bert_result(&answerer_bert, &bert_results);
374 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);
375 if (!noise_sweep)
376 {
377 if (bert_results.total_bits != bits_per_test - 43
378 ||
379 bert_results.bad_bits != 0
380 ||
381 bert_results.resyncs != 0)
382 {
383 printf("Tests failed.\n");
384 exit(2);
385 }
386 break;
387 }
388
389 /* Put a little silence between the chunks in the file. */
390 memset(out_amp, 0, sizeof(out_amp));
391 if (log_audio)
392 {
393 for (i = 0; i < 200; i++)
394 {
395 outframes = afWriteFrames(outhandle,
396 AF_DEFAULT_TRACK,
397 out_amp,
398 BLOCK_LEN);
399 }
400 }
401 if (modem_under_test_1 >= 0)
402 {
403 fsk_tx_init(&caller_tx, &preset_fsk_specs[modem_under_test_1], (get_bit_func_t) bert_get_bit, &caller_bert);
404 fsk_rx_init(&answerer_rx, &preset_fsk_specs[modem_under_test_1], TRUE, (put_bit_func_t) bert_put_bit, &answerer_bert);
405 }
406 if (modem_under_test_2 >= 0)
407 {
408 fsk_tx_init(&answerer_tx, &preset_fsk_specs[modem_under_test_2], (get_bit_func_t) bert_get_bit, &answerer_bert);
409 fsk_rx_init(&caller_rx, &preset_fsk_specs[modem_under_test_2], TRUE, (put_bit_func_t) bert_put_bit, &caller_bert);
410 }
411 noise_level++;
412 if ((model = both_ways_line_model_init(line_model_no, (float) noise_level, line_model_no, noise_level, channel_codec)) == NULL)
413 {
414 fprintf(stderr, " Failed to create line model\n");
415 exit(2);
416 }
417 bert_init(&caller_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
418 bert_set_report(&caller_bert, 100000, reporter, (void *) (intptr_t) 1);
419 bert_init(&answerer_bert, bits_per_test, BERT_PATTERN_ITU_O152_11, test_bps, 20);
420 bert_set_report(&answerer_bert, 100000, reporter, (void *) (intptr_t) 2);
421 }
422 }
423
424 if (log_audio)
425 {
426 if (afCloseFile(outhandle) != 0)
427 {
428 fprintf(stderr, " Cannot close wave file '%s'\n", OUTPUT_FILE_NAME);
429 exit(2);
430 }
431 afFreeFileSetup(filesetup);
432 }
433 if (decode_test_file)
434 {
435 if (afCloseFile(inhandle) != 0)
436 {
437 fprintf(stderr, " Cannot close wave file '%s'\n", decode_test_file);
438 exit(2);
439 }
440 }
441 else
442 {
443 printf("Tests passed.\n");
444 }
445 return 0;
446 }
447 /*- End of function --------------------------------------------------------*/
448 /*- End of file ------------------------------------------------------------*/

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