flt_butter.c 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #include "flt_butter.h"
  2. #include <float.h>
  3. #include <math.h>
  4. #include <stdint.h>
  5. int butter3_filter_init(LpfButter3 *butter, const float b[4],
  6. const float a[4])
  7. {
  8. for (uint8_t i = 0; i < 4; i++)
  9. {
  10. butter->B[i] = b[i];
  11. butter->A[i] = a[i];
  12. butter->X[i] = butter->Y[i] = 0.0f;
  13. }
  14. return 0;
  15. }
  16. int butter3_filter_reset(float sample, LpfButter3 *butter)
  17. {
  18. for (uint8_t i = 0; i < 4; i++)
  19. {
  20. butter->X[i] = butter->Y[i] = sample;
  21. }
  22. return 0;
  23. }
  24. float butter3_filter_apply(float in, LpfButter3 *butter)
  25. {
  26. float out;
  27. butter->X[3] = in;
  28. /* a(1)*y(n) = b(1)*x(n) + b(2)*x(n-1) + ... + b(nb+1)*x(n-nb)
  29. - a(2)*y(n-1) - ... - a(na+1)*y(n-na) */
  30. butter->Y[3] = butter->B[0] * butter->X[3] + butter->B[1] * butter->X[2] +
  31. butter->B[2] * butter->X[1] + butter->B[3] * butter->X[0] -
  32. butter->A[1] * butter->Y[2] - butter->A[2] * butter->Y[1] -
  33. butter->A[3] * butter->Y[0];
  34. /* we assume a(1)=1 */
  35. out = butter->Y[3];
  36. /* move X and Y */
  37. butter->X[0] = butter->X[1];
  38. butter->X[1] = butter->X[2];
  39. butter->X[2] = butter->X[3];
  40. butter->Y[0] = butter->Y[1];
  41. butter->Y[1] = butter->Y[2];
  42. butter->Y[2] = butter->Y[3];
  43. return out;
  44. }
  45. void butter2_filter_disable(LpfButter2 *lp)
  46. {
  47. lp->_sample_freq = 0.f;
  48. lp->_cutoff_freq = 0.f;
  49. lp->_delay_element1 = 0.0f;
  50. lp->_delay_element2 = 0.0f;
  51. lp->_b0 = 1.f;
  52. lp->_b1 = 0.f;
  53. lp->_b2 = 0.f;
  54. lp->_a1 = 0.f;
  55. lp->_a2 = 0.f;
  56. }
  57. int butter2_filter_set_cutoff_freq(LpfButter2 *lp, float sample_freq,
  58. float cutoff_freq)
  59. {
  60. if ((sample_freq <= 0.f) || (cutoff_freq <= 0.f) ||
  61. (cutoff_freq >= sample_freq / 2) || !isfinite(sample_freq) ||
  62. !isfinite(cutoff_freq))
  63. {
  64. butter2_filter_disable(lp);
  65. return -1;
  66. }
  67. // reset delay elements on filter change
  68. lp->_delay_element1 = 0;
  69. lp->_delay_element2 = 0;
  70. cutoff_freq = cutoff_freq >= 1.f ? cutoff_freq : 1.f;
  71. cutoff_freq =
  72. cutoff_freq <= (sample_freq / 2) ? cutoff_freq : (sample_freq / 2);
  73. // TODO: min based on actual numerical limit
  74. lp->_sample_freq = sample_freq;
  75. lp->_cutoff_freq = cutoff_freq;
  76. const float fr = lp->_sample_freq / lp->_cutoff_freq;
  77. const float ohm = tanf(M_PI / fr);
  78. const float c = 1.f + 2.f * cosf(M_PI / 4.f) * ohm + ohm * ohm;
  79. lp->_b0 = ohm * ohm / c;
  80. lp->_b1 = 2.f * lp->_b0;
  81. lp->_b2 = lp->_b0;
  82. lp->_a1 = 2.f * (ohm * ohm - 1.f) / c;
  83. lp->_a2 = (1.f - 2.f * cosf(M_PI / 4.f) * ohm + ohm * ohm) / c;
  84. if (!isfinite(lp->_b0) || !isfinite(lp->_b1) || !isfinite(lp->_b2) ||
  85. !isfinite(lp->_a1) || !isfinite(lp->_a2))
  86. {
  87. butter2_filter_disable(lp);
  88. return -1;
  89. }
  90. return 0;
  91. }
  92. int butter2_filter_init(LpfButter2 *butter, float sample_freq,
  93. float cuttoff_freq)
  94. {
  95. return butter2_filter_set_cutoff_freq(butter, sample_freq, cuttoff_freq);
  96. }
  97. float butter2_filter_apply(LpfButter2 *lp, float sample)
  98. {
  99. float delay_element_0 =
  100. sample - lp->_delay_element1 * lp->_a1 - lp->_delay_element2 * lp->_a2;
  101. const float output = delay_element_0 * lp->_b0 +
  102. lp->_delay_element1 * lp->_b1 +
  103. lp->_delay_element2 * lp->_b2;
  104. lp->_delay_element2 = lp->_delay_element1;
  105. lp->_delay_element1 = delay_element_0;
  106. return output;
  107. }
  108. float butter2_filter_reset(LpfButter2 *lp, float sample)
  109. {
  110. const float input = isfinite(sample) ? sample : 0.0f;
  111. if (fabsf(1 + lp->_a1 + lp->_a2) > FLT_EPSILON)
  112. {
  113. lp->_delay_element1 = lp->_delay_element2 = input / (1 + lp->_a1 + lp->_a2);
  114. if (!isfinite(lp->_delay_element1) || !isfinite(lp->_delay_element2))
  115. {
  116. lp->_delay_element1 = lp->_delay_element2 = input;
  117. }
  118. }
  119. else
  120. {
  121. lp->_delay_element1 = lp->_delay_element2 = input;
  122. }
  123. return butter2_filter_apply(lp, input);
  124. }