说实话,第一眼看到2026年MCM美赛E题的题目“被动式太阳能遮阳”时,我脑子里冒出的不是方程和代码,而是“这不就是我夏天在办公室靠窗帘避暑的那点事吗”。但当你真把它当成一道数学建模题去拆,会发现这题其实藏得很深:它既需要你建立太阳辐射的物理模型,又需要你设计合理的评价指标去优化遮阳方案,最后还要把工程经济学、建筑热工、甚至“美观”这种软指标拉进来做权衡。E题从来不是拼谁公式写得漂亮,而是拼谁能在有限时间内把一套“可解释、可复现、有决策价值”的建模流程跑完。这篇文章我打算把思路、核心代码和论文骨架都摊开来说,后面随着赛程进展也会持续更新实操细节,你只要跟着这个框架走,至少不会在开头阶段浪费两天。
1. 先弄明白E题到底想让你干什么
1.1 被动式 vs 主动式:这道题真正在问什么
建筑领域把遮阳分成两大类:主动式是电机驱动的百叶、追踪式光伏板、智能调光玻璃这类的玩电设备;被动式则是那些你装上去就再也不管它的东西——屋檐、遮阳板、竖向鳍片、固定百叶、雨篷,甚至种一棵落叶树都算。E题既然明说“被动式”,就意味着你要研究的对象在生命周期内是“死”的,它不会根据天气自动调整姿态。这样一来,问题的本质就变成了:在给定建筑朝向、气候条件和使用需求下,找到一组静态几何参数,让全年的遮阳效果达到某种最优平衡。
但这个“平衡”最微妙之处在于,建筑物不是只需要夏天防晒。冬天你反而希望阳光多晒进来一些,减少采暖能耗。同一块遮阳板,夏天它帮你挡住烈日,到了冬天它也会挡住好不容易升到低空的暖阳。于是你面对的是标准的“两个相互打架的目标”——夏季降温和冬季得热。这还不算完,评委很可能还会让你考虑自然采光、眩光风险、通风视线、造价成本。记住,MCM的E题本质是“综合应用题”,它考察的不是你能否记住某个热力学公式,而是你能不能把一个真实的工程问题抽象成一套决策模型,并让评委相信你的结论在物理上站得住脚。
1.2 建模目标拆解:从“遮阳”到“能源、舒适、成本”三层结构
很多队拿到E题第一反应是“我赶紧去算太阳高度角”。这没错,但容易陷入“用80%时间建模、20%时间解决问题”的陷阱。我建议你一开始就把目标拆成三层:
- 物理层:模拟太阳位置、直射辐射与散射辐射,计算透过遮阳构件进入窗户的辐射量。这是所有工作的地基。
- 性能层:把辐射结果转化为能耗(制冷/供暖负荷)、热舒适(室内温度波动)、视觉舒适(眩光概率、采光均匀度)。
- 决策层:在性能基础上加入成本、施工复杂度、维护周期、甚至建筑外观,进行多目标优化和方案的比较权衡。
很多团队在物理层就迷路了,搞了一堆复杂的辐射传递方程,到头来决策层只是简单加权。其实更好的思路是反过来:先想清楚你最终要回答什么问题,再决定物理层需要多精细。比如,如果题目只让你比较“水平挑檐”和“垂直翼板”谁在某个城市表现更好,那你的物理模型完全可以用小时步长的太阳几何加上简化传热模型,没必要上CFD。相反,如果题目让你设计一套全自动多参数优化方案,那物理模型的速度就必须快,宁可牺牲一点精度也要保证能在合理时间内跑完上万次模拟。这就是建模里的“奥卡姆剃刀”——简单粗暴但够用,永远好过精确却跑不动。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据准备与技术假设:开工前的物料清单
2.1 气象数据从哪找,怎么整理成模型输入
做被动式太阳能遮阳,没有气象数据你寸步难行。你至少需要目标城市的全年逐时太阳辐射(直射、散射)、干球温度、湿度,以及经纬度和时区。公开渠道我最推荐以下几个:
- NSRDB(National Solar Radiation Database):美国能源部出品,提供全球覆盖的逐时太阳辐射数据,可以直接按经纬度拉取。
- NASA POWER API:最省事,注册后直接在网页上选坐标、时间范围,导出CSV,包含温度、辐射、湿度等常用气象要素。
- EnergyPlus Weather File(EPW):如果你的题目给定了具体城市,直接去EPW官网下载该城市的典型气象年数据。EPW里面不仅有气象要素,还带位置、时区、海拔,省去手动填一堆常数的麻烦。
拿到数据后别急着塞进模型。先做三件小事:第一,检查有没有缺测值,简单用前后线性插值补掉;第二,统一单位。常见坑是有些数据给的是Wh/m²,有些是MJ/m²,你要全部换成W/m²或者kW·h/m²,否则后面计算太阳得热会差3.6倍;第三,给每天标上“第几天”,后面算太阳赤纬角要用的。如果你选的是“典型气象年”,那数据的年份往往是虚构的,别在论文里纠结“哪一年”,只说“基于典型气象年数据即可”。
2.2 建筑几何与材料参数:定义你的“研究对象”
你需要从题目描述里抠出研究对象的具体信息,如果没有给,就别问,自己设定一个合理的典型房间模型。我常用的配置如下:
- 一个朝正南的房间,面积4m×4m,层高2.8m。
- 南墙开一扇1.5m×1.5m的窗户,窗台高0.9m。
- 遮阳构件可选:水平挑檐(深度可调)、垂直翼板(间距和深度可调)、固定百叶(倾角可调)。
- 墙体传热系数假设为符合一般规范的值,比如240mm实心砖墙,传热系数约1.8 W/(m²·K)。窗户为双层中空玻璃,传热系数2.5 W/(m²·K),太阳能得热系数(SHGC)0.6。
这些参数并不要求很精确,但一定要把假设写清楚。评委最反感的是你默默用了一个非常特殊的参数却不解释来历。你可以找一两个权威建筑节能规范来背书,例如“参考GB 50176-2016民用建筑热工设计规范设定围护结构传热系数”之类,这样在论文里就算有出处。
2.3 我做假设时常用的一套路子
数学建模离不开假设,但很多人把假设写得像免责声明,一条条“假定天气稳定”、“假定材料均匀”,读起来味同嚼蜡。我的习惯是围绕“这个假设会带来多大误差”来写。比如:
- 假设窗户朝向固定为正南:由于太阳能资源主要来自南向,正南朝向能最大化冬季得热,且避免干扰变量,方便对比不同遮阳方案。在敏感性分析中,我会补充朝向偏移15°和30°的影响,证明结论稳健。
- 假设遮阳构件表面不透光:实际挑檐、翼板总会有一定透过率,但常规建材多为不透明材质,此假设对直射辐射计算影响小于5%。
- 假设室内温度维持恒温(例如空调设定25℃):这样就把复杂的热平衡简化为对辐射得热的响应,便于计算“额外制冷负荷”。如果题目要求考虑自然通风,则需要扩展开窗模型,但这会让求解难度陡增。
给你的建议是:前期先用简单假设把模型跑通,如果时间充裕,再逐步放松假设。这比一上来就建一个“全耦合动态热模型”然后卡在方程上强得多。
3. 太阳几何与遮阳性能模拟:第一个能运行的模型
3.1 太阳高度角、方位角计算原理
所有遮阳计算的地基是太阳位置。你不需要懂天文历法,只需要记住几个标准公式。算法是基于“平太阳时”与真太阳时的差异:
-
赤纬角(declination),用库珀公式(Cooper,1969)近似:
δ = 23.45° · sin( 360° × (284 + n) / 365 )
其中 n 是距1月1日已经过去的天数(0~364)。 -
太阳时角 H:
H = 15° × (当地太阳时 - 12)
当地太阳时 = 标准时间 + 经度修正 + 时差方程修正。为了简化,忽略时差方程,但你有本事别懒,因为题目不会因为你在公式里少一项就给你扣分,但会让你的模拟出现巨大偏差。时差方程 B = 360° × (n - 81) / 364,在一天内误差可达15分钟,太阳位置也会偏几度。正经代码还是要带上。 -
太阳高度角 α:
sin α = sin φ · sin δ + cos φ · cos δ · cos H
φ 是纬度。 -
太阳方位角 γ_s(从正南出发,向西为正或从正北顺时针,不同资料定义不一样,别搞混):
sin γ_s = - cos δ · sin H / cos α
这个公式有象限歧义,用 atan2 处理比较稳妥。我建议直接用标准的SPA算法简化版:γ_s = atan2( sin H, cos H · sin φ - tan δ · cos φ ),注意正负和零度方向。
3.2 遮阳构件遮挡效果与辐射透过率
有了太阳高度角和方位角,下一步判断某个遮阳构件是否遮挡了窗户。以水平挑檐为例,它像一个“帽檐”一样伸在南窗上方。判断逻辑如下:
- 挑檐深度为 D,挑檐离窗户顶部的垂直高度为 G(挑檐底面到窗顶的距离)。
- 在某个时刻,太阳高度角为 α,方位角为 γ_s,窗户朝向为 γ_w(南向为0,东向为-90,西向为90)。
- 从窗户上边缘出发,挑檐外沿与窗户上边缘连线的竖切面与太阳方向交角。如果太阳高度角升到一定值,挑檐外沿的影子在窗面上,挡住部分太阳光。
简化二维判断:太阳光线在垂直断面上的投影,其入射角可以通过高度角以及太阳相对窗户表面法线的方位夹角来计算。对于水平挑檐,定义“阴影深度比”:
SDO = (1 - tan α / (D / (G + H_window))) × ...
听起来有点绕,我更推荐用几何向量法:把挑檐外沿三维坐标、窗户四个角点坐标都算出来,用光线向量与窗户平面的交点来判断是否落在窗户矩形内。这样代码可读性更好,也方便扩展到竖向翼板、百叶。
关键物理量是直射辐射透过率:当有遮阳物遮挡某一部分窗户,只有未被遮挡的面积能透过直射辐射。近似地,透过率 = 未被遮挡面积 / 窗户总面积。散射辐射可以认为与遮挡关系不大,用天空各向同性模型,对天空视角系数折减。你得把直射和散射分开处理,因为它们的遮阳逻辑完全不一样。
3.3 Python示例代码:从日期经纬度到动态遮阳系数
我先给一段能直接跑太阳位置计算的示例代码,基于numpy和pandas。这段代码会输出该天的太阳高度角和方位角,并进一步计算一个简单水平挑檐对窗户的直射阴影覆盖率。
python复制import numpy as np
import pandas as pd
from datetime import datetime, timedelta
def solar_position(lat, lon, year, month, day, hour_utc, minute=0):
"""
计算太阳高度角和方位角(从正北顺时针)
输入:纬度(deg), 经度(deg), 日期, 小时(UTC)
输出:高度角(deg), 方位角(deg)
"""
# 儒略日
dt = datetime(year, month, day, hour_utc, minute)
n = dt.timetuple().tm_yday - 1 # 天数,1月1日为0
B = 2 * np.pi * (n - 81) / 364
EoT = 9.87 * np.sin(2*B) - 7.53 * np.cos(B) - 1.5 * np.sin(B) # 时差(分钟)
# 经度修正:UTC坐标与当地经度
local_solar_time = hour_utc + lon / 15.0 + EoT / 60.0
sin_LST = local_solar_time - 12.0
H = sin_LST * 15.0 # 时角(deg)
# 赤纬角
delta_deg = 23.45 * np.sin(2 * np.pi * (284 + n) / 365)
delta = np.deg2rad(delta_deg)
phi = np.deg2rad(lat)
omega = np.deg2rad(H)
# 高度角
sin_alpha = np.sin(phi) * np.sin(delta) + np.cos(phi) * np.cos(delta) * np.cos(omega)
alpha_deg = np.rad2deg(np.arcsin(sin_alpha))
# 方位角(从正北顺时针)
cos_gamma = (np.sin(delta) - sin_alpha * np.sin(phi)) / (np.cos(alpha_deg) * np.cos(phi))
cos_gamma = np.clip(cos_gamma, -1, 1)
gamma_deg = np.rad2deg(np.arccos(cos_gamma))
# 判断下午还是上午(以太阳时12点为界)
if H > 0: # 下午
gamma_deg = 360 - gamma_deg
return alpha_deg, gamma_deg
接着是水平挑檐阴影覆盖率。假设窗宽 W,窗高 H,挑檐深度 D,挑檐底面到窗顶距离 G。
python复制def horizontal_overhang_coverage(alpha, gamma, window_width, window_height, overhang_depth, gap):
"""
计算水平挑檐在某时刻遮挡窗户直射光的面积比例
简化:只考虑几何投影,忽略透射率
"""
if alpha <= 0:
return 0.0
# 太阳在窗户法线方向的横向投影
# 默认窗户朝南,正南方向为方位角180度左右(从北顺时针)
# 我们把太阳方位角转成与南向的夹角
# 注意:gamma是从正北顺时针,南向是180度。
# 太阳从东边来时,相对于南向的夹角是负的。
south_angle = 180.0
diff = gamma - south_angle # 东为正?西为负?自己确认
# 小于一定角度才能照到正面,这里只考虑正面
if abs(diff) > 90:
return 0.0
# 挑檐外沿与窗顶形成的阴影长度在竖直方向上的投影
# 阴影从窗顶向下延伸的长度 = (D) * tan(alpha) - G
shadow_ver = (overhang_depth * np.tan(np.deg2rad(alpha))) - gap
shadow_ver = max(0, min(shadow_ver, window_height))
# 考虑横向偏移对有效遮阳宽度的影响,这里简化计算
shadow_frac = shadow_ver / window_height
return shadow_frac
这个代码能直接算出一个挑檐在任意时刻“遮了多少直射比例”。把这套逻辑套到全年8760小时上,就能得到全年逐时的遮阳效率曲线。你只需要调用一次气象数据,把每个小时的高度角、方位角算出来,再乘对应的辐射强度。如果你需要更精细的结果,可以改进横向阴影分布,但作为起步,这已经足够让你画出有说服力的图表。
注意,我还没有加入“室内得热”或“能耗”计算,但这步完成后,你已经有了最核心的物理量——逐时得热削减比例。有了它,后面做优化就只剩堆指标了。
4. 多目标评价与优化:怎么让模型回答“在哪装什么最划算”
4.1 评价指标体系:能耗、热舒适、视觉舒适
把全年8760小时的太阳辐射和遮阳系数算出来后,下一步就是定义“好”的标准。我强烈建议你从三个维度构建指标:
-
能耗指标:全年空调制冷负荷 = 夏季(例如5-9月)进入室内的太阳辐射得热累加值。冬季采暖负荷则与冬季得热相关,但这个简化模型没考虑墙体传导和内部得热,所以更严谨的做法是用“等效减少的制冷负荷 / 增加的采暖负荷”来评估。你可以把制冷负荷近似为:夏季每kW·h太阳辐射得热相当于某固定制冷系数的耗电量,但这样可能有点绝对,最好是用软件模拟(比如EnergyPlus)来标定,但比赛时间有限,做不到就简化说明。
-
热舒适指标:可以考虑室内温度波动范围,简化成夏季小时平均辐射得热超过某阈值的累计时长。你还可以定义“过热小时数”,即太阳得热大于某个舒适上限的小时数。
-
视觉舒适指标:这是容易被忽略的加分点。遮阳不能完全把窗户挡死,否则自然采光全没了。你可以计算全年日照时间中,窗户的采光系数(简化就是透过遮阳后的可见光透射率)平均值,以及眩光概率。眩光概率可以用“窗户亮度超过某阈值”来近似,虽然粗糙,但在建模里作为相对比较足够了。
然后把这几个指标归一化到0-1,加权求和得到一个综合得分。权重可以用层次分析法或熵权法,不需要多么高端,关键是要能自圆其说,说明为什么夏季能耗权重比采光权重更高。
4.2 优化思路:枚举、启发式、代理模型
你确定了决策变量(挑檐深度、离窗高度、翼板倾角、百叶遮阳系数等)和目标函数(综合得分),现在要搜索最优解。可选方法很多,我按实现难度给个清单:
- 网格枚举:变量少(比如2-3个)、范围小的时候,直接用嵌套循环穷举。优点是肯定能找到全局最优,缺点是计算量大,但全年模拟一次只要几秒,几千组也就是晚上泡杯茶的功夫,完全没有压力。
- 遗传算法(NSGA-II):如果决策变量超过4个,或者你想做真正的多目标Pareto解集,用现成的
pymoo库里的NSGA-II是最省心的。设置种群大小100,进化50代,最多几千次模拟,完全能接受。而且Pareto前沿画出来特别能唬人,评委喜欢看到这样的图。 - 贝叶斯优化:简单说就是“下一组参数要往最有希望的方向试”,适合模拟器太慢只好省调用次数的情况。不过咱们这个题模拟器不慢,没必要用,除非你想炫技。
我推荐优先用网格枚举做基线结果,再用NSGA-II验证一组更复杂的参数组合。这样既证明了你有全局搜索意识,又避免了遗传算法“解可能不是最优”的质疑。
4.3 一个简单的优化示例与代码
假设你只优化水平挑檐的深度 D 和离窗顶的间隙 G,目标函数是“夏季制冷负荷削减率”。你先做一个一维扫描,看看D对全年得热的影响:
python复制import numpy as np
def annual_solar_heat_gain(lat, lon, D, G, window_h, window_w):
"""
返回全年累计的太阳辐射得热(kWh/m2)
简化模型:只考虑直射辐射。实际需要合理拆分直射散射
"""
# 这里应该循环全年每天 > 每小时
# 先用固定值代表某城市
total_heat = 0.0
for day in range(365):
# 假设每个小时都在跑,实际代码要完整展开
for hour in range(24):
alpha, gamma = solar_position(lat, lon, 2024, 1, 1, hour)
cover = horizontal_overhang_coverage(alpha, gamma, window_w, window_h, D, G)
# GHI -> DNI 简化
dni = 500 # 假设直射500 W/m2
# 透过遮阳的部分
heat = dni * (1 - cover) * window_w * window_h * 0.001 # kW
total_heat += heat
return total_heat / 1000.0 # kWh
# 扫描深度
depths = np.arange(0.2, 2.0, 0.2)
gaps = np.arange(0.0, 0.4, 0.1)
best = None
for D in depths:
for G in gaps:
heat = annual_solar_heat_gain(40, -105, D, G, 1.5, 1.5)
if best is None or heat < best[0]:
best = (heat, D, G)
print(best)
这只是个演示骨架,真正的代码需要把内层小时的循环补全,还要把直射散射分开。我个人建议赛后把代码整理成公开库,方便其他人复现。这会让你的论文加分,而且评委在审阅时如果看到有完整代码,会认为你做了扎实的工作。
4.4 常见优化坑
优化环节最容易翻车的不是算法,而是物理含义。比如你发现“遮阳深度越大越好”,于是优化结果把挑檐深度推到10米,这显然脱离现实。所以你必须在约束里加上“结构限制”(例如挑檐深度不超过窗户所在墙面的宽度)以及“视觉限制”(挑檐深度过大影响视线)。这样最后得到的方案才有工程意义。另外一个常见问题是“全年总得热最小”的陷阱——冬季采暖同样需要得热,你算总得热最小,往往是在牺牲冬季舒适度。正确的目标应该是区分季节,夏季总得热最小,冬季总得热最大(或者用一个“净能量”概念:夏季减分,冬季加分)。
5. 论文写作:从模型到评委认可的叙事线
5.1 摘要:数学建模的“脸面”
MCM的评委平均看一份论文的时间可能只有十几分钟,其中一半时间都花在摘要上。摘要里必须写清楚这几件事,缺一不可:
- 问题重述与背景:一句话带出“被动式太阳能遮阳是多目标权衡问题”。
- 模型的总体思路:提一下“我们建立了基于太阳几何的逐时模拟模型,结合多目标优化框架”。
- 关键结果:给出一个具体数字,比如“我们的最优方案使夏季空调能耗降低了28%”。
- 敏感性与鲁棒性:一句话说明“通过改变朝向和气候数据,模型结论保持稳定”。
千万不要在摘要里堆公式。评委看摘要不是看你会不会推公式,而是看你有没有完成“建模-求解-验证”全流程。摘要最好最后写,先写正文,写完后用最精简的话提炼出你的核心流程。
5.2 模型假设与敏感性分析:别给自己挖坑
很多队的假设写得像“免责条款”,把自己擅自简化的问题都藏进去了。我建议把假设分成“必要简化”和“可验证假设”两类:
- 必要简化:比如忽略遮阳构件本身的传热(因为它在室外,隔热能力对室内影响较小),这种简化你解释清楚原因即可。
- 可验证假设:比如“窗户玻璃的太阳得热系数恒定0.6”,你可以在敏感性分析里改成0.4和0.8,看最优方案是否变化。如果结果变化不大,说明结论稳健;如果变化很大,那你就得说清楚这种材料参数的变化会导致方案选择发生变化,评委反而觉得你的分析更有深度。
敏感性分析的具体做法:选择1个关键参数,比如遮阳构件的反射率,从0.2到0.8各跑一遍优化,输出目标函数的变化曲线。这种图能直接给评委留下“这个团队做事严谨”的印象。
5.3 可视化:让评委一眼看懂你的方案
你可以准备四类图,基本就够用了:
- 全年逐时热力图:横轴小时,纵轴日期,颜色代表“遮阳后得热强度”。对比无遮阳和有遮阳两张热力图,一眼就能看出遮阳在夏季的效果。
- 参数扫描曲线:横轴遮阳深度,纵轴夏季总得热,画2-3条不同季节曲线。这能直观展示“深度越大越省电”或“存在拐点”。
- 多目标Pareto前沿图:如果用了NSGA-II,把两个目标(比如夏季得热和冬季得热)画成散点图,用红色标出前沿点。评委普遍认为Pareto前沿是“高级模型”的标志。
- 3D几何示意图:用matplotlib画一个简单的建筑+遮阳板三维透视,配上太阳位置示意。不需要太精致,清晰即可。可以使用
mpl_toolkits.mplot3d画线框图。
我也建议你用plotly或者pyecharts做交互式图,但在论文PDF里生成静态截图即可,别搞动态图。
6. 后续更新计划:这篇帖子接下来会补什么
6.1 参赛期间我会跟进哪些素材
随着MCM比赛临近,我会把以下几个模块逐步补到这篇帖子里,建议你收藏备用:
- 完整代码仓库:整理一份可以从头跑通到论文图表的Jupyter Notebook,包含太阳几何、遮阳系数、能耗指标和优化扫描。代码里每个函数都带注释和参考依据。
- 经典题目变体解析:如果题目要求你考虑多种城市气候(比如北京、凤凰城、巴黎),我会补一份对不同气候类型的参数调整策略。
- 论文LaTeX模板片段:我会放一个符合MCM排版风格的摘要和正文片段,供你参考。
- 评委喜欢看的图表模板:我把自己觉得效果最好的几张图生成通用代码,直接改参数就能用。
6.2 你能在这里期待什么样的代码和思路更新
你可能会问:“你这些思路靠谱吗?”我的回答是:所有模型和代码我都会用公开气象数据做测试,并给出数值例子。比如我会跑一个“北京40°N,水平挑檐D=1m时全年逐时遮阳效率”的示例,把结果贴出来,方便你直接对比自己的代码是否正确。我还会分享如何用EPW数据驱动更精细的传热模型,让物理层从“太阳辐射”升级到“室内热平衡”。当然,这些需要一点时间,但保证不鸽。
另外,如果大家有特别感兴趣的问题,比如“怎么算遮阳板对采光的影响”“如何把光伏与遮阳结合在同一个优化里”,也可以在评论区留言,我会挑选高频问题优先写。说到底,做这道题,大家拼的不是谁的知识点更多,而是谁能更早地跑通一个“稳、准、省”的流程。
最后说个实在的经验:我见过太多队在前三天反复换模型,最后一天才发现代码根本跑不通。你最好的策略就是跟我这篇帖子的节奏走,第一周先把基础模型和可视化搞定,第二周再考虑加复杂度。建模这事,稳就是快。后面我会把更新内容同步在这里,建议你定期回来看。
