3

考虑到您需要以秒为单位的时间的定点表示,并且您的滴答之间的时间不能以该定点格式精确表示,您如何在简单的嵌入式系统中跟踪时间?在这些情况下,您如何避免累积错误。

这个问题是对 slashdot上这篇文章的回应。

0.1 秒不能整齐地表示为二进制定点数,就像 1/3 不能整齐地表示为十进制定点数一样。任何二进制定点表示都有一个小错误。例如,如果该点后面有 8 个二进制位(即使用 256 缩放的整数值),则 256 的 0.1 乘以 25.6,将四舍五入为 25 或 26,导致 -2.3% 量级的误差或分别为 +1.6%。在该点之后添加更多的二进制位会减小此错误的规模,但不能消除它。

随着反复加法,误差逐渐累积。

如何避免这种情况?

4

6 回答 6

7

一种方法不是尝试通过重复添加这个 0.1 秒常数来计算时间,而是保持一个简单的整数时钟滴答计数。此滴答计数可以根据需要转换为以秒为单位的定点时间,通常使用乘法后除法。给定中间表示中的足够位,这种方法允许任何合理的缩放,并且不会累积错误。

例如,如果当前滴答计数是 1024,我们可以通过将其乘以 256,然后除以 10 来获得当前时间(在该点之后有 8 位的定点) - 或者等效地,通过乘以 128 然后除以 5 . 无论哪种方式,都会有误差(除法中的余数),但误差是有界的,因为余数总是小于 5。没有累积误差。

于 2009-10-31T15:10:59.170 回答
2

另一种方法在整数乘法和除法被认为成本过高的情况下可能很有用(这在当今应该变得非常罕见)。它借鉴了Bresenhams 画线算法的思想。您将当前时间保持在固定点(而不是滴答计数),但您也保留了一个错误项。当误差项变得太大时,您可以对时间值进行修正,从而防止误差累积。

在点后 8 位示例中,0.1 秒的表示为 25 (256/10),误差项(余数)为 6。在每一步,我们将 6 加到误差累加器中。到目前为止,基于此,前两个步骤是......

Clock  Seconds  Error
-----  -------  -----
 25    0.0977    6
 50    0.1953   12

在第二步,错误值已经溢出——超过 10。因此,我们增加时钟并从错误中减去 10。每次错误值达到 10 或更高时都会发生这种情况。

因此,实际的顺序是...

Clock  Seconds  Error  Overflowed?
-----  -------  -----  -----------
 25    0.0977    6
 51    0.1992    2      Yes
 76    0.2969    8
102    0.3984    4      Yes

几乎总是存在误差(仅当误差值为零时时钟才精确正确),但误差受一个小常数的限制。时钟值没有累积误差。

于 2009-10-31T15:15:20.473 回答
0

仅硬件的解决方案是安排硬件时钟滴答运行得非常快——精确到足以补偿由于重复添加的滴答持续时间值的舍入而导致的累积损失。也就是说,调整硬件时钟滴答速度,使定点滴答持续时间值精确正确。

这仅在时钟仅使用一种定点格式时才有效。

于 2009-10-31T15:24:20.470 回答
0

为什么没有 0.1 秒计数器,并且每十次增加你的秒计数器,并将 0.1 计数器包装回 0?

于 2009-10-31T17:38:29.623 回答
0

在这个特定的例子中,我会简单地将时间计数保持在十分之一秒(或毫秒,或任何适合应用程序的时间尺度)。我一直在小型系统或控制系统中这样做。

因此 100 小时的时间值将存储为3_600_000刻度 - 零错误(硬件可能引入的错误除外)。

这种简单的技术带来的问题是:

  • 你需要考虑更大的数字。例如,您可能必须使用 64 位计数器而不是 32 位计数器
  • 您的所有计算都需要了解使用的单位 - 这是最有可能导致问题的区域。我尝试通过使用具有统一单位的时间计数器来帮助解决这个问题。例如,这个特定的计数器每秒只需要 10 个滴答声,但另一个计数器可能需要毫秒精度。在这种情况下,我会考虑使两个计数器都以毫秒为精度,以便它们使用相同的单位,即使一个并不真正需要这种精度。

我还不得不使用不“常规”的计时器来玩其他一些技巧。例如,我在一个需要每秒进行 300 次数据采集的设备上工作。硬件计时器每毫秒触发一次。无法缩放毫秒计时器以精确获得 1/300 秒单位。所以我们必须有逻辑可以在每 3、3 和 4 个滴答声上执行一次数据采集,以防止采集漂移。

如果您需要处理硬件时间错误,那么您需要多个时间源并将它们一起使用以保持整体时间同步。根据您的需要,这可能很简单,也可能非常复杂。

于 2009-10-31T21:01:55.670 回答
0

我在过去看到实现的东西:增量值不能以定点格式精确表示,但可以表示为分数。(这类似于“跟踪错误值”解决方案。)

实际上,在这种情况下,问题略有不同,但在概念上是相似的——问题不是这样的定点表示,而是从不是完美倍数的时钟源中导出定时器。我们有一个时钟频率为 32,768 Hz 的硬件时钟(常见于基于手表晶体的低功耗计时器)。我们想要一个毫秒计时器。

毫秒计时器应每 32.768 个硬件滴答声递增一次。第一个近似值是每 33 个硬件滴答声递增一次,名义上的误差为 0.7%。但是,请注意 0.768 是 768/1000 或 96/125,您可以这样做:

  • 为“小数”值保留一个变量。从 0 开始。
  • 等待硬件定时器计数 32。
  • 虽然是真的:
    • 增加毫秒计时器。
    • 将 96 添加到“小数”值。
    • 如果“小数”值 >= 125,则减去 125 并等待硬件计时器计数到 33。
    • 否则(“小数”值 < 125),等待硬件定时器计数到 32。

毫秒计数器上会有一些短期“抖动”(32 对 33 个硬件滴答声),但长期平均值将为 32.768 个硬件滴答声。

于 2009-11-01T06:32:45.017 回答