在用matlab解方程时经常用到符号变量syms,在后续对得到的解进行分析时,本小白采用的方法是用函数subs()进行数据的带入计算。但是方程过于复杂,数据量特别大的时候,发现这种做法非常非常慢!
直接向量化操作求数据是最快的,但是解方程有时候根本解不出来显式解,无法直接向量化操作。这时候可以利用for循环去求解N个数值方程的解来构成数据集,这样做可以避免解符号方程以及用subs求数据集
解一个符号方程,再subs代入N组数据 ,不如直接解N个数值方程!!!
---------------------------------------------------------------------------------(●'◡'●)----------------------------------------------------------------------------------
这里列举我解过的一个矩阵方程加以说明,求解这个含参矩阵J_open的特征值,并绘图分析特征值随参数PL的变化趋势
优化前:
clc;
clear;
tic;
syms P_L;%变量
%参数值如下:
R=4;
C1=24e-6;
C2=24e-6;
L1=360e-6;
L2=480e-6;
r1=0.5;
r2=0.5;
VIN=24;
VREF=36;
D=VREF/(VIN+VREF);
n=D*VIN/(1-D);
m=(D/(1-D))^2*r1+r2;
delta=n^2-4*m*P_L*(1+m/R);
V2OL=(n+sqrt(delta))/(2*(1+m/R));
a11=-r1/L1;
a12=0;
a13=-(1-D)/L1;
a14=0;
a21=0;
a22=-r2/L2;
a23=D/L2;
a24=-1/L2;
a31=(1-D)/C1;
a32=-D/C1;
a33=0;
a34=0;
a41=0;
a42=1/C2;
a43=0;
a44=P_L/(C2*V2OL^2)-1/(R*C2);
J_open=[a11,a12,a13,a14;
a21,a22,a23,a24;
a31,a32,a33,a34;
a41,a42,a43,a44];
tzzopen=eig(J_open);
disp(tzzopen);%方程的解是tzzopen
P_L=100;
start=0;
step=1;
%P_L为0-100时对应的tzzopen数据集:用subs代入参数求数据集
real_tzzopen1=real(subs(tzzopen(1),start:step:P_L));
imag_tzzopen1=imag(subs(tzzopen(1),start:step:P_L));
real_tzzopen2=real(subs(tzzopen(2),start:step:P_L));
imag_tzzopen2=imag(subs(tzzopen(2),start:step:P_L));
real_tzzopen3=real(subs(tzzopen(3),start:step:P_L));
imag_tzzopen3=imag(subs(tzzopen(3),start:step:P_L));
real_tzzopen4=real(subs(tzzopen(4),start:step:P_L));
imag_tzzopen4=imag(subs(tzzopen(4),start:step:P_L));
z=0:step:P_L;
plot3(real_tzzopen1,imag_tzzopen1,z,'r*');
hold on;
plot3(real_tzzopen2,imag_tzzopen2,z,'g*');
plot3(real_tzzopen3,imag_tzzopen3,z,'b*');
plot3(real_tzzopen4,imag_tzzopen4,z,'cyan*');
xline(0);
legend('\lambda1','\lambda2','\lambda3','\lambda4');
xlabel('$Re(\lambda)$','Interpreter','latex');
ylabel('$Im(\lambda)$','Interpreter','latex');
hold off;
t1=toc
t1是1.5288e3,难绷,这个参数变化是从0到100,只有101个数据,数据再多会更慢。。。当时我就是用这段代码分析矩阵出的图,慢的要死,还一度以为我的电脑太垃圾,拖慢科研进度
优化后:
clc;
clear;
tic;
root1_real=[];
root1_imag=[];
root2_real=[];
root2_imag=[];
root3_real=[];
root3_imag=[];
root4_real=[];
root4_imag=[];
P_L=100;
step=1;
start=0;
for i=start:step:P_L
lambda=SolEigValues(i);
root1_real=[root1_real,real(lambda(1))];
root1_imag=[root1_imag,imag(lambda(1))];
root2_real=[root2_real,real(lambda(2))];
root2_imag=[root2_imag,imag(lambda(2))];
root3_real=[root3_real,real(lambda(3))];
root3_imag=[root3_imag,imag(lambda(3))];
root4_real=[root4_real,real(lambda(4))];
root4_imag=[root4_imag,imag(lambda(4))];
end
z=0:step:P_L;
plot3(root1_real,root1_imag,z,'r*');
hold on;
plot3(root2_real,root2_imag,z,'g*');
plot3(root3_real,root3_imag,z,'b*');
plot3(root4_real,root4_imag,z,'cyan*');
%xline(0);
legend('\lambda1','\lambda2','\lambda3','\lambda4');
xlabel('$Re(\lambda)$','Interpreter','latex');
ylabel('$Im(\lambda)$','Interpreter','latex');
hold off;
t2=toc
function y=SolEigValues(PL)
R=4;
C1=24e-6;
C2=24e-6;
L1=360e-6;
L2=480e-6;
r1=0.5;
r2=0.5;
VIN=24;
VREF=36;
D=VREF/(VREF+VIN);
n=D*VIN/(1-D);
m=(D/(1-D))^2*r1+r2;
delta=n^2-4*m*PL*(1+m/R);
V2OL=(n+sqrt(delta))/(2*(1+m/R));
a11=-r1/L1;
a12=0;
a13=-(1-D)/L1;
a14=0;
a21=0;
a22=-r2/L2;
a23=D/L2;
a24=-1/L2;
a31=(1-D)/C1;
a32=-D/C1;
a33=0;
a34=0;
a41=0;
a42=1/C2;
a43=0;
a44=PL/(C2*V2OL^2)-1/(R*C2);
A=[a11,a12,a13,a14;
a21,a22,a23,a24;
a31,a32,a33,a34;
a41,a42,a43,a44];
y=eig(A);
end
t2是0.2338,可见速度差异有多大了。还是看了师兄写的代码才知道,原来它可以这么快,秒出结果。本来是定义符号变量解方程,再用subs将变量数据代入解求取数据集;但这段代码直接写for循环求数值解得到数据集,避免解符号方程,而且写了个SolEigValues函数来求解每个点下的数据解,简化了代码结构。
---------------------------------------------------------------------------------(●'◡'●)----------------------------------------------------------------------------------
综上,直接解数值方程远远快于解符号方程再代入数据,解一个符号方程,再subs代入N组数据 ,不如直接解N个数值方程!