2
0

power_meter_tests.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * SpanDSP - a series of DSP components for telephony
  3. *
  4. * power_meter_tests.c
  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. /*! \page power_meter_tests_page Power meter tests
  26. \section power_meter_tests_page_sec_1 What does it do?
  27. These tests assess the accuracy of power meters built from the power meter module.
  28. Both tones and noise are used to check the meter's behaviour.
  29. \section power_meter_tests_page_sec_2 How does it work?
  30. ???.
  31. */
  32. #if defined(HAVE_CONFIG_H)
  33. #include "config.h"
  34. #endif
  35. #include <stdlib.h>
  36. #include <stdio.h>
  37. #include <unistd.h>
  38. #include <memory.h>
  39. #include <float.h>
  40. #include <time.h>
  41. #include <sndfile.h>
  42. #include "spandsp.h"
  43. #include "spandsp-sim.h"
  44. #define IN_FILE_NAME "../test-data/local/short_nb_voice.wav"
  45. #define OUT_FILE_NAME "power_meter_tests.wav"
  46. static int power_surge_detector_tests(void)
  47. {
  48. SNDFILE *outhandle;
  49. power_surge_detector_state_t *sig;
  50. int i;
  51. int sample;
  52. int16_t amp[8000];
  53. int16_t amp_out[2*8000];
  54. awgn_state_t *awgnx;
  55. int32_t phase_rate;
  56. uint32_t phase_acc;
  57. int16_t phase_scale;
  58. float signal_power;
  59. int32_t signal_level;
  60. int signal_present;
  61. int prev_signal_present;
  62. int ok;
  63. int extremes[4];
  64. if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 2)) == NULL)
  65. {
  66. fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME);
  67. exit(2);
  68. }
  69. sig = power_surge_detector_init(NULL, -50.0f, 5.0f);
  70. prev_signal_present = false;
  71. phase_rate = dds_phase_rate(450.0f);
  72. phase_acc = 0;
  73. phase_scale = dds_scaling_dbm0(-33.0f);
  74. awgnx = awgn_init_dbm0(NULL, 1234567, -45.0f);
  75. extremes[0] = 8001;
  76. extremes[1] = -1;
  77. extremes[2] = 8001;
  78. extremes[3] = -1;
  79. for (sample = 0; sample < 800000; sample += 8000)
  80. {
  81. ok = 0;
  82. for (i = 0; i < 8000; i++)
  83. {
  84. amp[i] = awgn(awgnx);
  85. if (i < 4000)
  86. amp[i] += dds_mod(&phase_acc, phase_rate, phase_scale, 0);
  87. signal_level = power_surge_detector(sig, amp[i]);
  88. signal_present = (signal_level != 0);
  89. if (prev_signal_present != signal_present)
  90. {
  91. signal_power = power_surge_detector_current_dbm0(sig);
  92. if (signal_present)
  93. {
  94. if (ok == 0 && i >= 0 && i < 25)
  95. ok = 1;
  96. if (extremes[0] > i)
  97. extremes[0] = i;
  98. if (extremes[1] < i)
  99. extremes[1] = i;
  100. printf("On at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power);
  101. }
  102. else
  103. {
  104. if (ok == 1 && i >= 4000 + 0 && i < 4000 + 35)
  105. ok = 2;
  106. if (extremes[2] > i)
  107. extremes[2] = i;
  108. if (extremes[3] < i)
  109. extremes[3] = i;
  110. printf("Off at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power);
  111. }
  112. prev_signal_present = signal_present;
  113. }
  114. amp_out[2*i] = amp[i];
  115. amp_out[2*i + 1] = signal_present*5000;
  116. }
  117. sf_writef_short(outhandle, amp_out, 8000);
  118. if (ok != 2
  119. ||
  120. extremes[0] < 1
  121. ||
  122. extremes[1] > 30
  123. ||
  124. extremes[2] < 4001
  125. ||
  126. extremes[3] > 4030)
  127. {
  128. printf(" Surge not detected correctly (%d)\n", ok);
  129. exit(2);
  130. }
  131. }
  132. if (sf_close_telephony(outhandle))
  133. {
  134. fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
  135. exit(2);
  136. }
  137. printf("Min on %d, max on %d, min off %d, max off %d\n", extremes[0], extremes[1], extremes[2], extremes[3]);
  138. power_surge_detector_free(sig);
  139. awgn_free(awgnx);
  140. return 0;
  141. }
  142. /*- End of function --------------------------------------------------------*/
  143. static int power_surge_detector_file_test(const char *file)
  144. {
  145. SNDFILE *inhandle;
  146. SNDFILE *outhandle;
  147. int inframes;
  148. power_surge_detector_state_t *sig;
  149. int i;
  150. int16_t amp[8000];
  151. int16_t amp_out[2*8000];
  152. int sample;
  153. float signal_power;
  154. int32_t signal_level;
  155. int signal_present;
  156. int prev_signal_present;
  157. if ((inhandle = sf_open_telephony_read(file, 1)) == NULL)
  158. {
  159. fprintf(stderr, " Cannot open audio file '%s'\n", file);
  160. exit(2);
  161. }
  162. if ((outhandle = sf_open_telephony_write(OUT_FILE_NAME, 1)) == NULL)
  163. {
  164. fprintf(stderr, " Cannot create audio file '%s'\n", OUT_FILE_NAME);
  165. exit(2);
  166. }
  167. sig = power_surge_detector_init(NULL, -50.0f, 6.0f);
  168. prev_signal_present = false;
  169. sample = 0;
  170. while ((inframes = sf_readf_short(inhandle, amp, 8000)))
  171. {
  172. for (i = 0; i < inframes; i++)
  173. {
  174. signal_level = power_surge_detector(sig, amp[i]);
  175. signal_present = (signal_level != 0);
  176. if (prev_signal_present != signal_present)
  177. {
  178. signal_power = power_surge_detector_current_dbm0(sig);
  179. if (signal_present)
  180. printf("On at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power);
  181. else
  182. printf("Off at %f (%fdBm0)\n", (sample + i)/8000.0, signal_power);
  183. prev_signal_present = signal_present;
  184. }
  185. amp_out[2*i] = amp[i];
  186. amp_out[2*i + 1] = signal_present*5000;
  187. }
  188. sf_writef_short(outhandle, amp_out, inframes);
  189. sample += inframes;
  190. }
  191. if (sf_close_telephony(inhandle))
  192. {
  193. fprintf(stderr, " Cannot close audio file '%s'\n", file);
  194. exit(2);
  195. }
  196. if (sf_close_telephony(outhandle))
  197. {
  198. fprintf(stderr, " Cannot close audio file '%s'\n", OUT_FILE_NAME);
  199. exit(2);
  200. }
  201. return 0;
  202. }
  203. /*- End of function --------------------------------------------------------*/
  204. static int power_meter_tests(void)
  205. {
  206. awgn_state_t noise_source;
  207. power_meter_t meter;
  208. tone_gen_descriptor_t tone_desc;
  209. tone_gen_state_t gen;
  210. int i;
  211. int idum = 1234567;
  212. int16_t amp[1000];
  213. int len;
  214. int32_t level;
  215. power_meter_init(&meter, 7);
  216. printf("Testing with zero in the power register\n");
  217. printf("Power: expected %fdBm0, got %fdBm0\n", -90.169f, power_meter_current_dbm0(&meter));
  218. printf("Power: expected %fdBOv, got %fdBOv\n", -96.329f, power_meter_current_dbov(&meter));
  219. printf("Testing with a square wave 10dB from maximum\n");
  220. for (i = 0; i < 1000; i++)
  221. {
  222. amp[i] = (i & 1) ? 10362 : -10362;
  223. level = power_meter_update(&meter, amp[i]);
  224. //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter));
  225. }
  226. printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level);
  227. printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter));
  228. printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter));
  229. if (level < power_meter_level_dbov(-10.0f)*0.99f
  230. ||
  231. level > power_meter_level_dbov(-10.0f)*1.01f)
  232. {
  233. printf("Test failed (level)\n");
  234. exit(2);
  235. }
  236. if (0.1f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER))
  237. {
  238. printf("Test failed (dBm0)\n");
  239. exit(2);
  240. }
  241. if (0.1f < fabsf(power_meter_current_dbov(&meter) + 10.0))
  242. {
  243. printf("Test failed (dBOv)\n");
  244. exit(2);
  245. }
  246. printf("Testing with a sine wave tone 10dB from maximum\n");
  247. tone_gen_descriptor_init(&tone_desc,
  248. 1000,
  249. -4,
  250. 0,
  251. 1,
  252. 1,
  253. 0,
  254. 0,
  255. 0,
  256. true);
  257. tone_gen_init(&gen, &tone_desc);
  258. len = tone_gen(&gen, amp, 1000);
  259. for (i = 0; i < len; i++)
  260. {
  261. level = power_meter_update(&meter, amp[i]);
  262. //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter));
  263. }
  264. printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level);
  265. printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter));
  266. printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter));
  267. if (level < power_meter_level_dbov(-10.0f)*0.95f
  268. ||
  269. level > power_meter_level_dbov(-10.0f)*1.05f)
  270. {
  271. printf("Test failed (level)\n");
  272. exit(2);
  273. }
  274. if (0.2f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER))
  275. {
  276. printf("Test failed (dBm0)\n");
  277. exit(2);
  278. }
  279. if (0.2f < fabsf(power_meter_current_dbov(&meter) + 10.0))
  280. {
  281. printf("Test failed (dBOv)\n");
  282. exit(2);
  283. }
  284. printf("Testing with AWGN 10dB from maximum\n");
  285. awgn_init_dbov(&noise_source, idum, -10.0f);
  286. for (i = 0; i < 1000; i++)
  287. amp[i] = awgn(&noise_source);
  288. for (i = 0; i < 1000; i++)
  289. {
  290. level = power_meter_update(&meter, amp[i]);
  291. //printf("%12d %fdBm0 %fdBov\n", level, power_meter_current_dbm0(&meter), power_meter_current_dbov(&meter));
  292. }
  293. printf("Level: expected %" PRId32 "/%" PRId32 ", got %" PRId32 "\n", power_meter_level_dbov(-10.0f), power_meter_level_dbm0(-10.0f + DBM0_MAX_POWER), level);
  294. printf("Power: expected %fdBm0, got %fdBm0\n", -10.0f + DBM0_MAX_POWER, power_meter_current_dbm0(&meter));
  295. printf("Power: expected %fdBOv, got %fdBOv\n", -10.0f, power_meter_current_dbov(&meter));
  296. if (level < power_meter_level_dbov(-10.0f)*0.95f
  297. ||
  298. level > power_meter_level_dbov(-10.0f)*1.05f)
  299. {
  300. printf("Test failed (level)\n");
  301. exit(2);
  302. }
  303. if (0.2f < fabsf(power_meter_current_dbm0(&meter) + 10.0f - DBM0_MAX_POWER))
  304. {
  305. printf("Test failed (dBm0)\n");
  306. exit(2);
  307. }
  308. if (0.2f < fabsf(power_meter_current_dbov(&meter) + 10.0f))
  309. {
  310. printf("Test failed (dBOv)\n");
  311. exit(2);
  312. }
  313. return 0;
  314. }
  315. /*- End of function --------------------------------------------------------*/
  316. int main(int argc, char *argv[])
  317. {
  318. bool basic_tests;
  319. bool decode;
  320. int opt;
  321. const char *in_file;
  322. basic_tests = true;
  323. decode = false;
  324. in_file = IN_FILE_NAME;
  325. while ((opt = getopt(argc, argv, "d:")) != -1)
  326. {
  327. switch (opt)
  328. {
  329. case 'd':
  330. in_file = optarg;
  331. basic_tests = false;
  332. decode = true;
  333. break;
  334. default:
  335. //usage();
  336. exit(2);
  337. }
  338. }
  339. if (basic_tests)
  340. {
  341. power_meter_tests();
  342. power_surge_detector_tests();
  343. }
  344. if (decode)
  345. {
  346. power_surge_detector_file_test(in_file);
  347. }
  348. printf("Tests passed\n");
  349. return 0;
  350. }
  351. /*- End of function --------------------------------------------------------*/
  352. /*- End of file ------------------------------------------------------------*/