annotate splines.cpp @ 13:de3961f74f30 tip

Add Linux/gcc Makefile; build fix
author Chris Cannam
date Mon, 05 Sep 2011 15:22:35 +0100
parents 977f541d6683
children
rev   line source
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