Mercurial > hg > audiostuff
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 ------------------------------------------------------------*/ |