line_model.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /*
  2. * SpanDSP - a series of DSP components for telephony
  3. *
  4. * line_model.c - Model a telephone line.
  5. *
  6. * Written by Steve Underwood <steveu@coppice.org>
  7. *
  8. * Copyright (C) 2004 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. #if defined(HAVE_CONFIG_H)
  26. #include "config.h"
  27. #endif
  28. #include <stdlib.h>
  29. #include <unistd.h>
  30. #include <inttypes.h>
  31. #include <string.h>
  32. #include <time.h>
  33. #include <stdio.h>
  34. #include <fcntl.h>
  35. #if defined(HAVE_TGMATH_H)
  36. #include <tgmath.h>
  37. #endif
  38. #if defined(HAVE_MATH_H)
  39. #define GEN_CONST
  40. #include <math.h>
  41. #endif
  42. #if defined(HAVE_STDBOOL_H)
  43. #include <stdbool.h>
  44. #else
  45. #include "spandsp/stdbool.h"
  46. #endif
  47. #include "floating_fudge.h"
  48. #define SPANDSP_EXPOSE_INTERNAL_STRUCTURES
  49. #include "spandsp.h"
  50. #include "spandsp-sim.h"
  51. #include "spandsp/g168models.h"
  52. #if !defined(NULL)
  53. #define NULL (void *) 0
  54. #endif
  55. static const float null_line_model[] =
  56. {
  57. 0.0,
  58. 0.0,
  59. 0.0,
  60. 0.0,
  61. 0.0,
  62. 0.0,
  63. 0.0,
  64. 0.0,
  65. 0.0,
  66. 0.0,
  67. 0.0,
  68. 0.0,
  69. 0.0,
  70. 0.0,
  71. 0.0,
  72. 0.0,
  73. 0.0,
  74. 0.0,
  75. 0.0,
  76. 0.0,
  77. 0.0,
  78. 0.0,
  79. 0.0,
  80. 0.0,
  81. 0.0,
  82. 0.0,
  83. 0.0,
  84. 0.0,
  85. 0.0,
  86. 0.0,
  87. 0.0,
  88. 0.0,
  89. 0.0,
  90. 0.0,
  91. 0.0,
  92. 0.0,
  93. 0.0,
  94. 0.0,
  95. 0.0,
  96. 0.0,
  97. 0.0,
  98. 0.0,
  99. 0.0,
  100. 0.0,
  101. 0.0,
  102. 0.0,
  103. 0.0,
  104. 0.0,
  105. 0.0,
  106. 0.0,
  107. 0.0,
  108. 0.0,
  109. 0.0,
  110. 0.0,
  111. 0.0,
  112. 0.0,
  113. 0.0,
  114. 0.0,
  115. 0.0,
  116. 0.0,
  117. 0.0,
  118. 0.0,
  119. 0.0,
  120. 0.0,
  121. 0.0,
  122. 0.0,
  123. 0.0,
  124. 0.0,
  125. 0.0,
  126. 0.0,
  127. 0.0,
  128. 0.0,
  129. 0.0,
  130. 0.0,
  131. 0.0,
  132. 0.0,
  133. 0.0,
  134. 0.0,
  135. 0.0,
  136. 0.0,
  137. 0.0,
  138. 0.0,
  139. 0.0,
  140. 0.0,
  141. 0.0,
  142. 0.0,
  143. 0.0,
  144. 0.0,
  145. 0.0,
  146. 0.0,
  147. 0.0,
  148. 0.0,
  149. 0.0,
  150. 0.0,
  151. 0.0,
  152. 0.0,
  153. 0.0,
  154. 0.0,
  155. 0.0,
  156. 0.0,
  157. 0.0,
  158. 0.0,
  159. 0.0,
  160. 0.0,
  161. 0.0,
  162. 0.0,
  163. 0.0,
  164. 0.0,
  165. 0.0,
  166. 0.0,
  167. 0.0,
  168. 0.0,
  169. 0.0,
  170. 0.0,
  171. 0.0,
  172. 0.0,
  173. 0.0,
  174. 0.0,
  175. 0.0,
  176. 0.0,
  177. 0.0,
  178. 0.0,
  179. 0.0,
  180. 0.0,
  181. 0.0,
  182. 0.0,
  183. 0.0,
  184. 0.0,
  185. 1.0
  186. };
  187. SPAN_DECLARE_DATA const float *line_models[] =
  188. {
  189. null_line_model, /* 0 */
  190. proakis_line_model,
  191. ad_1_edd_1_model,
  192. ad_1_edd_2_model,
  193. ad_1_edd_3_model,
  194. ad_5_edd_1_model, /* 5 */
  195. ad_5_edd_2_model,
  196. ad_5_edd_3_model,
  197. ad_6_edd_1_model,
  198. ad_6_edd_2_model,
  199. ad_6_edd_3_model, /* 10 */
  200. ad_7_edd_1_model,
  201. ad_7_edd_2_model,
  202. ad_7_edd_3_model,
  203. ad_8_edd_1_model,
  204. ad_8_edd_2_model, /* 15 */
  205. ad_8_edd_3_model,
  206. ad_9_edd_1_model,
  207. ad_9_edd_2_model,
  208. ad_9_edd_3_model
  209. };
  210. static float calc_near_line_filter(one_way_line_model_state_t *s, float v)
  211. {
  212. float sum;
  213. int j;
  214. int p;
  215. /* Add the sample in the filter buffer */
  216. p = s->near_buf_ptr;
  217. s->near_buf[p] = v;
  218. if (++p == s->near_filter_len)
  219. p = 0;
  220. s->near_buf_ptr = p;
  221. /* Apply the filter */
  222. sum = 0.0f;
  223. for (j = 0; j < s->near_filter_len; j++)
  224. {
  225. sum += s->near_filter[j]*s->near_buf[p];
  226. if (++p >= s->near_filter_len)
  227. p = 0;
  228. }
  229. /* Add noise */
  230. sum += awgn(&s->near_noise);
  231. return sum;
  232. }
  233. /*- End of function --------------------------------------------------------*/
  234. static float calc_far_line_filter(one_way_line_model_state_t *s, float v)
  235. {
  236. float sum;
  237. int j;
  238. int p;
  239. /* Add the sample in the filter buffer */
  240. p = s->far_buf_ptr;
  241. s->far_buf[p] = v;
  242. if (++p == s->far_filter_len)
  243. p = 0;
  244. s->far_buf_ptr = p;
  245. /* Apply the filter */
  246. sum = 0.0f;
  247. for (j = 0; j < s->far_filter_len; j++)
  248. {
  249. sum += s->far_filter[j]*s->far_buf[p];
  250. if (++p >= s->far_filter_len)
  251. p = 0;
  252. }
  253. /* Add noise */
  254. sum += awgn(&s->far_noise);
  255. return sum;
  256. }
  257. /*- End of function --------------------------------------------------------*/
  258. SPAN_DECLARE(void) one_way_line_model(one_way_line_model_state_t *s,
  259. int16_t output[],
  260. const int16_t input[],
  261. int samples)
  262. {
  263. int i;
  264. float in;
  265. float out;
  266. float out1;
  267. int16_t amp[1];
  268. /* The path being modelled is:
  269. terminal
  270. | < hybrid
  271. |
  272. | < noise and filtering
  273. |
  274. | < hybrid
  275. CO
  276. |
  277. | < A-law distortion + bulk delay
  278. |
  279. CO
  280. | < hybrid
  281. |
  282. | < noise and filtering
  283. |
  284. | < hybrid
  285. terminal
  286. */
  287. for (i = 0; i < samples; i++)
  288. {
  289. in = input[i];
  290. /* Near end analogue section */
  291. /* Line model filters & noise */
  292. out = calc_near_line_filter(s, in);
  293. /* Long distance digital section */
  294. amp[0] = out;
  295. codec_munge(s->munge, amp, 1);
  296. out = amp[0];
  297. /* Introduce the bulk delay of the long distance link. */
  298. out1 = s->bulk_delay_buf[s->bulk_delay_ptr];
  299. s->bulk_delay_buf[s->bulk_delay_ptr] = out;
  300. out = out1;
  301. if (++s->bulk_delay_ptr >= s->bulk_delay)
  302. s->bulk_delay_ptr = 0;
  303. /* Far end analogue section */
  304. /* Line model filters & noise */
  305. out = calc_far_line_filter(s, out);
  306. if (s->mains_interference)
  307. {
  308. tone_gen(&s->mains_tone, amp, 1);
  309. out += amp[0];
  310. }
  311. output[i] = out + s->dc_offset;
  312. }
  313. }
  314. /*- End of function --------------------------------------------------------*/
  315. SPAN_DECLARE(void) one_way_line_model_set_dc(one_way_line_model_state_t *s, float dc)
  316. {
  317. s->dc_offset = dc;
  318. }
  319. /*- End of function --------------------------------------------------------*/
  320. SPAN_DECLARE(void) one_way_line_model_set_mains_pickup(one_way_line_model_state_t *s, int f, float level)
  321. {
  322. tone_gen_descriptor_t mains_tone_desc;
  323. if (f)
  324. {
  325. tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level - 10.0f), f*3, (int) level, 1, 0, 0, 0, true);
  326. tone_gen_init(&s->mains_tone, &mains_tone_desc);
  327. }
  328. s->mains_interference = f;
  329. }
  330. /*- End of function --------------------------------------------------------*/
  331. SPAN_DECLARE(void) both_ways_line_model(both_ways_line_model_state_t *s,
  332. int16_t output1[],
  333. const int16_t input1[],
  334. int16_t output2[],
  335. const int16_t input2[],
  336. int samples)
  337. {
  338. int i;
  339. float in1;
  340. float in2;
  341. float out1;
  342. float out2;
  343. float tmp1;
  344. float tmp2;
  345. int16_t amp[1];
  346. /* The path being modelled is:
  347. terminal
  348. | < hybrid echo
  349. |
  350. | < noise and filtering
  351. |
  352. | < hybrid echo
  353. CO
  354. |
  355. | < A-law distortion + bulk delay
  356. |
  357. CO
  358. | < hybrid echo
  359. |
  360. | < noise and filtering
  361. |
  362. | < hybrid echo
  363. terminal
  364. */
  365. for (i = 0; i < samples; i++)
  366. {
  367. in1 = input1[i];
  368. in2 = input2[i];
  369. /* Near end analogue sections */
  370. /* Echo from each terminal's CO hybrid */
  371. tmp1 = in1 + s->fout2*s->line1.near_co_hybrid_echo;
  372. tmp2 = in2 + s->fout1*s->line2.near_co_hybrid_echo;
  373. /* Line model filters & noise */
  374. s->fout1 = calc_near_line_filter(&s->line1, tmp1);
  375. s->fout2 = calc_near_line_filter(&s->line2, tmp2);
  376. /* Long distance digital section */
  377. /* Introduce distortion due to A-law or u-law munging. */
  378. amp[0] = s->fout1;
  379. codec_munge(s->line1.munge, amp, 1);
  380. s->fout1 = amp[0];
  381. amp[0] = s->fout2;
  382. codec_munge(s->line2.munge, amp, 1);
  383. s->fout2 = amp[0];
  384. /* Introduce the bulk delay of the long distance digital link. */
  385. out1 = s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr];
  386. s->line1.bulk_delay_buf[s->line1.bulk_delay_ptr] = s->fout1;
  387. s->fout1 = out1;
  388. if (++s->line1.bulk_delay_ptr >= s->line1.bulk_delay)
  389. s->line1.bulk_delay_ptr = 0;
  390. out2 = s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr];
  391. s->line2.bulk_delay_buf[s->line2.bulk_delay_ptr] = s->fout2;
  392. s->fout2 = out2;
  393. if (++s->line2.bulk_delay_ptr >= s->line2.bulk_delay)
  394. s->line2.bulk_delay_ptr = 0;
  395. /* Far end analogue sections */
  396. /* Echo from each terminal's own hybrid */
  397. out1 += in2*s->line1.far_cpe_hybrid_echo;
  398. out2 += in1*s->line2.far_cpe_hybrid_echo;
  399. /* Line model filters & noise */
  400. out1 = calc_far_line_filter(&s->line1, out1);
  401. out2 = calc_far_line_filter(&s->line2, out2);
  402. output1[i] = fsaturate(out1 + s->line1.dc_offset);
  403. output2[i] = fsaturate(out2 + s->line2.dc_offset);
  404. }
  405. }
  406. /*- End of function --------------------------------------------------------*/
  407. SPAN_DECLARE(void) both_ways_line_model_set_dc(both_ways_line_model_state_t *s, float dc1, float dc2)
  408. {
  409. s->line1.dc_offset = dc1;
  410. s->line2.dc_offset = dc2;
  411. }
  412. /*- End of function --------------------------------------------------------*/
  413. SPAN_DECLARE(void) both_ways_line_model_set_mains_pickup(both_ways_line_model_state_t *s, int f, float level1, float level2)
  414. {
  415. tone_gen_descriptor_t mains_tone_desc;
  416. if (f)
  417. {
  418. tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level1 - 10.0f), f*3, (int) level1, 1, 0, 0, 0, true);
  419. tone_gen_init(&s->line1.mains_tone, &mains_tone_desc);
  420. tone_gen_descriptor_init(&mains_tone_desc, f, (int) (level2 - 10.0f), f*3, (int) level2, 1, 0, 0, 0, true);
  421. tone_gen_init(&s->line2.mains_tone, &mains_tone_desc);
  422. }
  423. s->line1.mains_interference = f;
  424. s->line2.mains_interference = f;
  425. }
  426. /*- End of function --------------------------------------------------------*/
  427. SPAN_DECLARE(one_way_line_model_state_t *) one_way_line_model_init(int model, float noise, int codec, int rbs_pattern)
  428. {
  429. one_way_line_model_state_t *s;
  430. if ((s = (one_way_line_model_state_t *) malloc(sizeof(*s))) == NULL)
  431. return NULL;
  432. memset(s, 0, sizeof(*s));
  433. s->bulk_delay = 8;
  434. s->bulk_delay_ptr = 0;
  435. s->munge = codec_munge_init(codec, rbs_pattern);
  436. s->near_filter = line_models[model];
  437. s->near_filter_len = 129;
  438. s->far_filter = line_models[model];
  439. s->far_filter_len = 129;
  440. /* Put half the noise in each analogue section */
  441. awgn_init_dbm0(&s->near_noise, 1234567, noise - 3.02f);
  442. awgn_init_dbm0(&s->far_noise, 1234567, noise - 3.02f);
  443. s->dc_offset = 0.0f;
  444. s->mains_interference = 0;
  445. return s;
  446. }
  447. /*- End of function --------------------------------------------------------*/
  448. SPAN_DECLARE(int) one_way_line_model_free(one_way_line_model_state_t *s)
  449. {
  450. codec_munge_free(s->munge);
  451. free(s);
  452. return 0;
  453. }
  454. /*- End of function --------------------------------------------------------*/
  455. SPAN_DECLARE(both_ways_line_model_state_t *) both_ways_line_model_init(int model1,
  456. float noise1,
  457. float echo_level_cpe1,
  458. float echo_level_co1,
  459. int model2,
  460. float noise2,
  461. float echo_level_cpe2,
  462. float echo_level_co2,
  463. int codec,
  464. int rbs_pattern)
  465. {
  466. both_ways_line_model_state_t *s;
  467. if ((s = (both_ways_line_model_state_t *) malloc(sizeof(*s))) == NULL)
  468. return NULL;
  469. memset(s, 0, sizeof(*s));
  470. s->line1.munge = codec_munge_init(codec, rbs_pattern);
  471. s->line2.munge = codec_munge_init(codec, rbs_pattern);
  472. s->line1.bulk_delay = 8;
  473. s->line2.bulk_delay = 8;
  474. s->line1.bulk_delay_ptr = 0;
  475. s->line2.bulk_delay_ptr = 0;
  476. s->line1.near_filter = line_models[model1];
  477. s->line1.near_filter_len = 129;
  478. s->line2.near_filter = line_models[model2];
  479. s->line2.near_filter_len = 129;
  480. s->line1.far_filter = line_models[model1];
  481. s->line1.far_filter_len = 129;
  482. s->line2.far_filter = line_models[model2];
  483. s->line2.far_filter_len = 129;
  484. /* Put half the noise in each analogue section */
  485. awgn_init_dbm0(&s->line1.near_noise, 1234567, noise1 - 3.02f);
  486. awgn_init_dbm0(&s->line2.near_noise, 7654321, noise2 - 3.02f);
  487. awgn_init_dbm0(&s->line1.far_noise, 1234567, noise1 - 3.02f);
  488. awgn_init_dbm0(&s->line2.far_noise, 7654321, noise2 - 3.02f);
  489. s->line1.dc_offset = 0.0f;
  490. s->line2.dc_offset = 0.0f;
  491. s->line1.mains_interference = 0;
  492. s->line2.mains_interference = 0;
  493. /* Echos */
  494. s->line1.near_co_hybrid_echo = pow(10, echo_level_co1/20.0f);
  495. s->line2.near_co_hybrid_echo = pow(10, echo_level_co2/20.0f);
  496. s->line1.near_cpe_hybrid_echo = pow(10, echo_level_cpe1/20.0f);
  497. s->line2.near_cpe_hybrid_echo = pow(10, echo_level_cpe2/20.0f);
  498. return s;
  499. }
  500. /*- End of function --------------------------------------------------------*/
  501. SPAN_DECLARE(int) both_ways_line_model_free(both_ways_line_model_state_t *s)
  502. {
  503. codec_munge_free(s->line1.munge);
  504. codec_munge_free(s->line2.munge);
  505. free(s);
  506. return 0;
  507. }
  508. /*- End of function --------------------------------------------------------*/
  509. /*- End of file ------------------------------------------------------------*/