C# Linear Interpolation

谁说胖子不能爱 提交于 2019-11-29 00:07:01

Try this method for me:

static public double linear(double x, double x0, double x1, double y0, double y1)
{
    if ((x1 - x0) == 0)
    {
        return (y0 + y1) / 2;
    }
    return y0 + (x - x0) * (y1 - y0) / (x1 - x0);
}

Effectively you should be able to take your arrays and use it like this:

var newY = linear(X[0], X[0], X[1], Y[0], Y[1]);

I pulled the code from here, but verified that the algorithm matched the theory here, and so I think it's right. However, you probably should consider using polynomial interpolation if this is still steppy, please note the theory link, it shows that linear interpolation produces steppy waves.

So, the first link I gave, where I grabbed this code from, also has a polynomial algorithm:

static public double lagrange(double x, double[] xd, double[] yd)
{
    if (xd.Length != yd.Length)
    {
        throw new ArgumentException("Arrays must be of equal length."); //$NON-NLS-1$
    }
    double sum = 0;
    for (int i = 0, n = xd.Length; i < n; i++)
    {
        if (x - xd[i] == 0)
        {
            return yd[i];
        }
        double product = yd[i];
        for (int j = 0; j < n; j++)
        {
            if ((i == j) || (xd[i] - xd[j] == 0))
            {
                continue;
            }
            product *= (x - xd[i]) / (xd[i] - xd[j]);
        }
        sum += product;
    }
    return sum;
}

To use this one you're going to have to decide how you want to step up your x values, so let's say we wanted to do it by finding the midpoint between the current iteration and the next:

for (int i = 0; i < X.Length; i++)
{
    var newY = lagrange(new double[] { X[i]d, X[i+1]d }.Average(), X, Y);
}

Please note that there will be more to this loop, like ensuring there is an i+1 and such, but I wanted to see if I could give you a start.

andrei.ciprian

Theoretical base at Wolfram

The solution below computes the averages of Y values for given points with same X, just as the Matlab polyfit function does

Linq and .NET framework version > 3.5 are mandatory for this swift API. Comments inside the code.

using System;
using System.Collections.Generic;
using System.Linq;


/// <summary>
/// Linear Interpolation using the least squares method
/// <remarks>http://mathworld.wolfram.com/LeastSquaresFitting.html</remarks> 
/// </summary>
public class LinearLeastSquaresInterpolation
{
    /// <summary>
    /// point list constructor
    /// </summary>
    /// <param name="points">points list</param>
    public LinearLeastSquaresInterpolation(IEnumerable<Point> points)
    {
        Points = points;
    }
    /// <summary>
    /// abscissae/ordinates constructor
    /// </summary>
    /// <param name="x">abscissae</param>
    /// <param name="y">ordinates</param>
    public LinearLeastSquaresInterpolation(IEnumerable<float> x, IEnumerable<float> y)
    {
        if (x.Empty() || y.Empty())
            throw new ArgumentNullException("null-x");
        if (y.Empty())
            throw new ArgumentNullException("null-y");
        if (x.Count() != y.Count())
            throw new ArgumentException("diff-count");

        Points = x.Zip(y, (unx, uny) =>  new Point { x = unx, y = uny } );
    }

    private IEnumerable<Point> Points;
    /// <summary>
    /// original points count
    /// </summary>
    public int Count { get { return Points.Count(); } }

    /// <summary>
    /// group points with equal x value, average group y value
    /// </summary>
                                                    public IEnumerable<Point> UniquePoints
{
    get
    {
        var grp = Points.GroupBy((p) => { return p.x; });
        foreach (IGrouping<float,Point> g in grp)
        {
            float currentX = g.Key;
            float averageYforX = g.Select(p => p.y).Average();
            yield return new Point() { x = currentX, y = averageYforX };
        }
    }
}
    /// <summary>
    /// count of point set used for interpolation
    /// </summary>
    public int CountUnique { get { return UniquePoints.Count(); } }
    /// <summary>
    /// abscissae
    /// </summary>
    public IEnumerable<float> X { get { return UniquePoints.Select(p => p.x); } }
    /// <summary>
    /// ordinates
    /// </summary>
    public IEnumerable<float> Y { get { return UniquePoints.Select(p => p.y); } }
    /// <summary>
    /// x mean
    /// </summary>
    public float AverageX { get { return X.Average(); } }
    /// <summary>
    /// y mean
    /// </summary>
    public float AverageY { get { return Y.Average(); } }

    /// <summary>
    /// the computed slope, aka regression coefficient
    /// </summary>
    public float Slope { get { return ssxy / ssxx; } }

    // dotvector(x,y)-n*avgx*avgy
    float ssxy { get { return X.DotProduct(Y) - CountUnique * AverageX * AverageY; } }
    //sum squares x - n * square avgx
    float ssxx { get { return X.DotProduct(X) - CountUnique * AverageX * AverageX; } }

    /// <summary>
    /// computed  intercept
    /// </summary>
    public float Intercept { get { return AverageY - Slope * AverageX; } }

    public override string ToString()
    {
        return string.Format("slope:{0:F02} intercept:{1:F02}", Slope, Intercept);
    }
}

/// <summary>
/// any given point
/// </summary>
 public class Point 
 {
     public float x { get; set; }
     public float y { get; set; }
 }

/// <summary>
/// Linq extensions
/// </summary>
public static class Extensions 
{
    /// <summary>
    /// dot vector product
    /// </summary>
    /// <param name="a">input</param>
    /// <param name="b">input</param>
    /// <returns>dot product of 2 inputs</returns>
    public static float DotProduct(this IEnumerable<float> a, IEnumerable<float> b)
    {
        return a.Zip(b, (d1, d2) => d1 * d2).Sum();
    }
    /// <summary>
    /// is empty enumerable
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="a"></param>
    /// <returns></returns>
    public static bool Empty<T>(this IEnumerable<T> a)
    {
        return a == null || a.Count() == 0;
    }
}

Use it like:

var llsi = new LinearLeastSquaresInterpolation(new Point[] 
    {
        new Point {x=1, y=1}, new Point {x=1, y=1.1f}, new Point {x=1, y=0.9f}, 
        new Point {x=2, y=2}, new Point {x=2, y=2.1f}, new Point {x=2, y=1.9f}, 
        new Point {x=3, y=3}, new Point {x=3, y=3.1f}, new Point {x=3, y=2.9f}, 
        new Point {x=10, y=10}, new Point {x=10, y=10.1f}, new Point {x=10, y=9.9f},
        new Point {x=100, y=100}, new Point{x=100, y=100.1f}, new Point {x=100, y=99.9f}
    });

Or:

var llsi = new LinearLeastSquaresInterpolation(
    new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9 },
    new float[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 1, 2, 3, 4, 5, 6, 7, 8, 9 });
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!