20.9.23 update:我写公式编号用的是\tag{编号},我找了半天也没找到其他方式来可以实现自动右对齐的编号。这么写会导致:有些比较长的公式的编号在手机上会显示在公式中间,而不是公式最后(在电脑的网页上是正常的)。于是我就把那些公式的编号直接写在了公式的后面而不是用tag,这样一来就会有些公式的编号没对齐,还请各位见谅。如果你有解决手机上长公式编号显示问题的更好的办法,还请不吝赐教。
不要被文中的一坨坨公式给吓倒了,耐心仔细分析一下也不难的。
解题过程中我读过的所有有价值的参考资料在文中都有可以直接打开的链接(无需/登录付费论文网站)。
有不懂或不对的地方->评论区留言
现在带着大家elegantly(优雅地)走一遍建模过程。
开赛
选题
经过短暂的商讨,虽然都没有学过热学,但你们一致决定选A题,并决心死也要死在A题上!
搜索一下传热学
从百度百科 传热学得知:
传热的基本方式有热传导、热对流和热辐射三种。
因为本题涉及的材料的热辐射都很小,所以可忽略,即假设所有材料和人体都为绝对黑体。
热传导肯定是大头,那用不用考虑热对流呢?
还在刚才的百科界面我们看到:
热对流是指不同温度的流体各部分由相对运动引起的热量交换。工程上广泛遇到的
对流换热
,是指流体与其接触的固体壁面之间的换热过程,它是热传导和热对流综合作用的结果。
这个对流换热貌似和我们这题的:衣服和外界,衣服与皮肤的传热比较相似。(这里把空气层也算入衣服)
顺对流换热的藤摸牛顿的瓜,发现
对流换热的强度依据牛顿冷却定律,其基本计算公式是:
q = h ( T w − T f ) (1) q=h(T_w-T_f)\tag{1} q=h(Tw−Tf)(1)
式中q为单位面积的固体表面与流体之间在单位时间内交换的热量,称作热流密度;TW、Tf分别为固体表面和流体的温度;h称为传热系数,它表示在单位面积的固体表面上,当流体与固体表面之间的温度差为1K时,每单位时间内所传递的热量。h的大小反映对流换热的强弱,它与影响换热过程的诸因素有关,并且可以在很大的范围内变化。
搜索一下热传导
在百度百科 热传导发现
有傅里叶定律和热扩散方程(三维非稳态热传导)
关于傅里叶方程这篇博文公式表述的比较清楚
它的一般表示形式是:
q = − k ∇ T (2) q=−k∇T \tag{2} q=−k∇T(2)
∇T可表示为 ∂ T ∂ n \frac{\partial T}{\partial n} ∂n∂T
其中
q 是热流密度,是单位面积上的热通量, W ⋅ m − 2 W⋅m^{−2} W⋅m−2( W W W可替换成: J ⋅ s − 1 J\cdot s^{-1} J⋅s−1)
k是材料的热传导系数, W ⋅ m − 1 ⋅ K − 1 W⋅m^{−1}⋅K^{−1} W⋅m−1⋅K−1
∇T 是温度梯度, K ⋅ m − 1 K⋅m^{−1} K⋅m−1
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} W⋅m−2x是长度, m
知道了这些后,理论上我们已经可以手动推导出一维的热传导方程了。
但我们不想手动推导,搜的话,我着实搜不到比较好的文章,那我们就利用一下那个热扩散方程吧。
∂ 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} ∂t∂T=cρk(∂x2∂2T+∂y2∂2T+∂z2∂2T)(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} ∂t∂T=cρk∂x2∂2T(5)
然而这只是每层材料内部的温度变化规律
首先我们来介绍一下传热学定解问题的三类边界条件(分别对应于微分方程定解问题的三类边界条件)
第一类边界条件(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 Γ表示边界
第二类边界条件(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} ∂n∂T∣∣∣∣(x,y,z)∈Γ=f(x,y,z,t)(8)
第三类边界条件(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} −k∂n∂T=h(Tw−T0)(9)
其中 T w T_w Tw为物体边界边界温度
注意第二类与第三类的区别,第二类右侧的函数是已知的,而第三类的 T w T_w Tw是不断变化的,且变化规律是需要你去计算的。
显然这道题是第三类边界条件。
我们可以把整个衣服(包括空气层)当作一个整体,那衣服与外界,衣服与人体就有两个交界面,也就会有两个热交换系数,这两个都是需要通过与附件的温度数据进行拟合计算得到的。(实际上我们应该区分开空气层和衣服,也就是说空气层与第3层之间应该也有一个交换系数,但是为了简化,就按照它们两者之间只有热传导处理了)
关于边界条件如果还有不清楚的可以看这两个课件:课件1,课件2
根据能量守恒定律,每层材料的交界面处热流密度应是连续的
(当然温度也是连续的: 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(∂x∂T)−=kj+1(∂x∂T)+(10)
其中j表示第j层
至此我们已经分析完所有位置的传热情况了
你可像这样罗列出来:
(图中的 λ \lambda λ对应于本文的k)
(图中的公式其实不太严谨,但我懒得再打一遍了,看一下这种形式就好)
求解这类偏微分方程问题可以通过有限差分法得数值解或者设出稳定时每层温度关于x的函数,联立等式得到解析解。
差分比较好理解了,就是把时间和空间都离散化,然后一点点地递推。
差分法有显式差分和隐式差分。
关于这两种差分的区别建议先阅读文档1,再阅读文档2.
解析解可查看官方题解,这里不详细讨论。(官方题解在计算方法部分的等式,你可能觉得很weird(奇怪),那因为他写的是隐式差分的格式,但是上标比较奇怪,对于这种题我们一般用n时刻推n+1时刻,而他用的n-1时刻推n时刻)
把式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+1−Tin=cjρjkjΔxj2Ti+1n−2Tin+Ti−1n(11)
其中上标为n的表示n时刻的T,是已知的,n+1时刻的T是我们所要求的,下标i表示空间离散后的第i个点,j表示属于第j层
想要知道交界面在时间上的变化量,我们就得清楚到底是什么引起的温度的变化?
热流密度在空间上的变化!
我们可以从宏观上理解一下:试想一下如果一个物体左侧温度突然上升了,那么左侧温度梯度就会增大,热流密度也会增大,而右侧热流密度没变,左边进热的速度大于右边排热的速度,那温度必然得上升了。
这时候你可能会想,那如果右侧温度突然下降了,右侧热流密度也变大了,那温度是不是就不变了?
如果物体是一个点的话确实是的,温度一直是 ( 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} ∂t∂T=cρΔxkjpx−21Δx−kj+1px−21Δ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+1−Tin=kjΔxjTi−1n−Tin+kj+1Δxj+1Ti+1n−Tin(13)
c和 ρ \rho ρ可以设成左边的或者右边的,或者(左边+右边)/2
思路和交界面处一样,只不过一侧的热流密度的表达形式换成了 h ( T w − T 0 ) h(T_w-T_0) h(Tw−T0)
差分格式为:
显式差分可能是不稳定的,需要选择合适的时间步长和空间步长,大小不是关键,他们两者的比例是关键的。
比如这道题需要满足: 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才稳定,我还没去研究。
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+1−Tin=sjTi−1n−2sjTin+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.2小节的差分方程等式右侧的 T n T^n Tn替换成 T n + 1 T^{n+1} Tn+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+1−Tin=cjρjkjΔx2Ti+1n+1−2Tin+1+Ti−1n+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) −sjTi−1n+1+(1+2sj)Tin+1−sjTi+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为某一固定值
− 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) −sjTi−1n+1+(1+sj+cjρjΔx2kj+1Δt)Tin+1−cjρjΔx2kj+1ΔtTi+1n+1=Tin(17)
− 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+1−s1T2n+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) −s4Tm4−1+(1+s4+c4ρ4Δxh2Δt)Tm4n+1−c4ρ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) ⎝⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎛1−c1ρ1Δxh1Δt001+s1+c1ρ1Δxh1Δt−s1⋱0−s11+2s1⋱−s1⋱00−s1⋱1+s1+c1ρ1Δx2k2Δt⋱−s4⋯⋯−c1ρ1Δx2k2Δt⋱1+s4+c4ρ4Δxh2Δt00−c4ρ4Δxh2Δt1⎠⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎞⎝⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎛TeT1n+1T2n+1⋮Tm1n+1⋮Tm4n+1Tr⎠⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎞=⎝⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎜⎛TeT1nT2n⋮Tm1n⋮Tm4nTr⎠⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎟⎞
之后不断解方程就行了
我本来打算讲一下这种格式的,但是我写不动了,┭┮﹏┭┮,这个其实和一般的隐式差分差不多,结果更精确。这里推荐两篇参考资料吧:文档2,文章n
都说隐式差分稳定,可是它为什么稳定?
拿层内的热传导来说,在显式格式中,我们根据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} −sjTi−1n+1+(1+2sj)Tin+1−sjTi+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+1−Tin=sj(2Tin+1−Ti+1n+1−Ti−1n+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} Ti−1n+1也得特别大才能使等式成立, T i + 1 n + 1 T^{n+1}_{i+1} Ti+1n+1和 T i − 1 n + 1 T^{n+1}_{i-1} Ti−1n+1还存在与其他的方程中,把所有方程都考虑到的话,所有位置的n+1时刻的T都得特别大。而边界的温度是确定的,大不了,所以不会出现那种特别大的异常值。(特别小的异常值同理)
我们在模型建立部分,边界处建立的式9和交界面建立的式10虽然在任何时刻都满足但无法用差分表示,因为他们都是利用了热流密度连续的概念,一旦我们用了差分,就把连续的函数离散化了,就用不了连续的概念了(一旦认为dx不是0,那就是另一个点了,还谈何连续)(也就是说在差分方程中我们是无法表示这种左极限和右极限的)
那我们为什么能用差商代替导数?
这个是可以根据泰勒展开证明的。这里不做详尽说明,感兴趣的同学可以阅读这篇文档。
如果我们想表示稳态时那些临界点的状态,那同层内部是一样的:热流密度的导数是0。
单目标单变量优化问题
因为温度与 II 层厚度负相关,所以可以用二分法或者直接遍历
让你确定II层和IV层的最优厚度
厚度怎样是最优?
当然越薄越好了
但是这两层都是起到隔热作用的,想达到一样的隔热效果,一个变薄另一个就得增厚,所以两者的厚度负相关
从经济角度来考虑的话,IV是空气不要钱,所以我们让IV层尽量厚,那ii层就会尽量薄。
所以IV的厚度已经确定了:最厚的6.4mm(从舒适度来说的话,6.4也不是太厚)
所以这问还是个单目标单变量优化问题。
解题方法和第二问一样
这两问比较简单我就不附代码了。
#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
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()
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