5 * Copyright (C) 2002-2005 Monty and Xiph.Org
7 * Postfish is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2, or (at your option)
12 * Postfish is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with Postfish; see the file COPYING. If not, write to the
19 * Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
24 /* arbitrary reconstruction filter. Postfish uses this for declipping.
26 Many thanks to Johnathan Richard Shewchuk and his excellent paper
27 'An Introduction to the Conjugate Gradient Method Without the
28 Agonizing Pain' for the additional understanding needed to make the
29 n^3 -> n^2 log n jump possible. Google for it, you'll find it. */
34 #include "reconstruct.h"
36 /* fftw3 requires this kind of static setup */
37 static fftwf_plan fftwf_qf
;
38 static fftwf_plan fftwf_qb
;
39 static fftwf_plan fftwf_sf
;
40 static fftwf_plan fftwf_sb
;
43 static int blocksize
=0;
45 void reconstruct_init(int minblock
,int maxblock
){
48 q
=fftwf_malloc((maxblock
+2)*sizeof(*q
));
49 s
=fftwf_malloc((maxblock
+2)*sizeof(*s
));
51 /* fftw priming trick; run it thorugh the paces and prime a plan for
52 every size we may need. fftw will cache the information and not
53 need to re-measure later */
55 for(i
=minblock
;i
<=maxblock
;i
<<=1){
56 fftwf_qf
=fftwf_plan_dft_r2c_1d(i
,q
,(fftwf_complex
*)q
,FFTW_MEASURE
);
57 fftwf_qb
=fftwf_plan_dft_c2r_1d(i
,(fftwf_complex
*)q
,q
,FFTW_MEASURE
);
58 fftwf_destroy_plan(fftwf_qf
);
59 fftwf_destroy_plan(fftwf_qb
);
64 void reconstruct_reinit(int n
){
67 fftwf_destroy_plan(fftwf_qf
);
68 fftwf_destroy_plan(fftwf_qb
);
69 fftwf_destroy_plan(fftwf_sf
);
70 fftwf_destroy_plan(fftwf_sb
);
76 q
=fftwf_malloc((n
+2)*sizeof(*q
));
77 s
=fftwf_malloc((n
+2)*sizeof(*s
));
78 fftwf_qf
=fftwf_plan_dft_r2c_1d(n
,q
,(fftwf_complex
*)q
,FFTW_MEASURE
);
79 fftwf_qb
=fftwf_plan_dft_c2r_1d(n
,(fftwf_complex
*)q
,q
,FFTW_MEASURE
);
80 fftwf_sf
=fftwf_plan_dft_r2c_1d(n
,s
,(fftwf_complex
*)s
,FFTW_MEASURE
);
81 fftwf_sb
=fftwf_plan_dft_c2r_1d(n
,(fftwf_complex
*)s
,s
,FFTW_MEASURE
);
85 static void AtWA(float *w
,int n
){
87 fftwf_execute(fftwf_qf
);
88 for(i
=0;i
<n
+2;i
++)q
[i
]*=w
[i
];
89 fftwf_execute(fftwf_qb
); /* this is almost the same as A'; see the
90 correction factor rolled into w at the
91 beginning of reconstruct() */
94 /* This is not the inverse of XA'WAX; the algebra isn't valid (due to
95 the singularity of the selection matrix X) and as such is useless
96 for direct solution. However, it does _approximate_ the inverse
97 and as such makes an excellent system preconditioner. */
98 static void precondition(float *w
,int n
){
101 /* no need to remove scaling of result; the relative stretching of
102 the solution space is what's important */
104 fftwf_execute(fftwf_sf
); /* almost the same as A^-1'; see the correction
105 factor rolled into w at the beginning of
107 for(i
=0;i
<n
+2;i
++)s
[i
]/=w
[i
];
108 fftwf_execute(fftwf_sb
);
111 static float inner_product(float *a
, float *b
, int n
){
114 for(i
=0;i
<n
;i
++)acc
+=a
[i
]*b
[i
];
118 void reconstruct(float *x
, float *w
,
119 float *flag
, float e
,int max
){
125 float phi_new
,phi_old
,res_0
,res_new
;
128 /* hack; roll a correction factor for A'/A-1 into w */
129 for(j
=1;j
<n
-1;j
++)w
[j
]*=.5;
131 /* compute initial Atb */
132 for(j
=0;j
<n
;j
++)q
[j
]=x
[j
]*(flag
[j
]-1.);
134 res_new
=res_0
=inner_product(q
,q
,n
);
135 for(j
=0;j
<n
;j
++)Atb
[j
]=q
[j
];
137 /* compute initial residue */
138 for(j
=0;j
<n
;j
++)q
[j
]=x
[j
]*flag
[j
];
140 for(j
=0;j
<n
;j
++)s
[j
]=r
[j
]=(Atb
[j
]-q
[j
])*flag
[j
];
142 /* initial preconditioning */
144 for(j
=0;j
<n
;j
++)q
[j
]=d
[j
]=s
[j
]*=flag
[j
];
146 phi_new
=inner_product(r
,d
,n
);
148 for(i
=0;i
<max
&& sqrt(res_new
)/sqrt(res_0
)>e
;i
++){
151 alpha
=phi_new
/inner_product(d
,q
,n
);
152 for(j
=0;j
<n
;j
++)x
[j
]+=alpha
*d
[j
];
154 if((i
& 0x3f)==0x3f){
155 for(j
=0;j
<n
;j
++)q
[j
]=x
[j
]*flag
[j
];
157 for(j
=0;j
<n
;j
++)r
[j
]=(Atb
[j
]-q
[j
])*flag
[j
];
159 for(j
=0;j
<n
;j
++)r
[j
]-=alpha
*q
[j
]*flag
[j
];
161 /* apply preconditioner */
162 for(j
=0;j
<n
;j
++)s
[j
]=r
[j
]*flag
[j
];
164 for(j
=0;j
<n
;j
++)s
[j
]*=flag
[j
];
167 phi_new
=inner_product(r
,s
,n
);
168 res_new
=inner_product(r
,r
,n
);
169 beta
=phi_new
/phi_old
;
170 for(j
=0;j
<n
;j
++) q
[j
]=d
[j
]=s
[j
]+beta
*d
[j
];