大家好,我正在用C#编写一个应用程序,它从加速度计(wiimote内部)获取数据,然后对其进行处理并绘制图形。我使用Brian Peek的Wiimote库,所以我使用事件处理程序来获取数据:
void wiimote_WiimoteChanged(object sender, WiimoteChangedEventArgs e)
{
X = e.WiimoteState.AccelState.Values.X;
Y = e.WiimoteState.AccelState.Values.Y;
Z = e.WiimoteState.AccelState.Values.Z;
}
我想以100Hz的速率绘制/保存/处理数据,所以我创建了一个计时器对象(WiiTimer),将其"Tick Interval"设置为10ms,然后在计时器的每个刻度上,数据都被存储/处理:
private void WiiTimer_Tick(object sender, EventArgs e)
{
//Signal Processing (Some median and low pass filtering etc.) Ive removed the code for that since it is irrelevant here
sw.WriteLine((X * 9.8).ToString() + ", " + (Y * 9.8).ToString() + ", " + (Z*9.8).ToString() );
//Write Processed Data to file
}
现在的问题是,数据实际上并不是以100Hz保存的,因为信号处理需要一些时间,计时器无法每10ms调用一次OnTick事件处理程序。因此,数据存储率取决于你在一台机器上运行代码的速度,你有多少其他程序在运行等等
我该如何解决此问题?我曾想过在一个单独的线程上运行计时器,但这会导致其他问题,正如有人在这里的另一个问题上指出的那样:"您的计时器事件可能希望从另一个线程访问对象。但这样做会导致竞争条件。">
有什么想法吗?
计时器不是特别精确,所以如果你真的想要每秒100个样本,最好的方法是这样的:
private class Result
{
public double X { get; set; }
public double Y { get; set; }
public double Z { get; set; }
}
private Result lastResult;
void wiimote_WiimoteChanged(object sender, WiimoteChangedEventArgs e)
{
Result newResult = new Result {
X = e.WiimoteState.AccelState.Values.X,
Y = e.WiimoteState.AccelState.Values.Y,
Z = e.WiimoteState.AccelState.Values.Z,
}
lastResult = newResult;
}
void MainLoop()
{
DateTime nextResultTime = DateTime.Now.AddMilliseconds(10);
while(true)
{
if (DateTime.Now >= nextResultTime)
{
AddResult(lastResult);
nextResultTime = nextResultTime.AddMilliseconds(10);
}
else
{
Thread.Sleep(1);
}
}
}
只需在后台线程上运行MainLoop(如果wii事件在后台线程中触发,则可能没有必要这样做)。
这将使你每秒准确地获得100个样本,除非机器无法处理那么快的AddResult。在这种情况下,我认为你必须减轻AddResult内部的负载,并在捕获数据后进行一些后期处理——要么机器足够快,可以实时完成,要么就不行。