I have a program which reads analog data from an Arduino UNO R3 and sends that data along to other equipment which reads it and performs some actions accordingly. At the moment, every time I read data, it is being sent along, which is creating way more datapoints than needed to perform the task. Therefore, I would like to lump together the data in a moving average which is sent along instead. My code looks like this at the moment:
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);
I read the data from a textBox which receives the Arduino serial stream, and create the forceAnalog string from it. The string contains X,Y,Z values and looks something like: X-0.44 Y-0.15 Z-0.5 then receiveData is being cleared and reads the values again. This is then sent through a few calculations and to labels.
What I want to to is, instead of reading, storing one set of X,Y,Z values and passing it along, I would like to read for example 5,10,100... sets of X,Y,Z values, then create an average from these and pass it along for calculations. How do I go about doing this?
CodePudding user response:
The simplest option would be to accumulate n number of items, send the average, and reset the accumulator and count. Using an iterator block and system.Numerics for 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;
}
}
While Vector3 this is limited to floats, creating a equivalent Vector3d
using doubles should be fairly simple. Using a dedicated type for bundling the coordinate values tend to make your code much simpler, since you do not have to repeat each operation three times. If they manage to ship something like generic math you could make a method like this generic, and applicable to all types that support addition and division.