编码器的阻止:如何定时发射计时器,补偿早期/晚期射击

时间:2009-09-30 15:06:11

标签: language-agnostic timer

我有一个愚蠢而严重的编码器阻止案例。请帮助我完成它,这样我的大脑就会停止伤害并拒绝回答我的问题。

我想在最后一段时间间隔发射计时器。例如,如果t = 0,我的目标是100,我的间隔是20,我想在0,20,40,60,80和100点火。

计时器不准确,可能会提前或延迟开火。如果它首先在22点开火,我想在18点再次点火。如果它在19点开火,我想在21点开火。我知道计时器点火的时间是当前时间,目标时间和点火间隔。我该怎么办?

编辑:抱歉,我对我真正要问的是什么并不太具体。我正在试图找出什么样的数学(可能)需要进行一定程度的模数来计算延迟直到下一次发射。理想情况下,我还希望计时器与结束时间匹配 - 所以如果我最初在47启动计时器,它会自行调度为60而不是67,所以最后一次触发仍然是100。

4 个答案:

答案 0 :(得分:4)

如果您具有的基本功能是“在时间T安排X射击一次”,那么处理X的过程应该知道它应该被触发的时间T0(不需要它实际触发的时间T1) )以及期望的发射间隔DT并且为时间T0 + DT安排自身。如果原语是“从现在开始消防D”,那么它应该安排D = T0 + DT-T1(如果那是负的那么它需要立即再次安排自己但是记录预定的时间和“应该开火”时间不同,所以它可以继续补偿以下的射击。)

有人已经提到.NET的Timer会为你做这件事; Python的sched stdlib模块也是如此;所以,我敢肯定,做许多其他语言/框架/库。但是最后你可以根据需要在上面的任何一个单调度基元之上构建它(一个用于绝对时间,一个用于从现在开始的相对增量),只要你跟踪所需的和实际的发射时间。 !_)

答案 1 :(得分:3)

我会用系统时钟检查你的间隔。例如,如果您知道您的间隔是每20分钟,则触发第一个间隔,检查时间,并调整下一个间隔开始时间。

答案 2 :(得分:1)

如果您的语言/平台的基础计时器没有达到您想要的效果,那么通常最好按照“目标时间”来实现计时器,这意味着您希望计时器下次触发的绝对时间。如果您的平台要求“绝对时间”,那么您可以给它目标时间。如果它要求“相对时间”(或类似sleep,持续时间),那么它当然是target_time - current_time

依次计算每个目标时间的快捷方法是:

  • 当您第一次设置计时器时,计算“间隔”(可能必须是浮点值,假设不会削弱性能)以及第一次计时器点火的“目标时间”(再次,你可能需要分数)。记录两者,并设置你的基础计时器机制,无论是什么。
  • 当计时器触发时,通过将间隔添加到上一个目标时间来计算下一个目标时间。

这种方法的问题在于,当您将间隔添加到目标时间时,可能会得到一些非常微小的累积错误(如果没有使用浮动,则可能不会很小)。

因此,更长和更准确的方法是存储第一个开始时间,目标完成时间和点火次数(n)。然后依次重新计算每次新射击的目标时间,这样可以确保不会出现累积舍入错误。其公式为:

target(k) = start + ((target_end - start) * k) / n

如果您愿意:

target(k) = (k/n) * end + (1-k/n) * start

定时器的发射是k = 1,2,3,... n。我打算以0为基础,然后意识到这是愚蠢的; - )

实施计时器时你必须要做的最后一件事是“挂钟”时间与硬件时钟测量的实际经过时间之间的差异。挂钟时间可以突然向前或向后跳跃(如果您的挂钟受到夏令时的影响,则需要一小时;如果系统的时钟被调整或校正,则可以是任何数量)。实时总是增加(只要它不包裹)。您希望计时器遵守哪个取决于预期目的。如果您想知道最后一班公共汽车何时离开,您需要根据挂钟时间每天点火一次,但最常见的是您关心的是实时时间。一个好的计时器API可以选择这些东西。

答案 3 :(得分:0)

建立一个列出所需开火时间的表格,例如10:00,10:20,10:40,11:00和11:20。

如果您的计时器功能需要一个绝对时间,其余部分则是微不足道的。将其设置为在每个所需时间触发。如果由于某种原因你一次只能设置一个计时器,好吧,将它设置为在第一个所需的时间点火。当该事件发生时,将其设置为在下一次在表中再次触发,而不考虑它现在的时间。每次都过去,直到你完成为止。

如果你的计时器功能只接受一个间隔,也没什么大不了的。找出所需时间和当前时间之间的差异,并将其设置为以该间隔触发。就像第一次是10:00并且现在是9:23一样,将其设置为在10:00减去9:23等于37分钟。然后,当发生这种情况时,将间隔设置为下一个所需时间减去当前时间。如果它真的在10:02发射,那么间隔是10:20减去10:02等于18分钟。等

您可能应该检查下一个开火时间是否已经过去的可能性。如果进程可能花费的时间超过可能超过它的时间间隔,即使没有,系统可能已关闭。如果错过了开火时间,您可能希望进行追赶,或者只是跳过它并转到下一个所需的时间,具体取决于您的应用程序的详细信息。

如果你不能保持整个桌子 - 就像它继续无限 - 那么只需保持下一个开火时间。每次通过该过程时,将固定金额添加到下一个开火时间,而不考虑当前进程何时运行。然后根据当前时间计算间隔。就像你从10:00开始一直持续20分钟的间隔,现在是9:23,你将第一个间隔设置为37分钟。说实际发生在9:59。您将下一个开火时间设置为10:00加20分钟等于10:20,即将其设置为目标时间而不是实际时间。然后根据当前时间计算到下一个开火时间的间隔,即10:20减去9:59等于21分钟。等