以经典的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 kieqns = [20*log10(abs(kp + ki/(j*wc))) == gain_rise, ki/kp==wz];[ki kp]=solve(eqns);kp=double(kp)ki=double(ki)结果:
kp = 307.0926ki = 1.9295e+05vpasolve用例syms kp kieqns = [20*log10(abs(kp + ki/(j*wc))) == gain_rise, ki/kp==wz];[ki kp]=vpasolve(eqns)结果:
ki =192891.70190885358092200094503597 + 4821.8329924348312217466650244155ikp =306.99667840202430580932484824932 + 7.6741855550958895617299121076886ifsolve用例syms kp kieq1 = 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.0924ki = 1.9295e+05冠军加冕用法上,solve和vpasolve都十分简洁,fsolve由于句柄和初值的存在显得稍稍复杂,不过可以求助ChatGPT帮你写呀!
精度上,solve和fsolve的结果都可以看作是正确的,vpasolve的复数解我也不知道是什么鬼,就算仅看实部,精度也不如其他两位小主,因此打入冷宫。
速度上,solve比fsolve快。但fsolve真真是个很单纯的孩子,从迭代过程来看就是粗暴求解,用以检验会比较安心,而且其他两个无解的时候fsolve可能还会有解。
我宣布,solve是本届Matlab求解函数宫斗冠军。
