xue@11
|
1 /*
|
xue@11
|
2 Harmonic sinusoidal modelling and tools
|
xue@11
|
3
|
xue@11
|
4 C++ code package for harmonic sinusoidal modelling and relevant signal processing.
|
xue@11
|
5 Centre for Digital Music, Queen Mary, University of London.
|
xue@11
|
6 This file copyright 2011 Wen Xue.
|
xue@11
|
7
|
xue@11
|
8 This program is free software; you can redistribute it and/or
|
xue@11
|
9 modify it under the terms of the GNU General Public License as
|
xue@11
|
10 published by the Free Software Foundation; either version 2 of the
|
xue@11
|
11 License, or (at your option) any later version.
|
xue@11
|
12 */
|
xue@1
|
13 //---------------------------------------------------------------------------
|
xue@1
|
14
|
xue@1
|
15 #include "splines.h"
|
xue@1
|
16
|
Chris@5
|
17 /** \file splines.h */
|
Chris@5
|
18
|
xue@1
|
19 //---------------------------------------------------------------------------
|
Chris@5
|
20 /**
|
xue@1
|
21 function tridiagonal: solves linear system A[N][N]x[N]=d[N] where A is tridiagonal
|
xue@1
|
22
|
xue@1
|
23 In: tridiagonal matrix A[N][N] gives as three vectors - lower subdiagonal
|
xue@1
|
24 a[1:N-1], main diagonal b[0:N-1], upper subdiagonal c[0:N-2]
|
xue@1
|
25 vector d[N]
|
xue@1
|
26 Out: vector d[N] now containing x[N]
|
xue@1
|
27
|
xue@1
|
28 No return value.
|
xue@1
|
29 */
|
xue@1
|
30 void tridiagonal(int N, double* a, double* b, double* c, double* d)
|
xue@1
|
31 {
|
xue@1
|
32 for (int k=1; k<N; k++)
|
xue@1
|
33 {
|
xue@1
|
34 double m=a[k]/b[k-1];
|
xue@1
|
35 b[k]=b[k]-m*c[k-1];
|
xue@1
|
36 d[k]=d[k]-m*d[k-1];
|
xue@1
|
37 }
|
xue@1
|
38 d[N-1]=d[N-1]/b[N-1];
|
xue@1
|
39 for (int k=N-2; k>=0; k--)
|
xue@1
|
40 d[k]=(d[k]-c[k]*d[k+1])/b[k];
|
xue@1
|
41 }//tridiagonal
|
xue@1
|
42
|
Chris@5
|
43 /**
|
xue@1
|
44 function CubicSpline: computing piece-wise trinomial coefficients of a cubic spline
|
xue@1
|
45
|
xue@1
|
46 In: x[N+1], y[N+1]: knots
|
xue@1
|
47 bordermode: boundary mode of cubic spline
|
xue@1
|
48 bordermode=0: natural: y''(x0)=y''(x_N)=0
|
xue@1
|
49 bordermode=1: quadratic runout: y''(x0)=y''(x1), y''(x_N)=y''(x_(N-1))
|
xue@1
|
50 bordermode=2: cubic runout: y''(x0)=2y''(x1)-y''(x2), the same at the end point
|
xue@1
|
51 mode: spline format
|
xue@1
|
52 mode=0: spline defined on the l'th piece as y(x)=a[l]x^3+b[l]x^2+c[l]x+d[l]
|
xue@1
|
53 mode=1: spline defined on the l'th piece as y(x)=a[l]t^3+b[l]t^2+c[l]t+d[l], t=x-x[l]
|
xue@1
|
54 Out: a[N],b[N],c[N],d[N]: piecewise trinomial coefficients
|
xue@1
|
55 data[]: cubic spline computed for [xstart:xinterval:xend], if specified
|
xue@1
|
56 No return value. On start d must be allocated no less than N+1 storage units.
|
xue@1
|
57 */
|
xue@1
|
58 void CubicSpline(int N, double* a, double* b, double* c, double* d, double* x, double* y, int bordermode, int mode, double* data, double xinterval, double xstart, double xend)
|
xue@1
|
59 {
|
xue@1
|
60 double *h=new double[N];
|
xue@1
|
61 for (int i=0; i<N; i++) h[i]=x[i+1]-x[i];
|
xue@1
|
62
|
xue@1
|
63 for (int i=0; i<N-1; i++)
|
xue@1
|
64 {
|
xue@1
|
65 a[i]=h[i];
|
xue@1
|
66 b[i]=2*(h[i]+h[i+1]);
|
xue@1
|
67 c[i]=h[i+1];
|
xue@1
|
68 d[i+1]=6*((y[i+2]-y[i+1])/h[i+1]-(y[i+1]-y[i])/h[i]);
|
xue@1
|
69 }
|
xue@1
|
70 a[0]=0; c[N-2]=0;
|
xue@1
|
71
|
xue@1
|
72 if (bordermode==1)
|
xue@1
|
73 {
|
xue@1
|
74 b[0]+=h[0];
|
xue@1
|
75 b[N-2]+=h[N-1];
|
xue@1
|
76 }
|
xue@1
|
77 else if (bordermode==2)
|
xue@1
|
78 {
|
xue@1
|
79 b[0]+=2*h[0]; c[0]-=h[0];
|
xue@1
|
80 b[N-2]+=2*h[N-1]; a[N-2]-=h[N-1];
|
xue@1
|
81 }
|
xue@1
|
82
|
xue@1
|
83 tridiagonal(N-1, a, b, c, &d[1]);
|
xue@1
|
84
|
xue@1
|
85 if (bordermode==0)
|
xue@1
|
86 {
|
xue@1
|
87 d[0]=0; d[N]=0;
|
xue@1
|
88 }
|
xue@1
|
89 else if (bordermode==1)
|
xue@1
|
90 {
|
xue@1
|
91 d[0]=d[1]; d[N]=d[N-1];
|
xue@1
|
92 }
|
xue@1
|
93 else if (bordermode==2)
|
xue@1
|
94 {
|
xue@1
|
95 d[0]=2*d[1]-d[2];
|
xue@1
|
96 d[N]=2*d[N-1]-d[N-2];
|
xue@1
|
97 }
|
xue@1
|
98
|
xue@1
|
99 for (int i=0; i<N; i++)
|
xue@1
|
100 {
|
xue@1
|
101 double zi=d[i], zi1=d[i+1], xi=x[i], xi1=x[i+1], hi=h[i];
|
xue@1
|
102 double co1=y[i+1]/hi-hi*zi1/6, co2=y[i]/hi-hi*zi/6;
|
xue@1
|
103 if (mode==0)
|
xue@1
|
104 {
|
xue@1
|
105 a[i]=(zi1-zi)/6/hi;
|
xue@1
|
106 b[i]=(-xi*zi1+xi1*zi)/2/hi;
|
xue@1
|
107 c[i]=(zi1*xi*xi-zi*xi1*xi1)/2/hi+co1-co2;
|
xue@1
|
108 d[i]=(-zi1*xi*xi*xi+zi*xi1*xi1*xi1)/6/hi-co1*xi+co2*xi1;
|
xue@1
|
109 }
|
xue@1
|
110 else if (mode==1)
|
xue@1
|
111 {
|
xue@1
|
112 a[i]=(zi1-zi)/6/hi;
|
xue@1
|
113 b[i]=zi/2;
|
xue@1
|
114 c[i]=-zi*hi/2+co1-co2;
|
xue@1
|
115 d[i]=zi*hi*hi/6+co2*hi;
|
xue@1
|
116 }
|
xue@1
|
117 zi=zi1;
|
xue@1
|
118 }
|
xue@1
|
119 delete[] h;
|
xue@1
|
120 if (data)
|
xue@1
|
121 {
|
xue@1
|
122 if (xend<xstart) xend=x[N], xstart=x[0];
|
xue@1
|
123 int Count=(xend-xstart)/xinterval+1;
|
xue@1
|
124 for (int i=0, n=0; i<Count; i++)
|
xue@1
|
125 {
|
xue@1
|
126 double xx=xstart+i*xinterval;
|
xue@1
|
127 while (n<N-1 && xx>x[n+1]) n++;
|
xue@1
|
128 if (mode==1) xx=xx-x[n];
|
xue@1
|
129 data[i]=d[n]+xx*(c[n]+xx*(b[n]+xx*a[n]));
|
xue@1
|
130 }
|
xue@1
|
131 }
|
xue@1
|
132 }//CubicSpline
|
xue@1
|
133
|
Chris@5
|
134 /**
|
xue@1
|
135 function CubicSpline: computing piece-wise trinomial coefficients of a cubic spline with uniformly placed knots
|
xue@1
|
136
|
xue@1
|
137 In: y[N+1]: spline values at knots (0, h, 2h, ..., Nh)
|
xue@1
|
138 bordermode: boundary mode of cubic spline
|
xue@1
|
139 bordermode=0: natural: y''(x0)=y''(x_N)=0
|
xue@1
|
140 bordermode=1: quadratic runout: y''(x0)=y''(x1), y''(x_N)=y''(x_(N-1))
|
xue@1
|
141 bordermode=2: cubic runout: y''(x0)=2y''(x1)-y''(x2), the same at the end point
|
xue@1
|
142 mode: spline format
|
xue@1
|
143 mode=0: spline defined on the l'th piece as y(x)=a[l]x^3+b[l]x^2+c[l]x+d[l]
|
xue@1
|
144 mode=1: spline defined on the l'th piece as y(x)=a[l]t^3+b[l]t^2+c[l]t+d[l], t=x-x[l]
|
xue@1
|
145 Out: a[N],b[N],c[N],d[N]: piecewise trinomial coefficients
|
xue@1
|
146 data[]: cubic spline computed for [xstart:xinterval:xend], if specified
|
xue@1
|
147 No return value. On start d must be allocated no less than N+1 storage units.
|
xue@1
|
148 */
|
xue@1
|
149 void CubicSpline(int N, double* a, double* b, double* c, double* d, double h, double* y, int bordermode, int mode, double* data, double xinterval, double xstart, double xend)
|
xue@1
|
150 {
|
xue@1
|
151 for (int i=0; i<N-1; i++)
|
xue@1
|
152 {
|
xue@1
|
153 a[i]=h;
|
xue@1
|
154 b[i]=4*h;
|
xue@1
|
155 c[i]=h;
|
xue@1
|
156 d[i+1]=6*((y[i+2]-y[i+1])/h-(y[i+1]-y[i])/h);
|
xue@1
|
157 }
|
xue@1
|
158 a[0]=0; c[N-2]=0;
|
xue@1
|
159
|
xue@1
|
160 if (bordermode==1)
|
xue@1
|
161 {
|
xue@1
|
162 b[0]+=h;
|
xue@1
|
163 b[N-2]+=h;
|
xue@1
|
164 }
|
xue@1
|
165 else if (bordermode==2)
|
xue@1
|
166 {
|
xue@1
|
167 b[0]+=2*h; c[0]-=h;
|
xue@1
|
168 b[N-2]+=2*h; a[N-2]-=h;
|
xue@1
|
169 }
|
xue@1
|
170
|
xue@1
|
171 tridiagonal(N-1, a, b, c, &d[1]);
|
xue@1
|
172
|
xue@1
|
173 if (bordermode==0)
|
xue@1
|
174 {
|
xue@1
|
175 d[0]=0; d[N]=0;
|
xue@1
|
176 }
|
xue@1
|
177 else if (bordermode==1)
|
xue@1
|
178 {
|
xue@1
|
179 d[0]=d[1]; d[N]=d[N-1];
|
xue@1
|
180 }
|
xue@1
|
181 else if (bordermode==2)
|
xue@1
|
182 {
|
xue@1
|
183 d[0]=2*d[1]-d[2];
|
xue@1
|
184 d[N]=2*d[N-1]-d[N-2];
|
xue@1
|
185 }
|
xue@1
|
186
|
xue@1
|
187 for (int i=0; i<N; i++)
|
xue@1
|
188 {
|
xue@1
|
189 double zi=d[i], zi1=d[i+1];
|
xue@1
|
190 if (mode==0)
|
xue@1
|
191 {
|
xue@1
|
192 double co1=y[i+1]/h-h*zi1/6, co2=y[i]/h-h*zi/6;
|
xue@1
|
193 a[i]=(zi1-zi)/6/h;
|
xue@1
|
194 b[i]=(-i*zi1+(i+1)*zi)/2;
|
xue@1
|
195 c[i]=(zi1*i*i*h-zi*(i+1)*h*(i+1))/2+co1-co2;
|
xue@1
|
196 d[i]=(-zi1*i*h*i*h*i+zi*(i+1)*h*(i+1)*h*(i+1))/6-co1*i*h+co2*(i+1)*h;
|
xue@1
|
197 }
|
xue@1
|
198 else if (mode==1)
|
xue@1
|
199 {
|
xue@1
|
200 a[i]=(zi1-zi)/6/h;
|
xue@1
|
201 b[i]=zi/2;
|
xue@1
|
202 c[i]=-(zi*2+zi1)*h/6+(y[i+1]-y[i])/h;
|
xue@1
|
203 d[i]=y[i];
|
xue@1
|
204 }
|
xue@1
|
205 zi=zi1;
|
xue@1
|
206 }
|
xue@1
|
207 if (data)
|
xue@1
|
208 {
|
xue@1
|
209 if (xend<xstart) xend=N*h, xstart=0;
|
xue@1
|
210 int Count=(xend-xstart)/xinterval+1;
|
xue@1
|
211 for (int i=0, n=0; i<Count; i++)
|
xue@1
|
212 {
|
xue@1
|
213 double xx=xstart+i*xinterval;
|
xue@1
|
214 while (n<N-1 && xx>(n+1)*h) n++;
|
xue@1
|
215 if (mode==1) xx=xx-n*h;
|
xue@1
|
216 data[i]=d[n]+xx*(c[n]+xx*(b[n]+xx*a[n]));
|
xue@1
|
217 }
|
xue@1
|
218 }
|
xue@1
|
219 }//CubicSpline
|
xue@1
|
220
|
Chris@5
|
221 /**
|
xue@1
|
222 function Smooth_Interpolate: smoothly interpolate/extrapolate P-piece spline from P-1 values. The
|
xue@1
|
223 interpolation scheme is chosen according to P:
|
xue@1
|
224 P-1=1: constant
|
xue@1
|
225 P-1=2: linear function
|
xue@1
|
226 P-1=3: quadratic function
|
xue@1
|
227 P-1>=4: cubic spline
|
xue@1
|
228
|
xue@1
|
229 In: xind[P-1], x[P-1]: knot points
|
xue@1
|
230 Out: y[N]: smoothly interpolated signal, y(xind[p])=x[p], p=0, ..., P-2.
|
xue@1
|
231
|
xue@1
|
232 No return value.
|
xue@1
|
233 */
|
xue@1
|
234 void Smooth_Interpolate(double* y, int N, int P, double* x, double* xind)
|
xue@1
|
235 {
|
xue@1
|
236 if (P==2)
|
xue@1
|
237 {
|
xue@1
|
238 for (int n=0; n<N; n++) y[n]=x[0];
|
xue@1
|
239 }
|
xue@1
|
240 else if (P==3)
|
xue@1
|
241 {
|
xue@1
|
242 double alp=(x[1]-x[0])/(xind[1]-xind[0]);
|
xue@1
|
243 for (int n=0; n<N; n++) y[n]=x[0]+(n-xind[0])*alp;
|
xue@1
|
244 }
|
xue@1
|
245 else if (P==4)
|
xue@1
|
246 {
|
xue@1
|
247 double x0=xind[0], x1=xind[1], x2=xind[2], y0=x[0], y1=x[1], y2=x[2];
|
xue@1
|
248 double ix0_12=y0/((x0-x1)*(x0-x2)), ix1_02=y1/((x1-x0)*(x1-x2)), ix2_01=y2/((x2-x0)*(x2-x1));
|
xue@1
|
249 double a=ix0_12+ix1_02+ix2_01,
|
xue@1
|
250 b=-(x1+x2)*ix0_12-(x0+x2)*ix1_02-(x0+x1)*ix2_01,
|
xue@1
|
251 c=x1*x2*ix0_12+x0*x2*ix1_02+x0*x1*ix2_01;
|
xue@1
|
252 for (int n=0; n<N; n++) y[n]=c+n*(b+n*a);
|
xue@1
|
253 }
|
xue@1
|
254 else
|
xue@1
|
255 {
|
xue@1
|
256 double *fa=new double[P*4], *fb=&fa[P], *fc=&fa[P*2], *fd=&fa[P*3];
|
xue@1
|
257 CubicSpline(P-2, fa, fb, fc, fd, xind, x, 0, 1, y, 1, 0, N-1);
|
xue@1
|
258 delete[] fa;
|
xue@1
|
259 }
|
xue@1
|
260 }//Smooth_Interpolate
|