大家好我在C#中编写一个应用程序,从加速度计(在wiimote内部)获取数据,然后对其进行处理和绘制。 我正在使用Brian Peek's Wiimote library,所以我使用事件处理程序来获取数据:
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,然后在每个tick上设置数据存储的定时器/处理:
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事件处理程序。因此,数据存储速率取决于您运行代码的机器的运行速度,运行的其他程序数等。
我该如何解决这个问题?我想在一个单独的线程上运行计时器,但这会引起其他问题,正如有人在这里指出另一个问题: “你的计时器事件可能想要从另一个线程访问对象。但这样做会导致竞争条件。”
有什么想法吗?
答案 0 :(得分:1)
定时器不是特别精确,所以如果你真的想要每秒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内部的负担,并在捕获数据后进行一些后期处理 - 要么机器足够快,要么实时,要么就是没有。