在 C 中不使用 float 或 uint64 类型计算振荡器频率

Compute oscillator frequency without using float or uint64 types in C

我有一个 32.768 kHz 的振荡器,它可以产生 1 Hz 的脉冲。我正在用一个 40MHz 的时钟测量这个脉冲。我试图通过将预期结果与获得的结果进行比较来测量振荡器的实际频率。

如果没有约束,解决方案将是这样的:

computedFreq = (uint32) ( (float32)32768u /  ( ( (float32)measuredPeriod / (float32)40,000,000 ) / (float32)10u ) );

computedFreq = ( 32768*10*40,000,000 ) / measuredPeriod;

因此,对于 40,008,312 的测量周期,结果将为 327611。

如何在满足约束的情况下实现?

您的问题是测量范围高达 40010000 Hz,而您只对 20000 Hz 范围感兴趣。所以解决办法就是限制范围。

您可以使用 2 个点进行线性插值。

  1. Select 2 个输入值。 Min/max 分可能会:

    inMin = 40,000,000 - 10,000
    inMax = 40,000,000 + 10,000
    
  2. 使用您的公式预先计算相应的输出值(这里的值是粗略值,您自己计算):您可以将这些作为常量存储在您的代码中。

    outMin = ( 32768*10*40,000,000 ) / inMin = 327761 
    outMax = ( 32768*10*40,000,000 ) / inMax = 327598 
    

    请注意,由于公式的性质,最大值小于最小值。这在选择以下类型时很重要。

  3. 使用线性插值法使用前面两个点计算结果:

    out = (in - inMin) * (outMax - outMin) / (inMax - inMin) + outMin
    

    你必须为此使用有符号整数,因为 (outMax - outMin) 是负数。

    乘法的上限是(inMax - inMin) * (outMax - outMin),应该适合int32.

您可以选择任意 2 个点,但您应该选择不会产生太大值以致于乘法溢出的点。另外,如果点彼此太近,答案可能不太准确。

如果您有多余的精度,可以在 outMin/outMax 上使用大于 10 的乘数,然后四舍五入以保持更高的精度。

注意 32768 * 10 * 40000000 = 3200000000 * 2^12.

您可以使用这个事实来估算频率,如下所示:

computedFreq = (3200000000/measuredPeriod) << 12;

更新:

我明白39990000 <= measuredPeriod <= 40010000

在此限制下估算频率的更好方法是:

computedFreq = 327761-(measuredPeriod-39990000)/122;