lipsync/Boare.Lib.AppUtil/CubicSpline.cs

278 lines
12 KiB
C#
Raw Permalink Normal View History

#if !JAVA
/*
* CubicSpline.cs
* Copyright (c) 2008-2009 kbinani
*
* This file is part of Boare.Lib.AppUtil.
*
* Boare.Lib.AppUtil is free software; you can redistribute it and/or
* modify it under the terms of the BSD License.
*
* Boare.Lib.AppUtil is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
using System;
namespace Boare.Lib.AppUtil {
public class CubicSpline : ICloneable, IDisposable {
int m_num_key;
public double[] m_key, m_sp3_a, m_sp3_b, m_sp3_c, m_sp3_d;
double m_default;
public void Dispose() {
m_key = null;
m_sp3_a = null;
m_sp3_b = null;
m_sp3_c = null;
m_sp3_d = null;
GC.Collect();
m_num_key = 0;
}
public object Clone() {
CubicSpline ret = new CubicSpline( m_key, m_sp3_d );
ret.DefaultValue = m_default;
return ret;
}
public double DefaultValue {
get {
return m_default;
}
set {
m_default = value;
}
}
public double GetValue( double x ) {
int status;
double a, b, c, d, xx;
int i, index;
status = 0;
if ( this.m_num_key == -1 ) {
status = -2;
return 0.0;
}
if ( x < this.m_key[0] || this.m_key[this.m_num_key] < x ) {
status = -1;
return 0.0;
}//end if
index = -1;
for ( i = 0; i < this.m_num_key; i++ ) {// do i = 0, sp3%noOfKey - 1
if ( this.m_key[i] <= x && x <= this.m_key[i + 1] ) {// if(sp3%key(i) <= x .and. x <= sp3%key(i + 1))then
index = i;
break;// exit
}//end if
}//end do
xx = x - this.m_key[index];// xx = x - sp3%key(index)
a = this.m_sp3_a[index];// a = sp3%a(index)
b = this.m_sp3_b[index];// b = sp3%b(index)
c = this.m_sp3_c[index];// c = sp3%c(index)
d = this.m_sp3_d[index];// d = sp3%d(index)
return ((a * xx + b) * xx + c) * xx + d;// ans = ((a * xx + b) * xx + c) * xx + d
}//end subroutine spline3_val
/// <summary>配列の形で与えられるデータ点から3次のスプライン補間で用いる各区域のxの多項式の係数を計算します</summary>
/// <param name="x">データ点のx座標を格納した配列</param>
/// <param name="y">データ点のy座標を格納した配列</param>
public CubicSpline( double[] x, double[] y ) {
//integer, intent(in) :: n
//real(8), intent(in) :: x(0:n), y(0:n)
//integer, intent(out) :: status
int n = x.Length - 1;
int status;
m_num_key = -1;
m_default = 0.0;
double[] h, v, a, b, c, u, tmp, xx, yy;//real(8), allocatable :: h(:), v(:), a(:), b(:), c(:), u(:), tmp(:), xx(:), yy(:)
double buff1, buff2;//real(8) buff1, buff2
int i, iostatus, nn, j;//integer i, iostatus, nn, j
status = 0;
nn = n;
xx = new double[n + 1];
yy = new double[n + 1];//allocate(xx(0:n), yy(0:n))
xx = x;
yy = y;//yy(0:n) = y(0:n)
//nullify(sp3%a)
//nullify(sp3%b)
//nullify(sp3%c)
//nullify(sp3%d)
//nullify(sp3%key)
while ( true ) {//do
iostatus = 0;
for ( i = 1; i <= nn - 1; i++ ) {// do i = 1, nn - 1
if ( xx[i + 1] - x[i] == 0.0 ) {// if(xx(i + 1) - xx(i) == 0.0d0)then
for ( j = i; j <= nn - 2; j++ ) {// do j = i, nn - 2
xx[j] = xx[j + 1];// xx(j) = xx(j + 1)
yy[j] = yy[j + 1];// yy(j) = yy(j + 1)
}// end do
iostatus = -1;
// create the copy of xx
//if(allocated(tmp))then
//deallocate(tmp)
//end if
tmp = new double[nn];// allocate(tmp(0:nn - 1))
for ( int k = 0; k < nn; k++ ) {
tmp[k] = xx[k];
}// tmp(0:nn - 1) = xx(0:nn - 1)
// deallocate(xx)
xx = new double[nn];// allocate(xx(0:nn - 1))
for ( int k = 0; k < nn; k++ ) {
xx[k] = tmp[k];
}// xx(0:nn - 1) = tmp(0:nn - 1)
// create the copy of yy
for ( int k = 0; k < nn; k++ ) {
tmp[k] = yy[k];
}// tmp(0:nn - 1) = yy(0:nn - 1)
//deallocate(yy)
yy = new double[nn];// allocate(yy(0:nn - 1))
for ( int k = 0; k < nn; k++ ) {
yy[k] = tmp[k];
}// yy(0:nn - 1) = tmp(0:nn - 1)
break;// exit
}//end if
}//end do
if ( iostatus == 0 ) {// if(iostatus == 0)then
break;// exit
} else {// else
nn = nn - 1;// nn = nn - 1
}// end if
}// end do
//allocate(h(0:nn - 1), v(1:nn - 1), a(1:nn - 1), b(1:nn - 1), c(1:nn - 1), u(1:nn - 1))
h = new double[nn];
v = new double[nn - 1];
a = new double[nn - 1];
b = new double[nn - 1];
c = new double[nn - 1];
u = new double[nn - 1];
// executed in debug mode ******************************************************************************************************
//if(spline_debug_flag == 1)then ! **
//open(unit = 26, file = 'spline_debug.txt') ! **
//end if ! **
// *****************************************************************************************************************************
// calculate h_j
for ( i = 0; i < nn; i++ ) {// do i = 0, nn - 1
h[i] = xx[i + 1] - xx[i];// h(i) = xx(i + 1) - xx(i)
if ( h[i] <= 0.0 ) {// if(h(i) <= 0.0d0)then
this.m_key = new double[1];
this.m_sp3_a = new double[1];
this.m_sp3_b = new double[1];
this.m_sp3_c = new double[1];
this.m_sp3_d = new double[1];
return;
}
}
// calculate v_j
for ( i = 1; i < nn; i++ ) {// do i = 1, nn - 1
buff1 = yy[i + 1] - yy[i];// buff1 = yy(i + 1) - yy(i)
buff2 = yy[i] - y[i - 1];// buff2 = yy(i) - yy(i - 1)
if ( buff1 == 0.0 ) {// if(buff1 == 0.0d0)then
if ( buff2 == 0.0 ) {// if(buff2 == 0.0d0)then
v[i - 1] = 0;// v(i) = 0.0d0
} else {// else
v[i - 1] = 6.0 * (-(yy[i] - yy[i - 1]) / h[i - 1]);// v(i) = 6.0d0 * (- (yy(i) - yy(i - 1)) / h(i - 1))
}// end if
} else {// else
if ( buff2 == 0.0 ) {// if(buff2 == 0.0d0)then
v[i - 1] = 6.0 * ((yy[i + 1] - yy[i]) / h[i]);// v(i) = 6.0d0 * ((yy(i + 1) - yy(i)) / h(i))
} else {// else
v[i - 1] = 6.0 * ((yy[i + 1] - yy[i]) / h[i] - (yy[i] - yy[i - 1]) / h[i - 1]);// v(i) = 6.0d0 * ((yy(i + 1) - yy(i)) / h(i) - (yy(i) - yy(i - 1)) / h(i - 1))
}// end if
}// end if
}//end do
for ( i = 1; i < nn; i++ ) {// do i = 1, nn - 1
a[i - 1] = 2.0 * (h[i - 1] + h[i]);// a(i) = 2.0d0 * (h(i - 1) + h(i))
b[i - 1] = h[i - 1];// b(i) = h(i - 1)
c[i - 1] = h[i];// c(i) = h(i)
}// end do
LUDecTDM( nn - 1, a, b, c, v, out u );// call LUDecTDM(nn - 1, a, b, c, v, u)
m_num_key = nn;// sp3%noOfKey = nn
this.m_sp3_a = new double[nn];// allocate(sp3%a(0:nn - 1))
this.m_sp3_b = new double[nn];// allocate(sp3%b(0:nn - 1))
this.m_sp3_c = new double[nn];// allocate(sp3%c(0:nn - 1))
this.m_sp3_d = new double[nn];// allocate(sp3%d(0:nn - 1))
this.m_key = new double[nn + 1];// allocate(sp3%key(0:nn))
this.m_sp3_a[0] = u[0] / (6.0 * h[0]);// sp3%a(0) = u(1) / (6.0d0 * h(0))
this.m_sp3_b[0] = 0.0;// sp3%b(0) = 0.0d0
this.m_sp3_c[0] = (yy[1] - yy[0]) / h[0] - h[0] * u[0] / 6.0;// sp3%c(0) = (yy(1) - yy(0)) / h(0) - h(0) * u(1) / 6.0d0
this.m_sp3_a[nn - 1] = -u[nn - 2] / (6.0 * h[nn - 1]);// sp3%a(nn - 1) = -u(nn - 1) / (6.0d0 * h(nn - 1))
this.m_sp3_b[nn - 1] = u[nn - 2] * 0.5;// sp3%b(nn - 1) = u(nn - 1) * 0.5d0
this.m_sp3_c[nn - 1] = (yy[nn] - yy[nn - 1]) / h[nn - 1] - h[nn - 1] * u[nn - 2] / 3.0;// sp3%c(nn - 1) = (yy(nn) - yy(nn - 1)) / h(nn - 1) - h(nn - 1) * u(nn - 1) / 3.0d0
for ( i = 1; i <= nn - 2; i++ ) {// do i = 1, nn - 2
this.m_sp3_a[i] = (u[i] - u[i - 1]) / (6.0 * h[i]);// sp3%a(i) = (u(i + 1) - u(i)) / (6.0d0 * h(i))
this.m_sp3_b[i] = u[i - 1] * 0.5;// sp3%b(i) = u(i) * 0.5d0
this.m_sp3_c[i] = (yy[i + 1] - yy[i]) / h[i] - h[i] * (2.0 * u[i - 1] + u[i]) / 6.0;// sp3%c(i) = (yy(i + 1) - yy(i)) / h(i) - h(i) * (2.0d0 * u(i) + u(i + 1)) / 6.0d0
}//end do
this.m_key = xx;
// sp3%key(0:nn) = xx(0:nn)
for ( int k = 0; k < nn; k++ ) {
this.m_sp3_d[k] = yy[k];
}// sp3%d(0:nn - 1) = yy(0:nn - 1)
}
/// <summary>
/// This subroutine solves system of linear equation(only for
/// tridiagonal matrix system) by LU decompression method.
/// Meanings of variables are defined below.
/// ( a1 c1 0 ) ( x1 ) ( y1 )
/// ( b2 a2 c2 ) ( x2 ) ( y2 )
/// ( b3 a3 c3 ) ( x3 ) ( y3 )
/// ( ... ) ( ...) = ( ...)
/// ( bN-1 aN-1 cN-1 ) (xN-1) (yN-1)
/// ( 0 bN aN ) ( xN ) ( yN )
/// </summary>
/// <param name="N"></param>
/// <param name="a"></param>
/// <param name="b"></param>
/// <param name="c"></param>
/// <param name="y"></param>
/// <param name="x"></param>
private static void LUDecTDM( int N, double[] a, double[] b, double[] c, double[] y, out double[] x ) {
double[] d = new double[N];
double[] z = new double[N];
double[] l = new double[N];
int i;
x = new double[N];
d[0] = a[0];// d(1) = a(1)
for ( i = 1; i < N; i++ ) {// do i = 2, N
l[i] = b[i] / d[i - 1];// l(i) = b(i) / d(i - 1)
d[i] = a[i] - l[i] * c[i - 1];// d(i) = a(i) - l(i) * c(i - 1)
}// end do
z[0] = y[0];// z(1) = y(1)
for ( i = 1; i < N; i++ ) {// do i = 2, N
z[i] = y[i] - l[i] * z[i - 1];// z(i) = y(i) - l(i) * z(i - 1)
}// end do
x[N - 1] = z[N - 1] / d[N - 1];// x(N) = z(N) / d(N)
for ( i = N - 2; i >= 0; i-- ) {// do i = N - 1, 1, -1
x[i] = (z[i] - c[i] * x[i + 1]) / d[i];// x(i) = (z(i) - c(i) * x(i + 1)) / d(i)
}// end do
}
}
}
#endif