/m/tools/filters.c

https://github.com/sashakh/ma · C · 219 lines · 164 code · 23 blank · 32 comment · 19 complexity · f034515800bf3843e52080b942258dff MD5 · raw file

  1. /*
  2. * M - yet another soft modem
  3. *
  4. * Copyright (c) 2005 Sasha Khapyorsky <sashak@alsa-project.org>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301, USA
  20. *
  21. */
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <ctype.h>
  25. #include <math.h>
  26. #include "gen_tables.h"
  27. static void inverse_filter(double *buf, unsigned size)
  28. {
  29. int i;
  30. for (i = 0; i < size; i++)
  31. buf[i] = -buf[i];
  32. buf[size / 2] += 1.;
  33. }
  34. /*
  35. * hamming windowed sinc filter
  36. */
  37. void hwsinc_lp_filter(double fc, double *buf, unsigned size)
  38. {
  39. double sum = 0;
  40. int i;
  41. for (i = 0; i < size; i++) {
  42. int k = i - size / 2;
  43. buf[i] = (k == 0) ? 2 * M_PI * fc : sin(M_PI * 2. * fc * k) / k;
  44. buf[i] *= 0.54 - 0.46 * cos(2 * M_PI * i / (size - 1));
  45. sum += buf[i];
  46. }
  47. for (i = 0; i < size; i++)
  48. buf[i] /= sum;
  49. }
  50. void hwsinc_hp_filter(double fc, double *buf, unsigned size)
  51. {
  52. hwsinc_lp_filter(fc, buf, size);
  53. inverse_filter(buf, size);
  54. }
  55. void hwsinc_bp_filter(double fc_from, double fc_to, double *buf, unsigned size)
  56. {
  57. double lowpass[size];
  58. double highpass[size];
  59. int i;
  60. hwsinc_lp_filter(fc_from, lowpass, arrsize(lowpass));
  61. hwsinc_hp_filter(fc_to, highpass, arrsize(lowpass));
  62. for (i = 0; i < size; i++)
  63. buf[i] = lowpass[i] + highpass[i];
  64. inverse_filter(buf, size);
  65. }
  66. /*
  67. * Custom filters
  68. */
  69. /* ... */
  70. /*
  71. * Debug stuff
  72. */
  73. void dump_time_for_plot(const char *name, double *buf, unsigned size)
  74. {
  75. int i;
  76. FILE *f = fopen(name, "w");
  77. if (!f) {
  78. perror("fopen");
  79. return;
  80. }
  81. fprintf(f, "# plot \"%s\" using 1:2 with lines title \"amp\"\n", name);
  82. fprintf(f, "# sample\tamplitude\n");
  83. for (i = 0; i < size; i++) {
  84. fprintf(f, "%d\t%f\n", i, buf[i]);
  85. }
  86. fclose(f);
  87. }
  88. void dump_freq_for_plot(const char *name, double *mag, double *ph,
  89. unsigned size)
  90. {
  91. int i;
  92. FILE *f = fopen(name, "w");
  93. if (!f) {
  94. perror("fopen");
  95. return;
  96. }
  97. fprintf(f, "# plot \"%s\" using 1:2 with lines title \"mag\",\\\n"
  98. "# \"%s\" using 1:3 with lines title \"phase\"\n",
  99. name, name);
  100. fprintf(f, "# freqiency\tmagnitude\tphase\tmag in dB\n");
  101. for (i = 0; i < size; i++) {
  102. double freq = (double)i * SAMPLE_RATE / (size);
  103. fprintf(f, "%f\t%f\t%f\t%f\n", freq, mag[i], ph[i],
  104. 20. * log10(mag[i]));
  105. }
  106. fclose(f);
  107. }
  108. void dump_filter_for_plot(const char *name, double *filter, unsigned taps,
  109. unsigned size)
  110. {
  111. char filename[256];
  112. double buf[size];
  113. double mag[size], ph[size];
  114. double re[size], im[size];
  115. int i, j;
  116. sprintf(filename, "%st.%s", name, "dat");
  117. dump_time_for_plot(filename, filter, taps);
  118. for (i = 0; i < size; i++) {
  119. buf[i] = i < taps ? filter[i] : 0;
  120. }
  121. /* slowest dft */
  122. for (i = 0; i < size; i++) {
  123. re[i] = im[i] = 0;
  124. for (j = 0; j < size; j++) {
  125. re[i] += buf[j] * cos(2 * M_PI * i * j / size);
  126. im[i] -= buf[j] * sin(2 * M_PI * i * j / size);
  127. }
  128. re[i] /= size;
  129. im[i] /= size;
  130. }
  131. sprintf(filename, "%sf.%s", name, "dat");
  132. for (i = 0; i < size; i++) {
  133. mag[i] = sqrt(re[i] * re[i] + im[i] * im[i]);
  134. ph[i] = atan2(im[i], re[i]);
  135. }
  136. dump_freq_for_plot(filename, mag, ph, size);
  137. }
  138. #ifdef USE_FFTW3
  139. #include <complex.h>
  140. #include <fftw3.h>
  141. static void show_freq_domain_fftw3(const char *name, const double *buf,
  142. unsigned size)
  143. {
  144. fftw_plan p;
  145. fftw_complex *in, *out;
  146. int i;
  147. in = fftw_malloc(sizeof(*in) * size);
  148. out = fftw_malloc(sizeof(*out) * size);
  149. p = fftw_plan_dft_1d(size, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
  150. for (i = 0; i < size; i++) {
  151. in[i] = buf[i];
  152. }
  153. fftw_execute(p);
  154. for (i = 0; i < size; i++) {
  155. double re = creal(out[i]) / size;
  156. double im = cimag(out[i]) / size;
  157. double mag = re * re + im * im;
  158. fprintf(stderr, "%d (%f): re = %f , im = %f ; mag^2 = %f\n",
  159. i, (double)i / size, re, im, mag);
  160. if (i > size / 2)
  161. break;
  162. }
  163. fftw_destroy_plan(p);
  164. fftw_free(in);
  165. fftw_free(out);
  166. }
  167. #endif /* USE_FFTW3 */
  168. static void show_freq_domain_slow_dft(const char *name, const double *buf,
  169. unsigned size)
  170. {
  171. double re, im, mag;
  172. int i, j;
  173. for (i = 0; i < size; i++) {
  174. re = im = 0;
  175. for (j = 0; j < size; j++) {
  176. re += cos(2 * M_PI * j * i / size) * buf[j];
  177. im -= sin(2 * M_PI * j * i / size) * buf[j];
  178. }
  179. re /= size;
  180. im /= size;
  181. mag = re * re + im * im;
  182. fprintf(stderr, "%d (%f): re = %f , im = %f ; mag^2 = %f\n",
  183. i, (double)i / size, re, im, mag);
  184. if (i > size / 2)
  185. break;
  186. }
  187. }
  188. void show_freq_domain(const char *name, const double *buf, unsigned size)
  189. {
  190. fprintf(stderr, "\'%s\' frequency domain:\n", name);
  191. #ifdef USE_FFTW3
  192. show_freq_domain_fftw3(name, buf, size);
  193. #else
  194. show_freq_domain_slow_dft(name, buf, size);
  195. #endif
  196. }