








function [ ] = ParabolicEquation( h,k ) %求解抛物型方程中的一种:热传导方程 %h:x轴步长 %k:t轴步长 r=k/(h*h);%网格比 Mx=floor(1.0/h)+1;%网格在x轴上的节点个数(算上0) Nt=floor(1.0/k)+1;%网格在t轴上的节点个数(算上0) N=(Mx-2)*(Nt-1); %U的维数 %% %古典显格式* %直接递推的方法求古典显格式 UxianM=zeros(Mx,Nt); Uxian=[]; %先赋初值和边界值 for x=1:Mx UxianM(x,1)=InitialConditions((x-1)*h); end for t=1:Nt UxianM(1,t)=BoundaryConditions(0,(t-1)*k); UxianM(Mx,t)=BoundaryConditions(1,(t-1)*k); end %利用显格式公式逐行递推 for t=2:Nt for x=2:Mx-1 UxianM(x,t)=r*UxianM(x-1,t-1)+(1-2*r)*UxianM(x,t-1)+r*UxianM(x+1,t-1); end end %将结果按Ku=f方法的u的结构重排 for t=2:Nt Uxian= [Uxian;UxianM(2:Mx-1,t)]; end %% %古典隐格式* %求K,将K看出三对角块矩阵,形如: % C 0 ... % D C 0 ... % 0 D C 0 ... % 0 0 D C 0 ... % ... ... % ... D C %先计算C(C是三对角矩阵) C=eye(Mx-2)*(1+2*r); C=C+diag(ones(1,Mx-3)*(-r),1); %上次对角 C=C+diag(ones(1,Mx-3)*(-r),-1); %下次对角 %计算D D=eye(Mx-2)*-1; %计算K temp={}; for t=1:Nt-1 temp{t}=C; end mid = repmat({C},Nt-1,Nt-1);%对角块 for x=1:Nt-1 for t=1:Nt-1 if x~=t mid{x,t}=zeros(Mx-2,Mx-2); %非主对角线置0 end if x==t+1 mid{x,t}=D; %下次对角线上的块为D end end end Kyin=cell2mat(mid); %求f %将f分块 % f1 % f2 % ... % fNt-1 %f中大多数值为0,非0值用初边值条件添加 fyin=zeros(N,1); %先计算f1 f1=zeros(Mx-2,1); %计算f(1,1),中心点为U11 f1=zeros(Mx-2,1); f1(1)=r*BoundaryConditions(0,k)+InitialConditions(h); %计算f(Mx-2,1),中心点为U(Mx-2,1) f1(Mx-2)=r*BoundaryConditions(1,(Mx-1)*k)+InitialConditions(h*(Mx-2)); %计算f(x,1) (x!=1且x!=Mx-2) for x=2:Mx-3 f1(x)=InitialConditions(h*x); end fyin(1:Mx-2)=f1; %计算边值条件计算f2~fNt-1 for t=2:Nt-1 fyin((Mx-2)*(t-1)+1)=r* BoundaryConditions(0,k*(t)); fyin((Mx-2)*t)=r* BoundaryConditions(1,k*(t)); end %求u Uyin=inv(Kyin)*fyin; %% %Crank-Nicolson格式* %追赶法求解 %An*Un+1=Bn*Un+en %求An An=eye(Mx-2)*(1+r); An=An+diag(ones(1,Mx-3)*(-0.5*r),1); %上次对角 An=An+diag(ones(1,Mx-3)*(-0.5*r),-1); %下次对角 InvA=inv(An); %求Bn Bn=eye(Mx-2)*(1-r); Bn=Bn+diag(ones(1,Mx-3)*(0.5*r),1); %上次对角 Bn=Bn+diag(ones(1,Mx-3)*(0.5*r),-1); %下次对角 Cn=InvA*Bn; %追赶法 U0=[];%初值 for x=1:Mx U0(x)=InitialConditions((x-1)*h); end UcnM=zeros(Mx-2,Nt-1); Ucn=[]; %求U1 An*Un+1=Bn*Un+en,e1恰好是0向量 UcnM(:,1)=Cn*U0(2:Mx-1)'+zeros(Mx-2,1); %利用显格式公式逐行递推 for t=2:Nt-1 n=t-1; en=zeros(Mx-2,1); en(1)=0.5*r*BoundaryConditions(0,n*k)+0.5*r*BoundaryConditions(0,(n+1)*k); en(Mx-2)=0.5*r*BoundaryConditions(1,n*k)+0.5*r*BoundaryConditions(1,(n+1)*k); UcnM(:,n+1)=Cn*UcnM(:,n)+en; end %将结果按Ku=f方法的u的结构重排 for t=1:Nt-1 Ucn= [Ucn;UcnM(:,t)]; end %% %计算精确解,用于误差分析 U_M=zeros(Mx-2,Nt-1); U=[]; for x=1:Mx-2 for t=1:Nt-1 U_M(x,t)=ExactSolution(x*h,t*k); end end %将结果按Ku=f方法的u的结构重排 for t=1:Nt-1 U=[U;U_M(1:Mx-2,t)]; end %% %结果比较 %比较标准误差(均方根误差) temp=(U-Uxian).^2; temp=sum(sum(temp)); temp=temp/(Mx*Nt); Exian=sqrt(temp); temp=(U-Uyin).^2; temp=sum(sum(temp)); temp=temp/(Mx*Nt); Eyin=sqrt(temp); temp=(U-Ucn).^2; temp=sum(sum(temp)); temp=temp/(Mx*Nt); Ecn=sqrt(temp); fprintf('h: %d;k= %d\n',h,k); fprintf('古典显格式标准误差:%d\n',Exian); fprintf('古典隐格式标准误差:%d\n',Eyin); fprintf('CN格式标准误差:%d\n',Ecn); end
function [ Uxt ] = InitialConditions ( x ) %在此函数中定义初值条件 Uxt=sin(pi*x); end
function [ Uxt ] = ExactSolution( x,t) %在此函数中定义待求函数的精确解u(x,t),用于比较数值解 Uxt=exp(-1*pi*pi*t)*sin(pi*x); end
function [ Uxt ] = BoundaryConditions( LeftOrRight,t ) %在此函数中定义边值条件 %LeftOrRight标识左边界条件还是右边界条件 0代表左,1代表右 Uxt=-1; if LeftOrRight==0 Uxt=0; elseif LeftOrRight==1 Uxt=0; else %不应该出现此情况,抛异常 error('错误使用边界条件!'); end end
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/198926.html原文链接:https://javaforall.net
