STM32F446RE实现50Hz正弦波90度相移的替代方案咨询
针对STM32F446RE生成90度相移正弦波的可行方案
针对你在STM32F446RE项目中,实时采集50Hz正弦波并生成正交beta信号的需求,以下是几种替代希尔伯特滤波和LUT的方案:
1. 二阶广义积分器(SOGI)
SOGI是电力电子领域常用的正交信号生成方法,能实时跟踪输入正弦波的频率和幅值,输出严格正交的信号,适合50Hz这类固定或小幅波动频率的场景,计算量小,STM32上运行无压力。
实现代码示例
#include <math.h> typedef struct { float omega; // 谐振角频率,50Hz对应2*PI*50=314.16rad/s float k; // 阻尼系数,通常取1.414(sqrt(2)) float v_alpha; // 输入信号 float v_beta; // 正交输出信号 float x_alpha; // 内部状态变量 float x_beta; // 内部状态变量 } SOGI_HandleTypeDef; void SOGI_Init(SOGI_HandleTypeDef *hsogi) { hsogi->omega = 2 * M_PI * 50.0f; hsogi->k = sqrt(2.0f); hsogi->x_alpha = 0.0f; hsogi->x_beta = 0.0f; hsogi->v_beta = 0.0f; } void SOGI_Update(SOGI_HandleTypeDef *hsogi, float input, float Ts) { // Ts为ADC采样周期,比如采样率1kHz的话Ts=0.001s hsogi->v_alpha = input; // 更新状态方程 hsogi->x_alpha = hsogi->x_alpha + Ts * hsogi->omega * (hsogi->v_alpha - hsogi->x_alpha - hsogi->k * hsogi->x_beta); hsogi->x_beta = hsogi->x_beta + Ts * hsogi->omega * (hsogi->x_alpha - hsogi->x_beta); // 正交输出beta信号 hsogi->v_beta = hsogi->x_alpha - hsogi->k * hsogi->x_beta; }
使用说明
- 初始化时设置
omega为50Hz对应的角频率,k取√2保证动态响应和稳态精度平衡 - 每次ADC采样完成后,调用
SOGI_Update,传入采样值和采样周期Ts,即可从hsogi->v_beta得到正交信号 - 该方法对50Hz信号的相移精度高,幅值几乎无失真,且能适应小幅频率波动
2. 二阶全通滤波器
设计一个针对50Hz的二阶全通滤波器,可实现90度相移,同时保持幅值不变,阶数低,计算量小,失真远低于高阶希尔伯特滤波。
离散化实现(双线性变换)
假设采样率为$F_s$,离散化后的差分方程实现如下:
#include <math.h> typedef struct { float b0, b1, b2; float a1, a2; float x_prev1, x_prev2; float y_prev1, y_prev2; } AllPassFilter_HandleTypeDef; void AllPassFilter_Init(AllPassFilter_HandleTypeDef *hfilter, float Fs) { float omega0 = 2 * M_PI * 50.0f; float T = 1.0f / Fs; float omega0T = omega0 * T; float denom = 4.0f + 2.0f * omega0T + omega0T * omega0T; hfilter->b0 = 4.0f - 2.0f * omega0T + omega0T * omega0T; hfilter->b1 = 2.0f * omega0T * omega0T - 8.0f; hfilter->b2 = 4.0f - 2.0f * omega0T + omega0T * omega0T; hfilter->a1 = 2.0f * omega0T * omega0T - 8.0f; hfilter->a2 = 4.0f - 2.0f * omega0T + omega0T * omega0T; // 归一化系数 hfilter->b0 /= denom; hfilter->b1 /= denom; hfilter->b2 /= denom; hfilter->a1 /= denom; hfilter->a2 /= denom; // 初始化历史值 hfilter->x_prev1 = 0.0f; hfilter->x_prev2 = 0.0f; hfilter->y_prev1 = 0.0f; hfilter->y_prev2 = 0.0f; } float AllPassFilter_Process(AllPassFilter_HandleTypeDef *hfilter, float x) { float y = hfilter->b0 * x + hfilter->b1 * hfilter->x_prev1 + hfilter->b2 * hfilter->x_prev2 - hfilter->a1 * hfilter->y_prev1 - hfilter->a2 * hfilter->y_prev2; // 更新历史值 hfilter->x_prev2 = hfilter->x_prev1; hfilter->x_prev1 = x; hfilter->y_prev2 = hfilter->y_prev1; hfilter->y_prev1 = y; return y; }
使用说明
- 初始化时传入ADC采样率
Fs(比如1kHz、2kHz) - 每次采样后调用
AllPassFilter_Process,输入alpha信号,输出即为90度相移的beta信号 - 该滤波器仅对50Hz信号实现严格90度相移,幅值无变化,低阶设计保证信号失真极小
3. 锁相环(PLL)+ 正交信号生成
如果需要同时跟踪信号频率和相位,可以先通过PLL锁定alpha信号的相位,再用三角函数生成正交信号。适合信号频率可能小幅波动的场景。
简化实现代码
#include <math.h> #include <stdlib.h> typedef struct { float omega; // 估计的角频率 float theta; // 估计的相位 float kp; // 比例系数 float ki; // 积分系数 float integral; // 积分项 float alpha_amp; // 估计的幅值 } PLL_HandleTypeDef; void PLL_Init(PLL_HandleTypeDef *hpll) { hpll->omega = 2 * M_PI * 50.0f; hpll->theta = 0.0f; hpll->kp = 10.0f; hpll->ki = 1.0f; hpll->integral = 0.0f; hpll->alpha_amp = 0.0f; } float PLL_Update(PLL_HandleTypeDef *hpll, float alpha, float Ts) { // 简单幅值估计:滑动平均 hpll->alpha_amp = 0.9f * hpll->alpha_amp + 0.1f * fabs(alpha); // 计算相位误差 float error = alpha - hpll->alpha_amp * sin(hpll->theta); // 更新频率和相位 hpll->integral += error * Ts; hpll->omega = 2 * M_PI * 50.0f + hpll->kp * error + hpll->ki * hpll->integral; hpll->theta += hpll->omega * Ts; if (hpll->theta > 2 * M_PI) hpll->theta -= 2 * M_PI; else if (hpll->theta < 0) hpll->theta += 2 * M_PI; // 生成正交beta信号 return hpll->alpha_amp * cos(hpll->theta); }
使用说明
- 初始化时设置PLL的初始频率为50Hz,调整
kp和ki参数保证锁相速度和稳定性 - 每次采样后调用
PLL_Update,输入alpha信号,输出即为beta信号 - 该方法能适应频率波动,若STM32浮点运算性能有限,可改用定点运算优化三角函数和系数计算
内容的提问来源于stack exchange,提问作者user13224079
相关产品推荐
相关产品推荐

