算是第一次完整的做的数模国赛A题,炉温曲线,经典的偏微分方程和优化问题(虽然此题也有常微分的解法)。从一开始的看国赛A题论文的看不懂,到了解它每一步建模的原理、每一步改变模型形式的用意,也算是完成了一个标准解决难啃骨头的流程。摆脱心理作用,一步步切实的学习,才能有所进步捏。

前言

算是鸽了很久的一次总结。恰好在抽出时间总结的这一天是人工智能专业的正式介绍日,也算是了解到了一波“未来可期”。大一是混沌的一年,带着高中的余念步入大学,显然是深受其害了,但还好没太走远。总觉得冥冥中有着些命运的指引,有些经历虽然“不堪回首“,但扎实起来自己,学学东西的感觉,还是挺不错的。

炉温曲线

一个炉子,一个\(0.15mm\)的金属件过炉,炉子分几个温度不同长度不同的大温区,每个大温区包含几个小温区,过炉过程中,金属件中心的温度变化曲线就是炉温曲线。

下面分别是炉子和炉温曲线的示意图:

问题一

作为练习时长两月半的划水手,乍看此题,便觉得和18年国A的模型很相似。市面上虽然也有考虑热对流、热辐射的模型,但讲来讲去也只是来推导出一个牛顿冷却定律: \[ \frac {\partial T}{\partial x}=h[T_l(x)-T_x(x)] \] 那不妨我们就说这是道热传导的题。

对于热传导问题,我们对于其模型的创建,分为两步:

  • 运用傅里叶定律(\(\large{\frac {\partial T}{\partial t}=\frac{k}{\rho c_p} \frac {\partial^2 T}{\partial^2 x}}\)),构建控制方程;
  • 运用牛顿冷却定律,构建边界条件;

建立的热传导模型即为: \[ \begin{cases}{} \Large{\frac {\partial T}{\partial t}=\frac{k}{\rho c_p} \frac {\partial^2 T}{\partial^2 x}} \\ \large{k \frac {\partial T}{\partial x}=h[T_l(x)-T_x(x)]} \\ \end{cases} \] 为简化参数数量:我们设\(\alpha=\frac{k}{\rho c_p}\)

这题有一说法是可以简化偏微分模型为微分模型,即不考虑在厚度只有\(0.15mm\)的金属件上的空间差分,转为\(T(t)\)的求解问题,运用: \[ \frac{T(n+1)-T(n)}{dt}=-k(T(t)-T_{air}(t)) \] 进行迭代求解。

第一问需要我们借助附件数据拟合出每个温区的热传导系数(由于每个温区的温度不同,器件的加热情况不同,所以其各类热力学参数也不同)。

温区间隔的温度变化

我们首先来处理小温区间隔之间的温度:

由于傅里叶定律告诉我们,\(\frac {\partial T}{\partial t}=\frac{k}{\rho c_p} \frac {\partial^2 T}{\partial^2 x}\),当温度稳定时,\(\frac {\partial T}{\partial t}=0\)(温度不随时间改变),所以$=0 $,空间偏导的二阶导为零,证明一阶导为常数,可推断出,间隔之间的温度变化为线性的,两个端点,分别就是两个小温区的温度。

于是我们可以编得炉子温度分布函数:

%炉内温度分布
function Tu=TEMP(x)
Kelvin=273.15;%换成华氏
global T1 T2 T3 T4

if x<25
    Tu=(T1-25)/(25-0)*(x-0)+25+Kelvin;
elseif x<197.5
    Tu=T1+Kelvin;
elseif x<202.5
    Tu=(T2-T1)/5*(x-197.5)+T1+Kelvin;
elseif x<233
    Tu=T2+Kelvin;
elseif x<238
    Tu=(T3-T2)/5*(x-233)+T2+Kelvin;
elseif x<268.5
    Tu=T3+Kelvin;
elseif x<273.5
    Tu=(T4-T3)/5*(x-268.5)+T3+Kelvin;
elseif x<339.5
    Tu=T4+Kelvin;
elseif x<344.5
    Tu=(25-T4)/5*(x-339.5)+T4+Kelvin;
else
    Tu=25+Kelvin;
end
end

Crank-Nicalson格式的有限差分法

由于这题金属件的厚度只有\(0.15mm\),运用显式差分时极易不收敛,所以我们采用\(Crank-Nicalson\)格式的差分法(其具体推导可见差分法那一篇文章): \[ \begin{bmatrix} \frac{k}{dx}+h & -\frac{k}{dx} & \cdots & \cdots \\ \beta & -(1+2\beta) & -\beta & \cdots \\ & \ddots & \ddots & \ddots \\ \cdots & \beta & -(1+2\beta) & -\beta \\ \cdots & \cdots & -\frac{k}{dx} & \frac{k}{dx}+h \end{bmatrix} \begin{bmatrix} T^{n+1}_1\\ T^{n+1}_2 \\ \vdots\\ T^{n+1}_{m-1}\\T^{n+1}_{m} \end{bmatrix} =S \]

\[ S= \begin{bmatrix} -1+2\beta & -\beta & \cdots & \cdots \\ -\beta & -1+2\beta & -\beta & \cdots \\ & \ddots & \ddots & \ddots \\ \cdots & -\beta & -1+2\beta & -\beta \\ \cdots & \cdots & -\beta & -(1+2\beta) \end{bmatrix} \begin{bmatrix} T^{n}_1\\ T^{n}_2 \\ \vdots\\ T^{n}_{m-1}\\T^{n}_{m} \end{bmatrix} \]

再将\(S(1)、S(i_{max})\)修正为\(hT_{env}\)

该差分法的程序如下:

% 构造M系数矩阵的框架及其第一行和最后一行
A=alpha1*dt/(2*dy*dy);                            
M=eye(length_y,length_y);
M(1,1)=h+k/dy;
M(1,2)=-k/dy;
M(length_y,length_y-1)=-k/dy;
M(length_y,length_y)=h+k/dy;

% 完整构建M系数矩阵
for index_x=2:length_y-1
M(index_x,index_x-1)=A;
M(index_x,index_x)=-2*A-1;
M(index_x,index_x+1)=A;
end

% 隐式求解
N=zeros(length_y,1);
for index_t=2:348
   x=(index_t-1)*dt*v;
   Tu=TEMP(x);
   N(1)=h*Tu;
   N(length_y)=h*Tu;
       % 求出S的值,此处是N矩阵
       for index_x=2:length_y-1
            N(index_x)=-A*(T(index_x+1,index_t-1)+T(index_x-1,index_t-1))+(2*A-1)*T(index_x,index_t-1);
       end
   % 利用右除,算出T=M的逆*N,完成迭代
   T(:,index_t)=M\N;
end

随后需要进行最优参数拟合,考虑到不同温区的传热系数不同,我们需要进行遍历寻找的最优参数解空间即为: \[ \large{[k、h、\alpha_1、\alpha_2、\alpha_3、\alpha_4、\alpha_5]} \] 借助附件数据,我们得知温度的差分最大不超过个位数限制,因此可知\(\Large{\frac{\alpha dt}{dx^2} }\)为个位数数量级。附件中取\(dt=0.5\),我们照取。由于金属件厚度为\(0.15mm\),我们取\(dx=10^{-6}m\),可得\(\alpha\)的数量级为\(10^{-11}\)。由于解空间较大,我们先在\(10^{-11}\)数量级中寻找\(\alpha\),查阅相关资料后,确定在10~30中搜索\(h\),在\(10^{-6}\)数量级中搜索\(k\)

则,完整的拟合最优参数代码为:(简略搜索版)

clear all
clc
global T1 T2 T3 T4
T1=175;
T2=195;
T3=235;
T4=255;
Kelvin=273.15;
load standard.mat
t_max=standard(end,1);
dy=1e-6;
dt=0.5;%题目要求
y_max=0.15e-3;
v=70/60;%单位cm/s
length_y=round(y_max/dy+1);
length_t=round(t_max/dt+1);
standard(:,2)=standard(:,2)+Kelvin;%换温标
Errormin=inf;
Error_pre=[];

%确定搜索步长
dk = 1e-6;
dh = 1;
da = 1e-11;

for k=1e-6 : dk : 1e-5
    for h=10 : dh :30
        for alpha1=1e-11 : da :1e-10
            for alpha2=1e-11 : da :1e-10
                for alpha3=1e-11 : da :1e-10
                    for alpha4=1e-11 : da :1e-10
                        for alpha5=1e-11 : da :1e-10
                            T=zeros(length_y,length_t);
                            T(:,1)=ones(length_y,1)*(25+Kelvin);
                            %区域1
                            A=alpha1*dt/(2*dy*dy);                            
                            M=eye(length_y,length_y);
                            M(1,1)=h+k/dy;
                            M(1,2)=-k/dy;
                            M(length_y,length_y-1)=-k/dy;
                            M(length_y,length_y)=h+k/dy;
                            for index_x=2:length_y-1
                                M(index_x,index_x-1)=A;
                                M(index_x,index_x)=-2*A-1;
                                M(index_x,index_x+1)=A;
                            end
                            N=zeros(length_y,1);
                            for index_t=2:348
                                x=(index_t-1)*dt*v;
                                Tu=TEMP(x);
                                N(1)=h*Tu;
                                N(length_y)=h*Tu;
                                for index_x=2:length_y-1
                                    N(index_x)=-A*(T(index_x+1,index_t-1)+T(index_x-1,index_t-1))+(2*A-1)*T(index_x,index_t-1);
                                end
                                T(:,index_t)=M\N;
                            end
                            %区域2
                            A=alpha2*dt/(2*dy*dy);                            
                            for index_x=2:length_y-1
                                M(index_x,index_x-1)=A;
                                M(index_x,index_x)=-2*A-1;
                                M(index_x,index_x+1)=A;
                            end
                            N=zeros(length_y,1);
                            for index_t=349:409
                                x=(index_t-1)*dt*v;
                                Tu=TEMP(x);
                                N(1)=h*Tu;
                                N(length_y)=h*Tu;
                                for index_x=2:length_y-1
                                    N(index_x)=-A*(T(index_x+1,index_t-1)+T(index_x-1,index_t-1))+(2*A-1)*T(index_x,index_t-1);
                                end
                                T(:,index_t)=M\N;
                            end
                            %区域3
                            A=alpha3*dt/(2*dy*dy);                            
                            for index_x=2:length_y-1
                                M(index_x,index_x-1)=A;
                                M(index_x,index_x)=-2*A-1;
                                M(index_x,index_x+1)=A;
                            end
                            N=zeros(length_y,1);
                            for index_t=410:470
                                x=(index_t-1)*dt*v;
                                Tu=TEMP(x);
                                N(1)=h*Tu;
                                N(length_y)=h*Tu;
                                for index_x=2:length_y-1
                                    N(index_x)=-A*(T(index_x+1,index_t-1)+T(index_x-1,index_t-1))+(2*A-1)*T(index_x,index_t-1);
                                end
                                T(:,index_t)=M\N;
                            end
                            %区域4
                            A=alpha4*dt/(2*dy*dy);                            
                            for index_x=2:length_y-1
                                M(index_x,index_x-1)=A;
                                M(index_x,index_x)=-2*A-1;
                                M(index_x,index_x+1)=A;
                            end
                            N=zeros(length_y,1);
                            for index_t=471:592
                                x=(index_t-1)*dt*v;
                                Tu=TEMP(x);
                                N(1)=h*Tu;
                                N(length_y)=h*Tu;
                                for index_x=2:length_y-1
                                    N(index_x)=-A*(T(index_x+1,index_t-1)+T(index_x-1,index_t-1))+(2*A-1)*T(index_x,index_t-1);
                                end
                                T(:,index_t)=M\N;
                            end
                            %区域5
                            A=alpha5*dt/(2*dy*dy);                            
                            for index_x=2:length_y-1
                                M(index_x,index_x-1)=A;
                                M(index_x,index_x)=-2*A-1;
                                M(index_x,index_x+1)=A;
                            end
                            N=zeros(length_y,1);
                            for index_t=593:747
                                x=(index_t-1)*dt*v;
                                Tu=TEMP(x);
                                N(1)=h*Tu;
                                N(length_y)=h*Tu;
                                for index_x=2:length_y-1
                                    N(index_x)=-A*(T(index_x+1,index_t-1)+T(index_x-1,index_t-1))+(2*A-1)*T(index_x,index_t-1);
                                end
                                T(:,index_t)=M\N;
                            end
                            
                            %最小二乘
                            dT=T(76,39:end)-standard(:,2)';
                            Error=sum(dT.*dT)/length(standard);
                            Error_pre=[Error_pre Error];
                            if Error<Errormin
                                Errormin=Error;
                                alpha=[alpha1,alpha2,alpha3,alpha4,alpha5];
                                kmin=k;
                                hmin=h;
                            end
                        end
                    end
                end
            end
        end
    end
end

%plot(1:length_t,T(76,:),'b');
%hold on
%plot(39:747,standard(:,2))

搜索到解空间大致范围后,再进行数量级更小的精细搜索。得到最优参数,便能算出新温度组下的炉温曲线。

(虽然这简单一句话,包含着好几小时的matlab遍历用时)

问题二

问题二要求我们在满足制程界限的前提下,寻找最大的过炉速度。这是一道很明显的有约束条件的优化问题。则我们把整个速度区间遍历,满足制程界限的留下,不满足的删除,然后去确定留下的速度中最大的速度即可,并且也是采用先粗略遍历,再在最优解附近以更高精度遍历的方法。

(制程界限是针对于炉温曲线来要求的)

制程界限带来的约束条件为:

转化为数学语言即为: \[ s.t. \large{ \begin{cases} 240\leqslant \text{max}[T(t)]\leqslant250\\ \text{max}[|T'(x)|] \leqslant3\\ 60\leqslant t|_{[150\leqslant T(t)\leqslant190,T'(t)>0]}\leqslant120\\ 40 \leqslant t|_{[T(t)\geqslant217]}\leqslant90 \end{cases} } \] 我们设置一个\(flag\)函数,当\(v\)满足约束条件时,\(flag=1\),当不满足约束条件时,\(flag=0\),以此来保留和去除\(v\)。代码如下:(其中的BoxValue是用于第四问的对称指标来用的)

function flag=restrict(T,dt)
global BoxValue
T=T-273.15;%改成摄氏度便于写条件
dT=T(2:end)-T(1:end-1);
k=[0 dT/dt];%为了下面计数的方便
HeatUpLimit=0;
ExtrameHeatLimit=0;
Box=[];

for i=1:length(T)
    if k(i)>0 && T(i)>150 && T(i)<190
        HeatUpLimit=HeatUpLimit+1;
    elseif T(i)>217
        Box=[Box i];
        ExtrameHeatLimit=ExtrameHeatLimit+1;
    end
end

HeatUpTime=HeatUpLimit*dt;
ExtrameHeatTime=ExtrameHeatLimit*dt;

[HighestLimit,PeakIndex]=max(T);
PeakIndex
Box(1)
Box(end)
BoxValue=(2*PeakIndex-Box(1)-Box(end))*dt;

if max(k)>3 || min(k)<-3
    flag=0;
elseif HighestLimit>250 || HighestLimit<240
    flag=0;
elseif HeatUpTime<60 || HeatUpTime>120
    flag=0;
elseif ExtrameHeatTime<40 || ExtrameHeatTime>90
    flag=0;
else
    flag=1;
end
end

再在利用该函数保留下来的速度中,寻找最大的一个即可。(同时注意速度的单位转换)