C # Линейная интерполяция

У меня возникли проблемы с интерполяцией файла данных, который я преобразовал из .csv в массив X и массив Y, где X [0] соответствует точке Y [0], например.

Мне нужно интерполировать между значениями, чтобы получить плавный файл в конце. Я использую Picoscope для вывода функции, которая означает, что каждая строка равномерно распределена по времени, поэтому я использую только значения Y, поэтому яЯ пытаюсь сделать это странным образом, когда вы видите мой код.

Вид ценностей, с которыми он имеет дело:

X     Y
0     0
2.5   0
2.5   12000
7.5   12000
7.5   3000
10    3000
10    6000
11    6625.254
12    7095.154

Таким образом, если значения 2 Y рядом друг с другом одинаковы, это прямая линия между ними, но когда они изменяются, например, от X = 10 на участках, это становится синусоидальной волной в этом примере.

Я смотрел на уравнения для интерполяции и т. Д. И другие посты здесь, но я не имеюя делал такие математики годами, и, к сожалению, я не могуне могу понять это больше, потому что тамс 2 неизвестных и я могуне думаю, как запрограммировать это в C #.

Что у меня есть:

int a = 0, d = 0, q = 0;
bool up = false;
double times = 0, change = 0, points = 0, pointchange = 0; 
double[] newy = new double[8192];
while (a < sizeoffile-1 && d < 8192)
{
    Console.Write("...");
    if (Y[a] == Y[a+1])//if the 2 values are the same add correct number of lines in to make it last the correct time
    {
        times = (X[a] - X[a + 1]);//number of repetitions
        if ((X[a + 1] - X[a]) > times)//if that was a negative number try the other way around
            times = (X[a + 1] - X[a]);//number of repetitions 
        do
        {
            newy[d] = Y[a];//add the values to the newy array which replaces y later on in the program
            d++;//increment newy position
            q++;//reduce number of reps in this loop
        }
        while (q < times + 1 && d < 8192);
        q = 0;//reset reps
    }
    else if (Y[a] != Y[a + 1])//if the 2 values are not the same interpolate between them
    {
        change = (Y[a] - Y[a + 1]);//work out difference between the values
        up = true;//the waveform is increasing
        if ((Y[a + 1] - Y[a]) > change)//if that number was a negative try the other way around
        {
            change = (Y[a + 1] - Y[a]);//work out difference bwteen values
            up = false;//the waveform is decreasing
        }
        points = (X[a] - X[a + 1]);//work out amount of time between given points
        if ((X[a + 1] - X[a]) > points)//if that was a negative try other way around
            points = (X[a + 1] - X[a]);///work out amount of time between given points
        pointchange = (change / points);//calculate the amount per point in time the value changes by
        if (points > 1)//any lower and the values cause errors
        {
            newy[d] = Y[a];//load first point
            d++;
            do
            {
                if (up == true)//
                    newy[d] = ((newy[d - 1]) + pointchange);
                else if (up == false)
                    newy[d] = ((newy[d - 1]) - pointchange);
                d++;
                q++;
            }
            while (q < points + 1 && d < 8192);
            q = 0;
        }
        else if (points != 0 && points > 0)
        {
            newy[d] = Y[a];//load first point
            d++;
        }
    }
    a++;
}

и это создает близкий сигнал, но он все еще очень крут.

Так может кто-нибудь понять, почему это не такТочнее? Как улучшить его точность? Или другой способ сделать это с помощью массивов?

Спасибо за внимание :)

 Hans Passant11 окт. 2012 г., 14:34

Ответы на вопрос(2)

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);
}

Фактически вы должны быть в состоянии взять свои массивы и использовать их следующим образом:

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

Я вытащил код изВот, но проверил, что алгоритм соответствует теорииВоти вот ясчитать Это'верно. Тем не менее, вы, вероятно, должны рассмотреть возможность использования полиномиальной интерполяции, если она все еще является ступенчатой, обратите внимание на теоретическую ссылку, она показывает, что линейная интерполяция создает ступенчатые волны.

Итак, первая ссылка, которую я дал, откуда я взял этот код, также имеет полиномиальный алгоритм:

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;
}

Чтобы использовать это вывам придется решить, как вы хотите увеличить свойx ценности, так что давайтескажем, мы хотели сделать это путем нахождения средней точки между текущей итерацией и следующей:

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

Обратите внимание, что в этом цикле будет больше, например, обеспечениеi+1 и такое, но я хотел посмотреть, смогу ли я дать вам начало.

 Mike Perrenoud11 окт. 2012 г., 15:55
@ user1548411, пожалуйста, смотрите мои изменения.
 openshac04 апр. 2016 г., 13:11
return (y0 + y1) / 2 может вызвать исключение переполнения, если y0, y1 велики. Вы можете исправить эту покупку, используя вместо этого y0 + (y1 - y0) / 2.
 user154841111 окт. 2012 г., 15:37
так какое значение я положу в х? потому что это один из неизвестных нене так ли?
 ibrahimyilmaz30 дек. 2016 г., 08:54
произведение * = (x - xd [i]) / (xd [i] - xd [j]); первый xd [i] должен быть xd [j]wikimedia.org/api/rest_v1/media/math/render/svg/...

Теоретическая база в Вольфраме

Приведенное ниже решение вычисляет средние значения Y для заданных точек с одинаковым X, так же как и функция полифита Matlab.

Linq и версия .NET Framework> 3.5 являются обязательными для этого быстрого API. Комментарии внутри кода.

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
    public LinearLeastSquaresInterpolation(IEnumerable<point> points)
    {
        Points = points;
    }
    /// <summary>
    /// abscissae/ordinates constructor
    /// </summary>
    /// <param name="x">abscissae
    /// <param name="y">ordinates
    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 name="b">input
    /// <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">
    /// <returns></returns>
    public static bool Empty<t>(this IEnumerable<t> a)
    {
        return a == null || a.Count() == 0;
    }
}
</t></t></float></float></float></float></float,point></point></point></float></float></point>

Используйте это как:

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}
    });

Или же:

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 });
 ozziwald30 мая 2017 г., 20:10
Ты написал это? Если нет, то откуда он взялся и каково лицензирование в коде?
 andrei.ciprian12 июн. 2017 г., 22:14
Да. Вы можете использовать его бесплатно. Это'Наивная реализация, основанная на наименьших квадратах, как указано в этой ссылке на wolfram

Ваш ответ на вопрос