目录
一、global全局变量的使用
1.1 问题描述:
1.2 介绍全局变量
二、单文件多函数的实现
在使用matlab编程的过程中,常常会用到子函数,尤其是对于复杂的程序,子函数能让程序更有条理,逻辑性更强,下面分享两个子函数使用的小技巧。
在编写子函数的过程中,常遇到编写带参函数的情况,例如下面这种:
test1.m
function t=test1(x,b,c)
f1=x^2+2*x+c;
f2=x+b;
t=f1^2+f2^2;
end
其中 b和 c 就是函数中的参数,t 为函数返回的值,我们希望根据 “需要” 改变 b 和 c 的数值,从而能够在不同情况下对函数进行调用,而这种 “ 需要 ” 有时又是代码控制的,即:b和c的数值随着程序的运行自动改变。例如:
主程序1:x,b,c通过手动指定参数值来确定,结果为d=45。
main1.m
d=test1(1,2,3)
%x=1,b=2,c=3
主程序2:b,c通过手动指定参数值来确定,计算当x分别为1,2,3,4,5时的函数值,x的取值就是通过循环自动改变的,结果为d=[45 137 349 765 1493]
main2.m
b=2;
c=3;
x=1; %指定x初值
for i=1:5
d(i)=test1(x,b,c);
x=x+1;
end
主程序中对于子函数test1的调用格式为 d(i)=test1(x,b,c); 即把b,c作为参数传递给子函数,但如果参数数量很多,会很麻烦,像下面的情况:
main3.m
...(省略)
d=test1(x,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w);
...(省略)
每次调用都需要输入那么多参数,让程序变得很 “复杂”,如果要避免这种情况,就要用到全局变量了(见后文)。除此之外还有一种情况,在运用算法求解方程(组)时,我们习惯将被求解的方程(组)放到一个子函数中,然后在主程序中求解,如下面的情况:
test2.m
function t=test2(x)
f1=x^2+2*x+c;
f2=x+b;
t=f1^2+f2^2;
end
main4.m
b=1;
c=0;
options=gaoptimset('PopulationSize',500,'Generations',1000,'StallGenLimit',...
1000,'TolFun',1e-100); %设置遗传算法求解参数
[v,fval]=ga(@test2,1,options); %用遗传算法求解方程
上述程序是无法正常运行的,因为主程序中对参数进行赋值并不会改变子函数中的相应参数,要正常运行只能在子函数中重新为参数赋值,针对这种情况,用全局变量会方便很多。当然,用匿名函数的方法(即不创建子函数,直接在主函数中定义方程)也可以实现,但我们想让程序更加有条理。
全局变量(global variable)是变量的一种类型,区别于局部变量。若将一个变量声明为全局变量,则它所占的内存为全局内存,而不是本地工作区内存。因此全局变量就可以被所有工作区访问、修改。
下面用全局变量对主程序main4.m进行修改:
main4.m
global b c %使用前声明全局变量
b=1;
c=0;
options=gaoptimset('PopulationSize',500,'Generations',1000,'StallGenLimit',...
1000,'TolFun',1e-100); %设置遗传算法求解参数
[v,fval]=ga(@test1,1,options); %用遗传算法求解方程
将b和c声明为全局变量后,无论对其做怎样的修改,子程序中的b和c也会随之改变。本例结果为-0.292896584226416。
最后,实际应用中程序往往会相当复杂,下面是作者在课题中使用的程序:
子程序
function g=caculate_F(F)
f1=F(1).*(K_t_singleg1(i)+K_t_singlep1(i)+K_f_singleg1(i)+K_f_singlep1(i))+...
C_h.*F(1).^k +F(2)*(K_f_singleg1_21(i)+K_f_singlep1_21(i))-F(3); %方程1
f2=F(2).*(K_t_doubleg2(i)+K_t_doublep2(i)+K_f_doubleg2(i)+K_f_doublep2(i))+...
C_h.*F(2).^k +F(1)*(K_f_singleg1_12(i)+K_f_singlep1_12(i))-F(3); %方程2
f3=F(1)+F(2)-T0./r_b1; %方程3
g=f1.^2+f2.^2+f3.^2;
end
其中,K_t_singleg1、K_t_singlep1、K_f_singleg1、K_f_singlep1、K_f_singlep1_21、 K_f_singleg1_21、K_t_doubleg2、K_t_doublep2、K_f_doubleg2、K_f_doublep2、K_f_singleg1_12、K_f_singlep1_12、C_h、k、 T0、r_b1这些参数都是主程序中计算得到的,像K_t_singleg1这样的变量,其值都是向量形式。
主程序:
% 遗传算法求解
% 试了10个解,用时127s,速度太慢了-_-
% 定义全局变量
global K_t_singleg1 K_t_singlep1 K_f_singleg1 K_f_singlep1 K_f_singlep1_21 K_f_singleg1_21 ...
K_t_doubleg2 K_t_doublep2 K_f_doubleg2 K_f_doublep2 K_f_singleg1_12 K_f_singlep1_12 C_h k T0 r_b1
...(省略)
% 求解
tic
F1=ones(1,10);
F2=ones(1,10);
D=ones(1,10);
global i
for i=1:10
options=gaoptimset('PopulationSize',500,'Generations',1000,'StallGenLimit',1000,'TolFun',1e-100);
[v,fval]=ga(@caculate_F,3,options);
F1(i)=v(1);
F2(i)=v(2);
D(i)=v(3);
end
toc
这里将 i 也定义成全局变量,为了在子程序中提出K_t_singleg1中的第i个数,让方程的所有参数都为“1”个数,而不是一组向量(这会让程序报错)。
虽然编写子函数会让程序更加有条理,但在matlab中定义函数时,一个函数只能对应一个文件,这在子函数多的情况下,程序文件会变得相当混乱。我们希望能实现在一个文件中编写多个子函数。
这可以利用定义接口的方式在一个文件里定义多个函数,调用时先调用接口,然后通过调用匿名函数的方式调用。实例如下:
c_7_2_fun.m(定义函数)
function f=c_7_2_fun
% 定义一个接口,通过匿名函数调用
% 通过定义接口的方式,在一个函数文件例里可编写多个函数
f.lorenz1=@lorenz1;
end
function dx=lorenz1(t,x,b,r,s) % 带有附加参数的微分方程描述曲线
dx=[-b*x(1)+x(2)*x(3);-r*x(2)+r*x(3);-x(1)*x(2)+s*x(2)-x(3)];
end
c_7_2.m(调用函数)
%% 编写带有附加参数的函数
% 函数需列在单独的文件里,且函数名和文件名一致,可通过定义接口的方式,在一个函数文件例里编写多个函数
f=c_7_2_fun % 调用接口
% 设置附加参数的值
b1=8/3;r1=10;s1=28;tn=100;x0=[0;0;1e-10];
[t,x]=ode45(@f.lorenz1,[0,tn],x0,[],b1,r1,s1); % 无需使用和函数一样的变量名
% 求方程数值解
% 空矩阵表示使用默认的控制模版
编程愉快!