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

数字信号相位差计算算法异常问题求助

问题分析与修正方案

针对你在单片机上计算两路正弦信号相位差遇到的问题,逐个分析三种方法的错误点,并给出修正方案:

1. 峰值检测方法的问题与修正

原代码用buff_1[i] == mag_1判断峰值,由于离散采样的正弦信号几乎不可能恰好等于理论幅值(除非采样点正好落在峰值时刻),导致无法识别峰值,返回0°。

修正方案:遍历数组寻找最大值对应的索引:

// 修正后的峰值检测
float max_val1 = -FLT_MAX;
float max_val2 = -FLT_MAX;
peak_1 = 0;
peak_2 = 0;
for (int i = 0; i < buff_size; ++i) {
    if (buff_1[i] > max_val1) {
        max_val1 = buff_1[i];
        peak_1 = i;
    }
    if (buff_2[i] > max_val2) {
        max_val2 = buff_2[i];
        peak_2 = i;
    }
}
*phase = (float)(peak_1 - peak_2) * decimation / 125000000.0 * 360.0 * freq;

注意:该方法对噪声敏感,且若采样窗口非整周期,仍会存在误差。

2. 信号乘法法的问题与修正

原方法通过累加乘积取平均得到cos(theta),再用acos计算相位,但存在两个核心问题:

  • 若buff_size不是信号的整数周期,累加平均结果会偏离真实的cos(theta),导致相位计算偏差;
  • acos的输出范围是0°~180°,无法区分正负相位差(即超前/滞后)。

修正方案:采用正交解调法(更稳定且能区分相位方向):

// 正交解调法计算相位差
float I = 0, Q = 0;
for (int i = 0; i < buff_size; ++i) {
    // 用buff_1作为参考,与sin和cos正交分量相乘
    float ref_sin = buff_1[i];
    float ref_cos = cos(2*M_PI*freq/125000000.0*decimation*i);
    I += buff_2[i] * ref_cos;
    Q += buff_2[i] * ref_sin;
}
I /= buff_size;
Q /= buff_size;
*phase = atan2(Q, I) * 180.0 / M_PI;

若能保证buff_size为信号整数周期,精度会进一步提升。

3. 过零检测方法的问题与修正

原方法返回90°的核心问题有两个:

  • 循环从i=0开始,访问buff_1[i-1]会导致数组越界(读取非法内存),错误识别过零点位置;
  • 仅用整数索引计算过零点,未考虑离散采样时零点可能落在两个采样点之间,导致误差。

修正后的过零检测代码:

// 修正后的过零检测(寻找上升沿过零点)
float zero_cross1 = -1, zero_cross2 = -1;
// 从i=1开始,避免越界
for (int i = 1; i < buff_size; ++i) {
    // 检测上升沿过零:前一个点负,当前点非负
    if (buff_1[i-1] < 0 && buff_1[i] >= 0) {
        // 线性插值计算精确过零点位置
        zero_cross1 = (float)i - buff_1[i] / (buff_1[i] - buff_1[i-1]);
        break;
    }
}
for (int i = 1; i < buff_size; ++i) {
    if (buff_2[i-1] < 0 && buff_2[i] >= 0) {
        zero_cross2 = (float)i - buff_2[i] / (buff_2[i] - buff_2[i-1]);
        break;
    }
}
// 计算相位差
if (zero_cross1 != -1 && zero_cross2 != -1) {
    float time_diff = (zero_cross1 - zero_cross2) * decimation / 125000000.0;
    *phase = time_diff * 360.0 * freq;
    // 修正相位范围到-180°~180°
    if (*phase > 180) *phase -= 360;
    if (*phase < -180) *phase += 360;
} else {
    // 未检测到过零点的异常处理
    *phase = NAN;
}

关键修正点:

  • 从i=1开始遍历,避免数组越界;
  • 用线性插值计算精确的过零点位置(非整数索引),大幅提升精度;
  • 增加异常处理,避免未检测到过零点时的错误计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 21:55:55