手撕算法
本帖最后由 zzxxccqq 于 2023-6-28 17:01 编辑自己学的一点框架,关于电机转子位置确定的一篇示例:(本示例是没有考虑运行在一些低算力应用场合的,若有算法大佬,可以根据这个思路重写算法,让它兼容性更好)
代码部分:(仅供参考,欢迎各位指教)
//假设电机的数学模型是永磁同步电机的dq轴方程
//假设输出信号是定子d轴电流i_d
//假设状态变量是转子位置theta_e和转子速度omega_e
//假设已知的参数是定子电阻R_s,d轴电感L_d,q轴电感L_q,永磁体磁链psi_f
//假设输入信号是定子d轴电压u_d和定子q轴电压u_q
#include <math.h> //引入数学库
#define PI 3.1415926 //定义圆周率
//定义电机参数
double R_s = 0.5; //定子电阻,单位欧姆
double L_d = 0.01; //d轴电感,单位亨利
double L_q = 0.01; //q轴电感,单位亨利
double psi_f = 0.1; //永磁体磁链,单位韦伯
//定义滑膜面函数
double s(double i_d, double i_q, double omega_e)
{
return i_d + omega_e * L_q * i_q + omega_e * psi_f; //返回滑膜面函数的值
}
//定义滑膜面函数的导数
double ds(double u_d, double u_q, double i_d, double i_q, double omega_e)
{
return (u_d - R_s * i_d - L_d * omega_e * i_q) / L_d + omega_e * (u_q - R_s * i_q + L_q * omega_e * i_d) / L_q; //返回滑膜面函数的导数的值
}
//定义符号函数
double sgn(double x)
{
if (x > 0)
return 1.0; //如果x大于0,返回1
else if (x < 0)
return -1.0; //如果x小于0,返回-1
else
return 0.0; //如果x等于0,返回0
}
//定义滑膜控制律的函数
double u_d(double i_d, double i_q, double omega_e, double k, double lambda)
{
return R_s * i_d + L_d * ds(i_d, i_q, omega_e) + k * sgn(s(i_d, i_q, omega_e)) / lambda; //返回滑膜控制律的值
}
//定义更新输出信号和状态变量的函数
void update(double* i_d, double* i_q, double* theta_e, double* omega_e, double u_d, double u_q, double dt)
{
//使用欧拉法近似更新输出信号和状态变量
*i_d = *i_d + ds(u_d, u_q, *i_d, *i_q, *omega_e) * dt; //更新定子d轴电流
*i_q = *i_q + ds(u_q, u_d, *i_q, *i_d, -*omega_e) * dt; //更新定子q轴电流
*theta_e = fmod(*theta_e + *omega_e * dt, 2.0 * PI); //更新转子位置,并取余数保证在范围内
*omega_e = (*omega_e + psi_f / (L_q - L_d) / (*i_q + sgn(s(*i_d, *i_q, *omega_e)) / lambda)) \
/ (1.0 + psi_f / (L_q - L_d) / (*i_q + sgn(s(*i_d, *i_q, *omega_e)) / lambda) /\
(*i_q + sgn(s(*i_d, *i_q, *omega_e)) / lambda)); //更新转子速度,使用牛顿迭代法求解非线性方程
}
//主函数
int main() {
//定义输入信号
double u_q = 10.0; //定子q轴电压,单位伏特
//定义输出信号和状态变量的初始值
double i_d = 0.0; //定子d轴电流,单位安培
double i_q = 0.0; //定子q轴电流,单位安培
double theta_e = 0.0; //转子位置,单位弧度
double omega_e = PI / 2.0; //转子速度,单位弧度/秒
//定义滑膜控制律的参数
double k = 10.0; //正常数,用来调节收敛速度和抗干扰能力
double lambda = 1.0; //正常数,用来调节收敛速度和抗干扰能力
//定义更新的时间间隔
double dt = 0.001; //时间间隔,单位秒
//定义循环的次数
int n = 1000; //循环的次数
//循环更新输出信号和状态变量
for (int i = 0; i < n; i++)
{
//计算滑膜控制律的值
double u_d_value = u_d(i_d, i_q, omega_e, k, lambda); //滑膜控制律的值
//打印滑膜控制律的值
printf("u_d = %f V\n", u_d_value);
//更新输出信号和状态变量
update(&i_d, &i_q, &theta_e, &omega_e, u_d_value, u_q, dt);
//打印输出信号和状态变量的值
printf("i_d = %f A\n", i_d);
printf("i_q = %f A\n", i_q);
printf("theta_e = %f rad\n", theta_e);
printf("omega_e = %f rad/s\n", omega_e);
}
return 0;
}
/*
以上代码逻辑:
首先,我引入了数学库,定义了圆周率和电机参数,这些都是为了后面的计算做准备。
然后,我定义了滑膜面函数和其导数的函数,这些函数根据电机的数学模型和滑膜观测的原理,\
计算出滑膜面函数和其导数的值。
滑膜面函数表示输出信号和状态变量之间的关系,其导数表示输出信号和输入信号之间的关系。
接着,我定义了符号函数,这个函数用来判断系统状态变量与滑膜面之间的相对位置。\
符号函数是滑膜控制律的一部分,用来产生切换控制作用。
然后,我定义了滑膜控制律的函数,这个函数根据滑膜控制的原理,计算出滑膜控制律的值。\
滑膜控制律是一个反馈控制律,用来使得输出信号能够在有限时间内收敛到滑膜面上,并在滑膜面上保持稳定。
接下来,我定义了更新输出信号和状态变量的函数,这个函数根据电机的数学模型和欧拉法近似,更新输出信号和状态变量的值。\
更新的过程中,需要用到牛顿迭代法求解转子速度的非线性方程。
最后,我定义了输入信号、输出信号和状态变量的初始值,并定义了滑膜控制律的参数、更新的时间间隔和循环的次数。\
然后我用一个for循环来更新输出信号和状态变量,并打印出每次更新后的值,以便观察。
*/
下面是一个简单的结构框图
u_α, u_β——> Clark变换 ——> u_d, u_q
i_α, i_β——> Clark变换 ——> i_d, i_q
u_d, u_q, i_d, i_q——> 滑膜观测器 ——> θ_r, ω_r
θ_r, ω_r——> Park逆变换 ——> θ_αβ, ω_αβ
θ_αβ, ω_αβ——> 矢量控制器 ——> u_d*, u_q*
u_d*, u_q*——> Park逆变换 ——> u_α*, u_β*
u_α*, u_β*——> 逆变器 ——> u_a*, u_b*, u_c*
其中,u表示电压,i表示电流,θ表示角度,ω表示角速度,*表示期望值,αβ表示静止坐标系,dq表示同步旋转坐标系,r表示转子。
其中double sgn(double x)函数被我简写了,需要的在留言区联系我
页:
[1]