.NETのコア(C#)フィットラウンドテスト

説明

多くの場合、我々はマシンのパフォーマンスを記述するために、オブジェクトの旋回半径を行使する必要があります。しかし、最も現実世界の条件で、我々は唯一の移動物体のGPS位置ポイントセットを取得することができ、直接半径や中心位置を回すことができません。この目的のために、我々は、これにより旋回半径や中心位置を求める式に当てはめ円の座標を取得するために円形の方法を使用することができます。

解決プロセス

フィッティング方程式の多くの方法についてのラウンドがあり、この翻訳では多くのことを学んだ代数的近似、その結果は(パイソン)を比較ラウンド合うように、最小二乗法、直交距離回帰本稿では、パフォーマンスのシリーズと述べコントラスト3つの方法の効果を与え、最終的な解決策は、最小二乗最適な方法を得ることです。最近の調査にさらにあなたはそれを解決するために、線形代数の方法を利用することができることを学びました。大学のカリキュラムには知識「線形代数」を学んだので、ほとんどのコントラストを作るために、一緒にこの問題を解決するために、このメソッドを使用するのではと思います。

次に、物品が得られ、最小二乗法で議論円ため代数方程式を線形です。

レディ

参考行列計算ライブラリのMathNet.Numericsライブラリは、.NETの標準に従って、強力な科学技術計算ライブラリですので、あなたは、クロスプラットフォームのできる使用を。

クラスの説明の円を作成します。

public class Circle
{
    /// <summary>
    /// 圆心横坐标
    /// </summary>
    /// <value></value>
    public   double X { get; set; }
    /// <summary>
    /// 圆心纵坐标
    /// </summary>
    /// <value></value>
    public   double Y { get; set; }
    /// <summary>
    /// 圆半径
    /// </summary>
    /// <value></value>
    public  double R { get; set; }
}

、参照描画System.Drawing.Commonの画像生成クロスプラットフォームを実現するために、ライブラリー。次に、我々は、単に画像レンダリングのためのクラスの画像を達成するのを助けます。

public class ImageHelp
{
    private Image _image;
    public ImageHelp(int width, int height)
    {
        _image = new Bitmap(width, height);
        var graph = Graphics.FromImage(_image);
        graph.Clear(Color.White);
    }
    public void DrawCicle(Circle circle, Brush brush)
    {
        var graph = Graphics.FromImage(_image);
        var count=200;
        var fitPoints = new Point[count+1];
        var step = 2 * Math.PI / count;
        for (int i = 0; i < count; i++)
        {
            //circle
            var p = new Point();
            p.X = (int)(circle.X + Math.Cos(i * step) * circle.R);
            p.Y = (int)(circle.Y + Math.Sin(i * step) * circle.R);
            fitPoints[i] = p;
        }
        fitPoints[count] = fitPoints[0];//闭合圆
        graph.DrawLines(new Pen(brush, 2), fitPoints);
        graph.Dispose();
    }
    public void DrawPoints(double[] X, double[] Y, Brush brush)
    {
        var graph = Graphics.FromImage(_image);
        for (int i = 0; i < X.Length; i++)
        {
            graph.DrawEllipse(new Pen(brush, 2), (int)X[i], (int)Y[i], 6, 6);
        }
        graph.Dispose();
    }
    public void SaveImage(string file)
    {
        _image.Save(file, System.Drawing.Imaging.ImageFormat.Png);
    }
}

アナログ設定点、データ取得現実ので、画像データの記録等の精度の多くの不確定要因があります。アナログフォーカスポイントは、ノイズのある程度が追加されます。点の我々のデータセットに格納された次のコードにおけるXとY:

var count = 50;
var step = 2 * Math.PI / 100;
var rd = new Random();
//参照圆
var x0 = 204.1;
var y0 = 213.1;
var r0 = 98.4;
//噪音绝对差
var diff = (int)(r0 * 0.1);
var x = new double[count];
var y = new double[count];
//输出点集
for (int i = 0; i < count; i++)
{
    //circle
    x[i] = x0 + Math.Cos(i * step) * r0;
    y[i] = y0 + Math.Sin(i * step) * r0;
    //noise
    x[i] += Math.Cos(rd.Next() % 2 * Math.PI) * rd.Next(diff);
    y[i] += Math.Cos(rd.Next() % 2 * Math.PI) * rd.Next(diff);
}

最小二乗法

多くのオンライン分析の原則がありますが、ここにも言及した上記の翻訳は、ここでは詳細に説明されていません。直接掲示C#のコードを達成するために:

public Circle LeastSquaresFit(double[] X, double[] Y)
{
    if (X.Length < 3)
    {
        return null;
    }
    double cent_x = 0.0,
        cent_y = 0.0,
        radius = 0.0;
    double sum_x = 0.0f, sum_y = 0.0f;
    double sum_x2 = 0.0f, sum_y2 = 0.0f;
    double sum_x3 = 0.0f, sum_y3 = 0.0f;
    double sum_xy = 0.0f, sum_x1y2 = 0.0f, sum_x2y1 = 0.0f;
    int N = X.Length;
    double x, y, x2, y2;
    for (int i = 0; i < N; i++)
    {
        x = X[i];
        y = Y[i];
        x2 = x * x;
        y2 = y * y;
        sum_x += x;
        sum_y += y;
        sum_x2 += x2;
        sum_y2 += y2;
        sum_x3 += x2 * x;
        sum_y3 += y2 * y;
        sum_xy += x * y;
        sum_x1y2 += x * y2;
        sum_x2y1 += x2 * y;
    }
    double C, D, E, G, H;
    double a, b, c;
    C = N * sum_x2 - sum_x * sum_x;
    D = N * sum_xy - sum_x * sum_y;
    E = N * sum_x3 + N * sum_x1y2 - (sum_x2 + sum_y2) * sum_x;
    G = N * sum_y2 - sum_y * sum_y;
    H = N * sum_x2y1 + N * sum_y3 - (sum_x2 + sum_y2) * sum_y;
    a = (H * D - E * G) / (C * G - D * D);
    b = (H * C - E * D) / (D * D - G * C);
    c = -(a * sum_x + b * sum_y + sum_x2 + sum_y2) / N;
    cent_x = a / (-2);
    cent_y = b / (-2);
    radius = Math.Sqrt(a * a + b * b - 4 * c) / 2;
    var result = new Circle();
    result.X = cent_x;
    result.Y = cent_y;
    result.R = radius;
    return result;
}

線形代数

円の標準式から(x-c1)^2+(y-c2)^2=r^2得られた変換式のために2xc1+2yc2+(r^2−c1^2−c2^2)=x^2+y^2これらを、我々はc3一定の値を置き換えr^2−c1^2−c2^2、すなわち、: r^2−c1^2−c2^2=c3したがって、我々が得る2xc1+2yc2+c3=x^2+y^23つの未知数の`のC1、C2、C3ので左式にセットポイントを。

簡単にするために、我々は4点をしていると仮定し{[0,5],[0,-5],[5,0],[-5,0]}、式に4つの方程式が得られます。

  0c1 + 10c2 + c3 = 25
  0c1 - 10c2 + c3 = 25
 10c1 + 0c2  + c3 = 25
-10c1 + 0c2  + c3 = 25

式は、見ることができソリューションは簡単です。しかし、我々は、線形代数行列を使用して取得できます。

/***************************A**********B******C*/
|  0c1  10c2   1c3|   |  0  10   1|   |c1|   |25|
|  0c1 -10c2   1c3| = |  0 -10   1| * |c2| = |25|
| 10c1   0c2   1c3|   | 10   0   1|   |c3|   |25|
|-10c1   0c2   1c3|   |-10   0   1|          |25|

行列式においてA*B=C、マトリックスのみが得られたB得られた方程式の解です。C#の中には、MathNet.Numerics簡単に仕事をすることができます。

public Circle LinearAlgebraFit(double[] X, double[] Y)
{
    if (X.Length < 3)
    {
        return null;
    }
    var count = X.Length;
    var a = new double[count, 3];
    var c = new double[count, 1];
    for (int i = 0; i < count; i++)
    {
        //matrix
        a[i, 0] = 2 * X[i];
        a[i, 1] = 2 * Y[i];
        a[i, 2] = 1;
        c[i, 0] = X[i] * X[i] + Y[i] * Y[i];
    }
    var A = DenseMatrix.OfArray(a);
    var C = DenseMatrix.OfArray(c);
    //A*B=C
    var B = A.Solve(C);
    double c1 = B.At(0, 0),
        c2 = B.At(1, 0),
        r = Math.Sqrt(B.At(2, 0) + c1 * c1 + c2 * c2);
    var result = new Circle();
    result.X = c1;
    result.Y = c2;
    result.R = r;
    return result;
}

締結

Console.WriteLine($"raw   c1:{x0}, c2:{y0}, r:{r0}");
var fit = new FitCircle();
var sth = new Stopwatch();
sth.Start();
var lsf = fit.LeastSquaresFit(x, y);![](https://img2018.cnblogs.com/blog/1214143/201908/1214143-20190804173821455-1022769486.jpg)


Console.WriteLine($"LeastSquaresFit   c1:{lsf.X}, c2:{lsf.Y}, r:{lsf.R}, time:{sth.Elapsed}");
sth.Restart();
var laf = fit.LinearAlgebraFit(x, y);
Console.WriteLine($"LinearAlgebraFit  c1:{laf.X}, c2:{laf.Y}, r:{laf.R}, time:{sth.Elapsed}");
var img = new ImageHelp(512, 512);
img.DrawPoints(x, y, Brushes.Red);
img.DrawCicle(lsf, Brushes.Green);
img.DrawCicle(laf, Brushes.Orange);
img.SaveImage("graph.jpeg");

コンソール出力:

raw   c1:204.1, c2:213.1, r:98.4
LeastSquaresFit   c1:204.791071061878, c2:210.86075318831, r:100.436594821545, time:00:00:00.0011029
LinearAlgebraFit  c1:204.791071061878, c2:210.860753188315, r:100.436594821541, time:00:00:00.1691119

結果から分かるように、二つの方法の結果は基本的に同じですが、違いは唯一のかなりの数の小数点以下の桁に登場しました。しかし、違いは莫大な計算効率、100倍の速さよりも、最小二乗線形代数でした。
図面において、一致の両方が(緑色、オレンジ色は後で説明します)。

最小二乗法、およびループのためだけの単純なで、めったにメモリ書き込みを伴いません。しかし、線形代数は、マトリックスが生成される必要があるDenseMatrix.OfArrayメモリ書き込みを必要どちらも、および行列演算。さらに、円の効率に影響を与えるされ、計算集約有する行列演算は、線形代数を嵌。最終的な勝利は、まだ最小二乗法に属します。

おすすめ

転載: www.cnblogs.com/hsxian/p/11298954.html