18国赛A题 详解 附一维多层材料非稳态热传导数值解 maltab,c++结合python 代码

20.9.23 update:我写公式编号用的是\tag{编号},我找了半天也没找到其他方式来可以实现自动右对齐的编号。这么写会导致:有些比较长的公式的编号在手机上会显示在公式中间,而不是公式最后(在电脑的网页上是正常的)。于是我就把那些公式的编号直接写在了公式的后面而不是用tag,这样一来就会有些公式的编号没对齐,还请各位见谅。如果你有解决手机上长公式编号显示问题的更好的办法,还请不吝赐教。

文章目录

      • 前言
    • 1 第一问
      • 1.1 模型建立
        • 1.1.1 先处理主要矛盾:层内热传导
          • 1.1.1.1 傅里叶定律
        • 1.1.2 热力学中的边界
        • 1.1.3 本题的边界
        • 1.1.4 层间交界面
      • 1.2 模型求解
        • 1.2.1 基础知识
        • 1.2.2 差分方程
          • 1.2.2.1 每层内部
          • 1.2.2.2 层间交界面处
          • 1.2.2.3 边界处
        • 1.2.3 显式差分
          • 1.2.3.1 层内
        • 1.2.4 隐式差分
          • 1.2.4.1 古典隐式差分
            • 1.2.4.1.1层内
            • 1.2.4.1.2 交界面处
            • 1.2.4.1.3 边界处
          • 1.2.4.2 Crank-Nicholson差分格式
        • 1.2.5 确定热交换系数
      • 1.3 一些细节和思考
    • 2 第二问
    • 3 第三问
    • 4 代码
      • 4.1 显式差分
        • 4.1.1 c++计算
        • 4.1.2 python画图
      • 4.2 经典隐式差分(matlab)

前言

  • 对于准备建模的同学呢,建议先试着做一下这道题,之后呢再来看这篇文章。不然你听别人讲的时候感觉挺流畅的,一到自己做的时候就呃呃了。有编程能力的同学建议自己动手实现一下。如果空气与皮肤的热交换系数算出来不是8.3左右,那就是算错了(8.3是可以根据解析解算出来的)
  • 对于想看一维多层材料非稳态热传导数值解的同学,可点这个直接跳转到第一问模型求解部分。

不要被文中的一坨坨公式给吓倒了,耐心仔细分析一下也不难的。
解题过程中我读过的所有有价值的参考资料在文中都有可以直接打开的链接(无需/登录付费论文网站)。
有不懂或不对的地方->评论区留言

现在带着大家elegantly(优雅地)走一遍建模过程。
开赛
选题
经过短暂的商讨,虽然都没有学过热学,但你们一致决定选A题,并决心死也要死在A题上!

1 第一问

1.1 模型建立

搜索一下传热学
从百度百科 传热学得知:

传热的基本方式有热传导、热对流和热辐射三种。

因为本题涉及的材料的热辐射都很小,所以可忽略,即假设所有材料和人体都为绝对黑体。

热传导肯定是大头,那用不用考虑热对流呢
还在刚才的百科界面我们看到:

热对流是指不同温度的流体各部分由相对运动引起的热量交换。工程上广泛遇到的对流换热,是指流体与其接触的固体壁面之间的换热过程,它是热传导和热对流综合作用的结果。

这个对流换热貌似和我们这题的:衣服和外界,衣服与皮肤的传热比较相似。(这里把空气层也算入衣服)
对流换热的藤摸牛顿的,发现
对流换热的强度依据牛顿冷却定律,其基本计算公式是:
q = h ( T w − T f ) (1) q=h(T_w-T_f)\tag{1} q=h(TwTf)(1)

式中q为单位面积的固体表面与流体之间在单位时间内交换的热量,称作热流密度;TW、Tf分别为固体表面和流体的温度;h称为传热系数,它表示在单位面积的固体表面上,当流体与固体表面之间的温度差为1K时,每单位时间内所传递的热量。h的大小反映对流换热的强弱,它与影响换热过程的诸因素有关,并且可以在很大的范围内变化。

1.1.1 先处理主要矛盾:层内热传导

搜索一下热传导
在百度百科 热传导发现
有傅里叶定律和热扩散方程(三维非稳态热传导)

1.1.1.1 傅里叶定律

关于傅里叶方程这篇博文公式表述的比较清楚
它的一般表示形式是:
q = − k ∇ T (2) q=−k∇T \tag{2} q=kT(2)
∇T可表示为 ∂ T ∂ n \frac{\partial T}{\partial n} nT

其中
q 是热流密度,是单位面积上的热通量, W ⋅ m − 2 W⋅m^{−2} Wm2 W W W可替换成: J ⋅ s − 1 J\cdot s^{-1} Js1
k是材料的热传导系数, W ⋅ m − 1 ⋅ K − 1 W⋅m^{−1}⋅K^{−1} Wm1K1
∇T 是温度梯度, K ⋅ m − 1 K⋅m^{−1} Km1
n是该位置的法线方向,m

一维情况下就是
q x = − k d T d x (3) q_x=−k\frac{dT}{dx}\tag{3} qx=kdxdT(3)

其中
q x q_x qx 是x方向的热流密度, W ⋅ m − 2 W⋅m^{−2} Wm2

x是长度, m

注意热通量与热流密度概念上的区分
18国赛A题 详解 附一维多层材料非稳态热传导数值解 maltab,c++结合python 代码_第1张图片

( 图片来源:课件1)

知道了这些后,理论上我们已经可以手动推导出一维的热传导方程了。
但我们不想手动推导,搜的话,我着实搜不到比较好的文章,那我们就利用一下那个热扩散方程吧。
∂ T ∂ t = k c ρ ( ∂ 2 T ∂ x 2 + ∂ 2 T ∂ y 2 + ∂ 2 T ∂ z 2 ) (4) \frac{\partial T}{\partial t} = \frac{k}{c\rho} ( \frac{\partial ^{2} T}{\partial x^{2}}+\frac{\partial ^{2} T}{\partial y^{2}}+\frac{\partial ^{2} T}{\partial z^{2}} )\tag{4} tT=cρk(x22T+y22T+z22T)(4)

其中: t为时间;c为比热容; ρ \rho ρ为密度

它其实是三维的热传导方程,将其转化成一维的就得到了一维的热传导方程:
∂ T ∂ t = k c ρ ∂ 2 T ∂ x 2 (5) \frac{\partial T}{\partial t} = \frac{k}{c\rho} \frac{\partial ^{2} T}{\partial x^{2}}\tag{5} tT=cρkx22T(5)
然而这只是每层材料内部的温度变化规律

1.1.2 热力学中的边界

首先我们来介绍一下传热学定解问题的三类边界条件(分别对应于微分方程定解问题的三类边界条件)

  1. 第一类边界条件(Dirichlet边界条件)
    给定物体边界上温度分布以及随时间的变化规律
    T ( x , y , z , t ) ∣ ( x , y , z ) ∈ Γ = f ( x , y , z , t ) (6) T(x,y,z,t)|_{(x,y,z)\in\Gamma=f(x,y,z,t)}\tag{6} T(x,y,z,t)(x,y,z)Γ=f(x,y,z,t)(6)
    其中 Γ \Gamma Γ表示边界

  2. 第二类边界条件(Neumann边界条件)
    给定物体边界上的热流密度分布以及随时间的变化规律
    q Γ = f ( x , y , z , t ) (7) q_{\Gamma}=f(x,y,z,t)\tag{7} qΓ=f(x,y,z,t)(7)
    根据傅里叶定律可将其转化为:
    ∂ T ∂ n ∣ ( x , y , z ) ∈ Γ = f ( x , y , z , t ) (8) \frac{\partial T}{\partial n}\bigg|_{(x,y,z)\in\Gamma}=f(x,y,z,t)\tag{8} nT(x,y,z)Γ=f(x,y,z,t)(8)

  3. 第三类边界条件(Robin条件)
    给定物体表面上的热交换系数h和周围流体温度 T 0 T_0 T0,又称为对流边界条件。(这里用到了牛顿冷却公式)
    − k ∂ T ∂ n = h ( T w − T 0 ) (9) -k \frac{\partial T}{\partial n}=h(T_w-T_0)\tag{9} knT=h(TwT0)(9)
    其中 T w T_w Tw为物体边界边界温度

注意第二类与第三类的区别,第二类右侧的函数是已知的,而第三类的 T w T_w Tw是不断变化的,且变化规律是需要你去计算的。

1.1.3 本题的边界

显然这道题是第三类边界条件。
我们可以把整个衣服(包括空气层)当作一个整体,那衣服与外界,衣服与人体就有两个交界面,也就会有两个热交换系数,这两个都是需要通过与附件的温度数据进行拟合计算得到的。(实际上我们应该区分开空气层和衣服,也就是说空气层与第3层之间应该也有一个交换系数,但是为了简化,就按照它们两者之间只有热传导处理了)
关于边界条件如果还有不清楚的可以看这两个课件:课件1,课件2

1.1.4 层间交界面

根据能量守恒定律,每层材料的交界面处热流密度应是连续的
(当然温度也是连续的: T − = T + T^-=T^+ T=T+
k j ( ∂ T ∂ x ) − = k j + 1 ( ∂ T ∂ x ) + (10) k_j (\frac{\partial T}{\partial x})^-=k_{j+1} (\frac{\partial T}{\partial x})^+\tag{10} kj(xT)=kj+1(xT)+(10)
其中j表示第j层

至此我们已经分析完所有位置的传热情况了
你可像这样罗列出来:
18国赛A题 详解 附一维多层材料非稳态热传导数值解 maltab,c++结合python 代码_第2张图片


图片来源:优秀论文440

(图中的 λ \lambda λ对应于本文的k)
(图中的公式其实不太严谨,但我懒得再打一遍了,看一下这种形式就好)

1.2 模型求解

1.2.1 基础知识

求解这类偏微分方程问题可以通过有限差分法得数值解或者设出稳定时每层温度关于x的函数,联立等式得到解析解。

差分比较好理解了,就是把时间和空间都离散化,然后一点点地递推。
差分法有显式差分和隐式差分。
关于这两种差分的区别建议先阅读文档1,再阅读文档2.

解析解可查看官方题解,这里不详细讨论。(官方题解在计算方法部分的等式,你可能觉得很weird(奇怪),那因为他写的是隐式差分的格式,但是上标比较奇怪,对于这种题我们一般用n时刻推n+1时刻,而他用的n-1时刻推n时刻)

在处理一阶偏导和二阶偏导时,需要用到差商的概念。
18国赛A题 详解 附一维多层材料非稳态热传导数值解 maltab,c++结合python 代码_第3张图片

图片来源

1.2.2 差分方程

1.2.2.1 每层内部

把式5中的偏导替换成对应的差商便得到差分方程:
T i n + 1 − T i n Δ t = k j c j ρ j T i + 1 n − 2 T i n + T i − 1 n Δ x j 2 (11) \frac{T^{n+1}_{i}-T^{n}_{i}}{\Delta t}= \frac{k_j}{c_j\rho_j}\frac{T^{n}_{i+1}-2T^{n}_{i}+T^{n}_{i-1}}{\Delta x_j^2}\tag{11} ΔtTin+1Tin=cjρjkjΔxj2Ti+1n2Tin+Ti1n(11)
其中上标为n的表示n时刻的T,是已知的,n+1时刻的T是我们所要求的,下标i表示空间离散后的第i个点,j表示属于第j层

1.2.2.2 层间交界面处

想要知道交界面在时间上的变化量,我们就得清楚到底是什么引起的温度的变化?
热流密度在空间上的变化!

我们可以从宏观上理解一下:试想一下如果一个物体左侧温度突然上升了,那么左侧温度梯度就会增大,热流密度也会增大,而右侧热流密度没变,左边进热的速度大于右边排热的速度,那温度必然得上升了。
这时候你可能会想,那如果右侧温度突然下降了,右侧热流密度也变大了,那温度是不是就不变了?
如果物体是一个点的话确实是的,温度一直是 ( T 左 + T 右 ) 2 \frac{(T_左+T_右)}{2} 2(T+T)
但如果是物体是一个长条的话,左侧温度会升高,右侧会下降,稳定后中间点的温度是 ( T 左 + T 右 ) 2 \frac{(T_左+T_右)}{2} 2(T+T)(这里都假设介质均匀,且只有热传导,且左右两侧边界恒温)
我们那个热传导方程其实就是这么推出来的,温度在空间上的一阶偏导代表热流密度,当物体缩小至一个点时,空间上的热流密度的变化率就是一阶偏导的偏导:二阶偏导。
在分界面也是这样
∂ T ∂ t = k j p x − 1 2 Δ x − k j + 1 p x − 1 2 Δ x c ρ Δ x (12) \frac{\partial T}{\partial t} = \frac{k_j p_{x-\frac{1}{2}\Delta x}-k_{j+1}p_{x-\frac{1}{2}\Delta x}}{c\rho\Delta x}\tag{12} tT=cρΔxkjpx21Δxkj+1px21Δx(12)
但是这里的c和 ρ \rho ρ就不太好说了。
转化成差分形式:
c j ρ j 1 2 ( Δ x j + Δ x j + 1 ) T i n + 1 − T i n Δ t = k j T i − 1 n − T i n Δ x j + k j + 1 T i + 1 n − T i n Δ x j + 1 ( 13 ) c_j\rho_j\frac{1}{2}(\Delta x_j+\Delta x_{j+1}) \frac{T^{n+1}_{i}-T^{n}_{i}}{\Delta t}= k_{j}\frac{T^{n}_{i-1}-T^{n}_{i}}{\Delta x_{j}}+ k_{j+1}\frac{T^{n}_{i+1}-T^{n}_{i}}{\Delta x_{j+1}}\quad(13) cjρj21(Δxj+Δxj+1)ΔtTin+1Tin=kjΔxjTi1nTin+kj+1Δxj+1Ti+1nTin(13)
c和 ρ \rho ρ可以设成左边的或者右边的,或者(左边+右边)/2

1.2.2.3 边界处

思路和交界面处一样,只不过一侧的热流密度的表达形式换成了 h ( T w − T 0 ) h(T_w-T_0) h(TwT0)
差分格式为:
18国赛A题 详解 附一维多层材料非稳态热传导数值解 maltab,c++结合python 代码_第4张图片


图片来源:优秀论文440

下面对两种差分格式分别进行讨论。

1.2.3 显式差分

显式差分可能是不稳定的,需要选择合适的时间步长和空间步长,大小不是关键,他们两者的比例是关键的。

比如这道题需要满足: 0 < k c ρ Δ t Δ x 2 < 0.5 0< \frac{k}{c\rho} \frac{\Delta t}{\Delta x^2}<0.5 0<cρkΔx2Δt<0.5
这样显示差分才能得到稳定的数值解,否则数值解将不稳定而振荡

至于为什么要 k c ρ Δ t Δ x 2 \frac{k}{c\rho} \frac{\Delta t}{\Delta x^2} cρkΔx2Δt小于0.5才稳定,我还没去研究。

1.2.3.1 层内

T i n + 1 − T i n = s j T i − 1 n − 2 s j T i n + s j T i + 1 n (14) T^{n+1}_{i}-T^{n}_{i}=s_jT^{n}_{i-1}-2s_jT^{n}_{i}+s_{j}T^{n}_{i+1}\tag{14} Tin+1Tin=sjTi1n2sjTin+sjTi+1n(14)
其中 s j = k j Δ t c j ρ j Δ x j 2 s_j=\frac{k_j\Delta t}{c_j\rho_j\Delta x_j^2} sj=cjρjΔxj2kjΔt

其他情况同理把上文的差分方程移一下项就可以了
如果我们根据上述等式用已知的n时刻的T去推n+1时刻的T,那便是显式差分。

1.2.4 隐式差分

1.2.4.1 古典隐式差分

我们把1.2.2小节的差分方程等式右侧的 T n T^n Tn替换成 T n + 1 T^{n+1} Tn+1就得到了古典隐式差分格式。

1.2.4.1.1层内

T i n + 1 − T i n Δ t = k j c j ρ j T i + 1 n + 1 − 2 T i n + 1 + T i − 1 n + 1 Δ x 2 ( 15 ) \frac{T^{n+1}_{i}-T^{n}_{i}}{\Delta t}= \frac{k_j}{c_j\rho_j}\frac{T^{n+1}_{i+1}-2T^{n+1}_{i}+T^{n+1}_{i-1}}{\Delta x^2}\quad(15) ΔtTin+1Tin=cjρjkjΔx2Ti+1n+12Tin+1+Ti1n+1(15)
移一下项:
− s j T i − 1 n + 1 + ( 1 + 2 s j ) T i n + 1 − s j T i + 1 n + 1 = T i n ( 16 ) -s_jT^{n+1}_{i-1}+(1+2s_j)T^{n+1}_{i}-s_{j}T^{n+1}_{i+1}=T^{n}_{i}\quad(16) sjTi1n+1+(1+2sj)Tin+1sjTi+1n+1=Tin(16)

其中 s j = k j Δ t c j ρ j Δ x 2 s_j=\frac{k_j\Delta t}{c_j\rho_j\Delta x^2} sj=cjρjΔx2kjΔt
因为线性隐式差分方程组的是无条件稳定的,所以这里我们不再区分每层的 Δ x \Delta x Δx,令所有 Δ x \Delta x Δx为某一固定值

1.2.4.1.2 交界面处

− s j T i − 1 n + 1 + ( 1 + s j + k j + 1 Δ t c j ρ j Δ x 2 ) T i n + 1 − k j + 1 Δ t c j ρ j Δ x 2 T i + 1 n + 1 = T i n ( 17 ) -s_jT^{n+1}_{i-1}+(1+s_j+\frac{k_{j+1}\Delta t}{c_j\rho_j\Delta x^2})T^{n+1}_{i}-\frac{k_{j+1}\Delta t}{c_j\rho_j\Delta x^2}T^{n+1}_{i+1}=T^{n}_{i}\quad(17) sjTi1n+1+(1+sj+cjρjΔx2kj+1Δt)Tin+1cjρjΔx2kj+1ΔtTi+1n+1=Tin(17)

1.2.4.1.3 边界处

− h 1 Δ t c 1 ρ 1 Δ x T e + ( 1 + s 1 + h 1 Δ t c 1 ρ 1 Δ x ) T 1 n + 1 − s 1 T 2 n + 1 = T 1 n ( 18 ) -\frac{h1\Delta t}{c_1\rho_1\Delta x}T_{e}+(1+s_1+\frac{h1\Delta t}{c_1\rho_1\Delta x})T^{n+1}_{1}-s_{1}T^{n+1}_{2}=T^{n}_{1}\quad(18) c1ρ1Δxh1ΔtTe+(1+s1+c1ρ1Δxh1Δt)T1n+1s1T2n+1=T1n(18)
− s 4 T m 4 − 1 + ( 1 + s 4 + h 2 Δ t c 4 ρ 4 Δ x ) T m 4 n + 1 − h 2 Δ t c 4 ρ 4 Δ x T r n + 1 = T m 4 n ( 19 ) -s_{4}T_{m_4-1}+(1+s_4+\frac{h2\Delta t}{c_4\rho_4\Delta x})T^{n+1}_{m_4}-\frac{h2\Delta t}{c_4\rho_4\Delta x}T^{n+1}_{r}=T^{n}_{m_4}\quad(19) s4Tm41+(1+s4+c4ρ4Δxh2Δt)Tm4n+1c4ρ4Δxh2ΔtTrn+1=Tm4n(19)
其中m4代表第4层最后一个微元
于是得到方程组:
( 1 0 0 0 ⋯ 0 − h 1 Δ t c 1 ρ 1 Δ x 1 + s 1 + h 1 Δ t c 1 ρ 1 Δ x − s 1 0 ⋯ 0 0 − s 1 1 + 2 s 1 − s 1 ⋱ ⋱ ⋱ − s 1 1 + s 1 + k 2 Δ t c 1 ρ 1 Δ x 2 − k 2 Δ t c 1 ρ 1 Δ x 2 ⋱ ⋱ ⋱ − s 4 1 + s 4 + h 2 Δ t c 4 ρ 4 Δ x − h 2 Δ t c 4 ρ 4 Δ x 1 ) ( T e T 1 n + 1 T 2 n + 1 ⋮ T m 1 n + 1 ⋮ T m 4 n + 1 T r ) = ( T e T 1 n T 2 n ⋮ T m 1 n ⋮ T m 4 n T r ) %开始数学环境 \left( %左括号 \begin{array}{cccc} %该矩阵一共3列,每一列都居中放置 1& 0& 0& 0 &\cdots& 0 \\ %第一行元素 -\frac{h1\Delta t}{c_1\rho_1\Delta x} & 1+s_1+\frac{h1\Delta t}{c_1\rho_1\Delta x} & -s_{1}& 0 &\cdots& 0 \\ 0 & -s_1& 1+2s_1& -s_1\\ &\ddots&\ddots&\ddots\\ &&-s_1& 1+s_1+\frac{k_{2}\Delta t}{c_1\rho_1\Delta x^2}& -\frac{k_{2}\Delta t}{c_1\rho_1\Delta x^2}\\ &&\ddots&\ddots&\ddots\\ &&&-s_{4}& 1+s_4+\frac{h2\Delta t}{c_4\rho_4\Delta x} & -\frac{h2\Delta t}{c_4\rho_4\Delta x} \\ &&&&&1 \end{array} \right) %右括号 \left( \begin{array}{c} T_e \\ T^{n+1}_{1}\\ T^{n+1}_{2}\\ \vdots\\ T^{n+1}_{m1}\\ \vdots\\ T^{n+1}_{m4}\\ T_r \\ \end{array} \right)= \left( \begin{array}{c} T_e \\ T^{n}_{1}\\ T^{n}_{2}\\ \vdots\\ T^{n}_{m1}\\ \vdots\\ T^{n}_{m4}\\ T_r \\ \end{array} \right) 1c1ρ1Δxh1Δt001+s1+c1ρ1Δxh1Δts10s11+2s1s100s11+s1+c1ρ1Δx2k2Δts4c1ρ1Δx2k2Δt1+s4+c4ρ4Δxh2Δt00c4ρ4Δxh2Δt1TeT1n+1T2n+1Tm1n+1Tm4n+1Tr=TeT1nT2nTm1nTm4nTr
之后不断解方程就行了

1.2.4.2 Crank-Nicholson差分格式

我本来打算讲一下这种格式的,但是我写不动了,┭┮﹏┭┮,这个其实和一般的隐式差分差不多,结果更精确。这里推荐两篇参考资料吧:文档2,文章n

1.2.5 确定热交换系数

可以遍历来寻找残差平方和最小的两个系数(最小二乘法)。
在这里插入图片描述

在这里插入图片描述


图片来源:优秀论文440

1.3 一些细节和思考

  1. 都说隐式差分稳定,可是它为什么稳定?
    拿层内的热传导来说,在显式格式中,我们根据n时刻的T推测n+1时刻的T,计算变化量 Δ T \Delta T ΔT的时候系数中有个 Δ t Δ x 2 \frac{\Delta t}{\Delta x^2} Δx2Δt,如果我们 Δ x \Delta x Δx取的特别小(相对于 Δ t \Delta t Δt来说,那 Δ T \Delta T ΔT可能会特别大,可能你算出来一个时间步长温度变化上千度。而隐式的 − s j T i − 1 n + 1 + ( 1 + 2 s j ) T i n + 1 − s j T i + 1 n + 1 = T i n -s_jT^{n+1}_{i-1}+(1+2s_j)T^{n+1}_{i}-s_{j}T^{n+1}_{i+1}=T^{n}_{i} sjTi1n+1+(1+2sj)Tin+1sjTi+1n+1=Tin 我们把这个再移一下项便得到: T i n + 1 − T i n = s j ( 2 T i n + 1 − T i + 1 n + 1 − T i − 1 n + 1 T^{n+1}_{i}-T^{n}_{i}=s_{j}(2T^{n+1}_{i}-T^{n+1}_{i+1}-T^{n+1}_{i-1} Tin+1Tin=sj(2Tin+1Ti+1n+1Ti1n+1)虽然 S j Sj Sj也可能很大,但是后面减去的T是n+1时刻的T,而这个时刻的T是未知的,我们只能通过解方程得到。
    如果 T i n + 1 T^{n+1}_{i} Tin+1特别大,那 T i + 1 n + 1 T^{n+1}_{i+1} Ti+1n+1 T i − 1 n + 1 T^{n+1}_{i-1} Ti1n+1也得特别大才能使等式成立, T i + 1 n + 1 T^{n+1}_{i+1} Ti+1n+1 T i − 1 n + 1 T^{n+1}_{i-1} Ti1n+1还存在与其他的方程中,把所有方程都考虑到的话,所有位置的n+1时刻的T都得特别大。而边界的温度是确定的,大不了,所以不会出现那种特别大的异常值。(特别小的异常值同理)

  2. 我们在模型建立部分,边界处建立的式9和交界面建立的式10虽然在任何时刻都满足但无法用差分表示,因为他们都是利用了热流密度连续的概念,一旦我们用了差分,就把连续的函数离散化了,就用不了连续的概念了(一旦认为dx不是0,那就是另一个点了,还谈何连续)(也就是说在差分方程中我们是无法表示这种左极限和右极限的)

  3. 那我们为什么能用差商代替导数?
    这个是可以根据泰勒展开证明的。这里不做详尽说明,感兴趣的同学可以阅读这篇文档。

如果我们想表示稳态时那些临界点的状态,那同层内部是一样的:热流密度的导数是0。

  1. 我们现在要建立的是非稳态方程啊,能用稳态的等式吗?
    本人认为是不能的,应该用上文我写的非稳态的等式。
  2. 为什么优秀论文A466 把稳态等式写到非稳态等式方程组中还能得到貌似正确的结果呢?
    虽然他们用的是稳态的方程,但是因为计算时用到的两个相邻节点是非稳态的,所以如果拿Tn+1与Tn比的话还是有变化的。
    我们可以计算一下用稳态的方程计算得到的 Δ T \Delta T ΔT
    T i n = k j T i − 1 n + k j + 1 T i + 1 n k j + k j + 1 (20) T^{n}_{i}=\frac{k_jT^n_{i-1}+k_{j+1}T^n_{i+1}}{k_{j}+k_{j+1}}\tag{20} Tin=kj+kj+1kjTi1n+kj+1Ti+1n(20)
    T i n + 1 = k j T i − 1 n + 1 + k j + 1 T i + 1 n + 1 k j + k j + 1 (21) T^{n+1}_{i}=\frac{k_jT^{n+1}_{i-1}+k_{j+1}T^{n+1}_{i+1}}{k_j+k_{j+1}}\tag{21} Tin+1=kj+kj+1kjTi1n+1+kj+1Ti+1n+1(21)
    T i n + 1 − T i n = k j ( T i − 1 n + 1 − T i − 1 n ) + k j + 1 ( T i + 1 n + 1 − T i + 1 n ) k j + k j + 1 ( 22 ) T^{n+1}_{i}-T^{n}_{i}=\frac{k_j(T^{n+1}_{i-1}-T^n_{i-1})+k_{j+1}(T^{n+1}_{i+1}-T^n_{i+1})}{k_j+k_{j+1}}\quad(22) Tin+1Tin=kj+kj+1kj(Ti1n+1Ti1n)+kj+1(Ti+1n+1Ti+1n)(22)
    和用非稳态的方程计算得到的 Δ T \Delta T ΔT
    − s j T i − 1 n + 1 + ( 1 + s j + k j + 1 Δ t c j ρ j Δ x 2 ) T i n + 1 − k j + 1 Δ t c j ρ j Δ x 2 T i + 1 n + 1 = T i n ( 23 ) -s_jT^{n+1}_{i-1}+(1+s_j+\frac{k_{j+1}\Delta t}{c_j\rho_j\Delta x^2})T^{n+1}_{i}-\frac{k_{j+1}\Delta t}{c_j\rho_j\Delta x^2}T^{n+1}_{i+1}=T^{n}_{i}\quad(23) sjTi1n+1+(1+sj+cjρjΔx2kj+1Δt)Tin+1cjρjΔx2kj+1ΔtTi+1n+1=Tin(23)
    z j = Δ t c j ρ j Δ x 2 z_j=\frac{\Delta t}{c_j\rho_j\Delta x^2} zj=cjρjΔx2Δt
    − s j T i − 1 n + 1 + ( 1 + s j + k j + 1 z j ) T i n + 1 − k j + 1 z j T i + 1 n + 1 = T i n ( 24 ) -s_jT^{n+1}_{i-1}+(1+s_j+k_{j+1}z_j)T^{n+1}_{i}-k_{j+1}z_jT^{n+1}_{i+1}=T^{n}_{i}\quad(24) sjTi1n+1+(1+sj+kj+1zj)Tin+1kj+1zjTi+1n+1=Tin(24)
    移项可得
    T i n + 1 − T i n = s j ( T i − 1 n − T i n ) + z i ( k 2 T i + 1 n − k 1 T i n ) ( 25 ) T^{n+1}_{i}-T^{n}_{i}=s_j(T^{n}_{i-1}-T^{n}_{i})+z_i(k_2T^{n}_{i+1}-k_1T^{n}_{i})\quad(25) Tin+1Tin=sj(Ti1nTin)+zi(k2Ti+1nk1Tin)(25)
    对比式22与式25我们发现等式右侧一个是时间上的差,一个是空间上的差,即使把式22转换成空间上的差,与式25还是有差别,至于这个差别对结果的影响,我还不清楚。如果有路过的大侠清楚的话,还请跟我讲讲。

2 第二问

单目标单变量优化问题
因为温度与 II 层厚度负相关,所以可以用二分法或者直接遍历

3 第三问

让你确定II层和IV层的最优厚度
厚度怎样是最优?
当然越薄越好了
但是这两层都是起到隔热作用的,想达到一样的隔热效果,一个变薄另一个就得增厚,所以两者的厚度负相关
从经济角度来考虑的话,IV是空气不要钱,所以我们让IV层尽量厚,那ii层就会尽量薄。
所以IV的厚度已经确定了:最厚的6.4mm(从舒适度来说的话,6.4也不是太厚)
所以这问还是个单目标单变量优化问题。
解题方法和第二问一样

这两问比较简单我就不附代码了。

4 代码

4.1 显式差分

4.1.1 c++计算

#include
#include
using namespace std;

const float dt=0.002;
float dx[]={
     0.1,1,0.6,1};
float thickness[]={
     0.6, 6, 3.6, 5};
const float density[]={
     300,862,74.2,1.18};
const float c[]={
     1377,2100,1726,1005};
const float k[]={
     0.082,0.37,0.045,0.028};

const int n= 100;//大于空间上分的块数就行
const int r_num=5400;//真实数据的个数
int num;//空间上分的块数
float u[n],u_old[n],u_skin[r_num];
float u_data[r_num]={
     "使用下面python代码中get_data输出的数据"};
float get_dT(float u1,float u2,float u3,float dx1,float dx2,float c1,float density1,float k1,float k2)
{
     
    return ((u1*k1-u2*k1)/dx1+(u3*k2-u2*k2)/dx2)/(0.5*(dx1+dx2)*c1*density1);
}

void print_skin(int upper_bound,int num)
{
     
    printf("[");
    for(int i=upper_bound-num;i<upper_bound;i++)
    {
     
        if(u_skin[i]<0.1)
        break;
        printf("%.2f,",u_skin[i]);
        
    }
    printf("]");
}
void print_u()
{
     
    printf("[");
    for(int i=0;i<num-1;i++)
    {
     
        printf("%.8f,",u[i]);
    }
    printf("%.8f",u[num-1]);
    printf("]");
}
pair<int,int > get_j_type(int i);
void init()
{
     
    for(int i=0;i<4;i++)
    {
       
        thickness[i]=thickness[i]*0.001;
        dx[i]=dx[i]*0.001;
       
    }

}
void work(float envir_T,float person_T,float h1,float h2,float total_time)
{
     
    num=0;
    for(int i=0;i<4;i++)
    {
       
        num+=thickness[i]/dx[i];
    }
    num+=2;//加上两个边界
    int counter=0;
    u[0]=envir_T;
    u[num-1]=person_T;
    for(int i=1;i<num-1;i++)
    {
     
        u[i]=37;//初始化
    }
    float c1,density1,k1,k2,dx1,dx2,dT;
    int j,type;
    pair<int ,int >pair1;
    int one_second_num=round(1/dt);
    for(int t=1;t<=total_time*one_second_num;t++)
    {
     
        
        for(int i=0;i<num;i++)
            u_old[i]=u[i];
        for(int i=1;i<num-1;i++)
        {
     
            pair1= get_j_type(i);
            j=pair1.first,type=pair1.second;
            dx1=dx[j],density1=density[j],c1=c[j],k1=k[j];
            if (type==1)
            dx2=dx[j+1],k2=k[j+1];
            else
            dx2=dx1,k2=k1;
            
            if (i==1)//与环境的边界
            dT=(h1*(u_old[0]-u_old[1])-k1*(u_old[1]-u_old[2])/(dx1))/(density1*c1*dx1);
            else if (i==num-2 )//与皮肤的边界
            dT=(-h2*(u_old[num-2]-u_old[num-1])+k1*(u_old[num-3]-u_old[num-2])/dx1)/(density1*c1*dx1);
            else
            dT= get_dT(u_old[i - 1], u_old[i], u_old[i + 1], dx1,dx2 , c1, density1, k1, k2);
           
    
            u[i] = u_old[i] + dt * dT;
          
            if (u[i] > u[0] || u[i] < 0)
            {
     
                cout<<"h1  "<<h1<<"  h2  "<<h2<<endl;
                cout<<"j: "<<j<<endl;
                cout<<"thickness: "<<thickness[j]<<endl;
                cout<<"i: "<<i<<endl;
                cout<<"u[i] "<<u[i]<<endl;
                printf("overflow!!!!!!!!!!!!!!");
                exit(1);
            }
            if (i==num-2  && t%one_second_num==0)//每1s记录一下皮肤外侧温度
            {
     
                int temp=t/one_second_num-1;
                u_skin[temp]=u[i];
            }
        }
    }
}
pair<int ,int > get_j_type(int i)
{
     
    int j=-1,type=-1;
    
    int area = round(thickness[0]/dx[0]);
    for(int k=0;k<4;k++)
    {
     

        if (i <= area)
        {
     
            j=k;
            type=0; //type=0表示在层间
            if (i == area)
                type=1; //type=1表示在交界面
           break;
        }
        else if (k<3) //防止下标越界
            area = area + round(thickness[k + 1] / dx[k+1]);
    }
    return make_pair(j,type);
}
void  least_square(float &h1,float &h2 ,int total_time)
{
     
    float r,min_r=1e25;

    for(float i=104;i<115;i+=1)
    {
     
        for(float j=8;j<8.4;j+=0.1)
        {
     
            work(75,37,i,j,total_time);
            r=0;
            for(int k=0;k<r_num;k++)
            {
     
                if(u_skin[k]<0.1)
                break;
                r+=(u_skin[k]-u_data[k])*(u_skin[k]-u_data[k]);//残差平方和
            }
            if (r<min_r)
            {
     
                min_r=r;
                h1=i;
                h2=j;
            }

        }
    }
    cout<<"min_r  "<<min_r<<endl;
}
float get_errors(float h1,float h2,int total_time)
{
     
    work(75,37,h1,h2,total_time);
    float r=0;
    for(int k=0;k<r_num;k++)
    {
     
        if(u_skin[k]<0.1)
        break;
        r+=(u_skin[k]-u_data[k])*(u_skin[k]-u_data[k]);
    }
    return r;
}

int main()
{
     
    init();
    int total_time=5400;//显式差分误差稍微有点大,这里需要用全部的数据做拟合
    --------- 拟合
    // float h1,h2;
    // least_square(h1,h2,total_time);
    // cout<<"h1  "<
    cout<<get_errors(106,8.2,total_time)<<endl;
    print_skin(total_time,10);//如果要输出所有时刻的的皮肤外侧温度数据,就把这个10改成total_time
}

求解结果:
残差平方和:5.74285
h1=106 h2=8.2

4.1.2 python画图

import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

def get_data(num):
    path=r"路径.xlsx"
    data = pd.read_excel(io=path,sheet_name= '附件2',skiprows = [0],dtype=float)
    v=data.values
    u_data=v[0:num,1]
    print("{",end='')
    for i in u_data:
        print(i,end=',')
    print("};",end='')
    return u_data

if __name__ == "__main__":
    plt.rcParams['font.sans-serif'] = ['SimHei']
    data=get_data(5400)
    plt.plot(np.linspace(1, len(data), len(data)), data, 'r-',label='真实数据')
    u_skin=["把c++算完后的数据拷贝过来!!!"]
    plt.plot(np.linspace(1, len(u_skin), len(u_skin)), u_skin, 'b.',label='模拟数据')

    plt.xlabel('t/s')
    plt.ylabel('T/℃')
    plt.legend()
    plt.show()

结果图:
18国赛A题 详解 附一维多层材料非稳态热传导数值解 maltab,c++结合python 代码_第5张图片

4.2 经典隐式差分(matlab)

clc
clear

global dt,global dx,global Te,global Tr,global N;
global c,global density,global k, global s,global thickness;
global data,global u_skin;

dt=1;%时间步长 
dx=0.1*0.001; %空间步长
Te=75;Tr=37;

c=[1377,2100,1726,1005]; %比热容
density=[300,862,74.2,1.18];%密度
k=[0.082,0.37,0.045,0.028];
thickness=[0.6, 6, 3.6, 5];
s=zeros(1,4);

for i =1:4
   thickness(i)=thickness(i)*0.001;
end
for j =1:4
    s(j)=(dt*k(j))/(c(j)*density(j)*dx*dx);
end

num=round(5400)/dt;
u_skin=zeros(num,1);%不同时刻皮肤外侧温度
N=round(sum(thickness)/dx+2);
data = xlsread('appendix.xlsx',2,'B3:B5402');
u_skin(1801:end)=data(1801:end);
% [h1,h2]=least_squares()

work(106,8.36);

plot(1:num,data,'r')
hold on;
plot(1:num,u_skin,'b-.')
legend('真实数据','模拟数据')
ylabel('T/℃')
xlabel('t/s')



function work(h1,h2)
global N,global Te,global Tr,global dt,global dx,global u_skin;
global c,global density,global k, global s;

u_now=zeros(N,1);
u_next=zeros(N,1);%下一时刻每个位置的温度
u_now(2:end)=Tr;
u_now(1)=Te;u_now(N)=Tr;

A=zeros(N,N);
A(1,1)=1;
A(N,N)=1;

A(2,1)=-(h1*dt)/(c(1)*density(1)*dx);
A(2,2)=1+s(1)+(h1*dt)/(c(1)*density(1)*dx);
A(2,3)=-s(1);

A(N-1,N-2)=-s(4);
A(N-1,N-1)=1+s(4)+(h2*dt)/(c(4)*density(4)*dx);
A(N-1,N)=-(h2*dt)/(c(4)*density(4)*dx);

for i =3:N-2
    [j,type]=get_j_type(i);
    if type==0 %层内
        A(i,i-1)=-s(j);
        A(i,i)=1+2*s(j);
        A(i,i+1)=-s(j);
    else %交界面
        A(i,i-1)=-s(j);
        A(i,i)=1+s(j)+(dt*k(j+1))/(c(j)*density(j)*dx*dx);
        A(i,i+1)=-(dt*k(j+1))/(c(j)*density(j)*dx*dx);
    end    
end
total_time=1800;
for i = 1:round(total_time/dt)
    u_next(:)=A\u_now;
    u_now(:)=u_next;
    u_skin(i)=u_now(N-1);
end

% u_now(N-1)
end
function [j,type] = get_j_type(i)
    global thickness;global dx; 
    
    area = round(thickness(1) / dx);
    for k=1:4
        if i-1 <= area
            j=k;
            type=0; %type=0表示在层间
            if i-1==area
                type=1; %type=1表示在交界面
            end
            return 
        elseif k<=3 %防止下标越界
            area = area + round(thickness(k + 1) / dx);
        end
    end       
end
function [h1,h2] = least_squares()%最小二乘法
    global data,global u_skin;
    mini=100000000;  %最小残差平方和  
    for i=105:0.2:107
           for j=8.3:0.02:8.4
                work(i,j);
                u_skin2=u_skin(1:1800);%隐式差分比较精确,且1800s已稳定,所以只算前1800s
                data2=data(1:1800);
                error=(u_skin2-data2)'*(u_skin2-data2);
                if error<mini
                    mini=error;
                    h1=i;
                    h2=j;
                end
            end
    end
    mini   
end

求解结果:
残差平方和: 0.053506
h1=106 h2=8.36

18国赛A题 详解 附一维多层材料非稳态热传导数值解 maltab,c++结合python 代码_第6张图片

你可能感兴趣的:(数模,数学建模)