以经典的PI补偿器求解PI参数为例:
$$
20 \lg |k_p + \frac{k_i}{j \omega_c}| = gain\_rise
$$
$$
\frac{k_i}{k_p} = \omega_z
$$
第一个方程限定了补偿器在穿越频率处的增益,第二个方程拟定了零点位置。
(如果不懂涵义也没关系,这篇文章仅讨论针对类似的非线性方程组哪种求解函数最好用。如果想捋清楚各类补偿器的设计方法,后面单独写一篇文章。)
宫斗开始
首先淘汰fzero和roots这两个比较低端的函数,据说只支持单变量求解[1]。
决赛圈还剩下solve
、vpasolve
和fsolve
。
- solve:符号解或数值解,无需初始值,只需把方程等号改为双等号
==
。用法与vpasolve基本相同,感觉更为智能。 - vpasolve:符号解或数值解,无需初始值,只需把方程等号改为双等号
==
。若有符号解时比较准,数值解经常无解或错解,慎用! - fsolve:仅数值解,必须给初值,方程组必须以函数句柄方式调用,右端为零。数值解比较准。
注:所谓解析解就是符号解;所谓函数句柄,可以理解为指针地址。
宠幸例子
已知参数:
wc = 2 * pi * 4e3;
gain_rise = 49.7481;
wz = 2 * pi * 100;
solve
用例
syms kp ki
eqns = [20*log10(abs(kp + ki/(j*wc))) == gain_rise,
ki/kp==wz];
[ki kp]=solve(eqns);
kp=double(kp)
ki=double(ki)
结果:
kp =
307.0926
ki =
1.9295e+05
vpasolve
用例
syms kp ki
eqns = [20*log10(abs(kp + ki/(j*wc))) == gain_rise,
ki/kp==wz];
[ki kp]=vpasolve(eqns)
结果:
ki =
192891.70190885358092200094503597 + 4821.8329924348312217466650244155i
kp =
306.99667840202430580932484824932 + 7.6741855550958895617299121076886i
fsolve
用例
syms kp ki
eq1 = 20*log10(abs(kp + ki/(1i*wc))) - gain_rise;
eq2 = ki/kp - wz;
eqns = [eq1,eq2];
fun = @(vars) double(subs(eqns, [kp, ki], vars));
initial_guess = [1, 1];
sol = fsolve(fun, initial_guess);
kp = sol(1)
ki = sol(2)
结果:
kp =
307.0924
ki =
1.9295e+05
冠军加冕
用法上,solve
和vpasolve
都十分简洁,fsolve
由于句柄和初值的存在显得稍稍复杂,不过可以求助ChatGPT帮你写呀!
精度上,solve
和fsolve
的结果都可以看作是正确的,vpasolve
的复数解我也不知道是什么鬼,就算仅看实部,精度也不如其他两位小主,因此打入冷宫。
速度上,solve
比fsolve
快。但fsolve
真真是个很单纯的孩子,从迭代过程来看就是粗暴求解,用以检验会比较安心,而且其他两个无解的时候fsolve
可能还会有解。
我宣布,solve
是本届Matlab求解函数宫斗冠军。
我爱鸭鸭,yyds
很有趣的描述呀,我感觉自己自控这部分学得还不是很好,以后还得多研究研究,先过来学习一下。
Matrix谦虚啦,我也是一知半解停留在肤浅的表面,共同学习,握爪φ( ̄∇ ̄o)