C#,数值计算——插值和外推,二维三次样条插值(Spline2D_interp)的计算方法与源程序

1 文本格式

using System;

namespace Legalsoft.Truffer
{
    ///


    /// 二维三次样条插值
    /// Object for two-dimensional cubic spline interpolation on a matrix.Construct
    /// with a vector of x1 values, a vector of x2 values, and a matrix of tabulated
    /// function values yij.Then call interp for interpolated values.
    ///

    public class Spline2D_interp
    {
        private int[,] bcucof_wt = new int[,] {
            {  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0 },
            {  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0 },
            { -3,  0,  0,  3,  0,  0,  0,  0, -2,  0,  0, -1,  0,  0,  0,  0 },
            {  2,  0,  0, -2,  0,  0,  0,  0,  1,  0,  0,  1,  0,  0,  0,  0 },
            {  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
            {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0 },
            {  0,  0,  0,  0, -3,  0,  0,  3,  0,  0,  0,  0, -2,  0,  0, -1 },
            {  0,  0,  0,  0,  2,  0,  0, -2,  0,  0,  0,  0,  1,  0,  0,  1 },
            { -3,  3,  0,  0, -2, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
            {  0,  0,  0,  0,  0,  0,  0,  0, -3,  3,  0,  0, -2, -1,  0,  0 },
            {  9, -9,  9, -9,  6,  3, -3, -6,  6, -6, -3,  3,  4,  2,  1,  2 },
            { -6,  6, -6,  6, -4, -2,  2,  4, -3,  3,  3, -3, -2, -1, -1, -2 },
            {  2, -2,  0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
            {  0,  0,  0,  0,  0,  0,  0,  0,  2, -2,  0,  0,  1,  1,  0,  0 },
            { -6,  6, -6,  6, -3, -3,  3,  3, -4,  4,  2, -2, -2, -2, -1, -1 },
            {  4, -4,  4, -4,  2,  2, -2, -2,  2, -2, -2,  2,  1,  1,  1,  1 }
        };

        private int m { get; set; }
        private int n { get; set; }
        private double[,] y { get; set; }
        private double[] x1 { get; set; }
        private double[] yv { get; set; }
        private Spline_interp[] srp { get; set; }

        public Spline2D_interp(double[] x1v, double[] x2v, double[,] ym)
        {
            this.m = x1v.Length;
            this.n = x2v.Length;
            this.y = ym;
            this.yv = new double[m];
            this.x1 = x1v;
            this.srp = new Spline_interp[m];
            for (int i = 0; i < m; i++)
            {
                srp[i] = new Spline_interp(x2v, y[i, 0]);
            }
        }

        public double interp(double x1p, double x2p)
        {
            for (int i = 0; i < m; i++)
            {
                yv[i] = (srp[i]).interp(x2p);
            }
            Spline_interp scol = new Spline_interp(x1, yv);
            return scol.interp(x1p);
        }

        ///


        /// Given arrays y[0..3], y1[0..3], y2[0..3], and y12[0..3], containing the
        /// function, gradients, and cross-derivative at the four grid points of a
        /// rectangular grid cell(numbered counterclockwise from the lower left), and
        /// given d1 and d2, the length of the grid cell in the 1 and 2 directions,
        /// this routine returns the table c[0..3][0..3] that is used by routine bcuint
        /// for bicubic interpolation.
        ///

        ///
        ///
        ///
        ///
        ///
        ///
        ///
        private void bcucof(double[] y, double[] y1, double[] y2, double[] y12, double d1, double d2, double[,] c)
        { 
            //int[,] bcucof_wt = new int[16, 16]{ bcucof_wt_d };
            double d1d2 = d1 * d2;
            double[] cl = new double[16];
            double[] x = new double[16];

            for (int i = 0; i < 4; i++)
            {
                x[i] = y[i];
                x[i + 4] = y1[i] * d1;
                x[i + 8] = y2[i] * d2;
                x[i + 12] = y12[i] * d1d2;
            }
            for (int i = 0; i < 16; i++)
            {
                double xx = 0.0;
                for (int k = 0; k < 16; k++)
                {
                    xx += bcucof_wt[i, k] * x[k];
                }
                cl[i] = xx;
            }
            int l = 0;
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    c[i, j] = cl[l++];
                }
            }
        }

        ///


        /// Bicubic interpolation within a grid square.Input quantities are
        /// y, y1, y2, y12 (as described in bcucof); x1l and x1u, the lower and upper
        /// coordinates of the grid square in the 1 direction; x2l and x2u likewise for
        /// the 2 direction; and x1, x2, the coordinates of the desired point for the
        /// interpolation.The interpolated function value is returned as ansy, and the
        /// interpolated gradient values as ansy1 and ansy2.This routine calls bcucof.
        ///

        ///
        ///
        ///
        ///
        ///
        ///
        ///
        ///
        ///
        ///
        ///
        ///
        ///
        ///
        public void bcuint(double[] y, double[] y1, double[] y2, double[] y12, double x1l, double x1u, double x2l, double x2u, double x1, double x2, ref double ansy, ref double ansy1, ref double ansy2)
        {
            double d1 = x1u - x1l;
            double d2 = x2u - x2l;
            double[,] c = new double[4, 4];
            bcucof(y, y1, y2, y12, d1, d2, c);
            //if (x1u == x1l || x2u == x2l)
            if (Math.Abs(x1u - x1l) <= float.Epsilon || Math.Abs(x2u - x2l) <= float.Epsilon)
            {
                throw new Exception("Bad input in routine bcuint");
            }
            double t = (x1 - x1l) / d1;
            double u = (x2 - x2l) / d2;
            ansy = ansy2 = ansy1 = 0.0;
            for (int i = 3; i >= 0; i--)
            {
                ansy = t * ansy + ((c[i, 3] * u + c[i, 2]) * u + c[i, 1]) * u + c[i, 0];
                ansy2 = t * ansy2 + (3.0 * c[i, 3] * u + 2.0 * c[i, 2]) * u + c[i, 1];
                ansy1 = u * ansy1 + (3.0 * c[3, i] * t + 2.0 * c[2, i]) * t + c[1, i];
            }
            ansy1 /= d1;
            ansy2 /= d2;
        }

    }
}

2 代码格式

using System;

namespace Legalsoft.Truffer
{
    /// 
    /// 二维三次样条插值
    /// Object for two-dimensional cubic spline interpolation on a matrix.Construct
    /// with a vector of x1 values, a vector of x2 values, and a matrix of tabulated
    /// function values yij.Then call interp for interpolated values.
    /// 
    public class Spline2D_interp
    {
        private int[,] bcucof_wt = new int[,] {
            {  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 0 },
            {  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0 },
            { -3,  0,  0,  3,  0,  0,  0,  0, -2,  0,  0, -1,  0,  0,  0,  0 },
            {  2,  0,  0, -2,  0,  0,  0,  0,  1,  0,  0,  1,  0,  0,  0,  0 },
            {  0,  0,  0,  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
            {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  0,  0,  0 },
            {  0,  0,  0,  0, -3,  0,  0,  3,  0,  0,  0,  0, -2,  0,  0, -1 },
            {  0,  0,  0,  0,  2,  0,  0, -2,  0,  0,  0,  0,  1,  0,  0,  1 },
            { -3,  3,  0,  0, -2, -1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
            {  0,  0,  0,  0,  0,  0,  0,  0, -3,  3,  0,  0, -2, -1,  0,  0 },
            {  9, -9,  9, -9,  6,  3, -3, -6,  6, -6, -3,  3,  4,  2,  1,  2 },
            { -6,  6, -6,  6, -4, -2,  2,  4, -3,  3,  3, -3, -2, -1, -1, -2 },
            {  2, -2,  0,  0,  1,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
            {  0,  0,  0,  0,  0,  0,  0,  0,  2, -2,  0,  0,  1,  1,  0,  0 },
            { -6,  6, -6,  6, -3, -3,  3,  3, -4,  4,  2, -2, -2, -2, -1, -1 },
            {  4, -4,  4, -4,  2,  2, -2, -2,  2, -2, -2,  2,  1,  1,  1,  1 }
        };

        private int m { get; set; }
        private int n { get; set; }
        private double[,] y { get; set; }
        private double[] x1 { get; set; }
        private double[] yv { get; set; }
        private Spline_interp[] srp { get; set; }

        public Spline2D_interp(double[] x1v, double[] x2v, double[,] ym)
        {
            this.m = x1v.Length;
            this.n = x2v.Length;
            this.y = ym;
            this.yv = new double[m];
            this.x1 = x1v;
            this.srp = new Spline_interp[m];
            for (int i = 0; i < m; i++)
            {
                srp[i] = new Spline_interp(x2v, y[i, 0]);
            }
        }

        public double interp(double x1p, double x2p)
        {
            for (int i = 0; i < m; i++)
            {
                yv[i] = (srp[i]).interp(x2p);
            }
            Spline_interp scol = new Spline_interp(x1, yv);
            return scol.interp(x1p);
        }

        /// 
        /// Given arrays y[0..3], y1[0..3], y2[0..3], and y12[0..3], containing the
        /// function, gradients, and cross-derivative at the four grid points of a
        /// rectangular grid cell(numbered counterclockwise from the lower left), and
        /// given d1 and d2, the length of the grid cell in the 1 and 2 directions,
        /// this routine returns the table c[0..3][0..3] that is used by routine bcuint
        /// for bicubic interpolation.
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        private void bcucof(double[] y, double[] y1, double[] y2, double[] y12, double d1, double d2, double[,] c)
        { 
            //int[,] bcucof_wt = new int[16, 16]{ bcucof_wt_d };
            double d1d2 = d1 * d2;
            double[] cl = new double[16];
            double[] x = new double[16];

            for (int i = 0; i < 4; i++)
            {
                x[i] = y[i];
                x[i + 4] = y1[i] * d1;
                x[i + 8] = y2[i] * d2;
                x[i + 12] = y12[i] * d1d2;
            }
            for (int i = 0; i < 16; i++)
            {
                double xx = 0.0;
                for (int k = 0; k < 16; k++)
                {
                    xx += bcucof_wt[i, k] * x[k];
                }
                cl[i] = xx;
            }
            int l = 0;
            for (int i = 0; i < 4; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    c[i, j] = cl[l++];
                }
            }
        }

        /// 
        /// Bicubic interpolation within a grid square.Input quantities are
        /// y, y1, y2, y12 (as described in bcucof); x1l and x1u, the lower and upper
        /// coordinates of the grid square in the 1 direction; x2l and x2u likewise for
        /// the 2 direction; and x1, x2, the coordinates of the desired point for the
        /// interpolation.The interpolated function value is returned as ansy, and the
        /// interpolated gradient values as ansy1 and ansy2.This routine calls bcucof.
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public void bcuint(double[] y, double[] y1, double[] y2, double[] y12, double x1l, double x1u, double x2l, double x2u, double x1, double x2, ref double ansy, ref double ansy1, ref double ansy2)
        {
            double d1 = x1u - x1l;
            double d2 = x2u - x2l;
            double[,] c = new double[4, 4];
            bcucof(y, y1, y2, y12, d1, d2, c);
            //if (x1u == x1l || x2u == x2l)
            if (Math.Abs(x1u - x1l) <= float.Epsilon || Math.Abs(x2u - x2l) <= float.Epsilon)
            {
                throw new Exception("Bad input in routine bcuint");
            }
            double t = (x1 - x1l) / d1;
            double u = (x2 - x2l) / d2;
            ansy = ansy2 = ansy1 = 0.0;
            for (int i = 3; i >= 0; i--)
            {
                ansy = t * ansy + ((c[i, 3] * u + c[i, 2]) * u + c[i, 1]) * u + c[i, 0];
                ansy2 = t * ansy2 + (3.0 * c[i, 3] * u + 2.0 * c[i, 2]) * u + c[i, 1];
                ansy1 = u * ansy1 + (3.0 * c[3, i] * t + 2.0 * c[2, i]) * t + c[1, i];
            }
            ansy1 /= d1;
            ansy2 /= d2;
        }

    }
}

你可能感兴趣的:(C#数值计算,Numerical,Recipes,算法,c#,数值计算)