xue@1
|
1 //---------------------------------------------------------------------------
|
xue@1
|
2
|
xue@1
|
3 #include <stddef.h>
|
Chris@2
|
4 #include "sinest.h"
|
xue@1
|
5 #include "fft.h"
|
xue@1
|
6 #include "opt.h"
|
Chris@2
|
7 #include "sinsyn.h"
|
xue@1
|
8 #include "splines.h"
|
Chris@2
|
9 #include "windowfunctions.h"
|
xue@1
|
10
|
Chris@5
|
11 /** \file sinest.h */
|
Chris@5
|
12
|
xue@1
|
13 //---------------------------------------------------------------------------
|
Chris@5
|
14 /**
|
xue@1
|
15 function dsincd_unn: derivative of unnormalized discrete sinc function
|
xue@1
|
16
|
xue@1
|
17 In: x, scale N
|
xue@1
|
18
|
xue@1
|
19 Returns the derivative of sincd_unn(x, N)
|
xue@1
|
20 */
|
xue@1
|
21 double dsincd_unn(double x, int N)
|
xue@1
|
22 {
|
xue@1
|
23 double r=0;
|
xue@1
|
24 double omg=M_PI*x;
|
xue@1
|
25 double domg=omg/N;
|
xue@1
|
26 if (fabs(x)>1e-6)
|
xue@1
|
27 {
|
xue@1
|
28 r=M_PI*(cos(omg)-sin(omg)*cos(domg)/sin(domg)/N)/sin(domg);
|
xue@1
|
29 }
|
xue@1
|
30 else
|
xue@1
|
31 {
|
xue@1
|
32 if (domg!=0)
|
xue@1
|
33 {
|
xue@1
|
34 double sindomg=sin(domg);
|
xue@1
|
35 r=-omg*omg*omg*(1-1.0/(1.0*N*N))/3*M_PI/N/sindomg/sindomg;
|
xue@1
|
36 }
|
xue@1
|
37 else
|
xue@1
|
38 r=0;
|
xue@1
|
39 }
|
xue@1
|
40 return r;
|
xue@1
|
41 }//dsincd_unn
|
xue@1
|
42
|
Chris@5
|
43 /**
|
xue@1
|
44 function ddsincd_unn: 2nd-order derivative of unnormalized discrete sinc function
|
xue@1
|
45
|
xue@1
|
46 In: x, scale (equivalently, window size) N
|
xue@1
|
47
|
xue@1
|
48 Returns the 2nd-order derivative of sincd_unn(x, N)
|
xue@1
|
49 */
|
xue@1
|
50 double ddsincd_unn(double x, int N)
|
xue@1
|
51 {
|
xue@1
|
52 double r=0;
|
xue@1
|
53 double omg=M_PI*x;
|
xue@1
|
54 double domg=omg/N;
|
xue@1
|
55 double PI2=M_PI*M_PI;
|
xue@1
|
56 double NN=1.0/N/N-1;
|
xue@1
|
57 if (domg==0)
|
xue@1
|
58 {
|
xue@1
|
59 r=PI2*N*NN/3;
|
xue@1
|
60 }
|
xue@1
|
61 else
|
xue@1
|
62 {
|
xue@1
|
63 if (fabs(x)>1e-5)
|
xue@1
|
64 {
|
xue@1
|
65 r=sin(domg)*cos(omg)-sin(omg)*cos(domg)/N;
|
xue@1
|
66 }
|
xue@1
|
67 else
|
xue@1
|
68 {
|
xue@1
|
69 r=omg*omg*omg/N*NN/3;
|
xue@1
|
70 }
|
xue@1
|
71 double ss=sin(omg)*NN;
|
xue@1
|
72 r=-2.0/N*cos(domg)*r/sin(domg)/sin(domg)+ss;
|
xue@1
|
73 r=r*PI2/sin(domg);
|
xue@1
|
74 }
|
xue@1
|
75 return r;
|
xue@1
|
76 }//ddsincd_unn
|
xue@1
|
77
|
xue@1
|
78 //---------------------------------------------------------------------------
|
Chris@5
|
79 /**
|
xue@1
|
80 function Window: calculates the cosine-family-windowed spectrum of a complex sinusoid on [0:N-1] at
|
xue@1
|
81 frequency f bins with zero central phase.
|
xue@1
|
82
|
xue@1
|
83 In: f: frequency, in bins
|
xue@1
|
84 N: window size
|
xue@1
|
85 M, c[]: cosine-family window decomposition coefficients
|
xue@1
|
86 Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2.
|
xue@1
|
87
|
xue@1
|
88 Returns pointer to x. x is created anew if x=0 is specified on start.
|
xue@1
|
89 */
|
xue@1
|
90 cdouble* Window(cdouble* x, double f, int N, int M, double* c, int K1, int K2)
|
xue@1
|
91 {
|
xue@1
|
92 if (K1<0) K1=0;
|
xue@1
|
93 if (K2>N/2-1) K2=N/2-1;
|
xue@1
|
94
|
xue@1
|
95 if (!x) x=new cdouble[K2-K1+1];
|
xue@1
|
96 memset(x, 0, sizeof(cdouble)*(K2-K1+1));
|
xue@1
|
97
|
xue@1
|
98 for (int l=K1-M; l<=K2+M; l++)
|
xue@1
|
99 {
|
xue@1
|
100 double ang=(f-l)*M_PI;
|
xue@1
|
101 double omg=ang/N;
|
xue@1
|
102 long double si, co, sinn=sin(ang);
|
xue@1
|
103 si=sin(omg), co=cos(omg);
|
xue@1
|
104 double sa=(ang==0)?N:(sinn/si);
|
xue@1
|
105 double saco=sa*co;
|
xue@1
|
106
|
xue@1
|
107 int k1=l-M, k2=l+M;
|
xue@1
|
108 if (k1<K1) k1=K1;
|
xue@1
|
109 if (k2>K2) k2=K2;
|
xue@1
|
110
|
xue@1
|
111 for (int k=k1; k<=k2; k++)
|
xue@1
|
112 {
|
xue@1
|
113 int m=k-l, kt=k-K1;
|
xue@1
|
114 if (m<0) m=-m;
|
xue@1
|
115 if (k%2)
|
xue@1
|
116 {
|
xue@1
|
117 x[kt].x-=c[m]*saco;
|
xue@1
|
118 x[kt].y+=c[m]*sinn;
|
xue@1
|
119 }
|
xue@1
|
120 else
|
xue@1
|
121 {
|
xue@1
|
122 x[kt].x+=c[m]*saco;
|
xue@1
|
123 x[kt].y-=c[m]*sinn;
|
xue@1
|
124 }
|
xue@1
|
125 }
|
xue@1
|
126 }
|
xue@1
|
127 return x;
|
xue@1
|
128 }//Window
|
xue@1
|
129
|
Chris@5
|
130 /**
|
xue@1
|
131 function dWindow: calculates the cosine-family-windowed spectrum and its derivative of a complex
|
xue@1
|
132 sinusoid on [0:N-1] at frequency f bins with zero central phase.
|
xue@1
|
133
|
xue@1
|
134 In: f: frequency, in bins
|
xue@1
|
135 N: window size
|
xue@1
|
136 M, c[]: cosine-family window decomposition coefficients
|
xue@1
|
137 Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2,
|
xue@1
|
138 dx[0...K2-K1] containing the derivative spectrum at bins K1, ..., K2
|
xue@1
|
139
|
xue@1
|
140 No return value.
|
xue@1
|
141 */
|
xue@1
|
142 void dWindow(cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2)
|
xue@1
|
143 {
|
xue@1
|
144 if (K1<0) K1=0;
|
xue@1
|
145 if (K2>N/2-1) K2=N/2-1;
|
xue@1
|
146 memset(x, 0, sizeof(cdouble)*(K2-K1+1));
|
xue@1
|
147 memset(dx, 0, sizeof(cdouble)*(K2-K1+1));
|
xue@1
|
148
|
xue@1
|
149 for (int l=K1-M; l<=K2+M; l++)
|
xue@1
|
150 {
|
xue@1
|
151 double ang=(f-l), Omg=ang*M_PI, omg=Omg/N;
|
xue@1
|
152 long double si, co, sinn=sin(Omg), cosn=cos(Omg);
|
xue@1
|
153 si=sin(omg), co=cos(omg);
|
xue@1
|
154 double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N);
|
xue@1
|
155 double saco=sa*co, dsaco=dsa*co, sinnpi_n=sinn*M_PI/N, cosnpi=cosn*M_PI;
|
xue@1
|
156
|
xue@1
|
157 int k1=l-M, k2=l+M;
|
xue@1
|
158 if (k1<K1) k1=K1;
|
xue@1
|
159 if (k2>K2) k2=K2;
|
xue@1
|
160
|
xue@1
|
161 for (int k=k1; k<=k2; k++)
|
xue@1
|
162 {
|
xue@1
|
163 int m=k-l, kt=k-K1;
|
xue@1
|
164 if (m<0) m=-m;
|
xue@1
|
165 if (k%2)
|
xue@1
|
166 {
|
xue@1
|
167 x[kt].x-=c[m]*saco;
|
xue@1
|
168 x[kt].y+=c[m]*sinn;
|
xue@1
|
169 dx[kt].x-=c[m]*(-sinnpi_n+dsaco);
|
xue@1
|
170 dx[kt].y+=c[m]*cosnpi;
|
xue@1
|
171 }
|
xue@1
|
172 else
|
xue@1
|
173 {
|
xue@1
|
174 x[kt].x+=c[m]*saco;
|
xue@1
|
175 x[kt].y-=c[m]*sinn;
|
xue@1
|
176 dx[kt].x+=c[m]*(-sinnpi_n+dsaco);
|
xue@1
|
177 dx[kt].y-=c[m]*cosnpi;
|
xue@1
|
178 }
|
xue@1
|
179 }
|
xue@1
|
180 }
|
xue@1
|
181 }//dWindow
|
xue@1
|
182
|
Chris@5
|
183 /**
|
xue@1
|
184 function ddWindow: calculates the cosine-family-windowed spectrum and its 1st and 2nd derivatives of
|
xue@1
|
185 a complex sinusoid on [0:N-1] at frequency f bins with zero central phase.
|
xue@1
|
186
|
xue@1
|
187 In: f: frequency, in bins
|
xue@1
|
188 N: window size
|
xue@1
|
189 M, c[]: cosine-family window decomposition coefficients
|
xue@1
|
190 Out: x[0...K2-K1] containing the spectrum at bins K1, ..., K2,
|
xue@1
|
191 dx[0...K2-K1] containing the derivative spectrum at bins K1, ..., K2
|
xue@1
|
192 ddx[0...K2-K1] containing the 2nd-order derivative spectrum at bins K1, ..., K2
|
xue@1
|
193
|
xue@1
|
194 No return value.
|
xue@1
|
195 */
|
xue@1
|
196 void ddWindow(cdouble* ddx, cdouble* dx, cdouble* x, double f, int N, int M, double* c, int K1, int K2)
|
xue@1
|
197 {
|
xue@1
|
198 if (K1<0) K1=0;
|
xue@1
|
199 if (K2>N/2-1) K2=N/2-1;
|
xue@1
|
200 memset(x, 0, sizeof(cdouble)*(K2-K1+1));
|
xue@1
|
201 memset(dx, 0, sizeof(cdouble)*(K2-K1+1));
|
xue@1
|
202 memset(ddx, 0, sizeof(cdouble)*(K2-K1+1));
|
xue@1
|
203
|
xue@1
|
204 for (int l=K1-M; l<=K2+M; l++)
|
xue@1
|
205 {
|
xue@1
|
206 double ang=(f-l), Omg=ang*M_PI, omg=Omg/N;
|
xue@1
|
207 long double si, co, sinn=sin(Omg), cosn=cos(Omg);
|
xue@1
|
208 si=sin(omg), co=cos(omg);
|
xue@1
|
209 double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N), ddsa=ddsincd_unn(ang, N);
|
xue@1
|
210 double saco=sa*co, dsaco=dsa*co, sinnpi_n=sinn*M_PI/N, sinnpipi=sinn*M_PI*M_PI, cosnpi=cosn*M_PI,
|
xue@1
|
211 cosnpipi_n=cosnpi*M_PI/N, sipi_n=si*M_PI/N;
|
xue@1
|
212
|
xue@1
|
213 int k1=l-M, k2=l+M;
|
xue@1
|
214 if (k1<K1) k1=K1;
|
xue@1
|
215 if (k2>K2) k2=K2;
|
xue@1
|
216
|
xue@1
|
217 for (int k=k1; k<=k2; k++)
|
xue@1
|
218 {
|
xue@1
|
219 int m=k-l, kt=k-K1;
|
xue@1
|
220 if (m<0) m=-m;
|
xue@1
|
221 if (k%2)
|
xue@1
|
222 {
|
xue@1
|
223 x[kt].x-=c[m]*saco;
|
xue@1
|
224 x[kt].y+=c[m]*sinn;
|
xue@1
|
225 dx[kt].x-=c[m]*(-sinnpi_n+dsaco);
|
xue@1
|
226 dx[kt].y+=c[m]*cosnpi;
|
xue@1
|
227 ddx[kt].x-=c[m]*(-cosnpipi_n+ddsa*co-dsa*sipi_n);
|
xue@1
|
228 ddx[kt].y-=c[m]*sinnpipi;
|
xue@1
|
229 }
|
xue@1
|
230 else
|
xue@1
|
231 {
|
xue@1
|
232 x[kt].x+=c[m]*saco;
|
xue@1
|
233 x[kt].y-=c[m]*sinn;
|
xue@1
|
234 dx[kt].x+=c[m]*(-sinnpi_n+dsaco);
|
xue@1
|
235 dx[kt].y-=c[m]*cosnpi;
|
xue@1
|
236 ddx[kt].x+=c[m]*(-cosnpipi_n+ddsa*co-dsa*sipi_n);
|
xue@1
|
237 ddx[kt].y+=c[m]*sinnpipi;
|
xue@1
|
238 }
|
xue@1
|
239 }
|
xue@1
|
240 }
|
xue@1
|
241 }//ddWindow
|
xue@1
|
242
|
xue@1
|
243 //---------------------------------------------------------------------------
|
Chris@5
|
244 /**
|
xue@1
|
245 function IPWindow: computes the truncated inner product of a windowed spectrum with that of a sinusoid
|
xue@1
|
246 at reference frequency f.
|
xue@1
|
247
|
xue@1
|
248 In: x[0:N-1]: input spectrum
|
xue@1
|
249 f: reference frequency, in bins
|
xue@1
|
250 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
251 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
252 returnamplitude: specifies return value, true for amplitude, false for angle
|
xue@1
|
253
|
xue@1
|
254 Returns the amplitude or phase of the inner product, as specified by $returnamplitude. The return
|
xue@1
|
255 value is interpreted as the actual amplitude/phase of a sinusoid being estimated at f.
|
xue@1
|
256 */
|
xue@1
|
257 double IPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, bool returnamplitude)
|
xue@1
|
258 {
|
xue@1
|
259 cdouble r=IPWindowC(f, x, N, M, c, iH2, K1, K2);
|
xue@1
|
260 double result;
|
xue@1
|
261 if (returnamplitude) result=sqrt(r.x*r.x+r.y*r.y);
|
xue@1
|
262 else result=arg(r);
|
xue@1
|
263 return result;
|
xue@1
|
264 }//IPWindow
|
xue@1
|
265 //wrapper function
|
xue@1
|
266 double IPWindow(double f, void* params)
|
xue@1
|
267 {
|
xue@1
|
268 struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dipwindow; double ipwindow;} *p=(l_ip *)params;
|
xue@1
|
269 return IPWindow(f, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, true);
|
xue@1
|
270 }//IPWindow
|
xue@1
|
271
|
Chris@5
|
272 /**
|
xue@1
|
273 function ddIPWindow: computes the norm of the truncated inner product of a windowed spectrum with
|
xue@1
|
274 that of a sinusoid at reference frequency f, as well as its 1st and 2nd derivatives.
|
xue@1
|
275
|
xue@1
|
276 In: x[0:N-1]: input spectrum
|
xue@1
|
277 f: reference frequency, in bins
|
xue@1
|
278 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
279 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
280 Out: ipwindow and dipwindow: the truncated inner product norm and its derivative
|
xue@1
|
281
|
xue@1
|
282 Returns the 2nd derivative of the norm of the truncated inner product.
|
xue@1
|
283 */
|
xue@1
|
284 double ddIPWindow(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2, double& dipwindow, double& ipwindow)
|
xue@1
|
285 {
|
xue@1
|
286 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
287 int K=K2-K1+1;
|
xue@1
|
288 cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2], *lx=&x[K1];
|
xue@1
|
289 ddWindow(ddw, dw, w, f, N, M, c, K1, K2);
|
xue@1
|
290 cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw);
|
xue@1
|
291 delete[] w;
|
xue@1
|
292
|
xue@1
|
293 double R2=~r,
|
xue@1
|
294 R=sqrt(R2),
|
xue@1
|
295 dR2=2*(r.x*dr.x+r.y*dr.y),
|
xue@1
|
296 dR=dR2/(2*R),
|
xue@1
|
297 ddR2=2*(r.x*ddr.x+r.y*ddr.y+~dr),
|
xue@1
|
298 ddR=(R*ddR2-dR2*dR)/(2*R2);
|
xue@1
|
299 ipwindow=R*iH2;
|
xue@1
|
300 dipwindow=dR*iH2;
|
xue@1
|
301 return ddR*iH2;
|
xue@1
|
302 }//ddIPWindow
|
xue@1
|
303 //wrapper function
|
xue@1
|
304 double ddIPWindow(double f, void* params)
|
xue@1
|
305 {
|
xue@1
|
306 struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dipwindow; double ipwindow;} *p=(l_ip *)params;
|
xue@1
|
307 return ddIPWindow(f, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dipwindow, p->ipwindow);
|
xue@1
|
308 }//ddIPWindow
|
xue@1
|
309
|
xue@1
|
310 //---------------------------------------------------------------------------
|
Chris@5
|
311 /**
|
xue@1
|
312 function IPWindowC: computes the truncated inner product of a windowed spectrum with that of a
|
xue@1
|
313 sinusoid at reference frequency f.
|
xue@1
|
314
|
xue@1
|
315 In: x[0:N-1]: input spectrum
|
xue@1
|
316 f: reference frequency, in bins
|
xue@1
|
317 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
318 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
319
|
xue@1
|
320 Returns the inner product. The return value is interpreted as the actual amplitude-phase factor of a
|
xue@1
|
321 sinusoid being estimated at f.
|
xue@1
|
322 */
|
xue@1
|
323 cdouble IPWindowC(double f, cdouble* x, int N, int M, double* c, double iH2, int K1, int K2)
|
xue@1
|
324 {
|
xue@1
|
325 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
326 int K=K2-K1+1;
|
xue@1
|
327 cdouble *w=new cdouble[K];
|
xue@1
|
328 cdouble *lx=&x[K1], result=0;
|
xue@1
|
329 Window(w, f, N, M, c, K1, K2);
|
xue@1
|
330 for (int k=0; k<K; k++) result+=lx[k]^w[k];
|
xue@1
|
331 delete[] w;
|
xue@1
|
332 result*=iH2;
|
xue@1
|
333 return result;
|
xue@1
|
334 }//IPWindowC
|
xue@1
|
335
|
xue@1
|
336 //---------------------------------------------------------------------------
|
Chris@5
|
337 /**
|
xue@1
|
338 function sIPWindow: computes the total energy of truncated inner products between multiple windowed
|
xue@1
|
339 spectra and that of a sinusoid at a reference frequency f. This does not consider phase alignment
|
xue@1
|
340 between the spectra, supposedly measured at a sequence of known instants.
|
xue@1
|
341
|
xue@1
|
342 In: x[L][N]: input spectra
|
xue@1
|
343 f: reference frequency, in bins
|
xue@1
|
344 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
345 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
346 Out: lmd[L]: the actual individual inner products representing actual ampltiude-phase factors (optional)
|
xue@1
|
347
|
xue@1
|
348 Returns the energy of the vector of inner products.
|
xue@1
|
349 */
|
xue@1
|
350 double sIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* lmd)
|
xue@1
|
351 {
|
xue@1
|
352 double sip=0;
|
xue@1
|
353 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
354 int K=K2-K1+1;
|
xue@1
|
355 cdouble *w=new cdouble[K];
|
xue@1
|
356 Window(w, f, N, M, c, K1, K2);
|
xue@1
|
357 for (int l=0; l<L; l++)
|
xue@1
|
358 {
|
xue@1
|
359 cdouble *lx=&x[l][K1];
|
xue@1
|
360 cdouble r=Inner(K, lx, w);
|
xue@1
|
361 if (lmd) lmd[l]=r*iH2;
|
xue@1
|
362 sip+=~r;
|
xue@1
|
363 }
|
xue@1
|
364 sip*=iH2;
|
xue@1
|
365 delete[] w;
|
xue@1
|
366 return sip;
|
xue@1
|
367 }//sIPWindow
|
xue@1
|
368 //wrapper function
|
xue@1
|
369 double sIPWindow(double f, void* params)
|
xue@1
|
370 {
|
xue@1
|
371 struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double dipwindow; double ipwindow; cdouble* lmd;} *p=(l_ip *)params;
|
xue@1
|
372 return sIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->lmd);
|
xue@1
|
373 }//sIPWindow
|
xue@1
|
374
|
Chris@5
|
375 /**
|
xue@1
|
376 function dsIPWindow: computes the total energy of truncated inner products between multiple windowed
|
xue@1
|
377 spectra and that of a sinusoid at a reference frequency f, as well as its derivative. This does not
|
xue@1
|
378 consider phase synchronization between the spectra, supposedly measured at a sequence of known
|
xue@1
|
379 instants.
|
xue@1
|
380
|
xue@1
|
381 In: x[L][N]: input spectra
|
xue@1
|
382 f: reference frequency, in bins
|
xue@1
|
383 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
384 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
385 Out: sip, the energy of the vector of inner products.
|
xue@1
|
386
|
xue@1
|
387 Returns the derivative of the energy of the vector of inner products.
|
xue@1
|
388 */
|
xue@1
|
389 double dsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip)
|
xue@1
|
390 {
|
xue@1
|
391 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
392 int K=K2-K1+1;
|
xue@1
|
393 cdouble *w=new cdouble[K*2], *dw=&w[K];
|
xue@1
|
394 dWindow(dw, w, f, N, M, c, K1, K2);
|
xue@1
|
395 double dsip; sip=0;
|
xue@1
|
396 for (int l=0; l<L; l++)
|
xue@1
|
397 {
|
xue@1
|
398 cdouble* lx=&x[l][K1];
|
xue@1
|
399 cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw);
|
xue@1
|
400 double R2=~r, dR2=2*(r.x*dr.x+r.y*dr.y);
|
xue@1
|
401 sip+=R2, dsip+=dR2;
|
xue@1
|
402 }
|
xue@1
|
403 sip*=iH2, dsip*=iH2;
|
xue@1
|
404 delete[] w;
|
xue@1
|
405 return dsip;
|
xue@1
|
406 }//dsIPWindow
|
xue@1
|
407 //wrapper function
|
xue@1
|
408 double dsIPWindow(double f, void* params)
|
xue@1
|
409 {
|
xue@1
|
410 struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double sip;} *p=(l_ip1 *)params;
|
xue@1
|
411 return dsIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->sip);
|
xue@1
|
412 }//dsIPWindow
|
xue@1
|
413
|
Chris@5
|
414 /**
|
xue@1
|
415 function dsdIPWindow_unn: computes the energy of unnormalized truncated inner products between a given
|
xue@1
|
416 windowed spectrum and that of a sinusoid at a reference frequency f, as well as its 1st and 2nd
|
xue@1
|
417 derivatives. "Unnormalized" indicates that the inner product cannot be taken as the actual amplitude-
|
xue@1
|
418 phase factor of a sinusoid, but deviate from that by an unspecified factor.
|
xue@1
|
419
|
xue@1
|
420 In: x[N]: input spectrum
|
xue@1
|
421 f: reference frequency, in bins
|
xue@1
|
422 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
423 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
424 Out: sipwindow and dsipwindow, the energy and its derivative of the unnormalized inner product.
|
xue@1
|
425
|
xue@1
|
426 Returns the 2nd derivative of the inner product.
|
xue@1
|
427 */
|
xue@1
|
428 double ddsIPWindow_unn(double f, cdouble* x, int N, int M, double* c, int K1, int K2, double& dsipwindow, double& sipwindow, cdouble* w_unn)
|
xue@1
|
429 {
|
xue@1
|
430 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
431 int K=K2-K1+1;
|
xue@1
|
432
|
xue@1
|
433 cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2];
|
xue@1
|
434
|
xue@1
|
435 ddWindow(ddw, dw, w, f, N, M, c, K1, K2);
|
xue@1
|
436
|
xue@1
|
437 double rr=0, ri=0, drr=0, dri=0, ddrr=0, ddri=0;
|
xue@1
|
438 cdouble *lx=&x[K1];
|
xue@1
|
439 for (int k=0; k<K; k++)
|
xue@1
|
440 {
|
xue@1
|
441 rr+=lx[k].x*w[k].x+lx[k].y*w[k].y;
|
xue@1
|
442 ri+=lx[k].y*w[k].x-lx[k].x*w[k].y;
|
xue@1
|
443 drr+=lx[k].x*dw[k].x+lx[k].y*dw[k].y;
|
xue@1
|
444 dri+=lx[k].y*dw[k].x-lx[k].x*dw[k].y;
|
xue@1
|
445 ddrr+=lx[k].x*ddw[k].x+lx[k].y*ddw[k].y;
|
xue@1
|
446 ddri+=lx[k].y*ddw[k].x-lx[k].x*ddw[k].y;
|
xue@1
|
447 }
|
xue@1
|
448 delete[] w;
|
xue@1
|
449
|
xue@1
|
450 double R2=rr*rr+ri*ri,
|
xue@1
|
451 dR2=2*(rr*drr+ri*dri),
|
xue@1
|
452 ddR2=2*(rr*ddrr+ri*ddri+drr*drr+dri*dri);
|
xue@1
|
453 sipwindow=R2;
|
xue@1
|
454 dsipwindow=dR2;
|
xue@1
|
455 if (w_unn) w_unn->x=rr, w_unn->y=ri;
|
xue@1
|
456 return ddR2;
|
xue@1
|
457 }//ddsIPWindow_unn
|
xue@1
|
458
|
Chris@5
|
459 /**
|
xue@1
|
460 function ddsIPWindow: computes the total energy of truncated inner products between multiple windowed
|
xue@1
|
461 spectra and that of a sinusoid at a reference frequency f, as well as its 1st and 2nd derivatives.
|
xue@1
|
462 This does not consider phase synchronization between the spectra, supposedly measured at a sequence
|
xue@1
|
463 of known instants.
|
xue@1
|
464
|
xue@1
|
465 In: x[L][N]: input spectra
|
xue@1
|
466 f: reference frequency, in bins
|
xue@1
|
467 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
468 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
469 Out: sip and dsip, the energy of the vector of inner products and its derivative.
|
xue@1
|
470
|
xue@1
|
471 Returns the 2nd derivative of the energy of the vector of inner products.
|
xue@1
|
472 */
|
xue@1
|
473 double ddsIPWindow(double f, int L, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsip, double& sip)
|
xue@1
|
474 {
|
xue@1
|
475 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
476 int K=K2-K1+1;
|
xue@1
|
477 cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2];
|
xue@1
|
478 ddWindow(ddw, dw, w, f, N, M, c, K1, K2);
|
xue@1
|
479 double ddsip=0; dsip=sip=0;
|
xue@1
|
480 for (int l=0; l<L; l++)
|
xue@1
|
481 {
|
xue@1
|
482 cdouble* lx=&x[l][K1];
|
xue@1
|
483 cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw);
|
xue@1
|
484 double R2=~r, dR2=2*(r.x*dr.x+r.y*dr.y), ddR2=2*(r.x*ddr.x+r.y*ddr.y+~dr);
|
xue@1
|
485 sip+=R2, dsip+=dR2, ddsip+=ddR2;
|
xue@1
|
486 }
|
xue@1
|
487 sip*=iH2, dsip*=iH2, ddsip*=iH2;
|
xue@1
|
488 delete[] w;
|
xue@1
|
489 return ddsip;
|
xue@1
|
490 }//ddsIPWindow
|
xue@1
|
491 //wrapper function
|
xue@1
|
492 double ddsIPWindow(double f, void* params)
|
xue@1
|
493 {
|
xue@1
|
494 struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int Fr; cdouble** x; double dsip; double sip;} *p=(l_ip1 *)params;
|
xue@1
|
495 return ddsIPWindow(f, p->Fr, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dsip, p->sip);
|
xue@1
|
496 }//ddsIPWindow
|
xue@1
|
497
|
xue@1
|
498 //---------------------------------------------------------------------------
|
Chris@5
|
499 /**
|
xue@1
|
500 function sIPWindowC: computes the total energy of truncated inner products between multiple frames of
|
xue@1
|
501 a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f.
|
xue@1
|
502
|
xue@1
|
503 In: x[L][N]: the spectrogram
|
xue@1
|
504 offst_rel: frame offset, relative to frame size
|
xue@1
|
505 f: reference frequency, in bins
|
xue@1
|
506 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
507 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
508 Out: lmd[L]: the actual individual inner products representing actual ampltiude-phase factors (optional)
|
xue@1
|
509
|
xue@1
|
510 Returns the energy of the vector of inner products.
|
xue@1
|
511 */
|
xue@1
|
512 double sIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, cdouble* lmd)
|
xue@1
|
513 {
|
xue@1
|
514 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
515 int K=K2-K1+1;
|
xue@1
|
516 cdouble *w=new cdouble[K];
|
xue@1
|
517 double Cr=0;
|
xue@1
|
518 cdouble Cc=0;
|
xue@1
|
519 Window(w, f, N, M, c, K1, K2);
|
xue@1
|
520 for (int l=0; l<L; l++)
|
xue@1
|
521 {
|
xue@1
|
522 cdouble *lx=&x[l][K1];
|
xue@1
|
523 cdouble r=Inner(K, lx, w);
|
xue@1
|
524 Cr+=~r;
|
xue@1
|
525 double ph=-4*M_PI*f*offst_rel*l;
|
xue@1
|
526 cdouble r2=r*r;
|
xue@1
|
527 Cc+=r2.rotate(ph);
|
xue@1
|
528 if (lmd) lmd[l]=r;
|
xue@1
|
529 }
|
xue@1
|
530 delete[] w;
|
xue@1
|
531 double result=0.5*iH2*(Cr+abs(Cc));
|
xue@1
|
532 if (lmd)
|
xue@1
|
533 {
|
xue@1
|
534 double absCc=abs(Cc), hiH2=0.5*iH2;
|
xue@1
|
535 cdouble ej2ph=Cc/absCc;
|
xue@1
|
536 for (int l=0; l<L; l++)
|
xue@1
|
537 {
|
xue@1
|
538 double ph=4*M_PI*f*offst_rel*l;
|
xue@1
|
539 lmd[l]=hiH2*(lmd[l]+(ej2ph**lmd[l]).rotate(ph));
|
xue@1
|
540 }
|
xue@1
|
541 }
|
xue@1
|
542 return result;
|
xue@1
|
543 }//sIPWindowC
|
xue@1
|
544 //wrapper function
|
xue@1
|
545 double sIPWindowC(double f, void* params)
|
xue@1
|
546 {
|
xue@1
|
547 struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double dipwindow; double ipwindow;} *p=(l_ip *)params;
|
xue@1
|
548 return sIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2);
|
xue@1
|
549 }//sIPWindowC
|
xue@1
|
550
|
Chris@5
|
551 /**
|
xue@1
|
552 function dsIPWindowC: computes the total energy of truncated inner products between multiple frames of
|
xue@1
|
553 a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f, together
|
xue@1
|
554 with its derivative.
|
xue@1
|
555
|
xue@1
|
556 In: x[L][N]: the spectrogram
|
xue@1
|
557 offst_rel: frame offset, relative to frame size
|
xue@1
|
558 f: reference frequency, in bins
|
xue@1
|
559 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
560 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
561 Out: sip: energy of the vector of the inner products
|
xue@1
|
562
|
xue@1
|
563 Returns the 1st derivative of the energy of the vector of inner products.
|
xue@1
|
564 */
|
xue@1
|
565 double dsIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& sip)
|
xue@1
|
566 {
|
xue@1
|
567 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
568 int K=K2-K1+1;
|
xue@1
|
569
|
xue@1
|
570 cdouble *w=new cdouble[K*2], *dw=&w[K];
|
xue@1
|
571 dWindow(dw, w, f, N, M, c, K1, K2);
|
xue@1
|
572 double Cr=0, dCr=0;
|
xue@1
|
573 cdouble Cc=0, dCc=0;
|
xue@1
|
574 for (int l=0; l<L; l++)
|
xue@1
|
575 {
|
xue@1
|
576 cdouble *lx=&x[l][K1];
|
xue@1
|
577 cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw);
|
xue@1
|
578 Cr+=~r; dCr+=2*(r.x*dr.x+r.y*dr.y);
|
xue@1
|
579 int two=2;
|
xue@1
|
580 cdouble r2=r*r, dr2=r*dr*two;
|
xue@1
|
581 double lag=-4*M_PI*offst_rel*l, ph=lag*f;
|
xue@1
|
582 Cc=Cc+cdouble(r2).rotate(ph), dCc=dCc+(dr2+cdouble(0,lag)*r2).rotate(ph);
|
xue@1
|
583 }
|
xue@1
|
584 double Cc2=~Cc, dCc2=2*(Cc.x*dCc.x+Cc.y*dCc.y);
|
xue@1
|
585 double Cc1=sqrt(Cc2), dCc1=dCc2/(2*Cc1);
|
xue@1
|
586 sip=0.5*iH2*(Cr+Cc1);
|
xue@1
|
587 double dsip=0.5*iH2*(dCr+dCc1);
|
xue@1
|
588 delete[] w;
|
xue@1
|
589 return dsip;
|
xue@1
|
590 }//dsIPWindowC
|
xue@1
|
591 //wrapper function
|
xue@1
|
592 double dsIPWindowC(double f, void* params)
|
xue@1
|
593 {
|
xue@1
|
594 struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double sip;} *p=(l_ip *)params;
|
xue@1
|
595 return dsIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->sip);
|
xue@1
|
596 }//dsIPWindowC
|
xue@1
|
597
|
Chris@5
|
598 /**
|
xue@1
|
599 function ddsIPWindowC: computes the total energy of truncated inner products between multiple frames
|
xue@1
|
600 of a spectrogram and multiple frames of a spectrogram of a sinusoid at a reference frequency f,
|
xue@1
|
601 together with its 1st and 2nd derivatives.
|
xue@1
|
602
|
xue@1
|
603 In: x[L][N]: the spectrogram
|
xue@1
|
604 offst_rel: frame offset, relative to frame size
|
xue@1
|
605 f: reference frequency, in bins
|
xue@1
|
606 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
607 K1, K2: spectrum truncation bounds, in bins, inclusive
|
xue@1
|
608 Out: sipwindow, dsipwindow: energy of the vector of the inner products and its derivative
|
xue@1
|
609
|
xue@1
|
610 Returns the 2nd derivative of the energy of the vector of inner products.
|
xue@1
|
611 */
|
xue@1
|
612 double ddsIPWindowC(double f, int L, double offst_rel, cdouble** x, int N, int M, double* c, double iH2, int K1, int K2, double& dsipwindow, double& sipwindow)
|
xue@1
|
613 {
|
xue@1
|
614 if (K1<0) K1=0; if (K2>=N/2) K2=N/2-1;
|
xue@1
|
615 int K=K2-K1+1;
|
xue@1
|
616
|
xue@1
|
617 cdouble *w=new cdouble[K*3], *dw=&w[K], *ddw=&w[K*2];
|
xue@1
|
618 ddWindow(ddw, dw, w, f, N, M, c, K1, K2);
|
xue@1
|
619 double Cr=0, dCr=0, ddCr=0;
|
xue@1
|
620 cdouble Cc=0, dCc=0, ddCc=0;
|
xue@1
|
621 for (int l=0; l<L; l++)
|
xue@1
|
622 {
|
xue@1
|
623 cdouble *lx=&x[l][K1];
|
xue@1
|
624 cdouble r=Inner(K, lx, w), dr=Inner(K, lx, dw), ddr=Inner(K, lx, ddw);
|
xue@1
|
625 Cr+=~r; dCr+=2*(r.x*dr.x+r.y*dr.y); ddCr+=2*(r.x*ddr.x+r.y*ddr.y+~dr);
|
xue@1
|
626 int two=2;
|
xue@1
|
627 cdouble r2=r*r, dr2=r*dr*two, ddr2=(dr*dr+r*ddr)*two;
|
xue@1
|
628 double lag=-4*M_PI*offst_rel*l, ph=lag*f;
|
xue@1
|
629 Cc=Cc+cdouble(r2).rotate(ph), dCc=dCc+(dr2+cdouble(0,lag)*r2).rotate(ph), ddCc=ddCc+(ddr2+cdouble(0,2*lag)*dr2-r2*lag*lag).rotate(ph);
|
xue@1
|
630 }
|
xue@1
|
631 double Cc2=~Cc, dCc2=2*(Cc.x*dCc.x+Cc.y*dCc.y), ddCc2=2*(Cc.x*ddCc.x+Cc.y*ddCc.y+~dCc);
|
xue@1
|
632 double Cc1=sqrt(Cc2), dCc1=dCc2/(2*Cc1), ddCc1=(Cc1*ddCc2-dCc2*dCc1)/(2*Cc2);
|
xue@1
|
633 sipwindow=0.5*iH2*(Cr+Cc1);
|
xue@1
|
634 dsipwindow=0.5*iH2*(dCr+dCc1);
|
xue@1
|
635 double ddsipwindow=0.5*iH2*(ddCr+ddCc1);
|
xue@1
|
636 delete[] w;
|
xue@1
|
637 return ddsipwindow;
|
xue@1
|
638 }//ddsIPWindowC
|
xue@1
|
639 //wrapper function
|
xue@1
|
640 double ddsIPWindowC(double f, void* params)
|
xue@1
|
641 {
|
xue@1
|
642 struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double dipwindow; double ipwindow;} *p=(l_ip *)params;
|
xue@1
|
643 return ddsIPWindowC(f, p->L, p->offst_rel, p->x, p->N, p->M, p->c, p->iH2, p->k1, p->k2, p->dipwindow, p->ipwindow);
|
xue@1
|
644 }//ddsIPWindowC
|
xue@1
|
645
|
xue@1
|
646 //--------------------------------------------------------------------------
|
xue@1
|
647 /*
|
xue@1
|
648 Least-square-error sinusoid detection function
|
xue@1
|
649
|
xue@1
|
650 version1: picking the highest peak and take measurement of a single sinusoid
|
xue@1
|
651 version2: given a rough peak location and take measurement of a single sinusoid
|
xue@1
|
652
|
xue@1
|
653 Complex spectrum x is calculated using N data points windowed by a window function that is specified
|
xue@1
|
654 by the parameter set (M, c, iH2). c[0:M] is provided according to Table 3 in the transfer report, on
|
xue@1
|
655 pp.11. iH2 is simply 1/H2, where H2 can be calculated using formula (2.17) on pp.12.
|
xue@1
|
656
|
xue@1
|
657 f & epf are given/returned in bins.
|
xue@1
|
658
|
xue@1
|
659 Further reading: "Least-square-error estimation of sinusoids.pdf"
|
xue@1
|
660 */
|
xue@1
|
661
|
Chris@5
|
662 /**
|
xue@1
|
663 function LSESinusoid: LSE estimation of the predominant stationary sinusoid.
|
xue@1
|
664
|
xue@1
|
665 In: x[N]: windowed spectrum
|
xue@1
|
666 B: spectral truncation half width, in bins.
|
xue@1
|
667 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
668 epf: frequency error tolerance, in bins
|
xue@1
|
669 Out: a and pp: amplitude and phase estimates
|
xue@1
|
670
|
xue@1
|
671 Returns the frequency estimate, in bins.
|
xue@1
|
672 */
|
xue@1
|
673 double LSESinusoid(cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf)
|
xue@1
|
674 {
|
xue@1
|
675 struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0}; //(l_hx *)¶ms;
|
Chris@3
|
676 int dfshift=offsetof(l_hx, dhxpeak);
|
xue@1
|
677
|
xue@1
|
678 int inp;
|
xue@1
|
679 double minp=0;
|
xue@1
|
680 for (int i=0; i<N; i++)
|
xue@1
|
681 {
|
xue@1
|
682 double lf=i, tmp;
|
xue@1
|
683 p.k1=ceil(lf-B); if (p.k1<0) p.k1=0;
|
xue@1
|
684 p.k2=floor(lf+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
|
xue@1
|
685 tmp=IPWindow(lf, &p);
|
xue@1
|
686 if (minp<tmp) inp=i, minp=tmp;
|
xue@1
|
687 }
|
xue@1
|
688
|
xue@1
|
689 double f=inp;
|
xue@1
|
690 p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
|
xue@1
|
691 p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
|
xue@1
|
692 double tmp=Newton(f, ddIPWindow, &p, dfshift, epf);
|
xue@1
|
693 if (tmp==-1)
|
xue@1
|
694 {
|
xue@1
|
695 Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf);
|
xue@1
|
696 }
|
xue@1
|
697 else
|
xue@1
|
698 a=p.hxpeak;
|
xue@1
|
699 pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
|
xue@1
|
700 return f;
|
xue@1
|
701 }//LSESinusoid
|
xue@1
|
702
|
xue@1
|
703 /*function LSESinusoid: LSE estimation of stationary sinusoid near a given initial frequency.
|
xue@1
|
704
|
xue@1
|
705 In: x[N]: windowed spectrum
|
xue@1
|
706 f: initial frequency, in bins
|
xue@1
|
707 B: spectral truncation half width, in bins.
|
xue@1
|
708 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
709 epf: frequency error tolerance, in bins
|
xue@1
|
710 Out: f, a and pp: frequency, amplitude and phase estimates
|
xue@1
|
711
|
xue@1
|
712 No return value.
|
xue@1
|
713 */
|
xue@1
|
714 void LSESinusoid(double& f, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf)
|
xue@1
|
715 {
|
xue@1
|
716 struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0};
|
Chris@3
|
717 int dfshift=offsetof(l_hx, dhxpeak);
|
xue@1
|
718
|
xue@1
|
719 double inp=f;
|
xue@1
|
720 p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
|
xue@1
|
721 p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
|
xue@1
|
722 double tmp=Newton(f, ddIPWindow, &p, dfshift, epf);
|
xue@1
|
723 if (tmp==-1)
|
xue@1
|
724 {
|
xue@1
|
725 Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf);
|
xue@1
|
726 }
|
xue@1
|
727 else
|
xue@1
|
728 a=p.hxpeak;
|
xue@1
|
729 pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
|
xue@1
|
730 }//LSESinusoid
|
xue@1
|
731
|
Chris@5
|
732 /**
|
xue@1
|
733 function LSESinusoid: LSE estimation of stationary sinusoid predominant within [f1, f2].
|
xue@1
|
734
|
xue@1
|
735 In: x[N]: windowed spectrum
|
xue@1
|
736 [f1, f2]: frequency range
|
xue@1
|
737 B: spectral truncation half width, in bins.
|
xue@1
|
738 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
739 epf: frequency error tolerance, in bins
|
xue@1
|
740 Out: a and pp: amplitude and phase estimates
|
xue@1
|
741
|
xue@1
|
742 Returns the frequency estimate, in bins.
|
xue@1
|
743 */
|
xue@1
|
744 double LSESinusoid(int f1, int f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf)
|
xue@1
|
745 {
|
xue@1
|
746 struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0};
|
Chris@3
|
747 int dfshift=offsetof(l_hx, dhxpeak);
|
xue@1
|
748
|
xue@1
|
749 int inp;
|
xue@1
|
750 double minp=0;
|
xue@1
|
751 for (int i=f1; i<f2; i++)
|
xue@1
|
752 {
|
xue@1
|
753 double lf=i, tmp;
|
xue@1
|
754 p.k1=ceil(lf-B); if (p.k1<0) p.k1=0;
|
xue@1
|
755 p.k2=floor(lf+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
|
xue@1
|
756 tmp=IPWindow(lf, &p);
|
xue@1
|
757 if (minp<tmp) inp=i, minp=tmp;
|
xue@1
|
758 }
|
xue@1
|
759
|
xue@1
|
760 double f=inp;
|
xue@1
|
761 p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
|
xue@1
|
762 p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
|
xue@1
|
763 double tmp=Newton(f, ddIPWindow, &p, dfshift, epf);
|
xue@1
|
764 if (tmp==-1)
|
xue@1
|
765 {
|
xue@1
|
766 Search1Dmax(f, &p, IPWindow, inp-1, inp+1, &a, epf);
|
xue@1
|
767 }
|
xue@1
|
768 else
|
xue@1
|
769 a=p.hxpeak;
|
xue@1
|
770 pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
|
xue@1
|
771 return f;
|
xue@1
|
772 }//LSESinusoid
|
xue@1
|
773
|
Chris@5
|
774 /**
|
xue@1
|
775 function LSESinusoid: LSE estimation of stationary sinusoid near a given initial frequency within [f1,
|
xue@1
|
776 f2].
|
xue@1
|
777
|
xue@1
|
778 In: x[N]: windowed spectrum
|
xue@1
|
779 f: initial frequency, in bins
|
xue@1
|
780 [f1, f2]: frequency range
|
xue@1
|
781 B: spectral truncation half width, in bins.
|
xue@1
|
782 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
783 epf: frequency error tolerance, in bins
|
xue@1
|
784 Out: f, a and pp: frequency, amplitude and phase estimates
|
xue@1
|
785
|
xue@1
|
786 Returns 1 if managed to find a sinusoid, 0 if not, upon which $a and $pp are estimated at the initial
|
xue@1
|
787 f.
|
xue@1
|
788 */
|
xue@1
|
789 int LSESinusoid(double& f, double f1, double f2, cdouble* x, int N, double B, int M, double* c, double iH2, double& a, double& pp, double epf)
|
xue@1
|
790 {
|
xue@1
|
791 struct l_hx {int N; int k1; int k2; int M; double* c; double iH2; cdouble* x; double dhxpeak; double hxpeak;} p={N, 0, 0, M, c, iH2, x, 0, 0};//(l_hx *)¶ms;
|
Chris@3
|
792 int dfshift=offsetof(l_hx, dhxpeak);
|
xue@1
|
793
|
xue@1
|
794 int result=0;
|
xue@1
|
795 double inp=f;
|
xue@1
|
796 p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
|
xue@1
|
797 p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
|
xue@1
|
798 double tmp=Newton(f, ddIPWindow, &p, dfshift, epf, 100, 1e-256, f1, f2);
|
xue@1
|
799 if (tmp!=-1 && f>f1 && f<f2)
|
xue@1
|
800 {
|
xue@1
|
801 result=1;
|
xue@1
|
802 a=p.hxpeak;
|
xue@1
|
803 pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
|
xue@1
|
804 }
|
xue@1
|
805 else
|
xue@1
|
806 {
|
xue@1
|
807 Search1DmaxEx(f, &p, IPWindow, f1, f2, &a, epf);
|
xue@1
|
808 if (f<=f1 || f>=f2)
|
xue@1
|
809 {
|
xue@1
|
810 f=inp;
|
xue@1
|
811 cdouble r=IPWindowC(f, x, N, M, c, iH2, p.k1, p.k2);
|
xue@1
|
812 a=abs(r);
|
xue@1
|
813 pp=arg(r);
|
xue@1
|
814 }
|
xue@1
|
815 else
|
xue@1
|
816 {
|
xue@1
|
817 result=1;
|
xue@1
|
818 pp=IPWindow(f, x, N, M, c, iH2, p.k1, p.k2, false);
|
xue@1
|
819 }
|
xue@1
|
820 }
|
xue@1
|
821 return result;
|
xue@1
|
822 }//LSESinusoid
|
xue@1
|
823
|
Chris@5
|
824 /**
|
xue@1
|
825 function LSESinusoidMP: LSE estimation of a stationary sinusoid from multi-frames spectrogram without
|
xue@1
|
826 considering phase-frequency consistency across frames.
|
xue@1
|
827
|
xue@1
|
828 In: x[Fr][N]: spectrogram
|
xue@1
|
829 f: initial frequency, in bins
|
xue@1
|
830 [f1, f2]: frequency range
|
xue@1
|
831 B: spectral truncation half width, in bins.
|
xue@1
|
832 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
833 epf: frequency error tolerance, in bins
|
xue@1
|
834 Out: f, a[Fr] and ph[Fr]: frequency, amplitudes and phase angles estimates
|
xue@1
|
835
|
xue@1
|
836 Returns an error bound of the frequency estimate.
|
xue@1
|
837 */
|
xue@1
|
838 double LSESinusoidMP(double& f, double f1, double f2, cdouble** x, int Fr, int N, double B, int M, double* c, double iH2, double* a, double* ph, double epf)
|
xue@1
|
839 {
|
xue@1
|
840 struct l_ip1 {int N; int k1; int k2; int M; double* c; double iH2; int L; cdouble** x; double dsip; double sip; cdouble* lmd;} p={N, 0, 0, M, c,iH2, Fr, x, 0, 0, 0};
|
Chris@3
|
841 int dfshift=offsetof(l_ip1, dsip), fshift=offsetof(l_ip1, sip);
|
xue@1
|
842
|
xue@1
|
843 double inp=f;
|
xue@1
|
844 p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
|
xue@1
|
845 p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
|
xue@1
|
846 double errf=Newton1dmax(f, f1, f2, ddsIPWindow, &p, dfshift, fshift, dsIPWindow, dfshift, epf);
|
xue@1
|
847 if (errf<0) errf=Search1Dmax(f, &p, sIPWindow, f1, f2, a, epf);
|
xue@1
|
848 if (a || ph)
|
xue@1
|
849 {
|
xue@1
|
850 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
851 {
|
xue@1
|
852 cdouble r=IPWindowC(f, x[fr], N, M, c, iH2, p.k1, p.k2);
|
xue@1
|
853 if (a) a[fr]=abs(r);
|
xue@1
|
854 if (ph) ph[fr]=arg(r);
|
xue@1
|
855 }
|
xue@1
|
856 }
|
xue@1
|
857 return errf;
|
xue@1
|
858 }//LSESinusoidMP
|
xue@1
|
859
|
Chris@5
|
860 /**
|
xue@1
|
861 function LSESinusoidMP: LSE estimation of a stationary sinusoid from multi-frames spectrogram without
|
xue@1
|
862 considering phase-frequency consistency across frames.
|
xue@1
|
863
|
xue@1
|
864 In: x[Fr][N]: spectrogram
|
xue@1
|
865 f: initial frequency, in bins
|
xue@1
|
866 [f1, f2]: frequency range
|
xue@1
|
867 B: spectral truncation half width, in bins.
|
xue@1
|
868 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
869 epf: frequency error tolerance, in bins
|
xue@1
|
870 Out: f, a[Fr] and ph[Fr]: frequency, amplitudes and phase angles estimates
|
xue@1
|
871
|
xue@1
|
872 Returns an error bound of the frequency estimate. Although the frequencies are estimated assuming
|
xue@1
|
873 cross-frame frequency-phase consistency, the final output phase angles are reestimated independently
|
xue@1
|
874 for each frame using the frequency estimate.
|
xue@1
|
875 */
|
xue@1
|
876 double LSESinusoidMPC(double& f, double f1, double f2, cdouble** x, int Fr, int N, int Offst, double B, int M, double* c, double iH2, double* a, double* ph, double epf)
|
xue@1
|
877 {
|
xue@1
|
878 struct l_ip {int N; int k1; int k2; int M; double* c; double iH2; int L; double offst_rel; cdouble** x; double sdip; double sip;}
|
xue@1
|
879 p={N, 0, 0, M, c,iH2, Fr, Offst*1.0/N, x, 0, 0};
|
Chris@3
|
880 int dfshift=offsetof(l_ip, sdip), fshift=offsetof(l_ip, sip);
|
xue@1
|
881
|
xue@1
|
882 double inp=f;
|
xue@1
|
883 p.k1=ceil(inp-B); if (p.k1<0) p.k1=0;
|
xue@1
|
884 p.k2=floor(inp+B); if (p.k2>=p.N/2) p.k2=p.N/2-1;
|
xue@1
|
885 double errf=Newton1dmax(f, f1, f2, ddsIPWindowC, &p, dfshift, fshift, dsIPWindowC, dfshift, epf);
|
xue@1
|
886 if (errf<0) errf=Search1Dmax(f, &p, sIPWindowC, f1, f2, a, epf);
|
xue@1
|
887 if (a || ph)
|
xue@1
|
888 {
|
xue@1
|
889 cdouble* lmd=new cdouble[Fr];
|
xue@1
|
890 sIPWindowC(f, Fr, Offst*1.0/N, x, N, M, c, iH2, p.k1, p.k2, lmd);
|
xue@1
|
891 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
892 {
|
xue@1
|
893 lmd[fr]=IPWindowC(f, x[fr], N, M, c, iH2, p.k1, p.k2);
|
xue@1
|
894
|
xue@1
|
895 if (a) a[fr]=abs(lmd[fr]);
|
xue@1
|
896 if (ph) ph[fr]=arg(lmd[fr]);
|
xue@1
|
897 }
|
xue@1
|
898 delete[] lmd;
|
xue@1
|
899 }
|
xue@1
|
900 return errf;
|
xue@1
|
901 }//LSESinusoidMPC
|
xue@1
|
902
|
xue@1
|
903 //---------------------------------------------------------------------------
|
Chris@5
|
904 /**
|
xue@1
|
905 function IPMulti: least square estimation of multiple sinusoids, given their frequencies and an energy
|
xue@1
|
906 suppression index of eps, i.e. the least square error is minimized with an additional eps*||lmd||^2
|
xue@1
|
907 term.
|
xue@1
|
908
|
xue@1
|
909 In: x[Wid]: spectrum
|
xue@1
|
910 f[I]: frequencies
|
xue@1
|
911 M, c[]: cosine-family window specification parameters
|
xue@1
|
912 K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored
|
xue@1
|
913 eps: energy suppression factor
|
xue@1
|
914 Out: lmd[I]: amplitude-phase factors
|
xue@1
|
915
|
xue@1
|
916 No return value.
|
xue@1
|
917 */
|
xue@1
|
918 void IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int K1, int K2, int M, double* c, double eps)
|
xue@1
|
919 {
|
xue@1
|
920 if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1;
|
xue@1
|
921 MList* List=new MList;
|
xue@1
|
922 cdouble** Allocate2L(cdouble, I, K, wt, List);
|
xue@1
|
923 for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2);
|
xue@1
|
924 cdouble** whw=MultiplyXcXt(I, K, wt, List);
|
xue@1
|
925 cdouble* whx=MultiplyXcy(I, K, wt, &x[K1], List);
|
xue@1
|
926 for (int i=0; i<I; i++) whw[i][i]+=eps;
|
xue@1
|
927 GECP(I, lmd, whw, whx);
|
xue@1
|
928 delete List;
|
xue@1
|
929 }//IPMulti
|
xue@1
|
930
|
Chris@5
|
931 /**
|
xue@1
|
932 function IPMulti: least square estimation of multiple sinusoids, given their frequencies and an energy
|
xue@1
|
933 suppression index of eps, and optionally returns residue and sensitivity indicators for each sinusoid.
|
xue@1
|
934
|
xue@1
|
935 In: x[Wid]: spectrum
|
xue@1
|
936 f[I]: frequencies
|
xue@1
|
937 M, c[]: cosine-family window specification parameters
|
xue@1
|
938 K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored
|
xue@1
|
939 eps: energy suppression factor
|
xue@1
|
940 Out: lmd[I]: amplitude-phase factors
|
xue@1
|
941 sens[I]: sensitivity indicators
|
xue@1
|
942 r1[I]: residue indicators, measured by correlating residue with sinusoid spectra, optional
|
xue@1
|
943
|
xue@1
|
944 No return value. Sensibitily is computed BEFORE applying eps.
|
xue@1
|
945 */
|
xue@1
|
946 void IPMulti(int I, double* f, cdouble* lmd, cfloat* x, int Wid, int K1, int K2, int M, double* c, double eps, double* sens, double* r1)
|
xue@1
|
947 {
|
xue@1
|
948 if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1;
|
xue@1
|
949 MList* List=new MList;
|
xue@1
|
950 cdouble** Allocate2L(cdouble, I, K, wt, List);
|
xue@1
|
951 for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2);
|
xue@1
|
952 cdouble** whw=MultiplyXcXt(I, K, wt, List);
|
xue@1
|
953
|
xue@1
|
954 //*computes sensitivity if required
|
xue@1
|
955 if (sens)
|
xue@1
|
956 {
|
xue@1
|
957 cdouble** iwhw=Copy(I, whw, List);
|
xue@1
|
958 GICP(I, iwhw);
|
xue@1
|
959 cdouble** u=MultiplyXYc(I, I, K, iwhw, wt, List);
|
xue@1
|
960 for (int i=0; i<I; i++)
|
xue@1
|
961 {
|
xue@1
|
962 sens[i]=0; for (int k=0; k<K; k++) sens[i]+=~u[i][k]; sens[i]=sqrt(sens[i]);
|
xue@1
|
963 }
|
xue@1
|
964 } //*/
|
xue@1
|
965 cdouble* whx=MultiplyXcy(I, K, wt, &x[K1], List);
|
xue@1
|
966 for (int i=0; i<I; i++) whw[i][i]+=eps;
|
xue@1
|
967 GECP(I, lmd, whw, whx);
|
xue@1
|
968 //compute residue if required
|
xue@1
|
969 if (r1)
|
xue@1
|
970 {
|
xue@1
|
971 cdouble* wlmd=MultiplyXty(K, I, wt, lmd, List); //reconstruct
|
xue@1
|
972 for (int k=0; k<K; k++) wlmd[k]=wlmd[k]-x[K1+k]; //-residue
|
xue@1
|
973 for (int i=0; i<I; i++) //r1[i]=Inner(K, wlmd, wt[i]).abs(); //-residue weighted by window
|
xue@1
|
974 {
|
xue@1
|
975 r1[i]=0;
|
xue@1
|
976 for (int k=0; k<K; k++) r1[i]+=abs(wlmd[k])*abs(wt[i][k]);
|
xue@1
|
977 }
|
xue@1
|
978 }
|
xue@1
|
979 delete List;
|
xue@1
|
980 }//IPMulti
|
xue@1
|
981
|
Chris@5
|
982 /**
|
xue@1
|
983 function IPMultiSens: computes the sensitivity of the least square estimation of multiple sinusoids given
|
xue@1
|
984 their frequencies .
|
xue@1
|
985
|
xue@1
|
986 In: f[I]: frequencies
|
xue@1
|
987 M, c[]: cosine-family window specification parameters
|
xue@1
|
988 K1, K2: spectral truncation range, i.e. bins outside [K1, K2] are ignored
|
xue@1
|
989 eps: energy suppression factor
|
xue@1
|
990 Out: sens[I]: sensitivity indicators
|
xue@1
|
991
|
xue@1
|
992 No return value. Sensibility is computed AFTER applying eps
|
xue@1
|
993 */
|
xue@1
|
994 void IPMultiSens(int I, double* f, int Wid, int K1, int K2, int M, double* c, double* sens, double eps)
|
xue@1
|
995 {
|
xue@1
|
996 if (K1<0) K1=0; if (K2>=Wid/2) K2=Wid/2-1; int K=K2-K1+1;
|
xue@1
|
997 MList* List=new MList;
|
xue@1
|
998 cdouble** Allocate2L(cdouble, I, K, wt, List);
|
xue@1
|
999 for (int i=0; i<I; i++) Window(wt[i], f[i], Wid, M, c, K1, K2);
|
xue@1
|
1000
|
xue@1
|
1001 cdouble** whw=MultiplyXcXt(I, K, wt, List);
|
xue@1
|
1002 for (int i=0; i<I; i++) whw[i][i]+=eps;
|
xue@1
|
1003
|
xue@1
|
1004 cdouble** iwhw=Copy(I, whw, List);
|
xue@1
|
1005 GICP(I, iwhw);
|
xue@1
|
1006 cdouble** u=MultiplyXYc(I, I, K, iwhw, wt, List);
|
xue@1
|
1007 for (int i=0; i<I; i++)
|
xue@1
|
1008 {
|
xue@1
|
1009 sens[i]=0; for (int k=0; k<K; k++) sens[i]+=~u[i][k]; sens[i]=sqrt(sens[i]);
|
xue@1
|
1010 }
|
xue@1
|
1011 delete List;
|
xue@1
|
1012 }//IPMultiSens
|
xue@1
|
1013
|
Chris@5
|
1014 /**
|
xue@1
|
1015 function IPMulti: least square estimation of multi-sinusoids with GIVEN frequencies. This version
|
xue@1
|
1016 operates in groups at least B bins from each other, rather than LSE all frequencies together.
|
xue@1
|
1017
|
xue@1
|
1018 In: x[Wid]: spectrum
|
xue@1
|
1019 f[I]: frequencies, must be ordered low to high.
|
xue@1
|
1020 B: number of bins beyond which sinusoids are treated as non-interfering
|
xue@1
|
1021 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
1022 Out: lmd[I]: amplitude-phase factors
|
xue@1
|
1023
|
xue@1
|
1024 Returns 0.
|
xue@1
|
1025 */
|
xue@1
|
1026 double IPMulti(int I, double* f, cdouble* lmd, cdouble* x, int Wid, int M, double* c, double iH2, int B)
|
xue@1
|
1027 {
|
xue@1
|
1028 int i=0, ist=0;
|
xue@1
|
1029 double Bw=B;
|
xue@1
|
1030 while (i<I)
|
xue@1
|
1031 {
|
xue@1
|
1032 if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1)
|
xue@1
|
1033 {
|
xue@1
|
1034 if (i==I-1) i++;
|
xue@1
|
1035 //process frequencies from ist to i-1
|
xue@1
|
1036 if (i-1==ist) //one sinusoid
|
xue@1
|
1037 {
|
xue@1
|
1038 double fb=f[ist]; int K1=floor(fb-B+0.5), K2=floor(fb+B+0.5);
|
xue@1
|
1039 lmd[ist]=IPWindowC(fb, x, Wid, M, c, iH2, K1, K2);
|
xue@1
|
1040 }
|
xue@1
|
1041 else
|
xue@1
|
1042 {
|
xue@1
|
1043 MList* List=new MList;
|
xue@1
|
1044 int N=i-ist, K1=floor(f[ist]-B+0.5), K2=floor(f[i-1]+B+0.5), K=K2-K1+1;
|
xue@1
|
1045 cdouble** Allocate2L(cdouble, N, K, wt, List);
|
xue@1
|
1046 for (int n=0; n<N; n++) Window(wt[n], f[ist+n], Wid, M, c, K1, K2);
|
xue@1
|
1047 cdouble* whx=MultiplyXcy(N, K, wt, &x[K1], List); //w*'x=(wt*)x
|
xue@1
|
1048 cdouble** whw=MultiplyXcXt(N, K, wt, List);
|
xue@1
|
1049 /*debug cdouble** C=SubMatrix(0, whw, 1, 4, 1, 4, List); cdouble** C2=SubMatrix(0, whw, 1, 4, 1, 4, List); cdouble** Bh=SubMatrix(0, whw, 1, 4, 0, 1, List); cdouble* Y2=SubVector(0, whx, 1, 4);
|
xue@1
|
1050 cdouble x2[4]; cdouble x1=lmd[ist], Bhx1[4], dx2[4]; for (int j=0; j<4; j++) Bhx1[j]=x1^Bh[j][0]; GECP(4, x2, C, Y2); GECP(4, dx2, C2, Bhx1);*/
|
xue@1
|
1051 GECP(N, &lmd[ist], whw, whx); //solving complex linear system (w*'w)a=w*'x
|
xue@1
|
1052 delete List;
|
xue@1
|
1053 }
|
xue@1
|
1054 ist=i;
|
xue@1
|
1055 }
|
xue@1
|
1056 i++;
|
xue@1
|
1057 }
|
xue@1
|
1058 return 0;
|
xue@1
|
1059 }//IPMulti
|
xue@1
|
1060
|
Chris@5
|
1061 /**
|
xue@1
|
1062 function IPMulti_Direct: LSE estimation of multiple sinusoids given frequencies AND PHASES (direct
|
xue@1
|
1063 method)
|
xue@1
|
1064
|
xue@1
|
1065 In: x[Wid]: spectrum
|
xue@1
|
1066 f[I], ph[I]: frequencies and phase angles.
|
xue@1
|
1067 B: spectral truncation half width, in bins; sinusoids over 3B bins apart are regarded non-interfering
|
xue@1
|
1068 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
1069 Out: a[I]: amplitudes
|
xue@1
|
1070
|
xue@1
|
1071 Returns square norm of the residue.
|
xue@1
|
1072 */
|
xue@1
|
1073 double IPMulti_Direct(int I, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, double iH2, int B)
|
xue@1
|
1074 {
|
xue@1
|
1075 MList* List=new MList;
|
xue@1
|
1076 int i=0, ist=0, hWid=Wid/2;
|
xue@1
|
1077 cdouble* r=Copy(hWid, x, List); //to store the residue
|
xue@1
|
1078
|
xue@1
|
1079 double Bw=3.0*B;
|
xue@1
|
1080 while (i<I)
|
xue@1
|
1081 {
|
xue@1
|
1082 if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1)
|
xue@1
|
1083 {
|
xue@1
|
1084 if (i==I-1) i++;
|
xue@1
|
1085
|
xue@1
|
1086 //process frequencies from ist to i-1
|
xue@1
|
1087 if (i-1==ist) //one sinusoid
|
xue@1
|
1088 {
|
xue@1
|
1089 double fb=f[ist];
|
xue@1
|
1090 cdouble* w=Window(0, fb, Wid, M, c, 0, hWid-1);
|
xue@1
|
1091 for (int k=0; k<hWid; k++) w[k].rotate(ph[ist]);
|
xue@1
|
1092 double ip=Inner(2*hWid, (double*)x, (double*)w);
|
xue@1
|
1093 a[ist]=ip*iH2;
|
xue@1
|
1094 MultiAdd(hWid, r, r, w, -a[ist]);
|
xue@1
|
1095 delete[] w;
|
xue@1
|
1096 }
|
xue@1
|
1097 else
|
xue@1
|
1098 {
|
xue@1
|
1099 int N=i-ist;
|
xue@1
|
1100 cdouble** Allocate2L(cdouble, N, hWid, wt, List);
|
xue@1
|
1101 for (int n=0; n<N; n++)
|
xue@1
|
1102 {
|
xue@1
|
1103 Window(wt[n], f[ist+n], Wid, M, c, 0, hWid-1);
|
xue@1
|
1104 for (int k=0; k<hWid; k++) wt[n][k].rotate(ph[ist+n]);
|
xue@1
|
1105 }
|
xue@1
|
1106 double* whxr=MultiplyXy(N, hWid*2, (double**)wt, (double*)x, List); //w*'x=(wt*)x
|
xue@1
|
1107 double** whwr=MultiplyXXt(N, hWid*2, (double**)wt, List);
|
xue@1
|
1108 GECP(N, &a[ist], whwr, whxr); //solving complex linear system (w*'w)a=w*'x
|
xue@1
|
1109 for (int n=0; n<N; n++) MultiAdd(hWid, r, r, wt[n], -a[ist+n]);
|
xue@1
|
1110 }
|
xue@1
|
1111 ist=i;
|
xue@1
|
1112 }
|
xue@1
|
1113 i++;
|
xue@1
|
1114 }
|
xue@1
|
1115 double result=Inner(hWid, r, r).x;
|
xue@1
|
1116 delete List;
|
xue@1
|
1117 return result;
|
xue@1
|
1118 }//IPMulti_Direct
|
xue@1
|
1119
|
Chris@5
|
1120 /**
|
xue@1
|
1121 function IPMulti_GS: LSE estimation of multiple sinusoids given frequencies AND PHASES (Gram-Schmidt method)
|
xue@1
|
1122
|
xue@1
|
1123 In: x[Wid]: spectrum
|
xue@1
|
1124 f[I], ph[I]: frequencies and phase angles.
|
xue@1
|
1125 B: spectral truncation, in bins; sinusoids over 3B bins apart are regarded non-interfering
|
xue@1
|
1126 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
1127 Out: a[I]: amplitudes
|
xue@1
|
1128
|
xue@1
|
1129 Returns square norm of the residue.
|
xue@1
|
1130 */
|
xue@1
|
1131 double IPMulti_GS(int I, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, double iH2, int B, double** L, double** Q)
|
xue@1
|
1132 {
|
xue@1
|
1133 MList* List=new MList;
|
xue@1
|
1134 int i=0, ist=0, hWid=Wid/2;
|
xue@1
|
1135 cdouble* r=Copy(hWid, x, List); //to store the residue
|
xue@1
|
1136 double Bw=3.0*B;
|
xue@1
|
1137 while (i<I)
|
xue@1
|
1138 {
|
xue@1
|
1139 if ((i>0 && f[i]-f[i-1]>Bw) || i==I-1)
|
xue@1
|
1140 {
|
xue@1
|
1141 if (i==I-1) i++;
|
xue@1
|
1142
|
xue@1
|
1143 //process frequencies from ist to i-1
|
xue@1
|
1144 if (i-1==ist) //one sinusoid
|
xue@1
|
1145 {
|
xue@1
|
1146 double fb=f[ist];
|
xue@1
|
1147 cdouble* w=Window(0, fb, Wid, M, c, 0, hWid-1);
|
xue@1
|
1148 for (int k=0; k<hWid; k++) w[k].rotate(ph[ist]);
|
xue@1
|
1149 double ip=Inner(2*hWid, (double*)x, (double*)w);
|
xue@1
|
1150 a[ist]=ip*iH2;
|
xue@1
|
1151 MultiAdd(hWid, r, r, w, -a[ist]);
|
xue@1
|
1152 delete[] w;
|
xue@1
|
1153 }
|
xue@1
|
1154 else
|
xue@1
|
1155 {
|
xue@1
|
1156 int N=i-ist;
|
xue@1
|
1157 cdouble** Allocate2L(cdouble, N, hWid, wt, List);
|
xue@1
|
1158 Alloc2L(N, N, L, List); Alloc2L(N, hWid*2, Q, List);
|
xue@1
|
1159 for (int n=0; n<N; n++)
|
xue@1
|
1160 {
|
xue@1
|
1161 Window(wt[n], f[ist+n], Wid, M, c, 0, hWid-1);
|
xue@1
|
1162 for (int k=0; k<hWid; k++) wt[n][k].rotate(ph[ist+n]);
|
xue@1
|
1163 }
|
xue@1
|
1164 LQ_GS(N, hWid*2, (double**)wt, L, Q);
|
xue@1
|
1165 double* atl=MultiplyxYt(N, hWid*2, (double*)x, Q, List);
|
xue@1
|
1166 GExL(N, &a[ist], L, atl);
|
xue@1
|
1167 for (int n=0; n<N; n++) MultiAdd(hWid, r, r, wt[n], -a[ist+n]);
|
xue@1
|
1168 }
|
xue@1
|
1169 ist=i;
|
xue@1
|
1170 }
|
xue@1
|
1171 i++;
|
xue@1
|
1172 }
|
xue@1
|
1173 double result=Inner(hWid, r, r).x;
|
xue@1
|
1174 delete List;
|
xue@1
|
1175 return result;
|
xue@1
|
1176 }//IPMulti_GS
|
xue@1
|
1177
|
Chris@5
|
1178 /**
|
xue@1
|
1179 function IPMulti: LSE estimation of I sinusoids given frequency and phase and J sinusoids given
|
xue@1
|
1180 frequency only
|
xue@1
|
1181
|
xue@1
|
1182 In: x[Wid]: spectrum
|
xue@1
|
1183 f[I+J], ph[I]: frequencies and phase angles
|
xue@1
|
1184 M, c[], iH2: cosine-family window specification parameters
|
xue@1
|
1185 Out: a[I+J]: amplitudes
|
xue@1
|
1186 ph[I:I+J-1]: phase angles not given on start
|
xue@1
|
1187 wt[I+2J][hWid], Q[I+2J][hWid], L[I+2J][I+2J]: internal w matrix and its LQ factorization, optional
|
xue@1
|
1188
|
xue@1
|
1189 Returns the residue vector, newly created and registered to RetList, if specified. On start a[] should
|
xue@1
|
1190 have valid storage no less than I+2J.
|
xue@1
|
1191 */
|
xue@1
|
1192 cdouble* IPMulti(int I, int J, double* f, double* ph, double* a, cdouble* x, int Wid, int M, double* c, cdouble** wt, cdouble** Q, double** L, MList* RetList)
|
xue@1
|
1193 {
|
xue@1
|
1194 MList* List=new MList;
|
xue@1
|
1195 int hWid=Wid/2;
|
xue@1
|
1196 cdouble* r=Copy(hWid, x, RetList); //to store the residue
|
xue@1
|
1197 if (!wt){Allocate2L(cdouble, I+J*2, hWid, wt, List);}
|
xue@1
|
1198 if (!Q){Allocate2L(cdouble, I+J*2, hWid, Q, List);}
|
xue@1
|
1199 if (!L){Allocate2L(double, I+J*2, I+J*2, L, List);}
|
xue@1
|
1200 memset(wt[0], 0, sizeof(cdouble)*(I+J*2)*hWid);
|
xue@1
|
1201 memset(Q[0], 0, sizeof(cdouble)*(I+J*2)*hWid);
|
xue@1
|
1202 memset(L[0], 0, sizeof(double)*(I+J*2)*(I+J*2));
|
xue@1
|
1203
|
xue@1
|
1204 //*The direct form
|
xue@1
|
1205 for (int i=0; i<I; i++)
|
xue@1
|
1206 {
|
xue@1
|
1207 Window(wt[i], f[i], Wid, M, c, 0, hWid-1);
|
xue@1
|
1208 for (int k=0; k<hWid; k++) wt[i][k].rotate(ph[i]);
|
xue@1
|
1209 }
|
xue@1
|
1210 for (int j=0; j<J; j++)
|
xue@1
|
1211 {
|
xue@1
|
1212 cdouble *w1=wt[I+j*2], *w2=wt[I+j*2+1];
|
xue@1
|
1213 Window(w1, f[I+j], Wid, M, c, 0, hWid-1);
|
xue@1
|
1214 for (int k=0; k<hWid; k++) w2[k].y=w1[k].x, w2[k].x=-w1[k].y;
|
xue@1
|
1215 }
|
xue@1
|
1216
|
xue@1
|
1217 LQ_GS(I+J*2, hWid*2, (double**)wt, L, (double**)Q);
|
xue@1
|
1218 double *atl=MultiplyxYt(I+J*2, hWid*2, (double*)x, (double**)Q, List);
|
xue@1
|
1219 GExL(I+J*2, a, L, atl);
|
xue@1
|
1220
|
xue@1
|
1221 for (int i=0; i<I+J*2; i++) MultiAdd(hWid, r, r, wt[i], -a[i]);
|
xue@1
|
1222 for (int j=0; j<J; j++)
|
xue@1
|
1223 {
|
xue@1
|
1224 double xx=a[I+j*2], yy=a[I+j*2+1];
|
xue@1
|
1225 a[I+j]=sqrt(xx*xx+yy*yy);
|
xue@1
|
1226 ph[I+j]=atan2(yy, xx);
|
xue@1
|
1227 }
|
xue@1
|
1228 delete List;
|
xue@1
|
1229 return r;
|
xue@1
|
1230 }//IPMulti
|
xue@1
|
1231
|
xue@1
|
1232 //---------------------------------------------------------------------------
|
xue@1
|
1233 /*
|
xue@1
|
1234 Routines for estimation two sinusoids with 1 fixed and 1 flexible frequency
|
xue@1
|
1235
|
xue@1
|
1236 Further reading: "LSE estimation for 2 sinusoids with 1 at a fixed frequency.pdf"
|
xue@1
|
1237 */
|
xue@1
|
1238
|
Chris@5
|
1239 /**
|
xue@1
|
1240 function WindowDuo: calcualtes the square norm of the inner product between windowed spectra of two
|
xue@1
|
1241 sinusoids at frequencies f1 and f2, df=f1-f2.
|
xue@1
|
1242
|
xue@1
|
1243 In: df: frequency difference, in bins
|
xue@1
|
1244 N: DFT size
|
xue@1
|
1245 M, d[]: cosine-family window specification parameters (see "further reading").
|
xue@1
|
1246 Out: w[0], the inner product, optional
|
xue@1
|
1247
|
xue@1
|
1248 Returns square norm of the inner product.
|
xue@1
|
1249 */
|
xue@1
|
1250 double WindowDuo(double df, int N, double* d, int M, cdouble* w)
|
xue@1
|
1251 {
|
xue@1
|
1252 double wr=0, wi=0;
|
xue@1
|
1253 for (int m=-2*M; m<=2*M; m++)
|
xue@1
|
1254 {
|
xue@1
|
1255 double ang=df+m, Omg=ang*M_PI, omg=Omg/N;
|
xue@1
|
1256 double si=sin(omg), co=cos(omg), sinn=sin(Omg);
|
xue@1
|
1257 double sa=(ang==0)?N:(sinn/si);
|
xue@1
|
1258 double dm; if (m<0) dm=d[-m]; else dm=d[m];
|
xue@1
|
1259 wr+=dm*sa*co, wi+=-dm*sinn;
|
xue@1
|
1260 }
|
xue@1
|
1261 wr*=N, wi*=N;
|
xue@1
|
1262 if (w) w->x=wr, w->y=wi;
|
xue@1
|
1263 double result=wr*wr+wi*wi;
|
xue@1
|
1264 return result;
|
xue@1
|
1265 }//WindowDuo
|
xue@1
|
1266
|
Chris@5
|
1267 /**
|
xue@1
|
1268 function ddWindowDuo: calcualtes the square norm of the inner product between windowed spectra of two
|
xue@1
|
1269 sinusoids at frequencies f1 and f2, df=f1-f2, with its 1st and 2nd derivatives
|
xue@1
|
1270
|
xue@1
|
1271 In: df: frequency difference, in bins
|
xue@1
|
1272 N: DFT size
|
xue@1
|
1273 M, d[]: cosine-family window specification parameters (see "further reading" for d[]).
|
xue@1
|
1274 Out: w[0], the inner product, optional
|
xue@1
|
1275 window, dwindow: square norm and its derivative, of the inner product
|
xue@1
|
1276
|
xue@1
|
1277 Returns 2nd derivative of the square norm of the inner product.
|
xue@1
|
1278 */
|
xue@1
|
1279 double ddWindowDuo(double df, int N, double* d, int M, double& dwindow, double& window, cdouble* w)
|
xue@1
|
1280 {
|
xue@1
|
1281 double wr=0, wi=0, dwr=0, dwi=0, ddwr=0, ddwi=0, PI_N=M_PI/N, PIPI_N=PI_N*M_PI, PIPI=M_PI*M_PI;
|
xue@1
|
1282 for (int m=-2*M; m<=2*M; m++)
|
xue@1
|
1283 {
|
xue@1
|
1284 double ang=df+m, Omg=ang*M_PI, omg=Omg/N;
|
xue@1
|
1285 double si=sin(omg), co=cos(omg), sinn=sin(Omg), cosn=cos(Omg);
|
xue@1
|
1286 double sa=(ang==0)?N:(sinn/si), dsa=dsincd_unn(ang, N), ddsa=ddsincd_unn(ang, N);
|
xue@1
|
1287 double dm; if (m<0) dm=d[-m]; else dm=d[m];
|
xue@1
|
1288 wr+=dm*sa*co, wi+=-dm*sinn;
|
xue@1
|
1289 dwr+=dm*(dsa*co-PI_N*sinn), dwi+=-dm*M_PI*cosn;
|
xue@1
|
1290 ddwr+=dm*(ddsa*co-PI_N*dsa*si-PIPI_N*cosn), ddwi+=dm*PIPI*sinn;
|
xue@1
|
1291 }
|
xue@1
|
1292 wr*=N, wi*=N, dwr*=N, dwi*=N, ddwr*=N, ddwi*=N;
|
xue@1
|
1293 window=wr*wr+wi*wi;
|
xue@1
|
1294 dwindow=2*(wr*dwr+wi*dwi);
|
xue@1
|
1295 if (w) w->x=wr, w->y=wi;
|
xue@1
|
1296 double ddwindow=2*(wr*ddwr+dwr*dwr+wi*ddwi+dwi*dwi);
|
xue@1
|
1297 return ddwindow;
|
xue@1
|
1298 }//ddWindowDuo
|
xue@1
|
1299
|
Chris@5
|
1300 /**
|
xue@1
|
1301 function sIPWindowDuo: calculates the square norm of the orthogonal projection of a windowed spectrum
|
xue@1
|
1302 onto the linear span of the windowed spectra of two sinusoids at reference frequencies f1 and f2.
|
xue@1
|
1303
|
xue@1
|
1304 In: x[N]: spectrum
|
xue@1
|
1305 f1, f2: reference frequencies.
|
xue@1
|
1306 M, c[], d[], iH2: cosine-family window specification parameters.
|
xue@1
|
1307 K1, K2: spectrum truncation range, i.e. bins outside [K1, K2] are ignored.
|
xue@1
|
1308 Out: lmd1, lmd2: projection coefficients, interpreted as actual amplitude-phase factors
|
xue@1
|
1309
|
xue@1
|
1310 Returns the square norm of the orthogonal projection.
|
xue@1
|
1311 */
|
xue@1
|
1312 double sIPWindowDuo(double f1, double f2, cdouble* x, int N, double* c, double* d, int M, double iH2, int K1, int K2, cdouble& lmd1, cdouble& lmd2)
|
xue@1
|
1313 {
|
xue@1
|
1314 int K=K2-K1+1;
|
xue@1
|
1315 cdouble xw1=0, *lx=&x[K1], *w1=new cdouble[K*2], *r1=&w1[K];
|
xue@1
|
1316 Window(w1, f1, N, M, c, K1, K2);
|
xue@1
|
1317 double w1w1=0;
|
xue@1
|
1318 for (int k=0; k<K; k++) xw1+=(lx[k]^w1[k]), w1w1+=~w1[k]; cdouble mu1=xw1/w1w1;
|
xue@1
|
1319 for (int k=0; k<K; k++) r1[k]=lx[k]-mu1*w1[k];
|
xue@1
|
1320 Window(w1, f2, N, M, c, K1, K2);
|
xue@1
|
1321 cdouble r1w2=0, w12; for (int k=0; k<K; k++) r1w2+=(r1[k]^w1[k]);
|
xue@1
|
1322 double w=WindowDuo(f1-f2, N, d, M, &w12);
|
xue@1
|
1323 double v=1.0/iH2-w*iH2;
|
xue@1
|
1324 double result=~xw1/w1w1+~r1w2/v;
|
xue@1
|
1325 cdouble mu2=r1w2/v;
|
xue@1
|
1326 lmd2=mu2; lmd1=mu1-(mu2^w12)*iH2;
|
xue@1
|
1327 delete[] w1;
|
xue@1
|
1328 return result;
|
xue@1
|
1329 }//sIPWindowDuo
|
xue@1
|
1330 //wrapper function
|
xue@1
|
1331 double sIPWindowDuo(double f2, void* params)
|
xue@1
|
1332 {
|
xue@1
|
1333 struct l_ip {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} *p=(l_ip *)params;
|
xue@1
|
1334 cdouble r1, r2;
|
xue@1
|
1335 return sIPWindowDuo(p->f1, f2, p->x, p->N, p->c, p->d, p->M, p->iH2, p->k1, p->k2, r1, r2);
|
xue@1
|
1336 }//sIPWindowDuo
|
xue@1
|
1337
|
Chris@5
|
1338 /**
|
xue@1
|
1339 function ddsIPWindowDuo: calculates the square norm, and its 1st and 2nd derivatives against f2,, of
|
xue@1
|
1340 the orthogonal projection of a windowed spectrum onto the linear span of the windowed spectra of two
|
xue@1
|
1341 sinusoids at reference frequencies f1 and f2.
|
xue@1
|
1342
|
xue@1
|
1343 In: x[N]: spectrum
|
xue@1
|
1344 f1, f2: reference frequencies.
|
xue@1
|
1345 M, c[], d[], iH2: cosine-family window specification parameters.
|
xue@1
|
1346 K1, K2: spectrum truncation range, i.e. bins outside [K1, K2] are ignored.
|
xue@1
|
1347
|
xue@1
|
1348 Out: lmd1, lmd2: projection coefficients, interpreted as actual amplitude-phase factors
|
xue@1
|
1349 ddsip[3]: the 2nd, 1st and 0th derivatives (against f2) of the square norm.
|
xue@1
|
1350
|
xue@1
|
1351 No return value.
|
xue@1
|
1352 */
|
xue@1
|
1353 void ddsIPWindowDuo(double* ddsip2, double f1, double f2, cdouble* x, int N, double* c, double* d, int M, double iH2, int K1, int K2, cdouble& lmd1, cdouble& lmd2)
|
xue@1
|
1354 {
|
xue@1
|
1355 int K=K2-K1+1;
|
xue@1
|
1356 cdouble xw1=0, *lx=&x[K1], *w1=new cdouble[K*2], *r1=&w1[K];
|
xue@1
|
1357 Window(w1, f1, N, M, c, K1, K2);
|
xue@1
|
1358 double w1w1=0;
|
xue@1
|
1359 for (int k=0; k<K; k++) xw1+=(lx[k]^w1[k]), w1w1+=~w1[k]; cdouble mu1=xw1/w1w1;
|
xue@1
|
1360 for (int k=0; k<K; k++) r1[k]=lx[k]-mu1*w1[k];
|
xue@1
|
1361
|
xue@1
|
1362 cdouble r1w2, w12;
|
xue@1
|
1363 double u, du, ddu=ddsIPWindow_unn(f2, &r1[-K1], N, M, c, K1, K2, du, u, &r1w2);
|
xue@1
|
1364 double w, dw, ddw=ddWindowDuo(f1-f2, N, d, M, dw, w, &w12); dw=-dw;
|
xue@1
|
1365 double v=1.0/iH2-w*iH2, dv=-iH2*dw, ddv=-iH2*ddw;
|
xue@1
|
1366 double iv=1.0/v;//, div=-dv*iv*iv, ddiv=(2*dv*dv-v*ddv)*iv*iv*iv;
|
xue@1
|
1367
|
xue@1
|
1368 ddsip2[2]=~xw1/w1w1+u*iv;
|
xue@1
|
1369 ddsip2[1]=iv*(du-iv*u*dv);
|
xue@1
|
1370 ddsip2[0]=iv*(ddu-iv*(u*ddv+2*du*dv-2*iv*u*dv*dv));
|
xue@1
|
1371
|
xue@1
|
1372 cdouble mu2=r1w2*iv;
|
xue@1
|
1373 lmd2=mu2; lmd1=mu1-(mu2^w12)*iH2;
|
xue@1
|
1374
|
xue@1
|
1375 delete[] w1;
|
xue@1
|
1376 }//ddsIPWindowDuo
|
xue@1
|
1377 //wrapper function
|
xue@1
|
1378 double ddsIPWindowDuo(double f2, void* params)
|
xue@1
|
1379 {
|
xue@1
|
1380 struct l_ip {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} *p=(l_ip *)params;
|
xue@1
|
1381 double ddsip2[3]; cdouble r1, r2;
|
xue@1
|
1382 ddsIPWindowDuo(ddsip2, p->f1, f2, p->x, p->N, p->c, p->d, p->M, p->iH2, p->k1, p->k2, r1, r2);
|
xue@1
|
1383 p->dipwindow=ddsip2[1], p->ipwindow=ddsip2[2];
|
xue@1
|
1384 return ddsip2[0];
|
xue@1
|
1385 }//ddsIPWindowDuo
|
xue@1
|
1386
|
Chris@5
|
1387 /**
|
xue@1
|
1388 function LSEDuo: least-square estimation of two sinusoids of which one has a fixed frequency
|
xue@1
|
1389
|
xue@1
|
1390 In: x[N]: the windowed spectrum
|
xue@1
|
1391 f1: the fixed frequency
|
xue@1
|
1392 f2: initial value of the flexible frequency
|
xue@1
|
1393 fmin, fmax: search range for f2, the flexible frequency
|
xue@1
|
1394 B: spectral truncation half width
|
xue@1
|
1395 M, c[], d[], iH2:
|
xue@1
|
1396 epf: frequency error tolerance
|
xue@1
|
1397 Out: f2: frequency estimate
|
xue@1
|
1398 lmd1, lmd2: amplitude-phase factor estimates
|
xue@1
|
1399 Returns 1 if managed to find a good f2, 0 if not, upon which the initial f2 is used for estimating
|
xue@1
|
1400
|
xue@1
|
1401 amplitudes and phase angles.
|
xue@1
|
1402 */
|
xue@1
|
1403 int LSEDuo(double& f2, double fmin, double fmax, double f1, cdouble* x, int N, double B, double* c, double* d, int M, double iH2, cdouble& r1, cdouble &r2, double epf)
|
xue@1
|
1404 {
|
xue@1
|
1405 int result=0;
|
xue@1
|
1406 double inp=f2;
|
xue@1
|
1407 int k1=ceil(inp-B); if (k1<0) k1=0;
|
xue@1
|
1408 int k2=floor(inp+B); if (k2>=N/2) k2=N/2-1;
|
xue@1
|
1409 struct l_hx {int N; int k1; int k2; double* c; double* d; int M; double iH2; cdouble* x; double f1; double dipwindow; double ipwindow;} p={N, k1, k2, c, d, M, iH2, x, f1, 0, 0};
|
Chris@3
|
1410 int dfshift=offsetof(l_hx, dipwindow);// fshift=int(&((l_hx*)0)->ipwindow);
|
xue@1
|
1411
|
xue@1
|
1412 double tmp=Newton(f2, ddsIPWindowDuo, &p, dfshift, epf, 100, 1e-256, fmin, fmax);
|
xue@1
|
1413 if (tmp!=-1 && f2>fmin && f2<fmax) result=1;
|
xue@1
|
1414 else
|
xue@1
|
1415 {
|
xue@1
|
1416 Search1DmaxEx(f2, &p, sIPWindowDuo, fmin, fmax, NULL, epf);
|
xue@1
|
1417 if (f2<=fmin || f2>=fmax) f2=inp;
|
xue@1
|
1418 else result=1;
|
xue@1
|
1419 }
|
xue@1
|
1420 sIPWindowDuo(f1, f2, x, N, c, d, M, iH2, k1, k2, r1, r2);
|
xue@1
|
1421 return result;
|
xue@1
|
1422 }//LSEDuo
|
xue@1
|
1423
|
xue@1
|
1424 //---------------------------------------------------------------------------
|
xue@1
|
1425 /*
|
xue@1
|
1426 Time-frequency reassignment sinusoid estimation routines.
|
xue@1
|
1427
|
xue@1
|
1428 Further reading: A. R?bel, ¡°Estimating partial frequency and frequency slope using reassignment
|
xue@1
|
1429 operators,¡± in Proc. ICMC¡¯02. G?teborg. 2002.
|
xue@1
|
1430 */
|
xue@1
|
1431
|
Chris@5
|
1432 /**
|
xue@1
|
1433 function CDFTW: single-frequency windowed DTFT, centre-aligned
|
xue@1
|
1434
|
xue@1
|
1435 In: data[Wid]: waveform data x
|
xue@1
|
1436 win[Wid+1]: window function
|
xue@1
|
1437 k: frequency, in bins, where bin=1/Wid
|
xue@1
|
1438 Out: X: DTFT of xw at frequency k bins
|
xue@1
|
1439
|
xue@1
|
1440 No return value.
|
xue@1
|
1441 */
|
xue@1
|
1442 void CDFTW(cdouble& X, double k, int Wid, cdouble* data, double* win)
|
xue@1
|
1443 {
|
xue@1
|
1444 X=0;
|
xue@1
|
1445 int hWid=Wid/2;
|
xue@1
|
1446 for (int i=0; i<Wid; i++)
|
xue@1
|
1447 {
|
xue@1
|
1448 cdouble tmp=data[i]*win[Wid-i];
|
xue@1
|
1449 double ph=-2*M_PI*(i-hWid)*k/Wid;
|
xue@1
|
1450 tmp.rotate(ph);
|
xue@1
|
1451 X+=tmp;
|
xue@1
|
1452 }
|
xue@1
|
1453 }//CDFTW
|
xue@1
|
1454
|
Chris@5
|
1455 /**
|
xue@1
|
1456 function CuDFTW: single-frequency windowed DTFT of t*data[t], centre-aligned
|
xue@1
|
1457
|
xue@1
|
1458 In: data[Wid]: waveform data x
|
xue@1
|
1459 wid[Wid+1]: window function
|
xue@1
|
1460 k: frequency, in bins
|
xue@1
|
1461 Out: X: DTFT of txw at frequency k bins
|
xue@1
|
1462
|
xue@1
|
1463 No return value.
|
xue@1
|
1464 */
|
xue@1
|
1465 void CuDFTW(cdouble& X, int k, int Wid, cdouble* data, double* win)
|
xue@1
|
1466 {
|
xue@1
|
1467 X=0;
|
xue@1
|
1468 int hWid=Wid/2;
|
xue@1
|
1469 for (int i=0; i<Wid; i++)
|
xue@1
|
1470 {
|
xue@1
|
1471 double tw=((i-hWid)*win[Wid-i]);
|
xue@1
|
1472 cdouble tmp=data[i]*tw;
|
xue@1
|
1473 double ph=-2*M_PI*(i-hWid)*k/Wid;
|
xue@1
|
1474 tmp.rotate(ph);
|
xue@1
|
1475 X+=tmp;
|
xue@1
|
1476 }
|
xue@1
|
1477 }//CuDFTW
|
xue@1
|
1478
|
Chris@5
|
1479 /**
|
xue@1
|
1480 function TFReas: time-frequency reassignment
|
xue@1
|
1481
|
xue@1
|
1482 In: data[Wid]: waveform data
|
xue@1
|
1483 win[Wid+1], dwin[Wid+1], ddwin[Wid+1]: window function and its derivatives
|
xue@1
|
1484 f, t: initial digital frequency and time
|
xue@1
|
1485 Out: f, t: reassigned digital frequency and time
|
xue@1
|
1486 fslope: estimate of frequency derivative
|
xue@1
|
1487 plogaslope[0]: estimate of the derivative of logarithmic amplitude, optional
|
xue@1
|
1488
|
xue@1
|
1489 No return value.
|
xue@1
|
1490 */
|
xue@1
|
1491 void TFReas(double& f, double& t, double& fslope, int Wid, cdouble* data, double* win, double* dwin, double* ddwin, double* plogaslope)
|
xue@1
|
1492 {
|
xue@1
|
1493 int fi=floor(f*Wid+0.5);
|
xue@1
|
1494
|
xue@1
|
1495 cdouble x, xt, xw;
|
xue@1
|
1496 CDFTW(x, fi, Wid, data, win);
|
xue@1
|
1497 CuDFTW(xw, fi, Wid, data, win); xt.x=xw.y; xw.y=-xw.x; xw.x=xt.x;
|
xue@1
|
1498 CDFTW(xt, fi, Wid, data, dwin);
|
xue@1
|
1499 double px=~x;
|
xue@1
|
1500 t=t-(xw.y*x.x-xw.x*x.y)/px;
|
xue@1
|
1501 f=1.0*fi/Wid+(xt.y*x.x-xt.x*x.y)/px/(2*M_PI);
|
xue@1
|
1502 if (plogaslope) plogaslope[0]=-(xt.x*x.x+xt.y*x.y)/px;
|
xue@1
|
1503 cdouble xtt, xtw;
|
xue@1
|
1504 CuDFTW(xtw, fi, Wid, data, dwin); xtt.x=xtw.y; xtw.y=-xtw.x; xtw.x=xtt.x;
|
xue@1
|
1505 CDFTW(xtt, fi, Wid, data, ddwin);
|
xue@1
|
1506 double dtdt=-(xtw.y*x.x-xtw.x*x.y)/px+((xt.y*x.x-xt.x*x.y)*(xw.x*x.x+xw.y*x.y)+(xt.x*x.x+xt.y*x.y)*(xw.y*x.x-xw.x*x.y))/px/px,
|
xue@1
|
1507 dwdt=(xtt.y*x.x-xtt.x*x.y)/px-2*(xt.x*x.x+xt.y*x.y)*(xt.y*x.x-xt.x*x.y)/px/px;
|
xue@1
|
1508 if (dtdt!=0) fslope=dwdt/dtdt/(2*M_PI);
|
xue@1
|
1509 else fslope=0;
|
xue@1
|
1510 } //TFReas*/
|
xue@1
|
1511
|
Chris@5
|
1512 /**
|
xue@1
|
1513 function TFReas: sinusoid estimation using reassignment method
|
xue@1
|
1514
|
xue@1
|
1515 In: data[Wid]: waveform data
|
xue@1
|
1516 w[Wid+1], dw[Wid+1], ddw[Wid+1]: window function and its derivatives
|
xue@1
|
1517 win[Wid]: window function used for estimating amplitude and phase by projection onto a chirp
|
xue@1
|
1518 t: time for which the parameters are estimated
|
xue@1
|
1519 f: initial frequency at t
|
xue@1
|
1520 Out: f, a, ph: digital frequency, amplitude and phase angle estimated at t
|
xue@1
|
1521 fslope: frequency derivative estimate
|
xue@1
|
1522
|
xue@1
|
1523 No return value.
|
xue@1
|
1524 */
|
xue@1
|
1525 void TFReas(double& f, double t, double& a, double& ph, double& fslope, int Wid, cdouble* data, double* w, double* dw, double* ddw, double* win)
|
xue@1
|
1526 {
|
xue@1
|
1527 double localt=t, logaslope;
|
xue@1
|
1528 TFReas(f, localt, fslope, Wid, data, w, dw, ddw, &logaslope);
|
xue@1
|
1529
|
xue@1
|
1530 if (logaslope*Wid>6) logaslope=6.0/Wid;
|
xue@1
|
1531 else if (logaslope*Wid<-6) logaslope=-6.0/Wid;
|
xue@1
|
1532
|
xue@1
|
1533 f=f+fslope*(t-localt); //obtain frequency estimate at t
|
xue@1
|
1534
|
xue@1
|
1535 cdouble x=0;
|
xue@1
|
1536 if (win==0)
|
xue@1
|
1537 {
|
xue@1
|
1538 for (int n=0; n<Wid; n++)
|
xue@1
|
1539 {
|
xue@1
|
1540 double ni=n-t;
|
xue@1
|
1541 cdouble tmp=data[n];
|
xue@1
|
1542 double p=-2*M_PI*(f+0.5*fslope*ni)*ni;
|
xue@1
|
1543 tmp.rotate(p);
|
xue@1
|
1544 x+=tmp;
|
xue@1
|
1545 }
|
xue@1
|
1546 a=abs(x)/Wid;
|
xue@1
|
1547 }
|
xue@1
|
1548 else
|
xue@1
|
1549 {
|
xue@1
|
1550 double sumwin=0;
|
xue@1
|
1551 for (int n=0; n<Wid; n++)
|
xue@1
|
1552 {
|
xue@1
|
1553 double ni=n-t;
|
xue@1
|
1554 cdouble tmp=data[n]*win[n];
|
xue@1
|
1555 double p=-2*M_PI*(f+0.5*fslope*ni)*ni;
|
xue@1
|
1556 tmp.rotate(p);
|
xue@1
|
1557 x+=tmp; sumwin+=win[n];
|
xue@1
|
1558 }
|
xue@1
|
1559 a=abs(x)/sumwin;
|
xue@1
|
1560 }
|
xue@1
|
1561 ph=arg(x);
|
xue@1
|
1562 }//TFReas
|
xue@1
|
1563
|
xue@1
|
1564 //---------------------------------------------------------------------------
|
xue@1
|
1565 /*
|
xue@1
|
1566 Routines for additive and multiplicative reestimation of sinusoids.
|
xue@1
|
1567
|
xue@1
|
1568 Further reading: Wen X. and M. Sandler, "Additive and multiplicative reestimation schemes
|
xue@1
|
1569 for the sinusoid modeling of audio," in Proc. EUSIPCO'09, Glasgow, 2009.
|
xue@1
|
1570 */
|
xue@1
|
1571
|
Chris@5
|
1572 /**
|
xue@1
|
1573 function AdditiveUpdate: additive reestimation of time-varying sinusoid
|
xue@1
|
1574
|
xue@1
|
1575 In: x[Count]: waveform data
|
xue@1
|
1576 Wid, Offst: frame size and hop
|
xue@1
|
1577 fs[Count], as[Count], phs[Count]: initial estimate of sinusoid parameters
|
xue@1
|
1578 das[Count]: initial estimate of amplitude derivative
|
xue@1
|
1579 BasicAnalyzer: pointer to a sinusoid analyzer
|
xue@1
|
1580 LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline
|
xue@1
|
1581 Out: fs[Count], as[Count], phs[Count], das[Count]: estimates after additive update
|
xue@1
|
1582
|
xue@1
|
1583 No return value.
|
xue@1
|
1584 */
|
xue@1
|
1585 void AdditiveUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA)
|
xue@1
|
1586 {
|
xue@1
|
1587 int HWid=Wid/2, Fr=(Count-Wid)/Offst+1;
|
xue@1
|
1588
|
xue@1
|
1589 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
1590 {
|
xue@1
|
1591 int i=HWid+Offst*fr;
|
xue@1
|
1592 if (fs[i]<0 || fs[i]>0.5){}
|
xue@1
|
1593 }
|
xue@1
|
1594
|
xue@1
|
1595 cdouble *y=new cdouble[Count];
|
xue@1
|
1596 double *lf=new double[Count*4], *la=&lf[Count], *lp=&lf[Count*2], *lda=&lf[Count*3];
|
xue@1
|
1597
|
xue@1
|
1598 __int16* ref=new __int16[Count];
|
xue@1
|
1599 for (int i=0; i<Count; i++) y[i]=x[i].x-as[i]*cos(phs[i]), ref[i]=floor(fs[i]*Wid+0.5);
|
xue@1
|
1600 memcpy(lf, fs, sizeof(double)*Count);
|
xue@1
|
1601 BasicAnalyzer(lf, la, lp, lda, y, Count, Wid, Offst, ref, reserved, LogA);
|
xue@1
|
1602
|
xue@1
|
1603 //merge and interpolate
|
xue@1
|
1604 double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3],
|
xue@1
|
1605 *aa=&fa[Fr*4], *ab=&aa[Fr], *ac=&aa[Fr*2], *ad=&aa[Fr*3],
|
xue@1
|
1606 *xs=&fa[Fr*8], *ffr=&xs[Fr], *afr=&xs[Fr*2], *pfr=&xs[Fr*3];
|
xue@1
|
1607 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
1608 {
|
xue@1
|
1609 int i=HWid+Offst*fr;
|
xue@1
|
1610 double a=as[i], b=la[i], fai=phs[i], thet=lp[i], f=fs[i], g=lf[i], delt=fai-thet, da=das[i], db=lda[i];
|
xue@1
|
1611 xs[fr]=i;
|
xue@1
|
1612 if (fabs(f-g)*Wid>1)
|
xue@1
|
1613 {
|
xue@1
|
1614 afr[fr]=a, pfr[fr]=fai, ffr[fr]=f;
|
xue@1
|
1615 }
|
xue@1
|
1616 else
|
xue@1
|
1617 {
|
xue@1
|
1618 double rr=a*cos(fai)+b*cos(thet);
|
xue@1
|
1619 double ii=a*sin(fai)+b*sin(thet);
|
xue@1
|
1620 ffr[fr]=(a*f*(a+b*cos(delt))+b*g*(b+a*cos(delt))+(da*b-a*db)*sin(delt)/(2*M_PI))/(a*a+b*b+2*a*b*cos(delt));
|
xue@1
|
1621 afr[fr]=sqrt(rr*rr+ii*ii);
|
xue@1
|
1622 pfr[fr]=atan2(ii, rr);
|
xue@1
|
1623 }
|
xue@1
|
1624 if (LogA) afr[fr]=log(afr[fr]);
|
xue@1
|
1625 }
|
xue@1
|
1626 CubicSpline(Fr-1, fa, fb, fc, fd, xs, ffr, 1, 1);
|
xue@1
|
1627 CubicSpline(Fr-1, aa, ab, ac, ad, xs, afr, 1, 1);
|
xue@7
|
1628 for (int fr=0; fr<Fr-1; fr++) Sinusoid(Offst, &fs[int(xs[fr])], &as[int(xs[fr])], &phs[int(xs[fr])], &das[int(xs[fr])], aa[fr], ab[fr], ac[fr], ad[fr], fa[fr], fb[fr], fc[fr], fd[fr], pfr[fr], pfr[fr+1], LogA);
|
xue@7
|
1629 double tmpph=pfr[0]; Sinusoid_direct(&fs[int(xs[0])], &as[int(xs[0])], &phs[int(xs[0])], &das[int(xs[0])], -HWid, 0, aa[0], ab[0], ac[0], ad[0], fa[0], fb[0], fc[0], fd[0], tmpph, LogA);
|
xue@7
|
1630 ShiftTrinomial(xs[Fr-1]-xs[Fr-2], fa[Fr-1], fb[Fr-1], fc[Fr-1], fd[Fr-1], fa[Fr-2], fb[Fr-2], fc[Fr-2], fd[Fr-2]);
|
xue@7
|
1631 ShiftTrinomial(xs[Fr-1]-xs[Fr-2], aa[Fr-1], ab[Fr-1], ac[Fr-1], ad[Fr-1], aa[Fr-2], ab[Fr-2], ac[Fr-2], ad[Fr-2]);
|
xue@7
|
1632 tmpph=pfr[Fr-1]; Sinusoid_direct(&fs[int(xs[Fr-1])], &as[int(xs[Fr-1])], &phs[int(xs[Fr-1])], &das[int(xs[Fr-1])], 0, HWid, aa[Fr-1], ab[Fr-1], ac[Fr-1], ad[Fr-1], fa[Fr-1], fb[Fr-1], fc[Fr-1], fd[Fr-1], tmpph, LogA);
|
xue@1
|
1633 delete[] fa; //*/
|
xue@1
|
1634 /*
|
xue@1
|
1635 for (int i=0; i<Count; i++)
|
xue@1
|
1636 {
|
xue@1
|
1637 double rr=as[i]*cos(phs[i])+la[i]*cos(lp[i]);
|
xue@1
|
1638 double ii=as[i]*sin(phs[i])+la[i]*sin(lp[i]);
|
xue@1
|
1639 as[i]=sqrt(rr*rr+ii*ii);
|
xue@1
|
1640 phs[i]=atan2(ii, rr);
|
xue@1
|
1641 } //*/
|
xue@1
|
1642 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
1643 {
|
xue@1
|
1644 int i=HWid+Offst*fr;
|
xue@1
|
1645 if (fs[i]<0 || fs[i]>0.5){}
|
xue@1
|
1646 }
|
xue@1
|
1647 delete[] y; delete[] lf; delete[] ref;
|
xue@1
|
1648 }//AdditiveUpdate
|
xue@1
|
1649
|
Chris@5
|
1650 /**
|
xue@1
|
1651 function AdditiveAnalyzer: sinusoid analyzer with one additive update
|
xue@1
|
1652
|
xue@1
|
1653 In: x[Count]: waveform data
|
xue@1
|
1654 Wid, Offst: frame size and hop size
|
xue@1
|
1655 BasicAnalyzer: pointer to a sinusoid analyzer
|
xue@1
|
1656 ref[Count]: reference frequencies, in bins, used by BasicAnalyzer
|
xue@1
|
1657 BasicAnalyzer: pointer to a sinusoid analyzer
|
xue@1
|
1658 LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline
|
xue@1
|
1659 Out: fs[Count], as[Count], phs[Count]: sinusoid parameter estimates
|
xue@1
|
1660 das[Count]: estimate of amplitude derivative
|
xue@1
|
1661
|
xue@1
|
1662 No return value.
|
xue@1
|
1663 */
|
xue@1
|
1664 void AdditiveAnalyzer(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, __int16* ref, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA)
|
xue@1
|
1665 {
|
xue@1
|
1666 BasicAnalyzer(fs, as, phs, das, x, Count, Wid, Offst, ref, reserved, LogA);
|
xue@1
|
1667 AdditiveUpdate(fs, as, phs, das, x, Count, Wid, Offst, BasicAnalyzer, reserved, LogA);
|
xue@1
|
1668 }//AdditiveAnalyzer
|
xue@1
|
1669
|
Chris@5
|
1670 /**
|
xue@1
|
1671 function MultiplicativeUpdate: multiplicative reestimation of time-varying sinusoid
|
xue@1
|
1672
|
xue@1
|
1673 In: x[Count]: waveform data
|
xue@1
|
1674 Wid, Offst: frame size and hop
|
xue@1
|
1675 fs[Count], as[Count], phs[Count]: initial estimate of sinusoid parameters
|
xue@1
|
1676 das[Count]: initial estimate of amplitude derivative
|
xue@1
|
1677 BasicAnalyzer: pointer to a sinusoid analyzer
|
xue@1
|
1678 LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline
|
xue@1
|
1679 Out: fs[Count], as[Count], phs[Count], das[Count]: estimates after additive update
|
xue@1
|
1680
|
xue@1
|
1681 No return value.
|
xue@1
|
1682 */
|
xue@1
|
1683 void MultiplicativeUpdate(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA)
|
xue@1
|
1684 {
|
xue@1
|
1685 int HWid=Wid/2;
|
xue@1
|
1686 cdouble *y=new cdouble[Count];
|
xue@1
|
1687 double *lf=new double[Count*8], *la=&lf[Count], *lp=&lf[Count*2], *lda=&lf[Count*3],
|
xue@1
|
1688 *lf2=&lf[Count*4], *la2=&lf2[Count], *lp2=&lf2[Count*2], *lda2=&lf2[Count*3];
|
xue@1
|
1689 __int16 *lref=new __int16[Count];
|
xue@1
|
1690
|
xue@1
|
1691 for (int i=0; i<Count; i++) y[i]=x[i]*(cdouble(1.0).rotate(-phs[i]+i*0.15*2*M_PI)),
|
xue@1
|
1692 lref[i]=0.15*Wid;
|
xue@1
|
1693 BasicAnalyzer(lf, la, lp, lda, y, Count, Wid, Offst, lref, reserved, LogA);
|
xue@1
|
1694 for (int i=0; i<Count; i++) y[i]=y[i]*(cdouble(1.0/la[i]).rotate(-lp[i]+i*0.15*2*M_PI)), lref[i]=0.15*Wid;
|
xue@1
|
1695 BasicAnalyzer(lf2, la2, lp2, lda2, y, Count, Wid, Offst, lref, reserved, LogA);
|
xue@1
|
1696
|
xue@1
|
1697 /*
|
xue@1
|
1698 for (int i=0; i<Count; i++)
|
xue@1
|
1699 {
|
xue@1
|
1700 as[i]=la[i]*la2[i];
|
xue@1
|
1701 phs[i]=phs[i]+lp[i]+lp2[i]-0.3*2*M_PI*i;
|
xue@1
|
1702 fs[i]=fs[i]+lf[i]+lf2[i]-0.3;
|
xue@1
|
1703 } //*/
|
xue@1
|
1704
|
xue@1
|
1705 //merge
|
xue@1
|
1706 int Fr=(Count-Wid)/Offst+1;
|
xue@1
|
1707 double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3],
|
xue@1
|
1708 *aa=&fa[Fr*4], *ab=&aa[Fr], *ac=&aa[Fr*2], *ad=&aa[Fr*3],
|
xue@1
|
1709 *xs=&fa[Fr*8], *ffr=&xs[Fr], *afr=&xs[Fr*2], *pfr=&xs[Fr*3];
|
xue@1
|
1710 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
1711 {
|
xue@1
|
1712 int i=HWid+Offst*fr;
|
xue@1
|
1713 xs[fr]=i;
|
xue@1
|
1714 afr[fr]=la[i]*la2[i];
|
xue@1
|
1715 if (LogA) afr[fr]=log(afr[fr]);
|
xue@1
|
1716 ffr[fr]=fs[i]+lf[i]-0.15+lf2[i]-0.15;
|
xue@1
|
1717 pfr[fr]=phs[i]+lp[i]+lp2[i]-0.3*i*2*M_PI;
|
xue@1
|
1718 }
|
xue@1
|
1719 CubicSpline(Fr-1, fa, fb, fc, fd, xs, ffr, 1, 1);
|
xue@1
|
1720 CubicSpline(Fr-1, aa, ab, ac, ad, xs, afr, 1, 1);
|
xue@7
|
1721 for (int fr=0; fr<Fr-1; fr++) Sinusoid(Offst, &fs[int(xs[fr])], &as[int(xs[fr])], &phs[int(xs[fr])], &das[int(xs[fr])], aa[fr], ab[fr], ac[fr], ad[fr], fa[fr], fb[fr], fc[fr], fd[fr], pfr[fr], pfr[fr+1], LogA);
|
xue@7
|
1722 double tmpph=pfr[0]; Sinusoid_direct(&fs[int(xs[0])], &as[int(xs[0])], &phs[int(xs[0])], &das[int(xs[0])], -HWid, 0, aa[0], ab[0], ac[0], ad[0], fa[0], fb[0], fc[0], fd[0], tmpph, LogA);
|
xue@7
|
1723 ShiftTrinomial(xs[Fr-1]-xs[Fr-2], fa[Fr-1], fb[Fr-1], fc[Fr-1], fd[Fr-1], fa[Fr-2], fb[Fr-2], fc[Fr-2], fd[Fr-2]);
|
xue@7
|
1724 ShiftTrinomial(xs[Fr-1]-xs[Fr-2], aa[Fr-1], ab[Fr-1], ac[Fr-1], ad[Fr-1], aa[Fr-2], ab[Fr-2], ac[Fr-2], ad[Fr-2]);
|
xue@7
|
1725 tmpph=pfr[Fr-1]; Sinusoid_direct(&fs[int(xs[Fr-1])], &as[int(xs[Fr-1])], &phs[int(xs[Fr-1])], &das[int(xs[Fr-1])], 0, HWid, aa[Fr-1], ab[Fr-1], ac[Fr-1], ad[Fr-1], fa[Fr-1], fb[Fr-1], fc[Fr-1], fd[Fr-1], tmpph, LogA);
|
xue@7
|
1726
|
xue@7
|
1727 delete[] fa; //*/
|
xue@1
|
1728
|
xue@1
|
1729 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
1730 {
|
xue@1
|
1731 int i=HWid+Offst*fr;
|
xue@1
|
1732 if (fs[i]<0 || fs[i]>0.5){}
|
xue@1
|
1733 }
|
xue@1
|
1734
|
xue@1
|
1735 delete[] y; delete[] lf; delete[] lref;
|
xue@1
|
1736 }//MultiplicativeUpdate
|
xue@1
|
1737
|
Chris@5
|
1738 /**
|
xue@1
|
1739 function MultiplicativeAnalyzer: sinusoid analyzer with one multiplicative update
|
xue@1
|
1740
|
xue@1
|
1741 In: x[Count]: waveform data
|
xue@1
|
1742 Wid, Offst: frame size and hop size
|
xue@1
|
1743 BasicAnalyzer: pointer to a sinusoid analyzer
|
xue@1
|
1744 ref[Count]: reference frequencies, in bins, used by BasicAnalyzer
|
xue@1
|
1745 BasicAnalyzer: pointer to a sinusoid analyzer
|
xue@1
|
1746 LogA: indicates if amplitudes are interpolated at cubic spline or exponential cubic spline
|
xue@1
|
1747 Out: fs[Count], as[Count], phs[Count]: sinusoid parameter estimates
|
xue@1
|
1748 das[Count]: estimate of amplitude derivative
|
xue@1
|
1749
|
xue@1
|
1750 No return value.
|
xue@1
|
1751 */
|
xue@1
|
1752 void MultiplicativeAnalyzer(double* fs, double* as, double* phs, double* das, cdouble* x, int Count, int Wid, int Offst, __int16* ref, TBasicAnalyzer BasicAnalyzer, int reserved, bool LogA)
|
xue@1
|
1753 {
|
xue@1
|
1754 BasicAnalyzer(fs, as, phs, das, x, Count, Wid, Offst, ref, reserved, LogA);
|
xue@1
|
1755 MultiplicativeUpdate(fs, as, phs, das, x, Count, Wid, Offst, BasicAnalyzer, reserved);
|
xue@1
|
1756 }//MultiplicativeAnalyzer
|
xue@1
|
1757
|
xue@1
|
1758 /*
|
xue@1
|
1759 This is an earlier version of the multiplicative method without using a user-provided BasicAnalyzer.
|
xue@1
|
1760 This updates the sinusoid estimates at the selected consecutive FRAMES of x. Only frequency modulation
|
xue@1
|
1761 is included in the multiplier. The first frame (0) is centred at x[Wid/2]. fs, as, and phs are based
|
xue@1
|
1762 on frames rather than samples. Updates include frame frst, but not frame fren.
|
xue@1
|
1763 */
|
xue@1
|
1764 void MultiplicativeUpdateF(double* fs, double* as, double* phs, __int16* x, int Fr, int frst, int fren, int Wid, int Offst)
|
xue@1
|
1765 {
|
xue@1
|
1766 int HWid=Wid/2;
|
xue@1
|
1767
|
xue@1
|
1768 double *fa=new double[Fr*12], *fb=&fa[Fr], *fc=&fa[Fr*2], *fd=&fa[Fr*3],
|
xue@1
|
1769 *xs=&fa[Fr*8];
|
xue@1
|
1770 for (int fr=0; fr<Fr; fr++) xs[fr]=HWid+Offst*fr;
|
xue@1
|
1771 CubicSpline(Fr-1, fa, fb, fc, fd, xs, fs, 1, 1);
|
xue@1
|
1772
|
xue@1
|
1773 int dst=Offst*frst, den=Offst*(fren-1)+Wid, dcount=den-dst;
|
xue@1
|
1774 double *f=new double[dcount*2], *ph=&f[dcount];
|
xue@7
|
1775 for (int fr=frst; fr<fren-1; fr++) Sinusoid(Offst, &f[int(xs[fr])-dst], &ph[int(xs[fr])-dst], fa[fr], fb[fr], fc[fr], fd[fr], phs[fr], phs[fr+1]);
|
xue@7
|
1776 if (frst==0)
|
xue@7
|
1777 {
|
xue@7
|
1778 double tmpph=phs[0];
|
xue@7
|
1779 Sinusoid_direct(&f[int(xs[0])-dst], &ph[int(xs[0])-dst], -HWid, 0, fa[0], fb[0], fc[0], fd[0], tmpph);
|
xue@7
|
1780 }
|
xue@7
|
1781 else
|
xue@7
|
1782 Sinusoid(Offst, &f[int(xs[frst-1])-dst], &ph[int(xs[frst-1])-dst], fa[frst-1], fb[frst-1], fc[frst-1], fd[frst-1], phs[frst-1], phs[frst]);
|
xue@7
|
1783 if (fren==Fr)
|
xue@7
|
1784 {
|
xue@7
|
1785 double tmpph=phs[Fr-1];
|
xue@7
|
1786 ShiftTrinomial(Offst, fa[Fr-1], fb[Fr-1], fc[Fr-1], fd[Fr-1], fa[Fr-2], fb[Fr-2], fc[Fr-2], fd[Fr-2]);
|
xue@7
|
1787 Sinusoid_direct(&f[int(xs[Fr-1])-dst], &ph[int(xs[Fr-1])-dst], 0, HWid, fa[Fr-1], fb[Fr-1], fc[Fr-1], fd[Fr-1], tmpph);
|
xue@7
|
1788 }
|
xue@7
|
1789 else
|
xue@7
|
1790 Sinusoid(Offst, &f[int(xs[fren-1])-dst], &ph[int(xs[fren-1])-dst], fa[fren-1], fb[fren-1], fc[fren-1], fd[fren-1], phs[fren-1], phs[fren]);
|
xue@1
|
1791
|
xue@1
|
1792 cdouble* y=new cdouble[Wid];
|
xue@1
|
1793 AllocateFFTBuffer(Wid, Amp, W, X);
|
xue@1
|
1794 double* win=NewWindow(wtHann, Wid);
|
xue@1
|
1795 int M; double c[10], iH2; windowspec(wtHann, Wid, &M, c, &iH2);
|
xue@1
|
1796 for (int fr=frst; fr<fren; fr++)
|
xue@1
|
1797 {
|
xue@1
|
1798 __int16* lx=&x[Offst*fr];
|
xue@1
|
1799 double* lph=&ph[Offst*(fr-frst)];
|
xue@1
|
1800 for (int i=0; i<Wid; i++) y[i]=cdouble(lx[i]).rotate(-lph[i]+i*0.15*2*M_PI);
|
xue@1
|
1801 CFFTCW(y, win, Amp, 0, log2(Wid), W, X);
|
xue@1
|
1802 int pf=0.15*Wid, mpf=pf;
|
xue@1
|
1803 for (int k=pf-4; k<=pf+4; k++) if (Amp[k]>Amp[mpf]) mpf=k;
|
xue@1
|
1804 if (mpf>pf-4 && mpf<pf+4) pf=mpf;
|
xue@1
|
1805 double lfs=pf, lphs;
|
xue@1
|
1806 LSESinusoid(lfs, pf-3, pf+3, X, Wid, 3, M, c, iH2, as[fr], lphs, 1e-3);
|
xue@1
|
1807 fs[fr]=fs[fr]+lfs/Wid-0.15;
|
xue@1
|
1808 phs[fr]+=lphs-0.15*Wid*M_PI;
|
xue@1
|
1809 as[fr]*=2;
|
xue@1
|
1810 }
|
xue@1
|
1811
|
xue@1
|
1812 delete[] y;
|
xue@1
|
1813 delete[] f;
|
xue@1
|
1814 delete[] win;
|
xue@1
|
1815 delete[] fa;
|
xue@1
|
1816 FreeFFTBuffer(Amp);
|
xue@1
|
1817 }//MultiplicativeUpdateF
|
xue@1
|
1818
|
xue@1
|
1819 //---------------------------------------------------------------------------
|
xue@1
|
1820 /*
|
xue@1
|
1821 Earlier reestimation method routines.
|
xue@1
|
1822
|
xue@1
|
1823 Further reading: Wen X. and M. Sandler, "Evaluating parameters of time-varying
|
xue@1
|
1824 sinusoids by demodulation," in Proc. DAFx'08, Espoo, 2008.
|
xue@1
|
1825 */
|
xue@1
|
1826
|
Chris@5
|
1827 /**
|
xue@1
|
1828 function ReEstFreq: sinusoid reestimation by demodulating frequency.
|
xue@1
|
1829
|
xue@1
|
1830 In: x[Wid+Offst*(FrCount-1)]: waveform data
|
xue@1
|
1831 FrCount, Wid, Offst: frame count, frame size and hop size
|
xue@1
|
1832 fbuf[FrCount], ns[FrCount]: initial frequency estiamtes and their timing
|
xue@1
|
1833 win[Wid]: window function for estimating demodulated sinusoid
|
xue@1
|
1834 M, c[], iH2: cosine-family window specification parameters, must be consistent with win[]
|
xue@1
|
1835 Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid, optional
|
xue@1
|
1836 w[Wid/2], ps[Wid], xs[Wid], xc[Wid], fa[FrCount-1], fb[FrCount-1], fc[FrCount-1], fd[FrCount-1]: buffers
|
xue@1
|
1837 Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles
|
xue@1
|
1838
|
xue@1
|
1839 No return value.
|
xue@1
|
1840 */
|
xue@1
|
1841 void ReEstFreq(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* ps, double* fa, double* fb, double* fc, double* fd, double* ns, int* Wids)
|
xue@1
|
1842 {
|
xue@1
|
1843 int hWid=Wid/2;
|
xue@1
|
1844 //reestimate using frequency track
|
xue@1
|
1845 CubicSpline(FrCount-1, fa, fb, fc, fd, ns, fbuf, 0, 1);
|
xue@1
|
1846 for (int fr=0; fr<FrCount; fr++)
|
xue@1
|
1847 {
|
xue@1
|
1848 //find ps
|
xue@1
|
1849 if (fr==0)
|
xue@1
|
1850 {
|
xue@1
|
1851 double lfd=0, lfc=fc[0], lfb=fb[0], lfa=fa[0];
|
xue@1
|
1852 for (int j=0; j<Wid; j++)
|
xue@1
|
1853 {
|
xue@1
|
1854 double lx=j-hWid;
|
xue@1
|
1855 ps[j]=2*M_PI*lx*(lfd+lx*(lfc/2+lx*(lfb/3+lx*lfa/4)));
|
xue@1
|
1856 }
|
xue@1
|
1857 // memset(ps, 0, sizeof(double)*hWid);
|
xue@1
|
1858 }
|
xue@1
|
1859 else if (fr==FrCount-1)
|
xue@1
|
1860 {
|
xue@1
|
1861 int lfr=FrCount-2;
|
xue@1
|
1862 double lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
|
xue@1
|
1863 double lfd=-(hWid*(lfc+hWid*(lfb+hWid*lfa)));
|
xue@1
|
1864 ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4)));
|
xue@1
|
1865 for (int j=1; j<Wid; j++)
|
xue@1
|
1866 {
|
xue@1
|
1867 ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
|
xue@1
|
1868 }
|
xue@1
|
1869 // memset(&ps[hWid], 0, sizeof(double)*hWid);
|
xue@1
|
1870 }
|
xue@1
|
1871 else
|
xue@1
|
1872 {
|
xue@1
|
1873 int lfr=fr-1;
|
xue@1
|
1874 double lfd=fd[lfr]-fd[fr], lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
|
xue@1
|
1875 ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4)));
|
xue@1
|
1876 for (int j=1; j<hWid+1; j++)
|
xue@1
|
1877 {
|
xue@1
|
1878 ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
|
xue@1
|
1879 }
|
xue@1
|
1880 lfr=fr;
|
xue@1
|
1881 lfd=0, lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
|
xue@1
|
1882 for (int j=1; j<hWid; j++)
|
xue@1
|
1883 {
|
xue@1
|
1884 ps[j+hWid]=2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
|
xue@1
|
1885 }
|
xue@1
|
1886 }
|
xue@1
|
1887 double* ldata=&x[fr*Offst];
|
xue@1
|
1888 for (int j=0; j<Wid; j++)
|
xue@1
|
1889 {
|
xue@1
|
1890 xs[j].x=ldata[j]*cos(-ps[j]);
|
xue@1
|
1891 xs[j].y=ldata[j]*sin(-ps[j]);
|
xue@1
|
1892 }
|
xue@1
|
1893
|
xue@1
|
1894 if (Wids)
|
xue@1
|
1895 {
|
xue@1
|
1896 int lWid=Wids[fr], lhWid=Wids[fr]/2, lM;
|
xue@1
|
1897 SetTwiddleFactors(lWid, w);
|
xue@1
|
1898 double *lwin=NewWindow(wtHann, lWid), lc[4], liH2;
|
xue@1
|
1899 windowspec(wtHann, lWid, &lM, lc, &liH2);
|
xue@1
|
1900 CFFTCW(&xs[hWid-lhWid], lwin, NULL, NULL, log2(lWid), w, xc);
|
xue@1
|
1901 delete[] lwin;
|
xue@1
|
1902 double lf=fbuf[fr]*lWid, la, lp;
|
xue@1
|
1903 LSESinusoid(lf, lf-3, lf+3, xc, lWid, 3, lM, lc, liH2, la, lp, 1e-3);
|
xue@1
|
1904 if (la*2>abuf[fr]) fbuf[fr]=lf/lWid, abuf[fr]=la*2, pbuf[fr]=lp;
|
xue@1
|
1905 }
|
xue@1
|
1906 else
|
xue@1
|
1907 {
|
xue@1
|
1908 CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc);
|
xue@1
|
1909 double lf=fbuf[fr]*Wid, la, lp;
|
xue@1
|
1910 LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3);
|
xue@1
|
1911 if (la*2>abuf[fr])
|
xue@1
|
1912 fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp;
|
xue@1
|
1913 }
|
xue@1
|
1914 }
|
xue@1
|
1915 }//ReEstFreq
|
xue@1
|
1916
|
Chris@5
|
1917 /**
|
xue@1
|
1918 function ReEstFreq_2: sinusoid reestimation by demodulating frequency. This is that same as ReEstFreq(...)
|
xue@1
|
1919 except that it calls Sinusoid(...) to synthesize the phase track used for demodulation and that it
|
xue@1
|
1920 does not allow variable window sizes for estimating demodulated sinusoid.
|
xue@1
|
1921
|
xue@1
|
1922 In: x[Wid+Offst*(FrCount-1)]: waveform data
|
xue@1
|
1923 FrCount, Wid, Offst: frame count, frame size and hop size
|
xue@1
|
1924 fbuf[FrCount], ns[FrCount]: initial frequency estiamtes and their timing
|
xue@1
|
1925 win[Wid]: window function for LSE sinusoid estimation
|
xue@1
|
1926 M, c[], iH2: cosine-family window specification parameters, must be consistent with M, c, iH2
|
xue@1
|
1927 w[Wid/2], xs[Wid], xc[Wid], f3[FrCount-1], f2[FrCount-1], f1[FrCount-1], f0[FrCount-1]: buffers
|
xue@1
|
1928 Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles
|
xue@1
|
1929
|
xue@1
|
1930 No return value.
|
xue@1
|
1931 */
|
xue@1
|
1932 void ReEstFreq_2(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* f3, double* f2, double* f1, double* f0, double* ns)
|
xue@1
|
1933 {
|
xue@1
|
1934 int hWid=Wid/2;
|
xue@1
|
1935 //reestimate using frequency track
|
xue@1
|
1936 CubicSpline(FrCount-1, f3, f2, f1, f0, ns, fbuf, 1, 1);
|
xue@1
|
1937 double *refcos=(double*)malloc8(sizeof(double)*Wid), *refsin=&refcos[hWid], ph=0, centralph;
|
xue@1
|
1938
|
xue@1
|
1939 memset(f0, 0, sizeof(double)*FrCount);
|
xue@1
|
1940
|
xue@1
|
1941 int N=Wid+Offst*(FrCount-1);
|
xue@1
|
1942 double* cosine=new double[N], *sine=new double[N];
|
xue@7
|
1943 CosSin(&cosine[hWid], &sine[hWid], -hWid, 0, f3[0], f2[0], f1[0], f0[0], ph);
|
xue@1
|
1944 for (int fr=0; fr<FrCount-1; fr++)
|
xue@1
|
1945 {
|
xue@1
|
1946 int ncentre=hWid+Offst*fr;
|
xue@7
|
1947 if (fr==FrCount-2) CosSin(&cosine[ncentre], &sine[ncentre], 0, Wid, f3[fr], f2[fr], f1[fr], f0[fr], ph);
|
xue@7
|
1948 else CosSin(&cosine[ncentre], &sine[ncentre], 0, hWid, f3[fr], f2[fr], f1[fr], f0[fr], ph);
|
xue@1
|
1949 }
|
xue@1
|
1950 double err=0;
|
xue@1
|
1951 for (int n=0; n<N; n++) {double tmp=cosine[n]-x[n-hWid]; err+=tmp*tmp; tmp=cosine[n]*cosine[n]+sine[n]*sine[n]-1; err+=tmp*tmp;}
|
xue@1
|
1952
|
xue@1
|
1953 ph=0;
|
xue@1
|
1954 for (int fr=0; fr<FrCount; fr++)
|
xue@1
|
1955 {
|
xue@1
|
1956 double* ldata=&x[fr*Offst-hWid];
|
xue@1
|
1957
|
xue@1
|
1958 //store first half of demodulated frame to xs[0:hWid-1]
|
xue@1
|
1959 if (fr==0)
|
xue@1
|
1960 {
|
xue@7
|
1961 CosSin(&refcos[hWid], &refsin[hWid], -hWid, 0, f3[0], f2[0], f1[0], f0[0], ph);
|
xue@1
|
1962 for (int i=0; i<hWid; i++) xs[i].x=ldata[i]*refcos[i], xs[i].y=-ldata[i]*refsin[i];
|
xue@1
|
1963 }
|
xue@1
|
1964 else
|
xue@1
|
1965 {
|
xue@1
|
1966 ph=0;
|
xue@7
|
1967 CosSin(refcos, refsin, 0, hWid, f3[fr-1], f2[fr-1], f1[fr-1], f0[fr-1], ph);
|
xue@1
|
1968 for (int i=0; i<hWid; i++) xs[i].x=ldata[i]*refcos[i], xs[i].y=-ldata[i]*refsin[i];
|
xue@1
|
1969 }
|
xue@1
|
1970
|
xue@1
|
1971 //taking care of phase angles
|
xue@1
|
1972 if (fr==FrCount-1) {double tmp=ph; ph=centralph; centralph=tmp;}
|
xue@1
|
1973 else centralph=ph;
|
xue@1
|
1974
|
xue@1
|
1975 double *lrefcos=&refcos[-hWid], *lrefsin=&refsin[-hWid];
|
xue@1
|
1976 //store second half of demodulated frame to xs[hWid:Wid-1]
|
xue@1
|
1977 if (fr==FrCount-1)
|
xue@1
|
1978 {
|
xue@7
|
1979 CosSin(lrefcos, lrefsin, hWid, Wid, f3[FrCount-2], f2[FrCount-2], f1[FrCount-2], f0[FrCount-2], ph);
|
xue@1
|
1980 for (int i=hWid; i<Wid; i++) xs[i].x=ldata[i]*lrefcos[i], xs[i].y=-ldata[i]*lrefsin[i];
|
xue@1
|
1981 }
|
xue@1
|
1982 else
|
xue@1
|
1983 {
|
xue@7
|
1984 CosSin(refcos, refsin, 0, hWid, f3[fr], f2[fr], f1[fr], f0[fr], ph);
|
xue@1
|
1985 for (int i=hWid; i<Wid; i++) xs[i].x=ldata[i]*lrefcos[i], xs[i].y=-ldata[i]*lrefsin[i];
|
xue@1
|
1986 }
|
xue@1
|
1987
|
xue@1
|
1988 CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc);
|
xue@1
|
1989 double lf=fbuf[fr]*Wid, la, lp;
|
xue@1
|
1990 LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3);
|
xue@1
|
1991 if (la*2>abuf[fr])
|
xue@1
|
1992 fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp+centralph;
|
xue@1
|
1993 }
|
xue@1
|
1994 }//ReEstFreq_2
|
xue@1
|
1995
|
Chris@5
|
1996 /**
|
xue@1
|
1997 function ReEstFreqAmp: sinusoid reestimation by demodulating frequency and amplitude.
|
xue@1
|
1998
|
xue@1
|
1999 In: x[Wid+Offst*(FrCount-1)]: waveform data
|
xue@1
|
2000 FrCount, Wid, Offst: frame count, frame size and hop size
|
xue@1
|
2001 fbuf[FrCount], abuf[FrCount], ns[FrCount]: initial frequency and amplitude estiamtes and their
|
xue@1
|
2002 timing
|
xue@1
|
2003 win[Wid]: window function for estimating demodulated sinusoid
|
xue@1
|
2004 M, c[], iH2: cosine-family window specification parameters, must be consistent with win[]
|
xue@1
|
2005 Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid,
|
xue@1
|
2006 optional
|
xue@1
|
2007 w[Wid/2], ps[Wid], xs[Wid], xc[Wid]: buffers
|
xue@1
|
2008 fa[FrCount-1], fb[FrCount-1], fc[FrCount-1], fd[FrCount-1]: buffers
|
xue@1
|
2009 aa[FrCount-1], ab[FrCount-1], ac[FrCount-1], ad[FrCount-1]: buffers
|
xue@1
|
2010 Out: fbuf[FrCount], abuf[FrCount], pbuf[FrCount]: reestimated frequencies, amplitudes and phase angles
|
xue@1
|
2011
|
xue@1
|
2012 No return value.
|
xue@1
|
2013 */
|
xue@1
|
2014 void ReEstFreqAmp(int FrCount, int Wid, int Offst, double* x, double* fbuf, double* abuf, double* pbuf, double* win, int M, double* c, double iH2, cdouble* w, cdouble* xc, cdouble* xs, double* ps, double* as, double* fa, double* fb, double* fc, double* fd, double* aa, double* ab, double* ac, double* ad, double* ns, int* Wids)
|
xue@1
|
2015 {
|
xue@1
|
2016 int hWid=Wid/2;
|
xue@1
|
2017 //reestimate using amplitude and frequency track
|
xue@1
|
2018 CubicSpline(FrCount-1, fa, fb, fc, fd, ns, fbuf, 0, 1);
|
xue@1
|
2019 CubicSpline(FrCount-1, aa, ab, ac, ad, ns, abuf, 0, 1);
|
xue@1
|
2020 for (int fr=0; fr<FrCount; fr++)
|
xue@1
|
2021 {
|
xue@1
|
2022 if (fr==0)
|
xue@1
|
2023 {
|
xue@1
|
2024 double lfd=0, lfc=fc[0], lfb=fb[0], lfa=fa[0],
|
xue@1
|
2025 lad=ad[0], lac=ac[0], lab=ab[0], laa=aa[0];
|
xue@1
|
2026 for (int j=0; j<Wid; j++)
|
xue@1
|
2027 {
|
xue@1
|
2028 double lx=j-hWid;
|
xue@1
|
2029 ps[j]=2*M_PI*lx*(lfd+lx*(lfc/2+lx*(lfb/3+lx*lfa/4)));
|
xue@1
|
2030 }
|
xue@1
|
2031 for (int j=0; j<Wid; j++)
|
xue@1
|
2032 {
|
xue@1
|
2033 double lx=j-hWid;
|
xue@1
|
2034 as[j]=lad+lx*(lac+lx*(lab+lx*laa));
|
xue@1
|
2035 }
|
xue@1
|
2036 }
|
xue@1
|
2037 else if (fr==FrCount-1)
|
xue@1
|
2038 {
|
xue@1
|
2039 int lfr=FrCount-2;
|
xue@1
|
2040 double lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
|
xue@1
|
2041 double lfd=-(hWid*(lfc+hWid*(lfb+hWid*lfa)));
|
xue@1
|
2042 double lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr];
|
xue@1
|
2043 ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4)));
|
xue@1
|
2044 for (int j=1; j<Wid; j++)
|
xue@1
|
2045 {
|
xue@1
|
2046 ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
|
xue@1
|
2047 }
|
xue@1
|
2048 as[0]=ad[lfr];
|
xue@1
|
2049 for (int j=0; j<Wid; j++)
|
xue@1
|
2050 {
|
xue@1
|
2051 as[j]=lad+j*(lac+j*(lab+j*laa));
|
xue@1
|
2052 }
|
xue@1
|
2053 }
|
xue@1
|
2054 else
|
xue@1
|
2055 {
|
xue@1
|
2056 int lfr=fr-1;
|
xue@1
|
2057 double lfd=fd[lfr]-fd[fr], lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
|
xue@1
|
2058 double lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr];
|
xue@1
|
2059 ps[0]=-2*M_PI*hWid*(lfd+hWid*(lfc/2+hWid*(lfb/3+hWid*lfa/4)));
|
xue@1
|
2060 for (int j=0; j<hWid+1; j++)
|
xue@1
|
2061 {
|
xue@1
|
2062 ps[j]=ps[0]+2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
|
xue@1
|
2063 as[j]=lad+j*(lac+j*(lab+j*laa));
|
xue@1
|
2064 }
|
xue@1
|
2065 lfr=fr;
|
xue@1
|
2066 lfd=0, lfc=fc[lfr], lfb=fb[lfr], lfa=fa[lfr];
|
xue@1
|
2067 lad=ad[lfr], lac=ac[lfr], lab=ab[lfr], laa=aa[lfr];
|
xue@1
|
2068 for (int j=1; j<hWid; j++)
|
xue@1
|
2069 {
|
xue@1
|
2070 ps[j+hWid]=2*M_PI*j*(lfd+j*(lfc/2+j*(lfb/3+j*lfa/4)));
|
xue@1
|
2071 as[j+hWid]=lad+j*(lac+j*(lab+j*laa));
|
xue@1
|
2072 }
|
xue@1
|
2073 }
|
xue@1
|
2074 double *ldata=&x[fr*Offst];
|
xue@1
|
2075 for (int j=0; j<Wid; j++)
|
xue@1
|
2076 {
|
xue@1
|
2077 double tmp;
|
xue@1
|
2078 if ((fr==0 && j<hWid) || (fr==FrCount-1 && j>=hWid)) tmp=1;
|
xue@1
|
2079 else if (as[hWid]>100*as[j]) tmp=100;
|
xue@1
|
2080 else tmp=as[hWid]/as[j];
|
xue@1
|
2081 tmp=tmp*ldata[j];
|
xue@1
|
2082 xs[j].x=tmp*cos(-ps[j]);
|
xue@1
|
2083 xs[j].y=tmp*sin(-ps[j]);
|
xue@1
|
2084 }
|
xue@1
|
2085
|
xue@1
|
2086 if (Wids)
|
xue@1
|
2087 {
|
xue@1
|
2088 int lWid=Wids[fr], lhWid=Wids[fr]/2, lM;
|
xue@1
|
2089 SetTwiddleFactors(lWid, w);
|
xue@1
|
2090 double *lwin=NewWindow(wtHann, lWid), lc[4], liH2;
|
xue@1
|
2091 windowspec(wtHann, lWid, &lM, lc, &liH2);
|
xue@1
|
2092 CFFTCW(&xs[hWid-lhWid], lwin, NULL, NULL, log2(lWid), w, xc);
|
xue@1
|
2093 delete[] lwin;
|
xue@1
|
2094 double lf=fbuf[fr]*lWid, la, lp;
|
xue@1
|
2095 LSESinusoid(lf, lf-3, lf+3, xc, lWid, 3, lM, lc, liH2, la, lp, 1e-3);
|
xue@1
|
2096 if (la*2>abuf[fr]) fbuf[fr]=lf/lWid, abuf[fr]=la*2, pbuf[fr]=lp;
|
xue@1
|
2097 }
|
xue@1
|
2098 else
|
xue@1
|
2099 {
|
xue@1
|
2100 CFFTCW(xs, win, NULL, NULL, log2(Wid), w, xc);
|
xue@1
|
2101 double lf=fbuf[fr]*Wid, la, lp;
|
xue@1
|
2102 LSESinusoid(lf, lf-3, lf+3, xc, Wid, 3, M, c, iH2, la, lp, 1e-3);
|
xue@1
|
2103 if (la*2>abuf[fr]) fbuf[fr]=lf/Wid, abuf[fr]=la*2, pbuf[fr]=lp;
|
xue@1
|
2104 }
|
xue@1
|
2105 }
|
xue@1
|
2106 }//ReEstFreqAmp
|
xue@1
|
2107
|
Chris@5
|
2108 /**
|
xue@1
|
2109 function Reestimate2: iterative demodulation method for sinusoid parameter reestimation.
|
xue@1
|
2110
|
xue@1
|
2111 In: x[(FrCount-1)*Offst+Wid]: waveform data
|
xue@1
|
2112 FrCount, Wid, Offst: frame count, frame size and hop size
|
xue@1
|
2113 win[Wid]: window function
|
xue@1
|
2114 M, c[], iH2: cosine-family window specification parameters, must be consistent with win[]
|
xue@1
|
2115 Wids[FrCount]: specifies frame sizes for estimating individual frames of demodulated sinusoid,
|
xue@1
|
2116 optional
|
xue@1
|
2117 maxiter: maximal number of iterates
|
xue@1
|
2118 ae[FrCount], fe[FrCount], pe[FrCount]: initial amplitude, frequency and phase estimates
|
xue@1
|
2119 Out: aret[FrCount], fret[FrCount], pret[FrCount]: reestimated amplitudes, frequencies and phase angles
|
xue@1
|
2120
|
xue@1
|
2121 Returns the number of unused iterates left of the total of maxiter.
|
xue@1
|
2122 */
|
xue@1
|
2123 int Reestimate2(int FrCount, int Wid, int Offst, double* win, int M, double* c, double iH2, double* x, double* ae, double* fe, double* pe, double* aret, double* fret, double *pret, int maxiter, int* Wids)
|
xue@1
|
2124 {
|
xue@1
|
2125 AllocateFFTBuffer(Wid, fft, w, xc);
|
xue@1
|
2126 double convep=1e-4, dif=0, lastdif=0; //convep is the hard-coded threshold that stops the iteration
|
xue@1
|
2127 int iter=1, hWid=Wid/2;
|
xue@1
|
2128
|
xue@1
|
2129 double *ns=new double[FrCount*12], *as=new double[Wid*5];
|
xue@1
|
2130 double *fbuf=&ns[FrCount], *abuf=&ns[FrCount*2],
|
xue@1
|
2131 *aa=&ns[FrCount*3], *ab=&ns[FrCount*4], *ac=&ns[FrCount*5], *ad=&ns[FrCount*6],
|
xue@1
|
2132 *fa=&ns[FrCount*7], *fb=&ns[FrCount*8], *fc=&ns[FrCount*9], *fd=&ns[FrCount*10],
|
xue@1
|
2133 *pbuf=&ns[FrCount*11];
|
xue@1
|
2134 double *ps=&as[Wid];
|
xue@1
|
2135 cdouble *xs=(cdouble*)&as[Wid*3];
|
xue@1
|
2136
|
xue@1
|
2137 memcpy(fbuf, fe, sizeof(double)*FrCount);
|
xue@1
|
2138 memcpy(abuf, ae, sizeof(double)*FrCount);
|
xue@1
|
2139 memcpy(pbuf, pe, sizeof(double)*FrCount);
|
xue@1
|
2140 for (int i=0; i<FrCount; i++)
|
xue@1
|
2141 {
|
xue@1
|
2142 ns[i]=hWid+i*Offst;
|
xue@1
|
2143 }
|
xue@1
|
2144
|
xue@1
|
2145 while (iter<=maxiter)
|
xue@1
|
2146 {
|
xue@1
|
2147 ReEstFreq(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, fa, fb, fc, fd, ns, Wids);
|
xue@1
|
2148 ReEstFreq(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, fa, fb, fc, fd, ns, Wids);
|
xue@1
|
2149 ReEstFreqAmp(FrCount, Wid, Offst, x, fbuf, abuf, pbuf, win, M, c, iH2, w, xc, xs, ps, as, fa, fb, fc, fd, aa, ab, ac, ad, ns, Wids);
|
xue@1
|
2150
|
xue@1
|
2151 if (iter>1) lastdif=dif;
|
xue@1
|
2152 dif=0;
|
xue@1
|
2153 if (iter==1)
|
xue@1
|
2154 {
|
xue@1
|
2155 for (int fr=0; fr<FrCount; fr++)
|
xue@1
|
2156 {
|
xue@1
|
2157 if (fabs(abuf[fr])>fabs(ae[fr]))
|
xue@1
|
2158 dif+=fabs(fe[fr]-fbuf[fr])*Wid+fabs((ae[fr]-abuf[fr])/abuf[fr]);
|
xue@1
|
2159 else
|
xue@1
|
2160 dif+=fabs(fe[fr]-fbuf[fr])*Wid+fabs((ae[fr]-abuf[fr])/ae[fr]);
|
xue@1
|
2161 }
|
xue@1
|
2162 }
|
xue@1
|
2163 else
|
xue@1
|
2164 {
|
xue@1
|
2165 for (int fr=0; fr<FrCount; fr++)
|
xue@1
|
2166 {
|
xue@1
|
2167 if (fabs(abuf[fr])>fabs(aret[fr]))
|
xue@1
|
2168 dif+=fabs(fret[fr]-fbuf[fr])*Wid+fabs((aret[fr]-abuf[fr])/abuf[fr]);
|
xue@1
|
2169 else
|
xue@1
|
2170 dif+=fabs(fret[fr]-fbuf[fr])*Wid+fabs((aret[fr]-abuf[fr])/aret[fr]);
|
xue@1
|
2171 }
|
xue@1
|
2172 }
|
xue@1
|
2173 memcpy(fret, fbuf, sizeof(double)*FrCount);
|
xue@1
|
2174 memcpy(aret, abuf, sizeof(double)*FrCount);
|
xue@1
|
2175 dif/=FrCount;
|
xue@1
|
2176 if (fabs(dif)<convep || (iter>1 && fabs(dif-lastdif)<convep*lastdif)) break;
|
xue@1
|
2177 iter++;
|
xue@1
|
2178 }
|
xue@1
|
2179
|
xue@1
|
2180 memcpy(pret, pbuf, sizeof(double)*FrCount);
|
xue@1
|
2181
|
xue@1
|
2182 delete[] ns;
|
xue@1
|
2183 delete[] as;
|
xue@1
|
2184 delete[] fft;
|
xue@1
|
2185
|
xue@1
|
2186 return maxiter-iter;
|
xue@1
|
2187 }//Reestimate2
|
xue@1
|
2188
|
xue@1
|
2189 //---------------------------------------------------------------------------
|
xue@1
|
2190 /*
|
xue@1
|
2191 Derivative method as proposed in DAFx09
|
xue@1
|
2192
|
xue@1
|
2193 Further reading: Wen X. and M. Sandler, "Notes on model-based non-stationary sinusoid estimation methods
|
xue@1
|
2194 using derivatives," in Proc. DAFx'09, Como, 2009.
|
xue@1
|
2195 */
|
xue@1
|
2196
|
Chris@5
|
2197 /**
|
xue@1
|
2198 function Derivative: derivative method for estimating amplitude derivative, frequency, and frequency derivative given
|
xue@1
|
2199 signal and its derivatives.
|
xue@1
|
2200
|
xue@1
|
2201 In: x[Wid], dx[Wid], ddx[Wid]: waveform and its derivatives
|
xue@1
|
2202 win[Wid]: window function
|
xue@1
|
2203 f0: initial digital frequency estimate
|
xue@1
|
2204 Out: f0: new estimate of digital frequency
|
xue@1
|
2205 f1, a1: estimates of frequency and amplitude derivatives
|
xue@1
|
2206
|
xue@1
|
2207 No return value.
|
xue@1
|
2208 */
|
xue@1
|
2209 void Derivative(int Wid, double* win, cdouble* x, cdouble* dx, cdouble* ddx, double& f0, double* f1, double* a0, double* a1, double* ph)
|
xue@1
|
2210 {
|
xue@1
|
2211 AllocateFFTBuffer(Wid, fft, W, X);
|
xue@1
|
2212 CFFTCW(x, win, fft, NULL, log2(Wid), W, X);
|
xue@1
|
2213 int m=f0*Wid, m0=m-10, m1=m+10, hWid=Wid/2;
|
xue@1
|
2214 if (m0<0) m0=0; if (m1>hWid) m1=hWid;
|
xue@1
|
2215 for (int n=m0; n<=m1; n++) if (fft[n]>fft[m]) m=n;
|
xue@1
|
2216 cdouble Sw=0, S1w=0, S2w=0;
|
xue@1
|
2217 for (int n=0; n<Wid; n++)
|
xue@1
|
2218 {
|
xue@1
|
2219 cdouble tmp=x[n]*win[n];
|
xue@1
|
2220 Sw+=tmp.rotate(-2*M_PI*m*(n-hWid)/Wid);
|
xue@1
|
2221 tmp=dx[n]*win[n];
|
xue@1
|
2222 S1w+=tmp.rotate(-2*M_PI*m*(n-hWid)/Wid);
|
xue@1
|
2223 }
|
xue@1
|
2224 double omg0=(S1w/Sw).y;
|
xue@1
|
2225 Sw=0, S1w=0;
|
xue@1
|
2226 for (int n=0; n<Wid; n++)
|
xue@1
|
2227 {
|
xue@1
|
2228 cdouble tmp=x[n]*win[n];
|
xue@1
|
2229 Sw+=tmp.rotate(-omg0*(n-hWid)/Wid);
|
xue@1
|
2230 tmp=dx[n]*win[n];
|
xue@1
|
2231 S1w+=tmp.rotate(-omg0*(n-hWid)/Wid);
|
xue@1
|
2232 tmp=ddx[n]*win[n];
|
xue@1
|
2233 S2w+=tmp.rotate(-omg0*(n-hWid)/Wid);
|
xue@1
|
2234 }
|
xue@1
|
2235 omg0=(S1w/Sw).y;
|
xue@1
|
2236 double miu0=(S1w/Sw).x;
|
xue@1
|
2237 double psi0=(S2w/Sw).y-2*miu0*omg0;
|
xue@1
|
2238
|
xue@1
|
2239 f0=omg0/(2*M_PI);
|
xue@1
|
2240 *f1=psi0/(2*M_PI);
|
xue@1
|
2241 *a1=miu0;
|
xue@1
|
2242
|
xue@1
|
2243 FreeFFTBuffer(fft);
|
xue@1
|
2244 }//Derivative
|
xue@1
|
2245
|
Chris@5
|
2246 /**
|
xue@1
|
2247 function Xkw: computes windowed spectrum of x and its derivatives up to order K at angular frequency omg,
|
xue@1
|
2248 from x using window w and its derivatives.
|
xue@1
|
2249
|
xue@1
|
2250 In: x[Wid]: waveform data
|
xue@1
|
2251 w[K+1][Wid]: window functions and its derivatives up to order K
|
xue@1
|
2252 omg: angular frequency
|
xue@1
|
2253 Out: X[K+1]: windowed spectrum and its derivatives up to order K
|
xue@1
|
2254
|
xue@1
|
2255 No return value. This function is for internal use.
|
xue@1
|
2256 */
|
xue@1
|
2257 void Xkw(cdouble* X, int K, int Wid, double* x, double** w, double omg)
|
xue@1
|
2258 {
|
xue@1
|
2259 int hWid=Wid/2;
|
xue@1
|
2260 //calculate the first row
|
xue@1
|
2261 memset(X, 0, sizeof(cdouble)*(K+1));
|
xue@1
|
2262 for (int i=0; i<Wid; i++)
|
xue@1
|
2263 {
|
xue@1
|
2264 double n=i-hWid;
|
xue@1
|
2265 double ph=omg*n;
|
xue@1
|
2266 for (int k=0; k<=K; k++)
|
xue@1
|
2267 {
|
xue@1
|
2268 cdouble tmp=x[i]*w[k][i];
|
xue@1
|
2269 X[k]+=tmp.rotate(-ph);
|
xue@1
|
2270 }
|
xue@1
|
2271 }
|
xue@1
|
2272 //calculate the rest rows
|
xue@1
|
2273 for (int k=1; k<=K; k++)
|
xue@1
|
2274 {
|
xue@1
|
2275 cdouble *thisX=&X[k], *lastX=&X[k-1];
|
xue@1
|
2276 for (int kk=K-k; kk>=0; kk--) thisX[kk]=-lastX[kk+1]+cdouble(0, omg)*lastX[kk];
|
xue@1
|
2277 }
|
xue@1
|
2278 }//Xkw
|
xue@1
|
2279
|
Chris@5
|
2280 /**
|
xue@1
|
2281 function Xkw: computes windowed spectrum of x and its derivatives up to order K at angular frequency
|
xue@1
|
2282 omg, from x and its derivatives using window w.
|
xue@1
|
2283
|
xue@1
|
2284 In: x[K+1][Wid]: waveform data and its derivatives up to order K.
|
xue@1
|
2285 w[Wid]: window function
|
xue@1
|
2286 omg: angular frequency
|
xue@1
|
2287 Out: X[K+1]: windowed spectrum and its derivatives up to order K
|
xue@1
|
2288
|
xue@1
|
2289 No return value. This function is for testing only.
|
xue@1
|
2290 */
|
xue@1
|
2291 void Xkw(cdouble* X, int K, int Wid, double** x, double* w, double omg)
|
xue@1
|
2292 {
|
xue@1
|
2293 int hWid=Wid/2;
|
xue@1
|
2294 memset(X, 0, sizeof(cdouble)*(K+1));
|
xue@1
|
2295 for (int i=0; i<Wid; i++)
|
xue@1
|
2296 {
|
xue@1
|
2297 double n=i-hWid;
|
xue@1
|
2298 double ph=omg*n;
|
xue@1
|
2299 for (int k=0; k<=K; k++)
|
xue@1
|
2300 {
|
xue@1
|
2301 cdouble tmp=x[k][i]*w[i];
|
xue@1
|
2302 X[k]+=tmp.rotate(-ph);
|
xue@1
|
2303 }
|
xue@1
|
2304 }
|
xue@1
|
2305 }//Xkw
|
xue@1
|
2306
|
Chris@5
|
2307 /**
|
xue@1
|
2308 function Derivative: derivative method for estimating the model log(s)=h[M]'r[M], by discarding extra
|
xue@1
|
2309 equations
|
xue@1
|
2310
|
xue@1
|
2311 In: s[Wid]: waveform data
|
xue@1
|
2312 win[][Wid]: window function and its derivatives
|
xue@1
|
2313 h[M], dh[M]: pointers to basis functions and their derivatives
|
xue@1
|
2314 harg: pointer argument to be used by calls to functions in h[] amd dh[].
|
xue@1
|
2315 p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0.
|
xue@1
|
2316 q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0.
|
xue@1
|
2317 omg: initial angular frequency
|
xue@1
|
2318 Out: r[M]: estimated coefficients to h[M].
|
xue@1
|
2319
|
xue@1
|
2320 No return value.
|
xue@1
|
2321 */
|
xue@1
|
2322 void Derivative(int M, double (**h)(double t, void*), double (**dh)(double t, void*), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg)
|
xue@1
|
2323 {
|
xue@1
|
2324 int hWid=Wid/2, M1=M-1;
|
xue@1
|
2325 int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0
|
xue@1
|
2326 int Kc=ceil(Kr/2.0); //number of derivatives required
|
xue@1
|
2327
|
xue@1
|
2328 //ind marks the 2*M1 real elements of an M1-array of complex unknowns with
|
xue@1
|
2329 // numerical indices (0-based) or -1 if it is not a real unknown variable
|
xue@1
|
2330 //uind marks the Kr real unknowns with their positions in ind
|
xue@1
|
2331 int *uind=new int[Kr], *ind=new int[2*M1];
|
xue@1
|
2332 memset(ind, 0, sizeof(int)*2*M1);
|
xue@1
|
2333 for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1;
|
xue@1
|
2334 for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1;
|
xue@1
|
2335 {
|
xue@1
|
2336 int p=0, up=0;
|
xue@1
|
2337 while (p<2*M1)
|
xue@1
|
2338 {
|
xue@1
|
2339 if (ind[p]>=0)
|
xue@1
|
2340 {
|
xue@1
|
2341 uind[up]=p;
|
xue@1
|
2342 ind[p]=up;
|
xue@1
|
2343 up++;
|
xue@1
|
2344 }
|
xue@1
|
2345 p++;
|
xue@1
|
2346 }
|
xue@1
|
2347 if (up!=Kr) throw("");
|
xue@1
|
2348 }
|
xue@1
|
2349
|
xue@1
|
2350 cdouble* Skw=new cdouble[M];
|
xue@1
|
2351 Xkw(Skw, Kc, Wid, s, win, omg);
|
xue@1
|
2352
|
xue@1
|
2353 double* x=new double[Wid];
|
xue@1
|
2354 cdouble** Allocate2(cdouble, M, Kc, Smkw);
|
xue@1
|
2355 for (int m=1; m<M; m++)
|
xue@1
|
2356 {
|
xue@1
|
2357 for (int i=0; i<Wid; i++) x[i]=dh[m](i-hWid, harg)*s[i];
|
xue@1
|
2358 Xkw(Smkw[m], Kc-1, Wid, x, win, omg);
|
xue@1
|
2359 }
|
xue@1
|
2360
|
xue@1
|
2361 //allocate buffer for linear system A(pq)=b
|
xue@1
|
2362 Alloc2(2*Kc+2, Kr, A); double** AA; double *bb, *pqpq;
|
xue@1
|
2363 double *b=A[2*Kc], *pq=A[2*Kc+1];
|
xue@1
|
2364 for (int k=0; k<Kr; k++) b[k]=((double*)(&Skw[1]))[k];
|
xue@1
|
2365 // *pq=(double*)(&r[1]);
|
xue@1
|
2366 for (int k=0; k<Kc; k++) //looping through rows of A
|
xue@1
|
2367 {
|
xue@1
|
2368 //columns of A includes rows of Smkw corresponding to real unknowns
|
xue@1
|
2369 for (int m=0; m<M1; m++)
|
xue@1
|
2370 {
|
xue@1
|
2371 int lind;
|
xue@1
|
2372 if ((lind=ind[2*m])>=0) //the real part being unknown
|
xue@1
|
2373 {
|
xue@1
|
2374 A[2*k][lind]=Smkw[m+1][k].x;
|
xue@1
|
2375 A[2*k+1][lind]=Smkw[m+1][k].y;
|
xue@1
|
2376 }
|
xue@1
|
2377 if ((lind=ind[2*m+1])>=0) //the imag part being unknown
|
xue@1
|
2378 {
|
xue@1
|
2379 A[2*k+1][lind]=Smkw[m+1][k].x;
|
xue@1
|
2380 A[2*k][lind]=-Smkw[m+1][k].y;
|
xue@1
|
2381 }
|
xue@1
|
2382 }
|
xue@1
|
2383 }
|
xue@1
|
2384
|
xue@1
|
2385 bool dropeq=(2*Kc-1==Kr);
|
xue@1
|
2386 if (dropeq)
|
xue@1
|
2387 {
|
xue@1
|
2388 Allocate2(double, Kr+2, Kr, AA);
|
xue@1
|
2389 bb=AA[Kr], pqpq=AA[Kr+1];
|
xue@1
|
2390 memcpy(AA[0], A[0], sizeof(double)*Kr*(Kr-1));
|
xue@1
|
2391 memcpy(AA[Kr-1], A[Kr], sizeof(double)*Kr);
|
xue@1
|
2392 memcpy(bb, b, sizeof(double)*(Kr-1));
|
xue@1
|
2393 bb[Kr-1]=((double*)(&Skw[1]))[Kr];
|
xue@1
|
2394 }
|
xue@1
|
2395
|
xue@1
|
2396 double det;
|
xue@1
|
2397 GECP(Kr, pq, A, b, &det);
|
xue@1
|
2398 if (dropeq)
|
xue@1
|
2399 {
|
xue@1
|
2400 double det2;
|
xue@1
|
2401 GECP(Kr, pqpq, AA, bb, &det2);
|
xue@1
|
2402 if (fabs(det2)>fabs(det)) memcpy(pq, pqpq, sizeof(double)*Kr);
|
xue@1
|
2403 DeAlloc2(AA);
|
xue@1
|
2404 }
|
xue@1
|
2405 memset(&r[1], 0, sizeof(double)*M1*2);
|
xue@1
|
2406 for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k];
|
xue@1
|
2407
|
xue@1
|
2408 //estiamte r0
|
xue@1
|
2409 cdouble e0=0;
|
xue@1
|
2410 for (int i=0; i<Wid; i++)
|
xue@1
|
2411 {
|
xue@1
|
2412 cdouble expo=0;
|
xue@1
|
2413 double n=i-hWid;
|
xue@1
|
2414 for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;}
|
xue@1
|
2415 cdouble tmp=exp(expo)*win[0][i];
|
xue@1
|
2416 e0+=tmp.rotate(-omg*n);
|
xue@1
|
2417 }
|
xue@1
|
2418 r[0]=log(Skw[0]/e0);
|
xue@1
|
2419
|
xue@1
|
2420 delete[] x;
|
xue@1
|
2421 delete[] Skw;
|
xue@1
|
2422 delete[] uind;
|
xue@1
|
2423 delete[] ind;
|
xue@1
|
2424 DeAlloc2(Smkw);
|
xue@1
|
2425 DeAlloc2(A);
|
xue@1
|
2426 }//Derivative*/
|
xue@1
|
2427
|
Chris@5
|
2428 /**
|
xue@1
|
2429 function DerivativeLS: derivative method for estimating the model log(s)=h[M]'r[M], least-square
|
xue@1
|
2430 implementation
|
xue@1
|
2431
|
xue@1
|
2432 In: s[Wid]: waveform data
|
xue@1
|
2433 win[][Wid]: window function and its derivatives
|
xue@1
|
2434 h[M], dh[M]: pointers to basis functions and their derivatives
|
xue@1
|
2435 harg: pointer argument to be used by calls to functions in h[] amd dh[].
|
xue@1
|
2436 K: number of derivatives to take
|
xue@1
|
2437 p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0.
|
xue@1
|
2438 q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0.
|
xue@1
|
2439 omg: initial angular frequency
|
xue@1
|
2440 Out: r[M]: estimated coefficients to h[M].
|
xue@1
|
2441
|
xue@1
|
2442 No return value.
|
xue@1
|
2443 */
|
xue@1
|
2444 void DerivativeLS(int K, int M, double (**h)(double t, void* harg), double (**dh)(double t, void* harg), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg, bool r0)
|
xue@1
|
2445 {
|
xue@1
|
2446 int hWid=Wid/2, M1=M-1;
|
xue@1
|
2447 int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0
|
xue@1
|
2448 int Kc=ceil(Kr/2.0); //number of derivatives required
|
xue@1
|
2449 if (Kc<K) Kc=K;
|
xue@1
|
2450
|
xue@1
|
2451 int *uind=new int[Kr], *ind=new int[2*M1];
|
xue@1
|
2452 memset(ind, 0, sizeof(int)*2*M1);
|
xue@1
|
2453 for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1;
|
xue@1
|
2454 for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1;
|
xue@1
|
2455 {int p=0, up=0; while (p<2*M1){if (ind[p]>=0){uind[up]=p; ind[p]=up; up++;} p++;} if (up!=Kr) throw("");}
|
xue@1
|
2456
|
xue@1
|
2457 //allocate buffer for linear system A(pq)=b
|
xue@1
|
2458 cdouble* Skw=new cdouble[Kc+1];
|
xue@1
|
2459 double* x=new double[Wid];
|
xue@1
|
2460 cdouble** Allocate2(cdouble, M, Kc, Smkw);
|
xue@1
|
2461
|
xue@1
|
2462 Alloc2(2*Kc+2, 2*Kc, A);
|
xue@1
|
2463 double *b=A[2*Kc], *pq=A[2*Kc+1];
|
xue@1
|
2464
|
xue@1
|
2465 Xkw(Skw, Kc, Wid, s, win, omg);
|
xue@1
|
2466 for (int m=1; m<M; m++)
|
xue@1
|
2467 {
|
xue@1
|
2468 for (int i=0; i<Wid; i++) x[i]=dh[m](i-hWid, harg)*s[i];
|
xue@1
|
2469 Xkw(Smkw[m], Kc-1, Wid, x, win, omg);
|
xue@1
|
2470 }
|
xue@1
|
2471
|
xue@1
|
2472 for (int k=0; k<2*Kc; k++) b[k]=((double*)(&Skw[1]))[k];
|
xue@1
|
2473 for (int k=0; k<Kc; k++)
|
xue@1
|
2474 {
|
xue@1
|
2475 for (int m=0; m<M1; m++)
|
xue@1
|
2476 {
|
xue@1
|
2477 int lind;
|
xue@1
|
2478 if ((lind=ind[2*m])>=0)
|
xue@1
|
2479 {
|
xue@1
|
2480 A[2*k][lind]=Smkw[m+1][k].x;
|
xue@1
|
2481 A[2*k+1][lind]=Smkw[m+1][k].y;
|
xue@1
|
2482 }
|
xue@1
|
2483 if ((lind=ind[2*m+1])>=0)
|
xue@1
|
2484 {
|
xue@1
|
2485 A[2*k+1][lind]=Smkw[m+1][k].x;
|
xue@1
|
2486 A[2*k][lind]=-Smkw[m+1][k].y;
|
xue@1
|
2487 }
|
xue@1
|
2488 }
|
xue@1
|
2489 }
|
xue@1
|
2490
|
xue@1
|
2491 if (2*Kc==Kr) GECP(Kr, pq, A, b);
|
xue@1
|
2492 else LSLinear2(2*Kc, Kr, pq, A, b);
|
xue@1
|
2493
|
xue@1
|
2494 memset(&r[1], 0, sizeof(double)*M1*2);
|
xue@1
|
2495 for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k];
|
xue@1
|
2496 //estiamte r0
|
xue@1
|
2497 if (r0)
|
xue@1
|
2498 {
|
xue@1
|
2499 cdouble e0=0;
|
xue@1
|
2500 for (int i=0; i<Wid; i++)
|
xue@1
|
2501 {
|
xue@1
|
2502 cdouble expo=0;
|
xue@1
|
2503 double n=i-hWid;
|
xue@1
|
2504 for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;}
|
xue@1
|
2505 cdouble tmp=exp(expo)*win[0][i];
|
xue@1
|
2506 e0+=tmp.rotate(-omg*n);
|
xue@1
|
2507 }
|
xue@1
|
2508 r[0]=log(Skw[0]/e0);
|
xue@1
|
2509 }
|
xue@1
|
2510 delete[] x;
|
xue@1
|
2511 delete[] Skw;
|
xue@1
|
2512 delete[] uind;
|
xue@1
|
2513 delete[] ind;
|
xue@1
|
2514 DeAlloc2(Smkw);
|
xue@1
|
2515 DeAlloc2(A);
|
xue@1
|
2516 }//DerivativeLS
|
xue@1
|
2517
|
Chris@5
|
2518 /**
|
xue@1
|
2519 function DerivativeLS: derivative method for estimating the model log(s)=h[M]'r[M] using Fr
|
xue@1
|
2520 measurement points a quarter of Wid apart from each other, implemented by least-square.
|
xue@1
|
2521
|
xue@1
|
2522 In: s[Wid+(Fr-1)*Wid/4]: waveform data
|
xue@1
|
2523 win[][Wid]: window function and its derivatives
|
xue@1
|
2524 h[M], dh[M]: pointers to basis functions and their derivatives
|
xue@1
|
2525 harg: pointer argument to be used by calls to functions in h[] amd dh[].
|
xue@1
|
2526 Fr: number of measurement points
|
xue@1
|
2527 K: number of derivatives to take at each measurement point
|
xue@1
|
2528 p0[p0s]: zero-constraints on real parts of r, i.e. Re(r[p0[*]]) are constrained to 0.
|
xue@1
|
2529 q0[q0s]: zero-constraints on imaginary parts of r, i.e. Im(r[q0[*]]) are constrained to 0.
|
xue@1
|
2530 omg: initial angular frequency
|
xue@1
|
2531 r0: specifies if r[0] is to be computed.
|
xue@1
|
2532 Out: r[M]: estimated coefficients to h[M].
|
xue@1
|
2533
|
xue@1
|
2534 No return value.
|
xue@1
|
2535 */
|
xue@1
|
2536 void DerivativeLS(int Fr, int K, int M, double (**h)(double t, void* harg), double (**dh)(double t, void* harg), cdouble* r, int p0s, int* p0, int q0s, int* q0, int Wid, double* s, double** win, double omg, void* harg, bool r0)
|
xue@1
|
2537 {
|
xue@1
|
2538 int hWid=Wid/2, qWid=Wid/4, M1=M-1;
|
xue@1
|
2539 int Kr=(M1)*2-p0s-q0s; //number of real unknowns apart from p0 and q0
|
xue@1
|
2540 int Kc=ceil(Kr/2.0/Fr); //number of derivatives required
|
xue@1
|
2541 if (Kc<K) Kc=K;
|
xue@1
|
2542
|
xue@1
|
2543 int *uind=new int[Kr], *ind=new int[2*M1];
|
xue@1
|
2544 memset(ind, 0, sizeof(int)*2*M1);
|
xue@1
|
2545 for (int p=0; p<p0s; p++) ind[2*(p0[p]-1)]=-1;
|
xue@1
|
2546 for (int q=0; q<q0s; q++) ind[2*(q0[q]-1)+1]=-1;
|
xue@1
|
2547 {int p=0, up=0; while (p<2*M1){if (ind[p]>=0){uind[up]=p; ind[p]=up; up++;} p++;}}
|
xue@1
|
2548
|
xue@1
|
2549 //allocate buffer for linear system A(pq)=b
|
xue@1
|
2550 cdouble* Skw=new cdouble[Kc+1], Skw00;
|
xue@1
|
2551 double* x=new double[Wid];
|
xue@1
|
2552 cdouble** Allocate2(cdouble, M, Kc, Smkw);
|
xue@1
|
2553
|
xue@1
|
2554 Alloc2(2*Fr*Kc, 2*Fr*Kc, A);
|
xue@1
|
2555 double *pq=new double[2*Fr*Kc], *b=new double[2*Fr*Kc];
|
xue@1
|
2556
|
xue@1
|
2557 for (int fr=0; fr<Fr; fr++)
|
xue@1
|
2558 {
|
xue@1
|
2559 int Offst=qWid*fr; double* ss=&s[Offst];
|
xue@1
|
2560
|
xue@1
|
2561 Xkw(Skw, Kc, Wid, ss, win, omg); if (fr==0) Skw00=Skw[0];
|
xue@1
|
2562 for (int m=1; m<M; m++)
|
xue@1
|
2563 {
|
xue@1
|
2564 for (int i=0; i<Wid; i++) x[i]=dh[m](i+Offst-hWid, harg)*ss[i];
|
xue@1
|
2565 Xkw(Smkw[m], Kc-1, Wid, x, win, omg);
|
xue@1
|
2566 }
|
xue@1
|
2567
|
xue@1
|
2568 for (int k=0; k<2*Kc; k++) b[2*fr*Kc+k]=((double*)(&Skw[1]))[k];
|
xue@1
|
2569 for (int k=0; k<Kc; k++)
|
xue@1
|
2570 {
|
xue@1
|
2571 for (int m=0; m<M1; m++)
|
xue@1
|
2572 {
|
xue@1
|
2573 int lind;
|
xue@1
|
2574 if ((lind=ind[2*m])>=0)
|
xue@1
|
2575 {
|
xue@1
|
2576 A[2*fr*Kc+2*k][lind]=Smkw[m+1][k].x;
|
xue@1
|
2577 A[2*fr*Kc+2*k+1][lind]=Smkw[m+1][k].y;
|
xue@1
|
2578 }
|
xue@1
|
2579 if ((lind=ind[2*m+1])>=0)
|
xue@1
|
2580 {
|
xue@1
|
2581 A[2*fr*Kc+2*k+1][lind]=Smkw[m+1][k].x;
|
xue@1
|
2582 A[2*fr*Kc+2*k][lind]=-Smkw[m+1][k].y;
|
xue@1
|
2583 }
|
xue@1
|
2584 }
|
xue@1
|
2585 }
|
xue@1
|
2586 }
|
xue@1
|
2587 if (2*Fr*Kc==Kr) GECP(Kr, pq, A, b);
|
xue@1
|
2588 else LSLinear2(2*Fr*Kc, Kr, pq, A, b);
|
xue@1
|
2589
|
xue@1
|
2590 memset(&r[1], 0, sizeof(double)*M1*2);
|
xue@1
|
2591 for (int k=0; k<Kr; k++) ((double*)(&r[1]))[uind[k]]=pq[k];
|
xue@1
|
2592 //estiamte r0
|
xue@1
|
2593 if (r0)
|
xue@1
|
2594 {
|
xue@1
|
2595 cdouble e0=0;
|
xue@1
|
2596 for (int i=0; i<Wid; i++)
|
xue@1
|
2597 {
|
xue@1
|
2598 cdouble expo=0;
|
xue@1
|
2599 double n=i-hWid;
|
xue@1
|
2600 for (int m=1; m<M; m++){double lhm=h[m](n, harg); expo+=r[m]*lhm;}
|
xue@1
|
2601 cdouble tmp=exp(expo)*win[0][i];
|
xue@1
|
2602 e0+=tmp.rotate(-omg*n);
|
xue@1
|
2603 }
|
xue@1
|
2604 r[0]=log(Skw00/e0);
|
xue@1
|
2605 }
|
xue@1
|
2606 delete[] x;
|
xue@1
|
2607 delete[] Skw;
|
xue@1
|
2608 delete[] uind;
|
xue@1
|
2609 delete[] ind;
|
xue@1
|
2610 DeAlloc2(Smkw);
|
xue@1
|
2611 DeAlloc2(A);
|
xue@1
|
2612 delete[] pq; delete[] b;
|
xue@1
|
2613 }//DerivativeLS
|
xue@1
|
2614
|
xue@1
|
2615 //---------------------------------------------------------------------------
|
xue@1
|
2616 /*
|
xue@1
|
2617 Abe-Smith sinusoid estimator 2005
|
xue@1
|
2618
|
xue@1
|
2619 Further reading: M. Abe and J. O. Smith III, ¡°AM/FM rate estimation for time-varying sinusoidal
|
xue@1
|
2620 modeling,¡± in Proc. ICASSP'05, Philadelphia, 2005.
|
xue@1
|
2621 */
|
xue@1
|
2622
|
Chris@5
|
2623 /**
|
xue@1
|
2624 function RDFTW: windowed DTFT at frequency k bins
|
xue@1
|
2625
|
xue@1
|
2626 In: data[Wid]: waveform data
|
xue@1
|
2627 w[Wid]: window function
|
xue@1
|
2628 k: frequency, in bins
|
xue@1
|
2629 Out: Xr, Xi: real and imaginary parts of the DTFT of xw at frequency k bins
|
xue@1
|
2630
|
xue@1
|
2631 No return value.
|
xue@1
|
2632 */
|
xue@1
|
2633 void RDFTW(double& Xr, double& Xi, double k, int Wid, double* data, double* w)
|
xue@1
|
2634 {
|
xue@1
|
2635 Xr=Xi=0;
|
xue@1
|
2636 int hWid=Wid/2;
|
xue@1
|
2637 double* lw=&w[Wid];
|
xue@1
|
2638 for (int i=0; i<=Wid; i++)
|
xue@1
|
2639 {
|
xue@1
|
2640 double tmp;
|
xue@1
|
2641 tmp=*data**lw;
|
xue@1
|
2642 data++, lw--;
|
xue@1
|
2643 //*
|
xue@1
|
2644 double ph=-2*M_PI*(i-hWid)*k/Wid;
|
xue@1
|
2645 Xr+=tmp*cos(ph);
|
xue@1
|
2646 Xi+=tmp*sin(ph); //*/
|
xue@1
|
2647 }
|
xue@1
|
2648 }//RDFTW
|
xue@1
|
2649
|
Chris@5
|
2650 /**
|
xue@1
|
2651 function TFAS05: the Abe-Smith method 2005
|
xue@1
|
2652
|
xue@1
|
2653 In: data[Wid]: waveform data
|
xue@1
|
2654 w[Wid]: window function
|
xue@1
|
2655 res: resolution of frequency for QIFFT
|
xue@1
|
2656 Out: f, a, ph: frequency, amplitude and phase angle estimates
|
xue@1
|
2657 aesp, fslope: estimates of log amplitude and frequency derivatives
|
xue@1
|
2658
|
xue@1
|
2659 No return value.
|
xue@1
|
2660 */
|
xue@1
|
2661 void TFAS05(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res)
|
xue@1
|
2662 {
|
xue@1
|
2663 double fi=floor(f*Wid+0.5); //frequency (int) in bins
|
xue@1
|
2664 double xr0, xi0, xr_1, xi_1, xr1, xi1;
|
xue@1
|
2665 RDFTW(xr0, xi0, fi, Wid, data, w);
|
xue@1
|
2666 RDFTW(xr_1, xi_1, fi-res, Wid, data, w);
|
xue@1
|
2667 RDFTW(xr1, xi1, fi+res, Wid, data, w);
|
xue@1
|
2668 double winnorm=0; for (int i=0; i<=Wid; i++) winnorm+=w[i];
|
xue@1
|
2669 double y0=log(sqrt(xr0*xr0+xi0*xi0)/winnorm),
|
xue@1
|
2670 y_1=log(sqrt(xr_1*xr_1+xi_1*xi_1)/winnorm),
|
xue@1
|
2671 y1=log(sqrt(xr1*xr1+xi1*xi1)/winnorm);
|
xue@1
|
2672 double df=0;
|
xue@1
|
2673 //*
|
xue@1
|
2674 if (y0<y1)
|
xue@1
|
2675 {
|
xue@1
|
2676 double newfi=fi+res;
|
xue@1
|
2677 while (y0<y1)
|
xue@1
|
2678 {
|
xue@1
|
2679 y_1=y0, xr_1=xr0, xi_1=xi0;
|
xue@1
|
2680 y0=y1, xr0=xr1, xi0=xi1;
|
xue@1
|
2681 newfi+=res;
|
xue@1
|
2682 RDFTW(xr1, xi1, newfi, Wid, data, w);
|
xue@1
|
2683 y1=log(sqrt(xr1*xr1+xi1*xi1)/winnorm);
|
xue@1
|
2684 fi+=res;
|
xue@1
|
2685 }
|
xue@1
|
2686 }
|
xue@1
|
2687 else if(y0<y_1)
|
xue@1
|
2688 {
|
xue@1
|
2689 double newfi=fi-res;
|
xue@1
|
2690 while (y0<y_1)
|
xue@1
|
2691 {
|
xue@1
|
2692 y1=y0, xr1=xr0, xi1=xi0;
|
xue@1
|
2693 y0=y_1, xr0=xr_1, xi0=xi_1;
|
xue@1
|
2694 newfi-=res;
|
xue@1
|
2695 RDFTW(xr_1, xi_1, newfi, Wid, data, w);
|
xue@1
|
2696 y_1=log(sqrt(xr_1*xr_1+xi_1*xi_1)/winnorm);
|
xue@1
|
2697 fi-=res;
|
xue@1
|
2698 }
|
xue@1
|
2699 } //*/
|
xue@1
|
2700
|
xue@1
|
2701 double a2=(y1+y_1)*0.5-y0, a1=(y1-y_1)*0.5, a0=y0;
|
xue@1
|
2702 df=-a1*0.5/a2;
|
xue@1
|
2703 f=fi+df*res; //in bins
|
xue@1
|
2704 double y=a0-0.25*a1*a1/a2;
|
xue@1
|
2705 a=exp(y);
|
xue@1
|
2706 double ph0=(xi0==0 && xr0==0)?0:atan2(xi0, xr0),
|
xue@1
|
2707 ph_1=(xi_1==0 && xr_1==0)?0:atan2(xi_1, xr_1),
|
xue@1
|
2708 ph1=(xi1==0 && xr1==0)?0:atan2(xi1, xr1);
|
xue@1
|
2709 if (fabs(ph_1-ph0)>M_PI)
|
xue@1
|
2710 {
|
xue@1
|
2711 if (ph_1-ph0>0) ph_1-=M_PI*2;
|
xue@1
|
2712 else ph_1+=M_PI*2;
|
xue@1
|
2713 }
|
xue@1
|
2714 if (fabs(ph1-ph0)>M_PI)
|
xue@1
|
2715 {
|
xue@1
|
2716 if (ph1-ph0>0) ph1-=M_PI*2;
|
xue@1
|
2717 else ph1+=M_PI*2;
|
xue@1
|
2718 }
|
xue@1
|
2719 double b2=(ph1+ph_1)*0.5-ph0, b1=(ph1-ph_1)*0.5, b0=ph0;
|
xue@1
|
2720 ph=b0+b1*(df+b2*df);
|
xue@1
|
2721 //now we have the QI estimates
|
xue@1
|
2722 double uff=2*a2, vf=b1+2*b2*df, vff=2*b2;
|
xue@1
|
2723 double dfdp=Wid/(2*M_PI*res);
|
xue@1
|
2724 double upp=uff*dfdp*dfdp, vp=vf*dfdp, vpp=vff*dfdp*dfdp;
|
xue@1
|
2725 double p=-upp*0.5/(upp*upp+vpp*vpp);
|
xue@1
|
2726 double alf=-2*p*vp, beta=p*vpp/upp;
|
xue@1
|
2727 //*direct method
|
xue@1
|
2728 double beta_p=beta/p;
|
xue@1
|
2729 double feses=f-alf*beta/p /(2*M_PI)*Wid,
|
xue@1
|
2730 yeses=y-alf*alf*0.25/p+0.25*log(1+beta_p*beta_p),
|
xue@1
|
2731 pheses=ph+alf*alf*beta*0.25/p-0.5*atan(beta_p); //*/
|
xue@1
|
2732 /*adapted method
|
xue@1
|
2733 double zt[]={0, 0.995354, 0.169257, 1.393056, 0.442406, -0.717980, -0.251620, 0.177511, 0.158120, -0.503299};
|
xue@1
|
2734 double delt=res/Wid; double delt0=df*delt;
|
xue@1
|
2735 beta=zt[3]*beta+zt[4]*delt0*alf;
|
xue@1
|
2736 alf=(zt[1]+zt[2]*delt*delt)*alf;
|
xue@1
|
2737 double beta_p=beta/p;
|
xue@1
|
2738 double feses=f+zt[5]*alf*beta/p /(2*M_PI)*Wid,
|
xue@1
|
2739 yeses=y+zt[6]*alf*alf/p+zt[7]*log(1+beta_p*beta_p),
|
xue@1
|
2740 pheses=ph+zt[8]*alf*alf*beta/p+zt[9]*atan(beta_p); //*/
|
xue@1
|
2741 f=feses/Wid, a=exp(yeses), ph=pheses, fslope=2*beta/2/M_PI, aesp=alf;
|
xue@1
|
2742 }//TFAS05
|
xue@1
|
2743
|
Chris@5
|
2744 /**
|
xue@1
|
2745 function TFAS05_enh: the Abe-Smith method 2005 enhanced by LSE amplitude and phase estimation
|
xue@1
|
2746
|
xue@1
|
2747 In: data[Wid]: waveform data
|
xue@1
|
2748 w[Wid]: window function
|
xue@1
|
2749 res: resolution of frequency for QIFFT
|
xue@1
|
2750 Out: f, a, ph: frequency, amplitude and phase angle estimates
|
xue@1
|
2751 aesp, fslope: estimates of log amplitude and frequency derivatives
|
xue@1
|
2752
|
xue@1
|
2753 No return value.
|
xue@1
|
2754 */
|
xue@1
|
2755 void TFAS05_enh(double& f, double& t, double& a, double& ph, double& aesp, double& fslope, int Wid, double* data, double* w, double res)
|
xue@1
|
2756 {
|
xue@1
|
2757 TFAS05(f, t, a, ph, aesp, fslope, Wid, data, w, res);
|
xue@1
|
2758 double xr=0, xi=0, p, win2=0;
|
xue@1
|
2759 for (int n=0; n<=Wid; n++)
|
xue@1
|
2760 {
|
xue@1
|
2761 double ni=n-Wid/2, tmp=data[n]*w[n]*w[n];//*exp(-aesp*(n-Wid/2)); if (IsInfinite(tmp)) continue;
|
xue@1
|
2762 p=-2*M_PI*(f+0.5*fslope*ni)*ni;
|
xue@1
|
2763 xr+=tmp*cos(p);
|
xue@1
|
2764 xi+=tmp*sin(p);
|
xue@1
|
2765 win2+=w[n]*w[n];
|
xue@1
|
2766 }
|
xue@1
|
2767 a=sqrt(xr*xr+xi*xi)/win2;
|
xue@1
|
2768 ph=(xr==0 && xi==0)?0:atan2(xi, xr);
|
xue@1
|
2769 }//TFAS05_enh
|
xue@1
|
2770 //version without returning aesp and fslope
|
xue@1
|
2771 void TFAS05_enh(double& f, double& t, double& a, double& ph, int Wid, double* data, double* w, double res)
|
xue@1
|
2772 {
|
xue@1
|
2773 double aesp, fslope;
|
xue@1
|
2774 TFAS05_enh(f, t, a, ph, aesp, fslope, Wid, data, w, res);
|
xue@1
|
2775 }//TFAS05_enh
|
xue@1
|
2776
|
xue@1
|
2777 //---------------------------------------------------------------------------
|
Chris@5
|
2778 /**
|
xue@1
|
2779 function DerivativeLSv_AmpPh: estimate the constant-term in the local derivative method. This is used
|
xue@1
|
2780 by the local derivative algorithm, whose implementation is found in the header file as templates.
|
xue@1
|
2781
|
xue@1
|
2782 In: sv0: inner product <s, v0>, where s is the sinusoid being estimated.
|
xue@1
|
2783 integr_h[M][Wid]: M vectors containing samples of the integral of basis functions h[M].
|
xue@1
|
2784 v0[M]: a test function
|
xue@1
|
2785 lmd[M]: coefficients to h[M]
|
xue@1
|
2786
|
xue@1
|
2787 Returns coefficient of integr_h[0]=1.
|
xue@1
|
2788 */
|
xue@1
|
2789 cdouble DerivativeLSv_AmpPh(int Wid, int M, double** integr_h, cdouble* lmd, cdouble* v0, cdouble sv0)
|
xue@1
|
2790 {
|
xue@1
|
2791 cdouble e0=0;
|
xue@1
|
2792 for (int n=0; n<Wid; n++)
|
xue@1
|
2793 {
|
xue@1
|
2794 cdouble expo=0;
|
xue@1
|
2795 for (int m=1; m<=M; m++) expo+=lmd[m]*integr_h[m][n];
|
xue@1
|
2796 e0+=exp(expo)**v0[n];
|
xue@1
|
2797 }
|
xue@1
|
2798 return log(sv0/e0);
|
xue@1
|
2799 }//DerivativeLSv_AmpPh
|
xue@1
|
2800
|
xue@1
|
2801 //---------------------------------------------------------------------------
|
xue@1
|
2802 /*
|
xue@1
|
2803 Piecewise derivative algorithm
|
xue@1
|
2804
|
xue@1
|
2805 Further reading: Wen X. and M. Sandler, "Spline exponential approximation of time-varying
|
xue@1
|
2806 sinusoids," under review.
|
xue@1
|
2807 */
|
xue@1
|
2808
|
Chris@5
|
2809 /**
|
xue@1
|
2810 function setv: computes I test functions v[I] by modulation u[I] to frequency f
|
xue@1
|
2811
|
xue@1
|
2812 In: u[I+1][Wid], du[I+1][Wid]: base-band test functions and their derivatives
|
xue@1
|
2813 f: carrier frequency
|
xue@1
|
2814 Out: v[I][Wid], dv[I][Wid]: test functions and their derivatives
|
xue@1
|
2815
|
xue@1
|
2816 No return value.
|
xue@1
|
2817 */
|
xue@1
|
2818 void setv(int I, int Wid, cdouble** v, cdouble** dv, double f, cdouble** u, cdouble** du)
|
xue@1
|
2819 {
|
xue@1
|
2820 double fbin=floor(f*Wid+0.5)/Wid;
|
xue@1
|
2821 double omg=fbin*2*M_PI;
|
xue@1
|
2822 cdouble jomg=cdouble(0, omg);
|
xue@1
|
2823 for (int c=0; c<Wid; c++)
|
xue@1
|
2824 {
|
xue@1
|
2825 double t=c;
|
xue@1
|
2826 cdouble rot=polar(1.0, omg*t);
|
xue@1
|
2827 for (int i=0; i<I-1; i++) v[i][c]=u[i][c]*rot;
|
xue@1
|
2828 for (int i=0; i<I-1; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c];
|
xue@1
|
2829 //Here it is assumed that elements of u[] are modulated at 0, 1, -1, 2, -2, 3, -3, 4, ...;
|
xue@1
|
2830 //if f is under fbin then the closest ones are in order 0, -1, 1, -2, 3, -3, 3, .... This
|
xue@1
|
2831 //makes a difference to the whole of v[] only if I is even.
|
xue@1
|
2832 if (f>=fbin || I%2==1){v[I-1][c]=u[I-1][c]*rot; dv[I-1][c]=du[I-1][c]*rot+jomg*v[I-1][c];}
|
xue@1
|
2833 else{v[I-1][c]=u[I][c]*rot; dv[I-1][c]=du[I][c]*rot+jomg*v[I-1][c];}
|
xue@1
|
2834 }
|
xue@1
|
2835 }//setv
|
xue@1
|
2836
|
Chris@5
|
2837 /**
|
xue@1
|
2838 function setvhalf: computes I half-size test functions v[I] by modulation u[I] to frequency f.
|
xue@1
|
2839
|
xue@1
|
2840 In: u[I][hWid*2], du[I][Wid*2]: base-band test functions and their derivatives
|
xue@1
|
2841 f: carrier frequency
|
xue@1
|
2842 Out: v[I][hWid], dv[hWid]: half-size test functions and their derivatives
|
xue@1
|
2843
|
xue@1
|
2844 No return value.
|
xue@1
|
2845 */void setvhalf(int I, int hWid, cdouble** v, cdouble** dv, double f, cdouble** u, cdouble** du)
|
xue@1
|
2846 {
|
xue@1
|
2847 double fbin=floor(f*hWid)/hWid;
|
xue@1
|
2848 double omg=fbin*2*M_PI;
|
xue@1
|
2849 cdouble jomg=cdouble(0, omg);
|
xue@1
|
2850 for (int c=0; c<hWid; c++)
|
xue@1
|
2851 {
|
xue@1
|
2852 double t=c;
|
xue@1
|
2853 cdouble rot=polar(1.0, omg*t);
|
xue@1
|
2854 for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
|
xue@1
|
2855 for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c];
|
xue@1
|
2856 }
|
xue@1
|
2857 }//setvhalf
|
xue@1
|
2858
|
xue@1
|
2859 //#define ERROR_CHECK
|
xue@1
|
2860
|
Chris@5
|
2861 /**
|
xue@1
|
2862 function DerivativePiecewise: Piecewise derivative algorithm. In this implementation of the piecewise
|
xue@1
|
2863 method the test functions v are constructed from I "basic" (single-frame) test functions, each
|
xue@1
|
2864 covering the same period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I
|
xue@1
|
2865 test functions are used.
|
xue@1
|
2866
|
xue@1
|
2867 In: s[LT+1]: waveform data
|
xue@1
|
2868 ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined.
|
xue@1
|
2869 L, T: number and length of pieces.
|
xue@1
|
2870 N: number of independent coefficients
|
xue@1
|
2871 h[M][T]: piecewise basis functions
|
xue@1
|
2872 A[L][M][N]: L matrices that map independent coefficients onto component coefficients over the L pieces
|
xue@1
|
2873 u[I][2T}, du[I][2T]: base-band test functions
|
xue@1
|
2874 f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used
|
xue@1
|
2875 endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT]
|
xue@1
|
2876 Out: aita[N]: independent coefficients
|
xue@1
|
2877
|
xue@1
|
2878 No return value.
|
xue@1
|
2879 */
|
xue@1
|
2880 void DerivativePiecewise(int N, cdouble* aita, int L, double* f, int T, cdouble* s, double*** A, int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds)
|
xue@1
|
2881 {
|
xue@1
|
2882 MList* mlist=new MList;
|
xue@1
|
2883 int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L);
|
xue@1
|
2884 cdouble** Allocate2L(cdouble, L_1, I, sv, mlist);
|
xue@1
|
2885 cdouble** Allocate2(cdouble, I, T*2, v);
|
xue@1
|
2886 cdouble** Allocate2(cdouble, I, T*2, dv);
|
xue@1
|
2887 //compute <sr, v>
|
xue@1
|
2888 cdouble*** Allocate3L(cdouble, L_1, I, N, srv, mlist);
|
xue@1
|
2889 cdouble** Allocate2L(cdouble, I, M, shv1, mlist);
|
xue@1
|
2890 cdouble** Allocate2L(cdouble, I, M, shv2, mlist);
|
xue@1
|
2891
|
xue@1
|
2892 #ifdef ERROR_CHECK
|
xue@1
|
2893 cdouble dsv1[128], dsv2[128];
|
xue@1
|
2894 #endif
|
xue@1
|
2895 for (int l=0; l<L-1; l++)
|
xue@1
|
2896 {
|
xue@1
|
2897 //v from u given f[l]
|
xue@1
|
2898 double fbin=floor(f[l+1]*T*2)/(T*2.0);
|
xue@1
|
2899 double omg=fbin*2*M_PI;
|
xue@1
|
2900 cdouble jomg=cdouble(0, omg);
|
xue@1
|
2901 for (int c=0; c<T*2; c++)
|
xue@1
|
2902 {
|
xue@1
|
2903 double t=c-T;
|
xue@1
|
2904 cdouble rot=polar(1.0, omg*t);
|
xue@1
|
2905 for (int i=0; i<I; i++) v[i][c]=u[i][c]*rot;
|
xue@1
|
2906 for (int i=0; i<I; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c];
|
xue@1
|
2907 }
|
xue@1
|
2908
|
xue@1
|
2909 //compute -<s, v'> over the lth frame
|
xue@1
|
2910 cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]);
|
xue@1
|
2911
|
xue@1
|
2912 //compute <sr, v> over the lth frame
|
xue@1
|
2913 cdouble *ls1=&s[l*T], *ls2=&s[l*T+T];
|
xue@1
|
2914 for (int i=0; i<I; i++)
|
xue@1
|
2915 for (int m=0; m<M; m++)
|
xue@1
|
2916 shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]);
|
xue@1
|
2917 //memset(srv[l][0], 0, sizeof(cdouble)*I*N);
|
xue@1
|
2918 MultiplyXY(I, M, N, srv[l], shv1, A[l]);
|
xue@1
|
2919 MultiAddXY(I, M, N, srv[l], shv2, A[l+1]);
|
xue@1
|
2920
|
xue@1
|
2921 #ifdef ERROR_CHECK
|
xue@1
|
2922 //error check: <s', v>=-<s, v'>
|
xue@1
|
2923 if (ds)
|
xue@1
|
2924 {
|
xue@1
|
2925 cdouble* lds=&ds[l*T];
|
xue@1
|
2926 for (int i=0; i<I && l*I+1<36; i++)
|
xue@1
|
2927 {
|
xue@1
|
2928 cdouble lsv=Inner(2*T, lds, v[i]); //compute <s', v[i]>
|
xue@1
|
2929 //cdouble* ls=&s[l*T];
|
xue@1
|
2930 //cdouble lsv2=Inner(2*T, ls, dv[i]);
|
xue@1
|
2931 dsv1[l*I+i]=lsv-sv[l][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i]
|
xue@1
|
2932 }
|
xue@1
|
2933
|
xue@1
|
2934 //error check: srv[l]*pq=<s',v>
|
xue@1
|
2935 for (int i=0; i<I && l*I+i<36; i++)
|
xue@1
|
2936 {
|
xue@1
|
2937 cdouble lsv=0;
|
xue@1
|
2938 for (int n=0; n<N; n++) lsv+=srv[l][i][n]*aita[n];
|
xue@1
|
2939 dsv2[l*I+i]=lsv-sv[l][i]-dsv1[l*I+i];
|
xue@1
|
2940 }
|
xue@1
|
2941 }
|
xue@1
|
2942 #endif
|
xue@1
|
2943 }
|
xue@1
|
2944 L_1=L-1;
|
xue@1
|
2945 if (endmode==1 || endmode==3)
|
xue@1
|
2946 {
|
xue@1
|
2947 //v from u given f[l]
|
xue@1
|
2948 int hT=T/2;
|
xue@1
|
2949 double fbin=floor((f[0]+f[1])*hT)/T;
|
xue@1
|
2950 double omg=fbin*2*M_PI;
|
xue@1
|
2951 cdouble jomg=cdouble(0, omg);
|
xue@1
|
2952 for (int c=0; c<T; c++)
|
xue@1
|
2953 {
|
xue@1
|
2954 double t=c-hT;
|
xue@1
|
2955 cdouble rot=polar(1.0, omg*t);
|
xue@1
|
2956 for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
|
xue@1
|
2957 for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c];
|
xue@1
|
2958 }
|
xue@1
|
2959
|
xue@1
|
2960 //compute -<s, v'> over the lth frame
|
xue@1
|
2961 cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
|
xue@1
|
2962
|
xue@1
|
2963 //compute <sr, v> over the lth frame
|
xue@1
|
2964 for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
|
xue@1
|
2965 //memset(srv[L_1][0], 0, sizeof(cdouble)*I*N);
|
xue@1
|
2966 MultiplyXY(I, M, N, srv[L_1], shv1, A[0]);
|
xue@1
|
2967 #ifdef ERROR_CHECK
|
xue@1
|
2968 //error check: <s', v>=-<s, v'>
|
xue@1
|
2969 if (ds)
|
xue@1
|
2970 {
|
xue@1
|
2971 cdouble* lds=&ds[0];
|
xue@1
|
2972 for (int i=0; i<I && L_1*I+1<36; i++)
|
xue@1
|
2973 {
|
xue@1
|
2974 cdouble lsv=Inner(T, lds, v[i]); //compute <s', v[i]>
|
xue@1
|
2975 //cdouble* ls=&s[l*T];
|
xue@1
|
2976 //cdouble lsv2=Inner(2*T, ls, dv[i]);
|
xue@1
|
2977 dsv1[L_1*I+i]=lsv-sv[L_1][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i]
|
xue@1
|
2978 }
|
xue@1
|
2979
|
xue@1
|
2980 //error check: srv[l]*pq=<s',v>
|
xue@1
|
2981 for (int i=0; i<I && L_1*I+i<36; i++)
|
xue@1
|
2982 {
|
xue@1
|
2983 cdouble lsv=0;
|
xue@1
|
2984 for (int n=0; n<N; n++) lsv+=srv[L_1][i][n]*aita[n];
|
xue@1
|
2985 dsv2[L_1*I+i]=lsv-sv[L_1][i]-dsv1[L_1*I+i];
|
xue@1
|
2986 }
|
xue@1
|
2987 }
|
xue@1
|
2988 #endif
|
xue@1
|
2989 L_1++;
|
xue@1
|
2990 }
|
xue@1
|
2991 if (endmode==2 || endmode==3)
|
xue@1
|
2992 {
|
xue@1
|
2993 //v from u given f[l]
|
xue@1
|
2994 int hT=T/2;
|
xue@1
|
2995 double fbin=floor((f[L-1]+f[L])*hT)/T;
|
xue@1
|
2996 double omg=fbin*2*M_PI;
|
xue@1
|
2997 cdouble jomg=cdouble(0, omg);
|
xue@1
|
2998 for (int c=0; c<T; c++)
|
xue@1
|
2999 {
|
xue@1
|
3000 double t=c-hT;
|
xue@1
|
3001 cdouble rot=polar(1.0, omg*t);
|
xue@1
|
3002 for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
|
xue@1
|
3003 for (int i=0; i<I; i++) dv[i][c]=cdouble(2.0)*du[i][c*2]*rot+jomg*v[i][c];
|
xue@1
|
3004 }
|
xue@1
|
3005
|
xue@1
|
3006 //compute -<s, v'> over the lth frame
|
xue@1
|
3007 cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
|
xue@1
|
3008
|
xue@1
|
3009 //compute <sr, v> over the lth frame
|
xue@1
|
3010 for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
|
xue@1
|
3011 //memset(srv[L_1][0], 0, sizeof(cdouble)*I*N);
|
xue@1
|
3012 MultiplyXY(I, M, N, srv[L_1], shv1, A[L-1]);
|
xue@1
|
3013 #ifdef ERROR_CHECK
|
xue@1
|
3014 //error check: <s', v>=-<s, v'>
|
xue@1
|
3015 if (ds)
|
xue@1
|
3016 {
|
xue@1
|
3017 cdouble* lds=&ds[(L-1)*T];
|
xue@1
|
3018 for (int i=0; i<I && L_1*I+1<36; i++)
|
xue@1
|
3019 {
|
xue@1
|
3020 cdouble lsv=Inner(T, lds, v[i]); //compute <s', v[i]>
|
xue@1
|
3021 //cdouble* ls=&s[l*T];
|
xue@1
|
3022 //cdouble lsv2=Inner(2*T, ls, dv[i]);
|
xue@1
|
3023 dsv1[L_1*I+i]=lsv-sv[L_1][i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i]
|
xue@1
|
3024 }
|
xue@1
|
3025
|
xue@1
|
3026 //error check: srv[l]*pq=<s',v>
|
xue@1
|
3027 for (int i=0; i<I && L_1*I+i<36; i++)
|
xue@1
|
3028 {
|
xue@1
|
3029 cdouble lsv=0;
|
xue@1
|
3030 for (int n=0; n<N; n++) lsv+=srv[L_1][i][n]*aita[n];
|
xue@1
|
3031 dsv2[L_1*I+i]=lsv-sv[L_1][i]-dsv1[L_1*I+i];
|
xue@1
|
3032 }
|
xue@1
|
3033 }
|
xue@1
|
3034 #endif
|
xue@1
|
3035 L_1++;
|
xue@1
|
3036 }
|
xue@1
|
3037
|
xue@1
|
3038 if (L_1*2*I==2*N) GECP(N, aita, srv[0], sv[0]);
|
xue@1
|
3039 else LSLinear(L_1*I, N, aita, srv[0], sv[0]);
|
xue@1
|
3040
|
xue@1
|
3041 delete mlist;
|
xue@1
|
3042 }//DerivativePiecewise
|
xue@1
|
3043
|
Chris@5
|
3044 /**
|
xue@1
|
3045 function DerivativePiecewise2: Piecewise derivative algorithm in which the real and imaginary parts of
|
xue@1
|
3046 the exponent are modelled separately. In this implementation of the piecewise method the test
|
xue@1
|
3047 functions v are constructed from I "basic" (single-frame) test functions, each covering the same
|
xue@1
|
3048 period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I test functions are
|
xue@1
|
3049 used.
|
xue@1
|
3050
|
xue@1
|
3051 In: s[LT+1]: waveform data
|
xue@1
|
3052 ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined.
|
xue@1
|
3053 L, T: number and length of pieces.
|
xue@1
|
3054 N: number of independent coefficients
|
xue@1
|
3055 h[M][T]: piecewise basis functions
|
xue@1
|
3056 A[L][M][Np]: L matrices that do coefficient mapping (real part) over the L pieces
|
xue@1
|
3057 B[L][M][Nq]: L matrices that do coefficient mapping (imaginary part) over the L pieces
|
xue@1
|
3058 u[I][2T}, du[I][2T]: base-band test functions
|
xue@1
|
3059 f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used
|
xue@1
|
3060 endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT]
|
xue@1
|
3061 Out: p[Np], q[Nq]: independent coefficients
|
xue@1
|
3062
|
xue@1
|
3063 No return value.
|
xue@1
|
3064 */
|
xue@1
|
3065 void DerivativePiecewise2(int Np, double* p, int Nq, double* q, int L, double* f, int T, cdouble* s, double*** A, double*** B,
|
xue@1
|
3066 int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds)
|
xue@1
|
3067 {
|
xue@1
|
3068 MList* mlist=new MList;
|
xue@1
|
3069 int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L);
|
xue@1
|
3070 cdouble** Allocate2L(cdouble, L_1, I, sv, mlist);
|
xue@1
|
3071 cdouble** Allocate2(cdouble, I, T*2, v);
|
xue@1
|
3072 cdouble** Allocate2(cdouble, I, T*2, dv);
|
xue@1
|
3073 //compute <sr, v>
|
xue@1
|
3074 cdouble*** Allocate3L(cdouble, L_1, I, Np, srav, mlist);
|
xue@1
|
3075 cdouble*** srbv;
|
xue@1
|
3076 if (Np==Nq && B==A) srbv=srav; else {Allocate3L(cdouble, L_1, I, Nq, srbv, mlist);} //same model for amplitude and phase
|
xue@1
|
3077 cdouble** Allocate2L(cdouble, I, M, shv1, mlist);
|
xue@1
|
3078 cdouble** Allocate2L(cdouble, I, M, shv2, mlist);
|
xue@1
|
3079
|
xue@1
|
3080 for (int l=0; l<L-1; l++)
|
xue@1
|
3081 {
|
xue@1
|
3082 //v from u given f[l]
|
xue@1
|
3083 double fbin=floor(f[l+1]*T*2)/(T*2.0);
|
xue@1
|
3084 double omg=fbin*2*M_PI;
|
xue@1
|
3085 cdouble jomg=cdouble(0, omg);
|
xue@1
|
3086 for (int c=0; c<T*2; c++)
|
xue@1
|
3087 {
|
xue@1
|
3088 double t=c-T;
|
xue@1
|
3089 cdouble rot=polar(1.0, omg*t);
|
xue@1
|
3090 for (int i=0; i<I; i++) v[i][c]=u[i][c]*rot;
|
xue@1
|
3091 for (int i=0; i<I; i++) dv[i][c]=du[i][c]*rot+jomg*v[i][c];
|
xue@1
|
3092 }
|
xue@1
|
3093
|
xue@1
|
3094 //compute -<s, v'> over the lth frame
|
xue@1
|
3095 cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]);
|
xue@1
|
3096
|
xue@1
|
3097 //compute <sr, v> over the lth frame
|
xue@1
|
3098 cdouble *ls1=&s[l*T], *ls2=&s[l*T+T];
|
xue@1
|
3099 for (int i=0; i<I; i++)
|
xue@1
|
3100 for (int m=0; m<M; m++)
|
xue@1
|
3101 shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]);
|
xue@1
|
3102 memset(srav[l][0], 0, sizeof(cdouble)*I*Np);
|
xue@1
|
3103 MultiplyXY(I, M, Np, srav[l], shv1, A[l]);
|
xue@1
|
3104 MultiAddXY(I, M, Np, srav[l], shv2, A[l+1]);
|
xue@1
|
3105 if (srbv!=srav) //so that either B!=A or Np!=Nq
|
xue@1
|
3106 {
|
xue@1
|
3107 //memset(srbv[l][0], 0, sizeof(cdouble)*I*Nq);
|
xue@1
|
3108 MultiplyXY(I, M, Nq, srbv[l], shv1, B[l]);
|
xue@1
|
3109 MultiAddXY(I, M, Nq, srbv[l], shv2, B[l+1]);
|
xue@1
|
3110 }
|
xue@1
|
3111 }
|
xue@1
|
3112 L_1=L-1;
|
xue@1
|
3113 if (endmode==1 || endmode==3)
|
xue@1
|
3114 {
|
xue@1
|
3115 //v from u given f[l]
|
xue@1
|
3116 int hT=T/2;
|
xue@1
|
3117 double fbin=floor((f[0]+f[1])*hT)/T;
|
xue@1
|
3118 double omg=fbin*2*M_PI;
|
xue@1
|
3119 cdouble jomg=cdouble(0, omg);
|
xue@1
|
3120 for (int c=0; c<T; c++)
|
xue@1
|
3121 {
|
xue@1
|
3122 double t=c-hT;
|
xue@1
|
3123 cdouble rot=polar(1.0, omg*t);
|
xue@1
|
3124 for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
|
xue@1
|
3125 for (int i=0; i<I; i++) dv[i][c]=rot*du[i][c*2]*cdouble(2.0)+jomg*v[i][c];
|
xue@1
|
3126 }
|
xue@1
|
3127
|
xue@1
|
3128 //compute -<s, v'> over the lth frame
|
xue@1
|
3129 cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
|
xue@1
|
3130
|
xue@1
|
3131 //compute <sr, v> over the lth frame
|
xue@1
|
3132 for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
|
xue@1
|
3133 //memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np);
|
xue@1
|
3134 MultiplyXY(I, M, Np, srav[L_1], shv1, A[0]);
|
xue@1
|
3135 if (srbv!=srav) {memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq); MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[0]);}
|
xue@1
|
3136 L_1++;
|
xue@1
|
3137 }
|
xue@1
|
3138 if (endmode==2 || endmode==3)
|
xue@1
|
3139 {
|
xue@1
|
3140 //v from u given f[l]
|
xue@1
|
3141 int hT=T/2;
|
xue@1
|
3142 double fbin=floor((f[L-1]+f[L])*hT)/T;
|
xue@1
|
3143 double omg=fbin*2*M_PI;
|
xue@1
|
3144 cdouble jomg=cdouble(0, omg);
|
xue@1
|
3145 for (int c=0; c<T; c++)
|
xue@1
|
3146 {
|
xue@1
|
3147 double t=c-hT;
|
xue@1
|
3148 cdouble rot=polar(1.0, omg*t);
|
xue@1
|
3149 for (int i=0; i<I; i++) v[i][c]=u[i][c*2]*rot;
|
xue@1
|
3150 for (int i=0; i<I; i++) dv[i][c]=cdouble(2.0)*du[i][c*2]*rot+jomg*v[i][c];
|
xue@1
|
3151 }
|
xue@1
|
3152
|
xue@1
|
3153 //compute -<s, v'> over the lth frame
|
xue@1
|
3154 cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
|
xue@1
|
3155
|
xue@1
|
3156 //compute <sr, v> over the lth frame
|
xue@1
|
3157 for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
|
xue@1
|
3158 memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np);
|
xue@1
|
3159 MultiplyXY(I, M, Np, srav[L_1], shv1, A[L-1]);
|
xue@1
|
3160 if (srbv!=srav)
|
xue@1
|
3161 {
|
xue@1
|
3162 //memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq);
|
xue@1
|
3163 MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[L-1]);
|
xue@1
|
3164 }
|
xue@1
|
3165 L_1++;
|
xue@1
|
3166 }
|
xue@1
|
3167
|
xue@1
|
3168 //real implementation of <sr,v>aita=<s',v>
|
xue@1
|
3169 double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist);
|
xue@1
|
3170 for (int l=0; l<L_1; l++) for (int i=0; i<I; i++)
|
xue@1
|
3171 {
|
xue@1
|
3172 int li=l*I+i, li_H=li+L_1*I;
|
xue@1
|
3173 for (int n=0; n<Np; n++)
|
xue@1
|
3174 {
|
xue@1
|
3175 AM[li][n]=srav[l][i][n].x;
|
xue@1
|
3176 AM[li_H][n]=srav[l][i][n].y;
|
xue@1
|
3177 }
|
xue@1
|
3178 for (int n=0; n<Nq; n++)
|
xue@1
|
3179 {
|
xue@1
|
3180 AM[li][Np+n]=-srbv[l][i][n].y;
|
xue@1
|
3181 AM[li_H][Np+n]=srbv[l][i][n].x;
|
xue@1
|
3182 }
|
xue@1
|
3183 }
|
xue@1
|
3184 //least-square solution of (srv)(aita)=(sv)
|
xue@1
|
3185 double* pq=new double[Np+Nq]; mlist->Add(pq, 1);
|
xue@1
|
3186 double* b=new double[2*L_1*I]; for (int i=0; i<L_1*I; i++) b[i]=sv[0][i].x, b[i+L_1*I]=sv[0][i].y;
|
xue@1
|
3187
|
xue@1
|
3188 if (L_1*2*I==Np+Nq) GECP(Np+Nq, pq, AM, b);
|
xue@1
|
3189 else LSLinear(2*L_1*I, Np+Nq, pq, AM, b);
|
xue@1
|
3190
|
xue@1
|
3191 memcpy(p, pq, sizeof(double)*Np); memcpy(q, &pq[Np], sizeof(double)*Nq);
|
xue@1
|
3192
|
xue@1
|
3193 delete mlist;
|
xue@1
|
3194 }//DerivativePiecewise2
|
xue@1
|
3195
|
xue@1
|
3196 /*
|
xue@1
|
3197 Error check: test that ds[LT] equals s[LT] times reconstructed R'. Notice that DA is D time A where D
|
xue@1
|
3198 is a pre-emphasis because p[Np] applies to log amplitude rather than its derivative.
|
xue@1
|
3199 */
|
xue@1
|
3200 double testds_pqA(int Np, double* p, int Nq, double* q, int L, int T, cdouble* s, cdouble* ds, int M, double** h, double** dh, double*** DA, double*** B, cdouble* errds=0)
|
xue@1
|
3201 {
|
xue@1
|
3202 double err=0, ene=0, *lamdax=new double[M*2], *lamday=&lamdax[M];
|
xue@1
|
3203 for (int l=0; l<L; l++)
|
xue@1
|
3204 {
|
xue@1
|
3205 MultiplyXy(M, Np, lamdax, DA[l], p);
|
xue@1
|
3206 MultiplyXy(M, Nq, lamday, B[l], q);
|
xue@1
|
3207 for (int t=0; t<T; t++)
|
xue@1
|
3208 {
|
xue@1
|
3209 double drtx=0; for (int m=0; m<M; m++) drtx+=lamdax[m]*h[m][t];
|
xue@1
|
3210 double drty=0; for (int m=0; m<M; m++) drty+=lamday[m]*h[m][t];
|
xue@1
|
3211 cdouble drt=cdouble(drtx, drty);
|
xue@1
|
3212 cdouble eds=ds[l*T+t]-s[l*T+t]*drt;
|
xue@1
|
3213 err+=~eds; ene+=~ds[l*T+t];
|
xue@1
|
3214 if (errds) errds[l*T+t]=eds;
|
xue@1
|
3215 }
|
xue@1
|
3216 }
|
xue@1
|
3217 delete[] lamdax;
|
xue@1
|
3218 return err/ene;
|
xue@1
|
3219 }//testds_pqA
|
xue@1
|
3220
|
xue@1
|
3221 /*
|
xue@1
|
3222 Error check: dsv1[I] tests that <s', v[I]> equals -<s, v[I]'>, dsv2[I] tests that <sr, v[I]>*pq=
|
xue@1
|
3223 <s',v[I]>
|
xue@1
|
3224 */
|
xue@1
|
3225 void testdsv(cdouble* dsv1, cdouble* dsv2, int Np, double* p, int Nq, double* q, int TT, cdouble* dsl, int I, cdouble** vl, cdouble* svl, cdouble** sravl, cdouble** srbvl)
|
xue@1
|
3226 {
|
xue@1
|
3227 for (int i=0; i<I; i++)
|
xue@1
|
3228 {
|
xue@1
|
3229 cdouble lsv=Inner(TT, dsl, vl[i]); //compute <s', v[i]>
|
xue@1
|
3230 //cdouble* ls=&s[l*T];
|
xue@1
|
3231 dsv1[i]=lsv-svl[i]; //i.e. <s', v[i]>=-<s, v[i]'>+dsv1[lI+i]
|
xue@1
|
3232 //sv[l][i]=lsv;
|
xue@1
|
3233 }
|
xue@1
|
3234 //error check: srv[l]*pq=<s',v>
|
xue@1
|
3235 for (int i=0; i<I; i++)
|
xue@1
|
3236 {
|
xue@1
|
3237 cdouble lsv=0;
|
xue@1
|
3238 for (int n=0; n<Np; n++) lsv+=sravl[i][n]*p[n];
|
xue@1
|
3239 for (int n=0; n<Nq; n++) lsv+=srbvl[i][n]*cdouble(0, q[n]);
|
xue@1
|
3240 dsv2[i]=lsv-svl[i]-dsv1[i];
|
xue@1
|
3241 }
|
xue@1
|
3242 }//testdsv
|
xue@1
|
3243
|
xue@1
|
3244 /*
|
xue@1
|
3245 Error check: tests A[MN]x[N1]=b[N1], returns square error
|
xue@1
|
3246 */
|
xue@1
|
3247 double testlinearsystem(int M, int N, double** A, double* x, double* b)
|
xue@1
|
3248 {
|
xue@1
|
3249 double err=0;
|
xue@1
|
3250 for (int m=0; m<M; m++)
|
xue@1
|
3251 {
|
xue@1
|
3252 double errli=Inner(N, A[m], x)-b[m];
|
xue@1
|
3253 err+=errli*errli;
|
xue@1
|
3254 }
|
xue@1
|
3255 return err;
|
xue@1
|
3256 }//testlinearsystem
|
xue@1
|
3257
|
xue@1
|
3258 /*
|
xue@1
|
3259 Error check: test the total square norm of <s, v>
|
xue@1
|
3260 */
|
xue@1
|
3261 double testsv(int L, double* f, int T, cdouble* s, int I, cdouble** u, cdouble** du, int endmode)
|
xue@1
|
3262 {
|
xue@1
|
3263 cdouble** Allocate2(cdouble, I, T*2, v);
|
xue@1
|
3264 cdouble** Allocate2(cdouble, I, T*2, dv);
|
xue@1
|
3265 double ene=0;
|
xue@1
|
3266 for (int l=0; l<L-1; l++)
|
xue@1
|
3267 {
|
xue@1
|
3268 //v from u given f[l]
|
xue@1
|
3269 setv(I, T*2, v, dv, f[l+1], u, du);
|
xue@1
|
3270 //compute -<s, v'> over the lth frame
|
xue@1
|
3271 cdouble* ls=&s[l*T];
|
xue@1
|
3272 for (int i=0; i<I; i++)
|
xue@1
|
3273 {
|
xue@1
|
3274 cdouble d=Inner(2*T, ls, v[i]);
|
xue@1
|
3275 ene+=~d;
|
xue@1
|
3276 }
|
xue@1
|
3277 }
|
xue@1
|
3278 if (endmode==1 || endmode==3)
|
xue@1
|
3279 {
|
xue@1
|
3280 //v from u given f[l]
|
xue@1
|
3281 setvhalf(I, T, v, dv, (f[0]+f[1])/2, u, du);
|
xue@1
|
3282 cdouble* ls=&s[0];
|
xue@1
|
3283 for (int i=0; i<I; i++)
|
xue@1
|
3284
|
xue@1
|
3285 ene+=~Inner(T, ls, v[i]);
|
xue@1
|
3286 }
|
xue@1
|
3287 if (endmode==2 || endmode==3)
|
xue@1
|
3288 {
|
xue@1
|
3289 //v from u given f[l]
|
xue@1
|
3290 setvhalf(I, T, v, dv, (f[L-1]+f[L])/2, u, du);
|
xue@1
|
3291 cdouble* ls=&s[(L-1)*T];
|
xue@1
|
3292 for (int i=0; i<I; i++)
|
xue@1
|
3293 ene+=~Inner(T, ls, v[i]);
|
xue@1
|
3294 }
|
xue@1
|
3295 DeAlloc2(v); DeAlloc2(dv);
|
xue@1
|
3296 return ene;
|
xue@1
|
3297 }//testsv
|
xue@1
|
3298
|
Chris@5
|
3299 /**
|
xue@1
|
3300 function DerivativePiecewise3: Piecewise derivative algorithm in which the log amplitude and frequeny
|
xue@1
|
3301 are modeled separately as piecewise functions. In this implementation of the piecewise method the test
|
xue@1
|
3302 functions v are constructed from I "basic" (single-frame) test functions, each covering the same
|
xue@1
|
3303 period of 2T, by shifting these I functions by steps of T. A total number of (L-1)I test functions are
|
xue@1
|
3304 used.
|
xue@1
|
3305
|
xue@1
|
3306 In: s[LT+1]: waveform data
|
xue@1
|
3307 ds[LT+1]: derivative of s[LT], used only if ERROR_CHECK is defined.
|
xue@1
|
3308 L, T: number and length of pieces.
|
xue@1
|
3309 N: number of independent coefficients
|
xue@1
|
3310 h[M][T]: piecewise basis functions
|
xue@1
|
3311 dh[M][T]: derivative of h[M][T], used only if ERROR_CHECK is defined.
|
xue@1
|
3312 DA[L][M][Np]: L matrices that do coefficient mapping (real part) over the L pieces
|
xue@1
|
3313 B[L][M][Nq]: L matrices that do coefficient mapping (imaginary part) over the L pieces
|
xue@1
|
3314 u[I][2T}, du[I][2T]: base-band test functions
|
xue@1
|
3315 f[L+1]: reference frequencies at 0, T, ..., LT, only f[1]...f[L-1] are used
|
xue@1
|
3316 endmode: set to 1 or 3 to apply half-size testing over [0, T], to 2 or 3 to apply over [LT-T, LT]
|
xue@1
|
3317 Out: p[Np], q[Nq]: independent coefficients
|
xue@1
|
3318
|
xue@1
|
3319 No return value.
|
xue@1
|
3320 */
|
xue@1
|
3321 void DerivativePiecewise3(int Np, double* p, int Nq, double* q, int L, double* f, int T, cdouble* s, double*** DA, double*** B,
|
xue@1
|
3322 int M, double** h, int I, cdouble** u, cdouble** du, int endmode, cdouble* ds, double** dh)
|
xue@1
|
3323 {
|
xue@1
|
3324 MList* mlist=new MList;
|
xue@1
|
3325 int L_1=(endmode==0)?(L-1):((endmode==3)?(L+1):L);
|
xue@1
|
3326 cdouble** Allocate2L(cdouble, L_1, I, sv, mlist);
|
xue@1
|
3327 cdouble** Allocate2L(cdouble, I, T*2, v, mlist);
|
xue@1
|
3328 cdouble** Allocate2L(cdouble, I, T*2, dv, mlist);
|
xue@1
|
3329 //compute <sr, v>
|
xue@1
|
3330 cdouble*** Allocate3L(cdouble, L_1, I, Np, srav, mlist);
|
xue@1
|
3331 cdouble*** srbv;
|
xue@1
|
3332 if (Np==Nq && B==DA) srbv=srav; else {Allocate3L(cdouble, L_1, I, Nq, srbv, mlist);} //same model for amplitude and phase
|
xue@1
|
3333 cdouble** Allocate2L(cdouble, I, M, shv1, mlist);
|
xue@1
|
3334 cdouble** Allocate2L(cdouble, I, M, shv2, mlist);
|
xue@1
|
3335
|
xue@1
|
3336 #ifdef ERROR_CHECK
|
xue@1
|
3337 cdouble dsv1in[128], dsv2in[128];
|
xue@1
|
3338 #endif
|
xue@1
|
3339
|
xue@1
|
3340 for (int l=0; l<L-1; l++)
|
xue@1
|
3341 {
|
xue@1
|
3342 //v from u given f[l]
|
xue@1
|
3343 setv(I, T*2, v, dv, f[l+1], u, du);
|
xue@1
|
3344 //compute -<s, v'> over the lth frame
|
xue@1
|
3345 cdouble* ls=&s[l*T]; for (int i=0; i<I; i++) sv[l][i]=-Inner(2*T, ls, dv[i]);
|
xue@1
|
3346
|
xue@1
|
3347 //compute <sr, v> over the lth frame
|
xue@1
|
3348 cdouble *ls1=&s[l*T], *ls2=&s[l*T+T];
|
xue@1
|
3349 for (int i=0; i<I; i++)
|
xue@1
|
3350 for (int m=0; m<M; m++)
|
xue@1
|
3351 shv1[i][m]=Inner(T, ls1, h[m], v[i]), shv2[i][m]=Inner(T, ls2, h[m], &v[i][T]);
|
xue@1
|
3352 memset(srav[l][0], 0, sizeof(cdouble)*I*Np);
|
xue@1
|
3353 MultiplyXY(I, M, Np, srav[l], shv1, DA[l]);
|
xue@1
|
3354 MultiAddXY(I, M, Np, srav[l], shv2, DA[l+1]);
|
xue@1
|
3355 if (srbv!=srav) //so that either B!=A or Np!=Nq
|
xue@1
|
3356 {
|
xue@1
|
3357 MultiplyXY(I, M, Nq, srbv[l], shv1, B[l]);
|
xue@1
|
3358 MultiAddXY(I, M, Nq, srbv[l], shv2, B[l+1]);
|
xue@1
|
3359 }
|
xue@1
|
3360 #ifdef ERROR_CHECK
|
xue@1
|
3361 //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v>
|
xue@1
|
3362 if (ds) testdsv(&dsv1in[l*I], &dsv2in[l*I], Np, p, Nq, q, T*2, &ds[l*T], I, v, sv[l], srav[l], srbv[l]);
|
xue@1
|
3363 #endif
|
xue@1
|
3364 }
|
xue@1
|
3365 L_1=L-1;
|
xue@1
|
3366 if (endmode==1 || endmode==3)
|
xue@1
|
3367 {
|
xue@1
|
3368 //v from u given f[l]
|
xue@1
|
3369 setvhalf(I, T, v, dv, (f[0]+f[1])/2, u, du);
|
xue@1
|
3370 //compute -<s, v'> over the lth frame
|
xue@1
|
3371 cdouble* ls=&s[0]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
|
xue@1
|
3372 //compute <sr, v> over the lth frame
|
xue@1
|
3373 for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
|
xue@1
|
3374 //memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np);
|
xue@1
|
3375 MultiplyXY(I, M, Np, srav[L_1], shv1, DA[0]);
|
xue@1
|
3376 if (srbv!=srav) {memset(srbv[L_1][0], 0, sizeof(cdouble)*I*Nq); MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[0]);}
|
xue@1
|
3377 #ifdef ERROR_CHECK
|
xue@1
|
3378 //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v>
|
xue@1
|
3379 if (ds) testdsv(&dsv1in[L_1*I], &dsv2in[L_1*I], Np, p, Nq, q, T, &ds[0], I, v, sv[L_1], srav[L_1], srbv[L_1]);
|
xue@1
|
3380 #endif
|
xue@1
|
3381 L_1++;
|
xue@1
|
3382 }
|
xue@1
|
3383 if (endmode==2 || endmode==3)
|
xue@1
|
3384 {
|
xue@1
|
3385 //v from u given f[l]
|
xue@1
|
3386 setvhalf(I, T, v, dv, (f[L-1]+f[L])/2, u, du);
|
xue@1
|
3387 //compute -<s, v'> over the lth frame
|
xue@1
|
3388 cdouble* ls=&s[(L-1)*T]; for (int i=0; i<I; i++) sv[L_1][i]=-Inner(T, ls, dv[i]);
|
xue@1
|
3389 //compute <sr, v> over the lth frame
|
xue@1
|
3390 for (int i=0; i<I; i++) for (int m=0; m<M; m++) shv1[i][m]=Inner(T, ls, h[m], v[i]);
|
xue@1
|
3391 memset(srav[L_1][0], 0, sizeof(cdouble)*I*Np);
|
xue@1
|
3392 MultiplyXY(I, M, Np, srav[L_1], shv1, DA[L-1]);
|
xue@1
|
3393 if (srbv!=srav) MultiplyXY(I, M, Nq, srbv[L_1], shv1, B[L-1]);
|
xue@1
|
3394 #ifdef ERROR_CHECK
|
xue@1
|
3395 //error check: <s', v>=-<s, v'> and srv[l]*pq=<s',v>
|
xue@1
|
3396 if (ds) testdsv(&dsv1in[L_1*I], &dsv2in[L_1*I], Np, p, Nq, q, T, &ds[(L-1)*T], I, v, sv[L_1], srav[L_1], srbv[L_1]);
|
xue@1
|
3397 #endif
|
xue@1
|
3398 L_1++;
|
xue@1
|
3399 }
|
xue@1
|
3400
|
xue@1
|
3401 //real implementation of <sr,v>aita=<s',v>
|
xue@1
|
3402 double** Allocate2L(double, L_1*I*2, Np+Nq, AM, mlist);
|
xue@1
|
3403 for (int l=0; l<L_1; l++) for (int i=0; i<I; i++)
|
xue@1
|
3404 {
|
xue@1
|
3405 int li=l*I+i, li_H=li+L_1*I;
|
xue@1
|
3406 for (int n=0; n<Np; n++)
|
xue@1
|
3407 {
|
xue@1
|
3408 AM[li][n]=srav[l][i][n].x;
|
xue@1
|
3409 AM[li_H][n]=srav[l][i][n].y;
|
xue@1
|
3410 }
|
xue@1
|
3411 for (int n=0; n<Nq; n++)
|
xue@1
|
3412 {
|
xue@1
|
3413 AM[li][Np+n]=-srbv[l][i][n].y;
|
xue@1
|
3414 AM[li_H][Np+n]=srbv[l][i][n].x;
|
xue@1
|
3415 }
|
xue@1
|
3416 }
|
xue@1
|
3417 //least-square solution of (srv)(aita)=(sv)
|
xue@1
|
3418 double* pq=new double[Np+Nq]; mlist->Add(pq, 1);
|
xue@1
|
3419 double* b=new double[2*L_1*I]; for (int i=0; i<L_1*I; i++) b[i]=sv[0][i].x, b[i+L_1*I]=sv[0][i].y; mlist->Add(b, 1);
|
xue@1
|
3420 #ifdef ERROR_CHECK
|
xue@1
|
3421 //tests that AM is invariant to a constant shift of p
|
xue@1
|
3422 double errAM=0, errAM2=0, err1, err2;
|
xue@1
|
3423 for (int l=0; l<L_1*I; l++){double errli=0; for (int n=0; n<Np; n++) errli+=AM[l][n]; errAM+=errli*errli; errli=0; for (int n=0; n<Np; n+=2) errli+=AM[l][n]; errAM2+=errli*errli;}
|
xue@1
|
3424 //test square error of the input pq
|
xue@1
|
3425 if (ds)
|
xue@1
|
3426 {
|
xue@1
|
3427 memcpy(pq, p, sizeof(double)*Np); memcpy(&pq[Np], q, sizeof(double)*Nq);
|
xue@1
|
3428 err1=testlinearsystem(L_1*I*2, Np+Nq, AM, pq, b);
|
xue@1
|
3429 }
|
xue@1
|
3430 //test error of s'-sR where R is synthesized from the input pq
|
xue@1
|
3431 double errdsin, errdsvin; cdouble* edsin;
|
xue@1
|
3432 if (ds && dh)
|
xue@1
|
3433 {
|
xue@1
|
3434 edsin=new cdouble[L*T]; mlist->Add(edsin, 1);
|
xue@1
|
3435 errdsin=testds_pqA(Np, p, Nq, q, L, T, s, ds, M, h, dh, DA, B, edsin);
|
xue@1
|
3436 errdsvin=testsv(L, f, T, edsin, I, u, du, endmode);
|
xue@1
|
3437 }
|
xue@1
|
3438 #endif
|
xue@1
|
3439 Alloc2L(L_1*I*2, Np+Nq-1, Am, mlist);
|
xue@1
|
3440 for (int l=0; l<L_1*I*2; l++) memcpy(Am[l], &AM[l][1], sizeof(double)*(Np+Nq-1));
|
xue@1
|
3441 pq[0]=0;
|
xue@1
|
3442 //if (L_1*2*I==Np+Nq) GECP(Np+Nq, pq, AM, b);
|
xue@1
|
3443 //else LSLinear(2*L_1*I, Np+Nq, pq, AM, b);
|
xue@1
|
3444 if (L_1*2*I==Np+Nq-1) GECP(Np+Nq-1, &pq[1], Am, b);
|
xue@1
|
3445 else LSLinear(2*L_1*I, Np+Nq-1, &pq[1], Am, b);
|
xue@1
|
3446 #ifdef ERROR_CHECK
|
xue@1
|
3447 //test square error of output pq
|
xue@1
|
3448 if (ds) err2=testlinearsystem(L_1*I*2, Np+Nq, AM, pq, b);
|
xue@1
|
3449 //test error of s'-sR of the output pq
|
xue@1
|
3450 double errdsout, errdsvout; cdouble* edsout;
|
xue@1
|
3451 if (ds && dh)
|
xue@1
|
3452 {
|
xue@1
|
3453 edsout=new cdouble[L*T]; mlist->Add(edsout, 1);
|
xue@1
|
3454 errdsout=testds_pqA(Np, pq, Nq, &pq[Np], L, T, s, ds, M, h, dh, DA, B, edsout);
|
xue@1
|
3455 errdsvout=testsv(L, f, T, edsout, I, u, du, endmode);
|
xue@1
|
3456 }
|
xue@1
|
3457 #endif
|
xue@1
|
3458 memcpy(p, pq, sizeof(double)*Np); memcpy(q, &pq[Np], sizeof(double)*Nq);
|
xue@1
|
3459
|
xue@1
|
3460 delete mlist;
|
xue@1
|
3461 }//DerivativePiecewise3
|
xue@1
|
3462
|
xue@1
|
3463 //initialization routines for the piecewise derivative method
|
xue@1
|
3464
|
Chris@5
|
3465 /**
|
xue@1
|
3466 function seth: set h[M] to a series of power functions.
|
xue@1
|
3467
|
xue@1
|
3468 In: M, T.
|
xue@1
|
3469 Out: h[M][T], where h[m] is power function of order m.
|
xue@1
|
3470
|
xue@1
|
3471 No return value. h is allocated anew and must be freed by caller.
|
xue@1
|
3472 */
|
xue@1
|
3473 void seth(int M, int T, double**& h, MList* mlist)
|
xue@1
|
3474 {
|
xue@1
|
3475 if (M<=0){h=0; return;}
|
xue@1
|
3476 Allocate2L(double, M, T, h, mlist);
|
xue@1
|
3477 double* hm=h[0]; for (int t=0; t<T; t++) hm[t]=1;
|
xue@1
|
3478 for (int m=1; m<M; m++)
|
xue@1
|
3479 {
|
xue@1
|
3480 hm=h[m]; for (int t=0; t<T; t++) hm[t]=pow(t*1.0, m);
|
xue@1
|
3481 }
|
xue@1
|
3482 }//seth
|
xue@1
|
3483
|
Chris@5
|
3484 /**
|
xue@1
|
3485 function setdh: set dh[M] to the derivative of a series of power functions.
|
xue@1
|
3486
|
xue@1
|
3487 In: M, T.
|
xue@1
|
3488 Out: dh[M][T], where dh[m] is derivative of the power function of order m.
|
xue@1
|
3489
|
xue@1
|
3490 No return value. dh is allocated anew and must be freed by caller.
|
xue@1
|
3491 */
|
xue@1
|
3492 void setdh(int M, int T, double**& dh, MList* mlist)
|
xue@1
|
3493 {
|
xue@1
|
3494 if (M<=0){dh=0; return;}
|
xue@1
|
3495 Allocate2L(double, M, T, dh, mlist);
|
xue@1
|
3496 double* dhm=dh[0]; memset(dhm, 0, sizeof(double)*T);
|
xue@1
|
3497 if (M>1){dhm=dh[1]; for (int t=0; t<T; t++) dhm[t]=1;}
|
xue@1
|
3498 for (int m=2; m<M; m++)
|
xue@1
|
3499 {
|
xue@1
|
3500 dhm=dh[m]; for (int t=0; t<T; t++) dhm[t]=m*pow(t*1.0, m-1);
|
xue@1
|
3501 }
|
xue@1
|
3502 }//setdh
|
xue@1
|
3503
|
Chris@5
|
3504 /**
|
xue@1
|
3505 function setdih: set dih[M] to the difference of the integral of a series of power functions.
|
xue@1
|
3506
|
xue@1
|
3507 In: M, I
|
xue@1
|
3508 Out: dih[M][I], where the accumulation of dih[m] is the integral of the power function of order m.
|
xue@1
|
3509
|
xue@1
|
3510 No return value. dih is allocated anew and must be freed by caller.
|
xue@1
|
3511 */
|
xue@1
|
3512 void setdih(int M, int T, double**& dih, MList* mlist)
|
xue@1
|
3513 {
|
xue@1
|
3514 if (M<=0){dih=0; return;}
|
xue@1
|
3515 Allocate2L(double, M, T, dih, mlist);
|
xue@1
|
3516 double* dihm=dih[0]; for (int t=0; t<T; t++) dihm[t]=1;
|
xue@1
|
3517 for (int m=1; m<M; m++)
|
xue@1
|
3518 {
|
xue@1
|
3519 dihm=dih[m]; for (int t=0; t<T; t++) dihm[t]=(pow(t+1.0, m+1)-pow(t*1.0, m+1))/(m+1);
|
xue@1
|
3520 }
|
xue@1
|
3521 }//setdih
|
xue@1
|
3522
|
Chris@5
|
3523 /**
|
xue@1
|
3524 function sshLinear: sets M and h[M] for the linear spline model
|
xue@1
|
3525
|
xue@1
|
3526 In: T
|
xue@1
|
3527 Out: M=2, h[2][T] filled out for linear spline model.
|
xue@1
|
3528
|
xue@1
|
3529 No return value. h is allocated anew and must be freed by caller.
|
xue@1
|
3530 */
|
xue@1
|
3531 void sshLinear(int T, int& M, double** &h, MList* mlist)
|
xue@1
|
3532 {
|
xue@1
|
3533 M=2; Allocate2L(double, M, T, h, mlist);
|
xue@1
|
3534 for (int t=0; t<T; t++) h[0][t]=1, h[1][t]=t;
|
xue@1
|
3535 }//sshLinear
|
xue@1
|
3536
|
Chris@5
|
3537 /**
|
xue@1
|
3538 function sdihLinear: sets dih[M] for the linear spline model. For testing only.
|
xue@1
|
3539
|
xue@1
|
3540 In: T
|
xue@1
|
3541 Out: dih[2][T] filled out for linear spline model.
|
xue@1
|
3542
|
xue@1
|
3543 No return value. dih is allocated anew and must be freed by caller.
|
xue@1
|
3544 */
|
xue@1
|
3545 void sdihLinear(int T, double**& dih, MList* mlist)
|
xue@1
|
3546 {
|
xue@1
|
3547 Allocate2L(double, 2, T, dih, mlist);
|
xue@1
|
3548 for (int t=0; t<T; t++) dih[0][t]=1, dih[1][t]=t+0.5;
|
xue@1
|
3549 }//sdihLinear
|
xue@1
|
3550
|
Chris@5
|
3551 /**
|
xue@1
|
3552 function sshCubic: sets M and h[M] for cubic spline models.
|
xue@1
|
3553
|
xue@1
|
3554 In: T
|
xue@1
|
3555 Out: M=4 and h[M] filled out for cubic spline models, including cubic and cubic-Hermite.
|
xue@1
|
3556
|
xue@1
|
3557 No return value. h is allocated anew and must be freed by caller.
|
xue@1
|
3558 */
|
xue@1
|
3559 void sshCubic(int T, int& M, double** &h, MList* mlist)
|
xue@1
|
3560 {
|
xue@1
|
3561 M=4; Allocate2L(double, M, T, h, mlist);
|
xue@1
|
3562 for (int t=0; t<T; t++) h[3][t]=t*t*t, h[2][t]=t*t, h[1][t]=t, h[0][t]=1;
|
xue@1
|
3563 }//sshCubic
|
xue@1
|
3564
|
Chris@5
|
3565 /**
|
xue@1
|
3566 function sdihCubic: sets dih[M] for cubic spline models.
|
xue@1
|
3567
|
xue@1
|
3568 In: T
|
xue@1
|
3569 Out: dih[4] filled out for cubic spline models.
|
xue@1
|
3570
|
xue@1
|
3571 No return value. dih is allocated anew and must be freed by caller.
|
xue@1
|
3572 */
|
xue@1
|
3573 void sdihCubic(int T, double** &dih, MList* mlist)
|
xue@1
|
3574 {
|
xue@1
|
3575 Allocate2L(double, 4, T, dih, mlist);
|
xue@1
|
3576 for (int t=0; t<T; t++)
|
xue@1
|
3577 {
|
xue@1
|
3578 dih[3][t]=t*(t*(t+1.5)+1)+0.25, dih[2][t]=t*(t+1)+1.0/3, dih[1][t]=t+0.5, dih[0][t]=1;
|
xue@1
|
3579 }
|
xue@1
|
3580 }//sdihCubic*/
|
xue@1
|
3581
|
Chris@5
|
3582 /**
|
xue@1
|
3583 function ssALinearSpline: sets N and A[L] for the linear spline model
|
xue@1
|
3584
|
xue@1
|
3585 In: L, M, T
|
xue@1
|
3586 Out: N=L+1, A[L][M][N] filled out for the linear spline model
|
xue@1
|
3587
|
xue@1
|
3588 No return value. A is created anew and bust be freed by caller.
|
xue@1
|
3589 */
|
xue@1
|
3590 void ssALinearSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode)
|
xue@1
|
3591 {
|
xue@1
|
3592 N=L+1;
|
xue@1
|
3593 Allocate3L(double, L, M, N, A, mlist);
|
xue@1
|
3594 memset(A[0][0], 0, sizeof(double)*L*M*N);
|
xue@1
|
3595 double iT=1.0/T; for (int l=0; l<L; l++) A[l][0][l]=1, A[l][1][l]=-iT, A[l][1][l+1]=iT;
|
xue@1
|
3596 }//ssALinearSpline
|
xue@1
|
3597
|
Chris@5
|
3598 /**
|
xue@1
|
3599 function ssLinearSpline: sets M, N, h and A for the linear spline model
|
xue@1
|
3600
|
xue@1
|
3601 In: L, M, T
|
xue@1
|
3602 Out: N and h[][] and A[][][] filled out for the linear spline model
|
xue@1
|
3603
|
xue@1
|
3604 No reutrn value. A and h are created anew and bust be freed by caller.
|
xue@1
|
3605 */
|
xue@1
|
3606 void ssLinearSpline(int L, int T, int M, int &N, double** &h, double*** &A, MList* mlist, int mode)
|
xue@1
|
3607 {
|
xue@1
|
3608 seth(M, T, h, mlist);
|
xue@1
|
3609 ssALinearSpline(L, T, M, N, A, mlist);
|
xue@1
|
3610 }//ssLinearSpline
|
xue@1
|
3611
|
Chris@5
|
3612 /**
|
xue@1
|
3613 function ssACubicHermite: sets N and A[L] for cubic Hermite spline model
|
xue@1
|
3614
|
xue@1
|
3615 In: L, M, T
|
xue@1
|
3616 Out: N=2(L+1), A[L][M][N] filled out for the cubic Hermite spline
|
xue@1
|
3617
|
xue@1
|
3618 No return value. A is created anew and must be freed by caller.
|
xue@1
|
3619 */
|
xue@1
|
3620 void ssACubicHermite(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode)
|
xue@1
|
3621 {
|
xue@1
|
3622 N=2*(L+1);
|
xue@1
|
3623 Allocate3L(double, L, M, N, A, mlist); memset(A[0][0], 0, sizeof(double)*L*M*N);
|
xue@1
|
3624 double iT=1.0/T, iT2=iT*iT, iT3=iT2*iT;
|
xue@1
|
3625 for (int l=0; l<L; l++)
|
xue@1
|
3626 {
|
xue@1
|
3627 A[l][3][2*l]=2*iT3; A[l][3][2*l+2]=-2*iT3; A[l][3][2*l+1]=A[l][3][2*l+3]=iT2;
|
xue@1
|
3628 A[l][2][2*l]=-3*iT2; A[l][2][2*l+1]=-2*iT; A[l][2][2*l+2]=3*iT2; A[l][2][2*l+3]=-iT;
|
xue@1
|
3629 A[l][1][2*l+1]=1;
|
xue@1
|
3630 A[l][0][2*l]=1;
|
xue@1
|
3631 }
|
xue@1
|
3632 }//ssACubicHermite
|
xue@1
|
3633
|
Chris@5
|
3634 /**
|
xue@1
|
3635 function ssLinearSpline: sets M, N, h and A for the cubic Hermite spline model
|
xue@1
|
3636
|
xue@1
|
3637 In: L, M, T
|
xue@1
|
3638 Out: N and h[][] and A[][][] filled out for the cubic Hermite spline model
|
xue@1
|
3639
|
xue@1
|
3640 No reutrn value. A and h are created anew and bust be freed by caller.
|
xue@1
|
3641 */
|
xue@1
|
3642 void ssCubicHermite(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode)
|
xue@1
|
3643 {
|
xue@1
|
3644 seth(M, T, h, mlist);
|
xue@1
|
3645 ssACubicHermite(L, T, M, N, A, mlist);
|
xue@1
|
3646 }//ssCubicHermite
|
xue@1
|
3647
|
Chris@5
|
3648 /**
|
xue@1
|
3649 function ssACubicSpline: sets N and A[L] for cubic spline model
|
xue@1
|
3650
|
xue@1
|
3651 In: L, M, T
|
xue@1
|
3652 mode: boundary mode of cubic spline, 0=natural, 1=quadratic run-out, 2=cubic run-out
|
xue@1
|
3653 Out: N=2(L+1), A[L][M][N] filled out for the cubic spline
|
xue@1
|
3654
|
xue@1
|
3655 No return value. A is created anew and must be freed by caller.
|
xue@1
|
3656 */
|
xue@1
|
3657 void ssACubicSpline(int L, int T, int M, int& N, double*** &A, MList* mlist, int mode)
|
xue@1
|
3658 {
|
xue@1
|
3659 N=L+1;
|
xue@1
|
3660 Allocate3L(double, L, M, N, A, mlist); memset(A[0][0], 0, sizeof(double)*L*M*N);
|
xue@1
|
3661 Alloc2(L+1, L+1, ML); memset(ML[0], 0, sizeof(double)*(L+1)*(L+1));
|
xue@1
|
3662 Alloc2(L+1, L+1, MR); memset(MR[0], 0, sizeof(double)*(L+1)*(L+1));
|
xue@1
|
3663 //fill in ML and MR. The only difference between various cubic splines are ML.
|
xue@1
|
3664 double _6iT2=6.0/(T*T);
|
xue@1
|
3665 ML[0][0]=ML[L][L]=1;
|
xue@1
|
3666 for (int l=1; l<L; l++) ML[l][l-1]=ML[l][l+1]=1, ML[l][l]=4,
|
xue@1
|
3667 MR[l][l-1]=MR[l][l+1]=_6iT2, MR[l][l]=-2*_6iT2;
|
xue@1
|
3668 if (mode==0){} //no more coefficients are needed for natural cubic spline
|
xue@1
|
3669 else if (mode==1) ML[0][1]=ML[L][L-1]=-1; //setting for quadratic run-out
|
xue@1
|
3670 else if (mode==2) ML[0][1]=ML[L][L-1]=-2, ML[0][2]=ML[L][L-2]=1; //setting for cubic run-out
|
xue@1
|
3671 GICP(L+1, ML);
|
xue@1
|
3672 double** MM=MultiplyXY(L+1, ML, ML, MR);
|
xue@1
|
3673 double iT=1.0/T;
|
xue@1
|
3674 Alloc2(4, 2, M42); M42[3][0]=-1.0/6/T, M42[3][1]=1.0/6/T, M42[2][0]=0.5, M42[2][1]=M42[0][0]=M42[0][1]=0, M42[1][0]=-T/3.0, M42[1][1]=-T/6.0;
|
xue@1
|
3675 for (int l=0; l<L; l++)
|
xue@1
|
3676 {
|
xue@1
|
3677 MultiplyXY(4, 2, N, A[l], M42, &MM[l]);
|
xue@1
|
3678 A[l][1][l]-=iT; A[l][1][l+1]+=iT; A[l][0][l]+=1;
|
xue@1
|
3679 }
|
xue@1
|
3680 DeAlloc2(ML); DeAlloc2(MR); DeAlloc2(M42);
|
xue@1
|
3681 }//ssACubicSpline
|
xue@1
|
3682
|
Chris@5
|
3683 /**
|
xue@1
|
3684 function ssLinearSpline: sets M, N, h and A for the cubic spline model
|
xue@1
|
3685
|
xue@1
|
3686 In: L, M, T
|
xue@1
|
3687 Out: N and h[][] and A[][][] filled out for the cubic spline model
|
xue@1
|
3688
|
xue@1
|
3689 No reutrn value. A and h are created anew and bust be freed by caller.
|
xue@1
|
3690 */
|
xue@1
|
3691 void ssCubicSpline(int L, int T, int M, int& N, double** &h, double*** &A, MList* mlist, int mode)
|
xue@1
|
3692 {
|
xue@1
|
3693 seth(M, T, h, mlist);
|
xue@1
|
3694 ssACubicSpline(L, T, M, N, A, mlist, mode);
|
xue@1
|
3695 }//ssCubicSpline
|
xue@1
|
3696
|
Chris@5
|
3697 /**
|
xue@1
|
3698 function setu: sets u[I+1] as base-band windowed Fourier atoms, whose frequencies come in the order of
|
xue@1
|
3699 0, 1, -1, 2, -2, 3, -3, 4, etc, in bins.
|
xue@1
|
3700
|
xue@1
|
3701 In: I, Wid: number and size of atoms to generate.
|
xue@1
|
3702 WinOrder: order (=vanishing moment) of window function to use (2=Hann, 4=Hann^2, etc.)
|
xue@1
|
3703 Out: u[I+1][Wid], du[I+1]{Wid]: the I+1 atoms and their derivatives.
|
xue@1
|
3704
|
xue@1
|
3705 No return value. u and du are created anew and must be freed by caller.
|
xue@1
|
3706 */
|
xue@1
|
3707 void setu(int I, int Wid, cdouble**& u, cdouble**& du, int WinOrder, MList* mlist)
|
xue@1
|
3708 {
|
xue@1
|
3709 Allocate2L(cdouble, I+1, Wid, u, mlist);
|
xue@1
|
3710 Allocate2L(cdouble, I+1, Wid, du, mlist);
|
xue@1
|
3711
|
xue@1
|
3712 double** wins=CosineWindows(WinOrder, Wid, (double**)0, 2);
|
xue@1
|
3713 double omg=2*M_PI/Wid; cdouble jomg=cdouble(0, omg);
|
xue@1
|
3714 for (int t=0; t<Wid; t++)
|
xue@1
|
3715 {
|
xue@1
|
3716 u[0][t]=wins[0][t], du[0][t]=wins[1][t];
|
xue@1
|
3717 int li=1;
|
xue@1
|
3718 for (int i=1; i<=I; i++)
|
xue@1
|
3719 {
|
xue@1
|
3720 cdouble rot=polar(1.0, li*omg*t);
|
xue@1
|
3721 u[i][t]=u[0][t]*rot; du[i][t]=du[0][t]*rot+jomg*li*u[i][t];
|
xue@1
|
3722 li=-li; if (li>0) li++;
|
xue@1
|
3723 }
|
xue@1
|
3724 }
|
xue@1
|
3725 DeAlloc2(wins);
|
xue@1
|
3726 }//setu
|
xue@1
|
3727
|
Chris@5
|
3728 /**
|
xue@1
|
3729 function DerivativePiecewiseI: wrapper for DerivativePiecewise(), doing the initialization ,etc.
|
xue@1
|
3730
|
xue@1
|
3731 In: L, T: number and length of pieces
|
xue@1
|
3732 s[LT]: waveform signal
|
xue@1
|
3733 ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined.
|
xue@1
|
3734 f[L+1]: reference frequencies at knots
|
xue@1
|
3735 M: polynomial degree of piecewise approximation
|
xue@1
|
3736 SpecifyA, ssmode: pointer to a function that fills A[L], and mode argument to call it
|
xue@1
|
3737 WinOrder: order(=vanishing moment) of window used for constructing test functions
|
xue@1
|
3738 I: number of test functions per frame.
|
xue@1
|
3739 endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT]
|
xue@1
|
3740 Out: aita[N]: independent coefficients, where N is specified by SpecifyA.
|
xue@1
|
3741
|
xue@1
|
3742 No return vlue.
|
xue@1
|
3743 */
|
xue@1
|
3744 void DerivativePiecewiseI(cdouble* aita, int L, double* f, int T, cdouble* s, int M,
|
xue@1
|
3745 void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssmode,
|
xue@1
|
3746 int WinOrder, int I, int endmode, cdouble* ds)
|
xue@1
|
3747 {
|
xue@1
|
3748 MList* mlist=new MList;
|
xue@1
|
3749 cdouble **u, **du;
|
xue@1
|
3750 setu(I, 2*T, u, du, WinOrder, mlist);
|
xue@1
|
3751
|
xue@1
|
3752 int N; double **h, ***A;
|
xue@1
|
3753 seth(M, T, h, mlist);
|
xue@1
|
3754 SpecifyA(L, T, M, N, A, mlist, ssmode);
|
xue@1
|
3755
|
xue@1
|
3756 DerivativePiecewise(N, aita, L, f, T, s, A, M, h, I, u, du, endmode, ds);
|
xue@1
|
3757 delete mlist;
|
xue@1
|
3758 }//DerivativePiecewiseI
|
xue@1
|
3759
|
Chris@5
|
3760 /**
|
xue@1
|
3761 function DerivativePiecewiseII: wrapper for DerivativePiecewise2(), doing the initialization ,etc.
|
xue@1
|
3762 This models the derivative of log ampltiude and frequency as separate piecewise polynomials, the first
|
xue@1
|
3763 specified by SpecifyA, the second by SpecifyB.
|
xue@1
|
3764
|
xue@1
|
3765 In: L, T: number and length of pieces
|
xue@1
|
3766 s[LT]: waveform signal
|
xue@1
|
3767 ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined.
|
xue@1
|
3768 f[L+1]: reference frequencies at knots
|
xue@1
|
3769 M: polynomial degree of piecewise approximation
|
xue@1
|
3770 SpecifyA, ssAmode: pointer to a function that fills A[L], and mode argument to call it
|
xue@1
|
3771 SpecifyB, ssBmode: pointer to a function that fills B[L], and mode argument to call it
|
xue@1
|
3772 WinOrder: order(=vanishing moment) of window used for constructing test functions
|
xue@1
|
3773 I: number of test functions per frame.
|
xue@1
|
3774 endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT]
|
xue@1
|
3775 Out: p[Np], q[Nq]: independent coefficients, where Np and Nq are specified by SpecifyA and SpecifyB.
|
xue@1
|
3776
|
xue@1
|
3777 No reutrn value.
|
xue@1
|
3778 */
|
xue@1
|
3779 void DerivativePiecewiseII(double* p, double* q, int L, double* f, int T, cdouble* s, int M,
|
xue@1
|
3780 void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssAmode,
|
xue@1
|
3781 void (*SpecifyB)(int L, int T, int M, int &N, double*** &B, MList* mlist, int mode), int ssBmode,
|
xue@1
|
3782 int WinOrder, int I, int endmode, cdouble* ds)
|
xue@1
|
3783 {
|
xue@1
|
3784 MList* mlist=new MList;
|
xue@1
|
3785 cdouble **u, **du;
|
xue@1
|
3786 setu(I, 2*T, u, du, WinOrder, mlist);
|
xue@1
|
3787
|
xue@1
|
3788 int Np, Nq;
|
xue@1
|
3789 double **h, ***A, ***B;
|
xue@1
|
3790 seth(M, T, h, mlist);
|
xue@1
|
3791 SpecifyA(L, T, M, Np, A, mlist, ssAmode);
|
xue@1
|
3792 SpecifyB(L, T, M, Nq, B, mlist, ssBmode);
|
xue@1
|
3793
|
xue@1
|
3794 DerivativePiecewise2(Np, p, Nq, q, L, f, T, s, A, B, M, h, I, u, du, endmode, ds);
|
xue@1
|
3795
|
xue@1
|
3796 delete mlist;
|
xue@1
|
3797 }//DerivativePiecewiseII
|
xue@1
|
3798
|
Chris@5
|
3799 /**
|
xue@1
|
3800 function DerivativePiecewiseIII: wrapper for DerivativePiecewise3(), doing the initialization ,etc.
|
xue@1
|
3801 Notice that this time the log amplitude, rather than its derivative, is modeled as a piecewise
|
xue@1
|
3802 polynomial specified by SpecifyA.
|
xue@1
|
3803
|
xue@1
|
3804 In: L, T: number and length of pieces
|
xue@1
|
3805 s[LT]: waveform signal
|
xue@1
|
3806 ds[LT]: derivative of s[LT], used only when ERROR_CHECK is defined.
|
xue@1
|
3807 f[L+1]: reference frequencies at knots
|
xue@1
|
3808 M: polynomial degree of piecewise approximation
|
xue@1
|
3809 SpecifyA, ssAmode: pointer to a function that fills A[L], and mode argument to call it
|
xue@1
|
3810 SpecifyB, ssBmode: pointer to a function that fills B[L], and mode argument to call it
|
xue@1
|
3811 WinOrder: order(=vanishing moment) of window used for constructing test functions
|
xue@1
|
3812 I: number of test functions per frame.
|
xue@1
|
3813 endmode: set to 1 or 3 to apply half-size frame over [0, T], to 2 or 3 to apply over [LT-T, LT]
|
xue@1
|
3814 Out: p[Np], q[Nq]: independent coefficients, where Np and Nq are specified by SpecifyA and SpecifyB.
|
xue@1
|
3815
|
xue@1
|
3816 No reutrn value.
|
xue@1
|
3817 */
|
xue@1
|
3818 void DerivativePiecewiseIII(double* p, double* q, int L, double* f, int T, cdouble* s, int M,
|
xue@1
|
3819 void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int ssAmode,
|
xue@1
|
3820 void (*SpecifyB)(int L, int T, int M, int &N, double*** &B, MList* mlist, int mode), int ssBmode,
|
xue@1
|
3821 int WinOrder, int I, int endmode, cdouble* ds)
|
xue@1
|
3822 {
|
xue@1
|
3823 MList* mlist=new MList;
|
xue@1
|
3824 int Np, Nq;
|
xue@1
|
3825 double **h, ***A, ***B, **dh=0;
|
xue@1
|
3826 cdouble **u, **du;
|
xue@1
|
3827 setu(I, T*2, u, du, WinOrder, mlist);
|
xue@1
|
3828 seth(M, T, h, mlist);
|
xue@1
|
3829 if (ds) setdh(M, T, dh, mlist);
|
xue@1
|
3830 SpecifyA(L, T, M, Np, A, mlist, ssAmode);
|
xue@1
|
3831 SpecifyB(L, T, M, Nq, B, mlist, ssBmode);
|
xue@1
|
3832 Alloc2L(M, M, DM, mlist);
|
xue@1
|
3833 memset(DM[0], 0, sizeof(double)*M*M); for (int m=0; m<M-1; m++) DM[m][m+1]=m+1;
|
xue@1
|
3834 double** DA=0;
|
xue@1
|
3835
|
xue@1
|
3836 for (int l=0; l<L; l++)
|
xue@1
|
3837 {
|
xue@1
|
3838 DA=MultiplyXY(M, M, Np, DA, DM, A[l], mlist);
|
xue@1
|
3839 Copy(M, Np, A[l], DA);
|
xue@1
|
3840 }
|
xue@1
|
3841
|
xue@1
|
3842 DerivativePiecewise3(Np, p, Nq, q, L, f, T, s, A, B, M, h, I, u, du, endmode, ds, dh);
|
xue@1
|
3843
|
xue@1
|
3844 delete mlist;
|
xue@1
|
3845 }//DerivativePiecewiseIII
|
xue@1
|
3846
|
Chris@5
|
3847 /**
|
xue@1
|
3848 function AmpPhCorrectionExpA: model-preserving amplitude and phase correction in piecewise derivative
|
xue@1
|
3849 method.
|
xue@1
|
3850
|
xue@1
|
3851 In: aita[N]: inital independent coefficients
|
xue@1
|
3852 L, T: number and size of pieces
|
xue@1
|
3853 sre[LT]: waveform data
|
xue@1
|
3854 h[M][T], dih[M][T]: piecewise basis functions and their difference-integrals
|
xue@1
|
3855 A[L][M][N]: L coefficient mapping matrices
|
xue@1
|
3856 SpecifyA: pointer to the function used for constructing A
|
xue@1
|
3857 WinOrder: order(=vanishing moment) of window used for constructing test functions
|
xue@1
|
3858 Out: aita[N]: corrected independent coefficients
|
xue@1
|
3859 s2[LT]: reconstruct sinusoid BEFORE correction
|
xue@1
|
3860
|
xue@1
|
3861 Returns the estimate of phase angle at 0.
|
xue@1
|
3862 */
|
xue@1
|
3863 double AmpPhCorrectionExpA(cdouble* s2, int N, cdouble* aita, int L, int T, cdouble* sre, int M, double** h, double** dih, double*** A,
|
xue@1
|
3864 void (*SpecifyA)(int L, int T, int M, int &N, double*** &A, MList* mlist, int mode), int WinOrder)
|
xue@1
|
3865 {
|
xue@1
|
3866 MList* mlist=new MList;
|
xue@1
|
3867 //*amplitude and phase correction
|
xue@1
|
3868 //amplitude is done by updating p, i.e. Re(aita)
|
xue@1
|
3869 double *s2ph=new double[L+1]; mlist->Add(s2ph, 1);
|
xue@1
|
3870 double *phcor=new double[L+1]; mlist->Add(phcor, 1);
|
xue@1
|
3871 cdouble* lamda=new cdouble[M]; mlist->Add(lamda, 1);
|
xue@1
|
3872 double* lamdax=new double[M]; mlist->Add(lamdax, 1);
|
xue@1
|
3873 double* lamday=new double[M]; mlist->Add(lamday, 1);
|
xue@1
|
3874 {
|
xue@1
|
3875 double tmpph=0;
|
xue@1
|
3876 memset(s2ph, 0, sizeof(double)*(L+1));
|
xue@1
|
3877 s2ph[0]=tmpph;
|
xue@1
|
3878 for (int l=0; l<L; l++)
|
xue@1
|
3879 {
|
xue@1
|
3880 MultiplyXy(M, N, lamda, A[l], aita); for (int m=0; m<M; m++) lamdax[m]=lamda[m].x, lamday[m]=lamda[m].y;
|
xue@1
|
3881 SinusoidExpA(T, &s2[l*T], M, lamdax, lamday, h, dih, tmpph); s2ph[l+1]=tmpph;
|
xue@1
|
3882 }
|
xue@1
|
3883 double* win=new double[2*T+1]; CosineWindows(WinOrder, 2*T, &win, 1); mlist->Add(win, 1);
|
xue@1
|
3884 for (int l=1; l<L; l++)
|
xue@1
|
3885 {
|
xue@1
|
3886 cdouble inn=Inner(2*T, &sre[l*T-T], win, &s2[l*T-T])/Inner(2*T, &s2[l*T-T], win, &s2[l*T-T]);
|
xue@1
|
3887 cdouble loginn=log(inn);
|
xue@1
|
3888 if (SpecifyA==ssACubicHermite)
|
xue@1
|
3889 {
|
xue@1
|
3890 aita[l*2]+=loginn.x;
|
xue@1
|
3891 s2ph[l]+=loginn.y;
|
xue@1
|
3892 phcor[l]=loginn.y;
|
xue@1
|
3893 if (l==1) aita[0]+=loginn.x, phcor[0]=loginn.y, s2ph[0]+=loginn.y;
|
xue@1
|
3894 if (l==L-1) aita[L*2]+=loginn.x, phcor[L]=loginn.y, s2ph[L]+=loginn.y;
|
xue@1
|
3895 }
|
xue@1
|
3896 else
|
xue@1
|
3897 {
|
xue@1
|
3898 aita[l]+=loginn.x;
|
xue@1
|
3899 s2ph[l]+=loginn.y;
|
xue@1
|
3900 phcor[l]=loginn.y;
|
xue@1
|
3901 if (l==1)
|
xue@1
|
3902 {
|
xue@1
|
3903 inn=Inner(T, sre, &win[T], s2)/Inner(T, s2, &win[T], s2);
|
xue@1
|
3904 loginn=log(inn);
|
xue@1
|
3905 aita[0]+=loginn.x;
|
xue@1
|
3906 s2ph[0]+=loginn.y;
|
xue@1
|
3907 phcor[0]=loginn.y;
|
xue@1
|
3908 }
|
xue@1
|
3909 if (l==L-1)
|
xue@1
|
3910 {
|
xue@1
|
3911 inn=Inner(T, &sre[L*T-T], win, &s2[L*T-T])/Inner(T, &s2[L*T-T], win, &s2[L*T-T]);
|
xue@1
|
3912 loginn=log(inn);
|
xue@1
|
3913 aita[L]+=loginn.x;
|
xue@1
|
3914 s2ph[L]+=loginn.y;
|
xue@1
|
3915 phcor[L]=loginn.y;
|
xue@1
|
3916 }
|
xue@1
|
3917 }
|
xue@1
|
3918 }
|
xue@1
|
3919
|
xue@1
|
3920 for (int l=1; l<=L; l++)
|
xue@1
|
3921 {
|
xue@1
|
3922 int k=floor((phcor[l]-phcor[l-1])/(2*M_PI)+0.5);
|
xue@1
|
3923 if (k!=0)
|
xue@1
|
3924 phcor[l]+=2*M_PI*k;
|
xue@1
|
3925 }
|
xue@1
|
3926 //*
|
xue@1
|
3927 //now phcor[] contains phase corrector to be interpolated
|
xue@1
|
3928 double *b=new double[L], *zet=new double[L+1], *dzet=new double[L+1]; memset(zet, 0, sizeof(double)*(L+1)); memset(dzet, 0, sizeof(double)*(L+1));
|
xue@1
|
3929 mlist->Add(b, 1); mlist->Add(zet, 1); mlist->Add(dzet, 1);
|
xue@1
|
3930 double ihT[]={T, T/2.0*T, T/3.0*T*T, T/4.0*T*T*T};
|
xue@1
|
3931
|
xue@1
|
3932 Alloc2L(L, N, BB, mlist);
|
xue@1
|
3933 //prepare linear system (BB)(zet)=(b)
|
xue@1
|
3934 for (int l=0; l<L; l++)
|
xue@1
|
3935 {
|
xue@1
|
3936 MultiplyxY(N, 4, BB[l], ihT, A[l]);
|
xue@1
|
3937 b[l]=phcor[l+1]-phcor[l];
|
xue@1
|
3938 }
|
xue@1
|
3939 Alloc2L(L, L, copyA, mlist);
|
xue@1
|
3940 if (L+1==N) for (int l=0; l<L; l++) memcpy(copyA[l], &BB[l][1], sizeof(double)*L);
|
xue@1
|
3941 else if (L+1==N/2) for (int l=0; l<L; l++) for (int k=0; k<L; k++) copyA[l][k]=BB[l][2*k+2];
|
xue@1
|
3942 double* copyb=Copy(L, b, mlist);
|
xue@1
|
3943 zet[0]=0; GECP(L, &zet[1], copyA, copyb);
|
xue@1
|
3944 if (L+1==N) for (int l=0; l<L; l++) memcpy(copyA[l], &BB[l][1], sizeof(double)*L);
|
xue@1
|
3945 else if (L+1==N/2) for (int l=0; l<L; l++) for (int k=0; k<L; k++) copyA[l][k]=BB[l][2*k+2];
|
xue@1
|
3946 Copy(L, copyb, b); for (int l=0; l<L; l++) copyb[l]-=BB[l][0];
|
xue@1
|
3947 dzet[0]=1; GECP(L, &dzet[1], copyA, copyb);
|
xue@1
|
3948
|
xue@1
|
3949 #ifdef ERROR_CHECK
|
xue@1
|
3950 //Test that (BB)(zet)=b and (BB)(dzet)=b
|
xue@1
|
3951 double* bbzet=MultiplyXy(L, L+1, BB, zet, mlist);
|
xue@1
|
3952 MultiAdd(L, bbzet, bbzet, b, -1);
|
xue@1
|
3953 double err1=Inner(L, bbzet, bbzet);
|
xue@1
|
3954 double* bbdzet=MultiplyXy(L, L+1, BB, dzet, mlist);
|
xue@1
|
3955 MultiAdd(L, bbdzet, bbdzet, b, -1);
|
xue@1
|
3956 double err2=Inner(L, bbdzet, bbdzet);
|
xue@1
|
3957 MultiAdd(L+1, dzet, dzet, zet, -1);
|
xue@1
|
3958 //Test that (BB)dzet=0
|
xue@1
|
3959 MultiplyXy(L, L+1, bbdzet, BB, dzet);
|
xue@1
|
3960 double err3=Inner(L, bbzet, bbzet);
|
xue@1
|
3961 #endif
|
xue@1
|
3962 //now that (zet)+(miu)(dzet) is the general solution to (BB)(zet)=b,
|
xue@1
|
3963 // we look for (miu) that maximizes smoothness
|
xue@1
|
3964
|
xue@1
|
3965 double innuv=0, innvv=0, lmd0[4], lmdd[4], clmdd[4],
|
xue@1
|
3966 T2=T*T, T3=T2*T, T4=T3*T, T5=T4*T;
|
xue@1
|
3967 for (int l=0; l<L; l++)
|
xue@1
|
3968 {
|
xue@1
|
3969 MultiplyXy(4, L+1, lmd0, A[l], zet);
|
xue@1
|
3970 MultiplyXy(4, L+1, lmdd, A[l], dzet);
|
xue@1
|
3971 clmdd[1]=T*lmdd[1]+T2*lmdd[2]+T3*lmdd[3];
|
xue@1
|
3972 clmdd[2]=T2*lmdd[1]+(4.0/3)*T3*lmdd[2]+1.5*T4*lmdd[3];
|
xue@1
|
3973 clmdd[3]=T3*lmdd[1]+1.5*T4*lmdd[2]+1.8*T5*lmdd[3];
|
xue@1
|
3974 innuv+=Inner(3, &lmd0[1], &clmdd[1]);
|
xue@1
|
3975 innvv+=Inner(3, &lmdd[1], &clmdd[1]);
|
xue@1
|
3976 }
|
xue@1
|
3977 MultiAdd(L+1, zet, zet, dzet, -innuv/innvv);
|
xue@1
|
3978
|
xue@1
|
3979 if (SpecifyA==ssACubicHermite)
|
xue@1
|
3980 for (int l=0; l<=L; l++) aita[2*l].y+=zet[l];
|
xue@1
|
3981 else
|
xue@1
|
3982 for (int l=0; l<=L; l++) aita[l].y+=zet[l];
|
xue@1
|
3983 //*/
|
xue@1
|
3984 }
|
xue@1
|
3985 double result=s2ph[0];
|
xue@1
|
3986 delete mlist;
|
xue@1
|
3987 return result;
|
xue@1
|
3988 }//AmpPhCorrectionExpA
|
Chris@5
|
3989
|