来自传入串行数据的移动平均值 C#/.NET

Moving average from incoming serial data C#/.NET

我有一个程序可以从 Arduino UNO R3 读取模拟数据并将该数据发送到其他设备读取它并相应地执行一些操作。目前,每次我读取数据时,它都会被发送,这会创建比执行任务所需的更多的数据点。因此,我想将数据集中在一个移动平均线中,而不是一起发送。我的代码目前看起来像这样:

string forceAnalog = recieveData.Text;
recieveData.Clear();
var forceList = forceAnalog.ToUpper().Split(':').ToList();
foreach (var item in forceList)
    if (item.Trim().StartsWith("X"))
    {
        textBoxX.Text = item.Remove(0, 1);
    }
    else if (item.Trim().StartsWith("Y"))
    {
        textBoxY.Text = item.Remove(0, 1);
    }
    else if (item.Trim().StartsWith("Z"))
    {
        textBoxZ.Text = item.Remove(0, 1);
    }

string forceXanalog = textBoxX.Text;
string forceYanalog = textBoxY.Text;
string forceZanalog = textBoxZ.Text;

if (double.TryParse(forceXanalog, out forceX)) ;
if (double.TryParse(forceYanalog, out forceY)) ;
if (double.TryParse(forceZanalog, out forceZ)) ;

forceXvalue = (forceX * calibrationFactorX / 1023) - 5;
forceYvalue = (forceY * calibrationFactorY / 1023) - 5;
forceZvalue = (forceZ * calibrationFactorZ / 1023) - 50;

this.forceXlabel.Text = string.Format("{0:F2}", forceXvalue);
this.forceYlabel.Text = string.Format("{0:F2}", forceYvalue);
this.forceZlabel.Text = string.Format("{0:F2}", forceZvalue);

我从接收 Arduino 串行流的文本框读取数据,并从中创建 forceAnalog 字符串。该字符串包含 X、Y、Z 值,类似于:X-0.44 Y-0.15 Z-0.5 然后 receiveData 被清除并再次读取值。然后通过一些计算将其发送到标签。

我想要的是,不是读取,而是存储一组 X、Y、Z 值并将其传递,我想读取例如 5,10,100... 组 X、Y、 Z 值,然后从中创建一个平均值并将其传递给计算。我该怎么做?

最简单的选择是累积 n 个项目,发送平均值,然后重置累加器和计数。使用迭代器块和 system.Numerics 用于 Vector3:

public static IEnumerable<Vector3> AverageN(
    this IEnumerable<Vector3> highFrequencySamples,
    int everNthSample)
{
    var acc = Vector3.Zero;
    var n = 0;
    foreach (var sample in highFrequencySamples)
    {
        acc += sample;
        n++;
        if (n == everNthSample)
        {
            // Output the average since we have reached the number of samples needed
            yield return acc / n;
            acc = Vector3.Zero;
            n = 0;
        }
    }

    if (n > 0)
    {
        yield return acc / n;
    }
}

虽然 Vector3 这仅限于浮点数,但使用双精度创建等效的 Vector3d 应该相当简单。使用专用类型来捆绑坐标值往往会使您的代码更简单,因为您不必将每个操作重复三次。如果他们设法发布类似 generic math 的东西,你可以制作一个像这样通用的方法,并适用于支持加法和除法的所有类型。