/mchf-eclipse/drivers/freedv/filter.c

https://github.com/df8oe/UHSDR · C · 283 lines · 136 code · 49 blank · 98 comment · 23 complexity · 1aa83cb623bdd42f72fd0c2fc37e6976 MD5 · raw file

  1. /*
  2. Copyright (C) 2018 James C. Ahlstrom
  3. All rights reserved.
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU Lesser General Public License version 2.1, as
  6. published by the Free Software Foundation. This program is
  7. distributed in the hope that it will be useful, but WITHOUT ANY
  8. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  9. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  10. License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program; if not, see <http://www.gnu.org/licenses/>.
  13. */
  14. #include <stdlib.h>
  15. #include <string.h>
  16. #include <math.h>
  17. #include <complex.h>
  18. #include "filter.h"
  19. #include "filter_coef.h"
  20. #include "debug_alloc.h"
  21. #include "fdv_arm_math.h"
  22. #define cmplx(value) (COSF(value) + SINF(value) * I)
  23. /*
  24. * This is a library of filter functions. They were copied from Quisk and converted to single precision.
  25. */
  26. /*---------------------------------------------------------------------------*\
  27. FUNCTIONS...: quisk_filt_cfInit
  28. AUTHOR......: Jim Ahlstrom
  29. DATE CREATED: 27 August 2015
  30. MODIFIED: 4 June 2018
  31. Initialize a FIR filter that has complex samples, and either real or complex coefficients.
  32. \*---------------------------------------------------------------------------*/
  33. void quisk_filt_cfInit(struct quisk_cfFilter * filter, float * coefs, int taps) {
  34. // Prepare a new filter using coefs and taps. Samples are complex. Coefficients can
  35. // be real or complex.
  36. filter->dCoefs = coefs;
  37. filter->cpxCoefs = NULL;
  38. filter->cSamples = (complex float *)MALLOC(taps * sizeof(complex float));
  39. memset(filter->cSamples, 0, taps * sizeof(complex float));
  40. filter->ptcSamp = filter->cSamples;
  41. filter->nTaps = taps;
  42. filter->cBuf = NULL;
  43. filter->nBuf = 0;
  44. filter->decim_index = 0;
  45. }
  46. /*---------------------------------------------------------------------------*\
  47. FUNCTIONS...: quisk_filt_destroy
  48. AUTHOR......: Jim Ahlstrom
  49. DATE CREATED: 27 August 2015
  50. MODIFIED: 4 June 2018
  51. Destroy the FIR filter and free all resources.
  52. \*---------------------------------------------------------------------------*/
  53. void quisk_filt_destroy(struct quisk_cfFilter * filter) {
  54. if (filter->cSamples) {
  55. FREE(filter->cSamples);
  56. filter->cSamples = NULL;
  57. }
  58. if (filter->cBuf) {
  59. FREE(filter->cBuf);
  60. filter->cBuf = NULL;
  61. }
  62. if (filter->cpxCoefs) {
  63. FREE(filter->cpxCoefs);
  64. filter->cpxCoefs = NULL;
  65. }
  66. }
  67. /*---------------------------------------------------------------------------*\
  68. FUNCTIONS...: quisk_cfInterpDecim
  69. AUTHOR......: Jim Ahlstrom
  70. DATE CREATED: 27 August 2015
  71. MODIFIED: 4 June 2018
  72. Take an array of samples cSamples of length count, multiply the sample rate
  73. by interp, and then divide the sample rate by decim. Return the new number
  74. of samples. Each specific interp and decim will require its own custom
  75. low pass FIR filter with real coefficients.
  76. \*---------------------------------------------------------------------------*/
  77. int quisk_cfInterpDecim(complex float * cSamples, int count, struct quisk_cfFilter * filter, int interp, int decim) {
  78. // Interpolate by interp, and then decimate by decim.
  79. // This uses the float coefficients of filter (not the complex). Samples are complex.
  80. int i, k, nOut;
  81. float * ptCoef;
  82. complex float * ptSample;
  83. complex float csample;
  84. if (count > filter->nBuf) { // increase size of sample buffer
  85. filter->nBuf = count * 2;
  86. if (filter->cBuf)
  87. FREE(filter->cBuf);
  88. filter->cBuf = (complex float *)MALLOC(filter->nBuf * sizeof(complex float));
  89. }
  90. memcpy(filter->cBuf, cSamples, count * sizeof(complex float));
  91. nOut = 0;
  92. for (i = 0; i < count; i++) {
  93. // Put samples into buffer left to right. Use samples right to left.
  94. *filter->ptcSamp = filter->cBuf[i];
  95. while (filter->decim_index < interp) {
  96. ptSample = filter->ptcSamp;
  97. ptCoef = filter->dCoefs + filter->decim_index;
  98. csample = 0;
  99. for (k = 0; k < filter->nTaps / interp; k++, ptCoef += interp) {
  100. csample += *ptSample * *ptCoef;
  101. if (--ptSample < filter->cSamples)
  102. ptSample = filter->cSamples + filter->nTaps - 1;
  103. }
  104. cSamples[nOut] = csample * interp;
  105. nOut++;
  106. filter->decim_index += decim;
  107. }
  108. if (++filter->ptcSamp >= filter->cSamples + filter->nTaps)
  109. filter->ptcSamp = filter->cSamples;
  110. filter->decim_index = filter->decim_index - interp;
  111. }
  112. return nOut;
  113. }
  114. /*---------------------------------------------------------------------------*\
  115. FUNCTIONS...: quisk_ccfInterpDecim
  116. AUTHOR......: Jim Ahlstrom
  117. DATE CREATED: 7 June 2018
  118. Take an array of samples cSamples of length count, multiply the sample rate
  119. by interp, and then divide the sample rate by decim. Return the new number
  120. of samples. Each specific interp and decim will require its own custom
  121. low pass FIR filter with complex coefficients. This filter can be tuned.
  122. This filter is not currently used.
  123. \*---------------------------------------------------------------------------*/
  124. #if 0
  125. int quisk_ccfInterpDecim(complex float * cSamples, int count, struct quisk_cfFilter * filter, int interp, int decim) {
  126. // Interpolate by interp, and then decimate by decim.
  127. // This uses the complex coefficients of filter (not the real). Samples are complex.
  128. int i, k, nOut;
  129. complex float * ptCoef;
  130. complex float * ptSample;
  131. complex float csample;
  132. if (count > filter->nBuf) { // increase size of sample buffer
  133. filter->nBuf = count * 2;
  134. if (filter->cBuf)
  135. FREE(filter->cBuf);
  136. filter->cBuf = (complex float *)MALLOC(filter->nBuf * sizeof(complex float));
  137. }
  138. memcpy(filter->cBuf, cSamples, count * sizeof(complex float));
  139. nOut = 0;
  140. for (i = 0; i < count; i++) {
  141. // Put samples into buffer left to right. Use samples right to left.
  142. *filter->ptcSamp = filter->cBuf[i];
  143. while (filter->decim_index < interp) {
  144. ptSample = filter->ptcSamp;
  145. ptCoef = filter->cpxCoefs + filter->decim_index;
  146. csample = 0;
  147. for (k = 0; k < filter->nTaps / interp; k++, ptCoef += interp) {
  148. csample += *ptSample * *ptCoef;
  149. if (--ptSample < filter->cSamples)
  150. ptSample = filter->cSamples + filter->nTaps - 1;
  151. }
  152. cSamples[nOut] = csample * interp;
  153. nOut++;
  154. filter->decim_index += decim;
  155. }
  156. if (++filter->ptcSamp >= filter->cSamples + filter->nTaps)
  157. filter->ptcSamp = filter->cSamples;
  158. filter->decim_index = filter->decim_index - interp;
  159. }
  160. return nOut;
  161. }
  162. #endif
  163. /*---------------------------------------------------------------------------*\
  164. FUNCTIONS...: quisk_cfTune
  165. AUTHOR......: Jim Ahlstrom
  166. DATE CREATED: 4 June 2018
  167. Tune a low pass filter with float coefficients into an analytic I/Q bandpass filter
  168. with complex coefficients. The "freq" is the center frequency / sample rate.
  169. If the float coefs represent a low pass filter with bandwidth 1 kHz, the new bandpass
  170. filter has width 2 kHz. The filter can be re-tuned repeatedly.
  171. \*---------------------------------------------------------------------------*/
  172. void quisk_cfTune(struct quisk_cfFilter * filter, float freq) {
  173. float D, tune;
  174. int i;
  175. if ( ! filter->cpxCoefs)
  176. filter->cpxCoefs = (complex float *)MALLOC(filter->nTaps * sizeof(complex float));
  177. tune = 2.0 * M_PI * freq;
  178. D = (filter->nTaps - 1.0) / 2.0;
  179. for (i = 0; i < filter->nTaps; i++) {
  180. float tval = tune * (i - D);
  181. filter->cpxCoefs[i] = cmplx(tval) * filter->dCoefs[i];
  182. }
  183. }
  184. /*---------------------------------------------------------------------------*\
  185. FUNCTIONS...: quisk_ccfFilter
  186. AUTHOR......: Jim Ahlstrom
  187. DATE CREATED: 4 June 2018
  188. Filter complex samples using complex coefficients. The inSamples and outSamples may be
  189. the same array. The loop runs forward over coefficients but backwards over samples.
  190. Therefore, the coefficients must be reversed unless they are created by quisk_cfTune.
  191. Low pass filter coefficients are symmetrical, so this does not usually matter.
  192. \*---------------------------------------------------------------------------*/
  193. void quisk_ccfFilter(complex float * inSamples, complex float * outSamples, int count, struct quisk_cfFilter * filter) {
  194. int i, k;
  195. complex float * ptSample;
  196. complex float * ptCoef;
  197. complex float accum;
  198. for (i = 0; i < count; i++) {
  199. *filter->ptcSamp = inSamples[i];
  200. accum = 0;
  201. ptSample = filter->ptcSamp;
  202. ptCoef = filter->cpxCoefs;
  203. for (k = 0; k < filter->nTaps; k++, ptCoef++) {
  204. accum += *ptSample * *ptCoef;
  205. if (--ptSample < filter->cSamples)
  206. ptSample = filter->cSamples + filter->nTaps - 1;
  207. }
  208. outSamples[i] = accum;
  209. if (++filter->ptcSamp >= filter->cSamples + filter->nTaps)
  210. filter->ptcSamp = filter->cSamples;
  211. }
  212. }