iir.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /********************************************************************
  2. * *
  3. * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. *
  4. * USE, DISTRIBUTION AND REPRODUCTION OF THIS SOURCE IS GOVERNED BY *
  5. * THE GNU LESSER/LIBRARY PUBLIC LICENSE, WHICH IS INCLUDED WITH *
  6. * THIS SOURCE. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. *
  7. * *
  8. * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2000 *
  9. * by Monty <monty@xiph.org> and the XIPHOPHORUS Company *
  10. * http://www.xiph.org/ *
  11. * *
  12. ********************************************************************
  13. function: Direct Form I, II IIR filters, plus some specializations
  14. last mod: $Id: iir.c,v 1.2.2.3 2000/11/04 10:24:15 xiphmont Exp $
  15. ********************************************************************/
  16. /* LPC is actually a degenerate case of form I/II filters, but we need
  17. both */
  18. #include <ogg/ogg.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #include "iir.h"
  23. void IIR_init(IIR_state *s,int stages,float gain, float *A, float *B){
  24. memset(s,0,sizeof(IIR_state));
  25. s->stages=stages;
  26. s->gain=gain;
  27. s->coeff_A=_ogg_malloc(stages*sizeof(float));
  28. s->coeff_B=_ogg_malloc((stages+1)*sizeof(float));
  29. s->z_A=_ogg_calloc(stages*2,sizeof(float));
  30. memcpy(s->coeff_A,A,stages*sizeof(float));
  31. memcpy(s->coeff_B,B,(stages+1)*sizeof(float));
  32. }
  33. void IIR_clear(IIR_state *s){
  34. if(s){
  35. free(s->coeff_A);
  36. free(s->coeff_B);
  37. free(s->z_A);
  38. memset(s,0,sizeof(IIR_state));
  39. }
  40. }
  41. float IIR_filter(IIR_state *s,float in){
  42. int stages=s->stages,i;
  43. float newA;
  44. float newB=0;
  45. float *zA=s->z_A+s->ring;
  46. newA=in/=s->gain;
  47. for(i=0;i<stages;i++){
  48. newA+= s->coeff_A[i] * zA[i];
  49. newB+= s->coeff_B[i] * zA[i];
  50. }
  51. newB+=newA*s->coeff_B[stages];
  52. zA[0]=zA[stages]=newA;
  53. if(++s->ring>=stages)s->ring=0;
  54. return(newB);
  55. }
  56. /* prevents ringing down to underflow */
  57. void IIR_clamp(IIR_state *s,float thresh){
  58. float *zA=s->z_A+s->ring;
  59. int i;
  60. for(i=0;i<s->stages;i++)
  61. if(fabs(zA[i])>=thresh)break;
  62. if(i<s->stages)
  63. memset(s->z_A,0,sizeof(float)*s->stages*2);
  64. }
  65. /* this assumes the symmetrical structure of the feed-forward stage of
  66. a Chebyshev bandpass to save multiplies */
  67. float IIR_filter_ChebBand(IIR_state *s,float in){
  68. int stages=s->stages,i;
  69. float newA;
  70. float newB=0;
  71. float *zA=s->z_A+s->ring;
  72. newA=in/=s->gain;
  73. newA+= s->coeff_A[0] * zA[0];
  74. for(i=1;i<(stages>>1);i++){
  75. newA+= s->coeff_A[i] * zA[i];
  76. newB+= s->coeff_B[i] * (zA[i]-zA[stages-i]);
  77. }
  78. newB+= s->coeff_B[i] * zA[i];
  79. for(;i<stages;i++)
  80. newA+= s->coeff_A[i] * zA[i];
  81. newB+= newA-zA[0];
  82. zA[0]=zA[stages]=newA;
  83. if(++s->ring>=stages)s->ring=0;
  84. return(newB);
  85. }
  86. #ifdef _V_SELFTEST
  87. /* z^-stage, z^-stage+1... */
  88. static float cheb_bandpass_B[]={-1.,0.,5.,0.,-10.,0.,10.,0.,-5.,0.,1};
  89. static float cheb_bandpass_A[]={-0.6665900311,
  90. 1.0070146601,
  91. -3.1262875409,
  92. 3.5017171569,
  93. -6.2779211945,
  94. 5.2966481740,
  95. -6.7570216587,
  96. 4.0760335768,
  97. -3.9134284363,
  98. 1.3997338886};
  99. static float data[128]={
  100. 0.0426331,
  101. 0.0384521,
  102. 0.0345764,
  103. 0.0346069,
  104. 0.0314636,
  105. 0.0310059,
  106. 0.0318604,
  107. 0.0336304,
  108. 0.036438,
  109. 0.0348511,
  110. 0.0354919,
  111. 0.0343628,
  112. 0.0325623,
  113. 0.0318909,
  114. 0.0263367,
  115. 0.0225525,
  116. 0.0195618,
  117. 0.0160828,
  118. 0.0168762,
  119. 0.0145569,
  120. 0.0126343,
  121. 0.0127258,
  122. 0.00820923,
  123. 0.00787354,
  124. 0.00558472,
  125. 0.00204468,
  126. 3.05176e-05,
  127. -0.00357056,
  128. -0.00570679,
  129. -0.00991821,
  130. -0.0101013,
  131. -0.00881958,
  132. -0.0108948,
  133. -0.0110168,
  134. -0.0119324,
  135. -0.0161438,
  136. -0.0194702,
  137. -0.0229187,
  138. -0.0260315,
  139. -0.0282288,
  140. -0.0306091,
  141. -0.0330505,
  142. -0.0364685,
  143. -0.0385742,
  144. -0.0428772,
  145. -0.043457,
  146. -0.0425415,
  147. -0.0462341,
  148. -0.0467529,
  149. -0.0489807,
  150. -0.0520325,
  151. -0.0558167,
  152. -0.0596924,
  153. -0.0591431,
  154. -0.0612793,
  155. -0.0618591,
  156. -0.0615845,
  157. -0.0634155,
  158. -0.0639648,
  159. -0.0683594,
  160. -0.0718079,
  161. -0.0729675,
  162. -0.0791931,
  163. -0.0860901,
  164. -0.0885315,
  165. -0.088623,
  166. -0.089386,
  167. -0.0899353,
  168. -0.0886841,
  169. -0.0910645,
  170. -0.0948181,
  171. -0.0919495,
  172. -0.0891418,
  173. -0.0916443,
  174. -0.096344,
  175. -0.100464,
  176. -0.105499,
  177. -0.108612,
  178. -0.112213,
  179. -0.117676,
  180. -0.120911,
  181. -0.124329,
  182. -0.122162,
  183. -0.120605,
  184. -0.12326,
  185. -0.12619,
  186. -0.128998,
  187. -0.13205,
  188. -0.134247,
  189. -0.137939,
  190. -0.143555,
  191. -0.14389,
  192. -0.14859,
  193. -0.153717,
  194. -0.159851,
  195. -0.164551,
  196. -0.162811,
  197. -0.164276,
  198. -0.156952,
  199. -0.140564,
  200. -0.123291,
  201. -0.10321,
  202. -0.0827637,
  203. -0.0652466,
  204. -0.053772,
  205. -0.0509949,
  206. -0.0577698,
  207. -0.0818176,
  208. -0.114929,
  209. -0.148895,
  210. -0.181122,
  211. -0.200714,
  212. -0.21048,
  213. -0.203644,
  214. -0.179413,
  215. -0.145325,
  216. -0.104492,
  217. -0.0658264,
  218. -0.0332031,
  219. -0.0106201,
  220. -0.00363159,
  221. -0.00909424,
  222. -0.0244141,
  223. -0.0422058,
  224. -0.0537415,
  225. -0.0610046,
  226. -0.0609741,
  227. -0.0547791};
  228. /* comparison test code from http://www-users.cs.york.ac.uk/~fisher/mkfilter/
  229. (the above page kicks ass, BTW)*/
  230. #define NZEROS 10
  231. #define NPOLES 10
  232. #define GAIN 4.599477515e+02
  233. static float xv[NZEROS+1], yv[NPOLES+1];
  234. static float filterloop(float next){
  235. xv[0] = xv[1]; xv[1] = xv[2]; xv[2] = xv[3]; xv[3] = xv[4]; xv[4] = xv[5];
  236. xv[5] = xv[6]; xv[6] = xv[7]; xv[7] = xv[8]; xv[8] = xv[9]; xv[9] = xv[10];
  237. xv[10] = next / GAIN;
  238. yv[0] = yv[1]; yv[1] = yv[2]; yv[2] = yv[3]; yv[3] = yv[4]; yv[4] = yv[5];
  239. yv[5] = yv[6]; yv[6] = yv[7]; yv[7] = yv[8]; yv[8] = yv[9]; yv[9] = yv[10];
  240. yv[10] = (xv[10] - xv[0]) + 5 * (xv[2] - xv[8]) + 10 * (xv[6] - xv[4])
  241. + ( -0.6665900311 * yv[0]) + ( 1.0070146601 * yv[1])
  242. + ( -3.1262875409 * yv[2]) + ( 3.5017171569 * yv[3])
  243. + ( -6.2779211945 * yv[4]) + ( 5.2966481740 * yv[5])
  244. + ( -6.7570216587 * yv[6]) + ( 4.0760335768 * yv[7])
  245. + ( -3.9134284363 * yv[8]) + ( 1.3997338886 * yv[9]);
  246. return(yv[10]);
  247. }
  248. #include <stdio.h>
  249. int main(){
  250. /* run the pregenerated Chebyshev filter, then our own distillation
  251. through the generic and specialized code */
  252. float *work=_ogg_malloc(128*sizeof(float));
  253. IIR_state iir;
  254. int i;
  255. for(i=0;i<128;i++)work[i]=filterloop(data[i]);
  256. {
  257. FILE *out=fopen("IIR_ref.m","w");
  258. for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
  259. fclose(out);
  260. }
  261. IIR_init(&iir,NPOLES,GAIN,cheb_bandpass_A,cheb_bandpass_B);
  262. for(i=0;i<128;i++)work[i]=IIR_filter(&iir,data[i]);
  263. {
  264. FILE *out=fopen("IIR_gen.m","w");
  265. for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
  266. fclose(out);
  267. }
  268. IIR_clear(&iir);
  269. IIR_init(&iir,NPOLES,GAIN,cheb_bandpass_A,cheb_bandpass_B);
  270. for(i=0;i<128;i++)work[i]=IIR_filter_ChebBand(&iir,data[i]);
  271. {
  272. FILE *out=fopen("IIR_cheb.m","w");
  273. for(i=0;i<128;i++)fprintf(out,"%g\n",work[i]);
  274. fclose(out);
  275. }
  276. IIR_clear(&iir);
  277. return(0);
  278. }
  279. #endif