You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

分子分母范围受限的实数有理近似算法求解(IC测试时钟场景)

我正在学习分子、分母同时存在约束的实数有理近似求解方法,目前查阅了诸多资料,了解了连分数法、Farey序列、Stern-Brocot树等实现方案,但现有公开示例均仅支持单独约束分子或分母其中一项。

应用场景

我目前从事混合信号IC测试工作,其中一项测试需要测定IC的最高工作频率:初始给IC输入12 MHz的时钟,之后逐步降低时钟频率,直到IC可以正常运行简单数字序列。
测试平台的主时钟可调范围为25~66 MHz,时钟设置函数接收double类型参数。当前测试版本将主时钟固定为50.0 MHz,通过循环调用分频函数调整输出频率,分频系数为1~4096之间的整数。

但该方案存在测量精度不足的问题:当前测试中器件总是只能在以下档位通过测试:

  • 50 / 5 = 10 Mhz
  • 50 / 6 = 8.333 MHz

为了提升测量精度,我希望每次循环迭代时可以同时调整主时钟频率和分频系数,因此需要实现同时约束分子、分母的类连分数近似算法,预期调用逻辑如下:

while(dFmax > dFmin)
{
    std::pair<double, int> bestSettings = GetBestClkSettings(dFmax);
    double dFreq = bestSettings.first;
    int iDiv = bestSettings.second;

    // Set up clock and timesets        
    clkset(dFreq);
    clkdivide(iDiv);

    // Run pattern
    // ...
    
    // Get results
    // ...
    
    dFmax -= 0.1;
}

我花了数小时调试相关代码,还尝试编写了类二分查找的逻辑验证思路,我知道当前的代码存在缺陷无法达到目标,仅用来展示已做过的相关尝试,代码如下:

#include <iostream>
#include <stdio.h>
#include <cmath>

struct fraction {
    int n;
    int d;
    
    fraction()
    {
        this->n = -1;
        this->d = -1;
    }
    fraction(int n, int d)
    {
        this->n = n;
        this->d = d;
    }
    
    double asDouble()
    {
        double dReal = static_cast<double>(n) / static_cast<double>(d);
        return dReal;
    }
};

fraction ApproximateFrequency(double dTargetFreqMHz, double dTol)
{
    fraction result;
    
    if (dTargetFreqMHz < (25.0 / 4096) || dTargetFreqMHz > 66.0)
    {
        return result;
    }
    else if (dTargetFreqMHz >= 25.0 && dTargetFreqMHz <= 66.0)
    {
        result.n = static_cast<int>(dTargetFreqMHz);
        result.d = 1;
        return result;
    }

    int iFrqLo = 25;
    int iFrqHi = 66;
    int iDivLo = 1;
    int iDivHi = 4096;

    int iFrqCurr = (iFrqLo + iFrqHi) / 2;
    int iDivCurr = (iDivLo + iDivHi) / 2;
    double dFreq = static_cast<double>(iFrqCurr) / static_cast<double>(iDivCurr);
    double dPrevFreq = 0;
    int iNumIters = 1;
    
    while (fabs(dTargetFreqMHz - dFreq) > dTol && fabs(dFreq - dPrevFreq) > 1e-8 && iNumIters < 25)
    {
        dPrevFreq = dFreq;
        
        if (dFreq < dTargetFreqMHz)
        {
            // 需提升频率
            // 方案1:提高主时钟频率
            int iFrqNew = (iFrqCurr + iFrqHi) / 2;
            double dFrqIfClkInc = static_cast<double>(iFrqNew) / static_cast<double>(iDivCurr);
            double dClkIncDiff = fabs(dTargetFreqMHz - dFrqIfClkInc);
            
            // 方案2:降低分频系数
            int iDivNew = (iDivLo + iDivCurr) / 2;
            double dFrqIfDivDec = static_cast<double>(iFrqCurr) / static_cast<double>(iDivNew);
            double dDivDecDiff = fabs(dTargetFreqMHz - dFrqIfDivDec);
            
            // 选择效果更好的方案
            if (dClkIncDiff < dDivDecDiff && iFrqNew >= 25 && iFrqNew <= 66)
            {
                iFrqCurr = iFrqNew;
            }
            else if (dDivDecDiff < dClkIncDiff && iDivNew >= 1 && iDivNew <= 4096)
            {
                iDivCurr = iDivNew;
            }
        }
        else
        {
            // 需降低频率
            // 方案1:降低主时钟频率
            int iFrqNew = (iFrqLo + iFrqCurr) / 2;
            double dFrqIfClkDec = static_cast<double>(iFrqNew) / static_cast<double>(iDivCurr);
            double dClkDecDiff = fabs(dTargetFreqMHz - dFrqIfClkDec);
            
            // 方案2:提高分频系数
            int iDivNew = (iDivCurr + iDivHi) / 2;
            double dFrqIfDivInc = static_cast<double>(iFrqCurr) / static_cast<double>(iDivNew);
            double dDivIncDiff = fabs(dTargetFreqMHz - dFrqIfDivInc);
            
            // 选择效果更好的方案
            if (dClkDecDiff < dDivIncDiff && iFrqNew >= 25 && iFrqNew <= 66)
            {
                iFrqCurr = iFrqNew;
            }
            else if (dDivIncDiff < dClkDecDiff && iDivNew >= 1 && iDivNew <= 4096)
            {
                iDivCurr = iDivNew;
            }
        }
        
        // 输出当前设置对应的频率
        dFreq = static_cast<double>(iFrqCurr) / static_cast<double>(iDivCurr);
        std::cout << "prev = " << dPrevFreq << ", current = " << dFreq << std::endl;
        iNumIters++;
    }
    
    result.n = iFrqCurr;
    result.d = iDivCurr;
    return result;
}

int main(int argc, char* argv[])
{
    double dTargetFreqMHz = 20.0;
    std::cout << "Target: " << dTargetFreqMHz << "\n\n";
    double dTol = 0.05;
    fraction mcf = ApproximateFrequency(dTargetFreqMHz, dTol);
    printf("tol=%f, n/d = %d/%d = %f (err=%f)\n", dTol, mcf.n, mcf.d, mcf.asDouble(), mcf.asDouble()-dTargetFreqMHz);
}

恳请各位提供相关建议或思路指引,非常感谢。


内容的提问来源于stack exchange,提问作者szojss62

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 21:15:08