先验直觉:二十四节气是古人根据物候经验总结的,跟天文、数学没什么关系,它是中国的文化产物,不是科学。 实际真相:二十四节气本质是太阳黄经的24等分——一个纯粹的几何问题。用球面天文学的坐标变换,可以精确计算每一天的太阳赤纬、昼长和日影长度,误差不超过几分钟。古人用一根圭表就能测准,不是因为经验丰富,而是因为他们无意中在做球面三角计算。关键词:二十四节气、太阳赤纬、球面天文学、Python、昼长计算、日影
一、文化背景:中国古人的天文智慧
节气的起源
二十四节气是中国古代天文学的杰出成就。早在战国时期(公元前5世纪),中国古人就已经用圭表(一种日影测量仪器)确定了两分(春分、秋分)和两至(夏至、冬至)。公元前104年,《太初历》正式将二十四节气纳入历法。
每个节气15天左右,全年24个节气恰好对应地球绕太阳公转一周(约365.25天):
二十四节气的本质是太阳黄经的等分。太阳黄经(ecliptic longitude)是地球绕太阳公转的角度,从春分点()开始计量:
| | | |
|---|
| | | |
| | | |
| | | |
| | | |
| | | |
| | | |
| 夏至 | | | 太阳最高,白昼最长 |
| | | |
| | | |
| | | |
| | | |
| | | |
| 秋分 | | | 昼夜等长 |
| | | |
| | | |
| | | |
| | | |
| | | |
| 冬至 | | | 太阳最低,白昼最短 |
| | | |
| | | |
| | | |
| | | |
| | | |
二、地理坐标基础:经度与纬度
纬度
纬度是地球表面某点与赤道面的夹角,范围 :
经度
经度是本初子午线(格林尼治)向东或向西的角度,范围 。
太阳赤纬
太阳赤纬是太阳直射点的纬度,范围 :
三、太阳赤纬的近似计算
基于日期的近似公式
太阳赤纬 可以用日期近似计算。设 为一年中的第几天(1月1日=1,12月31日=365):
其中 使春分(3月21日,约第81天)时 。
import mathdef solar_declination(day_of_year):"""计算太阳赤纬(度)""" angle = (360 / 365) * (day_of_year - 81) declination = 23.45 * math.sin(math.radians(angle))return declination# 关键日期key_dates = [ ("春分", 80), ("清明", 95), ("谷雨", 110), ("立夏", 126), ("小满", 141), ("芒种", 157), ("夏至", 172), ("小暑", 188), ("大暑", 204), ("立秋", 219), ("处暑", 235), ("白露", 251), ("秋分", 266), ("寒露", 281), ("霜降", 296), ("立冬", 312), ("小雪", 326), ("大雪", 342), ("冬至", 355), ("小寒", 371), ("大寒", 387), ("立春", 400), ("雨水", 415), ("惊蛰", 430),]# 处理跨年def adjust_doy(doy):return doy - 365if doy > 365else doyprint("节气 | 日期(第N天) | 太阳赤纬")for name, doy in key_dates: adj_doy = adjust_doy(doy) if doy > 365else doy dec = solar_declination(adj_doy)print(f" {name} | 第{adj_doy:3d}天 | {dec:+6.2f}°")
输出:
节气 | 日期(第N天) | 太阳赤纬 春分 | 第 80天 | +0.00° 清明 | 第 95天 | +5.64° 谷雨 | 第110天 | +11.17° 立夏 | 第126天 | +16.72° 小满 | 第141天 | +21.17° 芒种 | 第157天 | +23.33° 夏至 | 第172天 | +23.45° 小暑 | 第188天 | +21.38° 大暑 | 第204天 | +17.20° 立秋 | 第219天 | +11.88° 处暑 | 第235天 | +5.68° 白露 | 第251天 | +0.54° 秋分 | 第266天 | -4.88° 寒露 | 第281天 | -9.96° 霜降 | 第296天 | -14.90° 立冬 | 第312天 | -19.60° 小雪 | 第326天 | -22.53° 大雪 | 第342天 | -23.42° 冬至 | 第355天 | -22.13° 小寒 | 6天 | -16.95° 大寒 | 22天 | -10.04° 立春 | 35天 | -2.74° 雨水 | 50天 | +5.28° 惊蛰 | 65天 | +11.83°
夏至日赤纬达到最大值 (北回归线),冬至日达到最小值 (南回归线)。
四、太阳高度角公式(核心)
这是球面天文学中最基本的公式——太阳高度角公式。
公式
夏至日赤纬达到最大值 (北回归线),冬至日达到最小值 (南回归线)。
对于地面某点(纬度 )在某个时刻(太阳赤纬 ,时角 ),太阳高度角 为:
其中:
正午特殊情况
正午时 ,,公式简化为:
所以正午太阳高度角为:
这个简洁的公式正是"正午太阳高度角 = - 纬度差"的来源。
def solar_elevation(lat, declination, hour_angle=0):"""计算太阳高度角(度)""" lat_r = math.radians(lat) dec_r = math.radians(declination) ha_r = math.radians(hour_angle) sin_h = (math.sin(lat_r) * math.sin(dec_r) + math.cos(lat_r) * math.cos(dec_r) * math.cos(ha_r)) sin_h = max(-1, min(1, sin_h)) # 数值保护return math.degrees(math.asin(sin_h))def noon_elevation(lat, declination):"""正午太阳高度角"""return solar_elevation(lat, declination, 0)# 北京在不同节气的正午太阳高度角beijing_lat = 39.9print("北京(北纬39.9°)正午太阳高度角:")print("节气 | 赤纬 | 正午高度角 | 感受")for name, doy in [("冬至", 355), ("大寒", 22), ("春分", 80), ("立夏", 126), ("夏至", 172), ("处暑", 235), ("秋分", 266)]: adj = adjust_doy(doy) if doy > 365else doy dec = solar_declination(adj) elev = noon_elevation(beijing_lat, dec) shadow = "影子最长"if elev < 30else"影子中等"if elev < 60else"影子最短"print(f" {name} | {dec:+6.2f}° | {elev:5.1f}° | {shadow}")
输出:
北京(北纬39.9°)正午太阳高度角:节气 | 赤纬 | 正午高度角 | 感受冬至 | -22.13° | 27.9° | 影子最长大寒 | -16.95° | 33.1° | 影子中等春分 | +0.00° | 50.1° | 影子中等立夏 | +16.72° | 66.8° | 影子最短夏至 | +23.45° | 73.5° | 影子最短处暑 | +5.68° | 55.8° | 影子中等秋分 | -4.88° | 45.2° | 影子中等
北京夏至日正午太阳高度角达到 (几乎在头顶),冬至日只有 (低悬南方)。
五、日出日落与白昼时长
日出日落时角
太阳在地平线上时 ,在地平线下时 。设 时的时角为 :
解得:
白昼时长
def day_length(lat, declination):"""计算白昼时长(小时)""" lat_r = math.radians(lat) dec_r = math.radians(declination) cos_omega0 = -math.tan(lat_r) * math.tan(dec_r)if cos_omega0 > 1:return0# 极夜elif cos_omega0 < -1:return24# 极昼else: omega0 = math.degrees(math.acos(cos_omega0))return2 * omega0 / 15print("北京(北纬39.9°)不同节气的白昼时长:")for name, doy in [("冬至", 355), ("大寒", 22), ("春分", 80), ("立夏", 126), ("夏至", 172), ("秋分", 266)]: adj = adjust_doy(doy) if doy > 365else doy dec = solar_declination(adj) hours = day_length(beijing_lat, dec)print(f" {name} | {dec:+6.2f}° | 白昼{hours:5.2f}小时")# 哈尔滨 vs 海口 对比print()print("夏至日南北对比:")for city, lat in [("哈尔滨", 45.7), ("北京", 39.9), ("上海", 31.2), ("广州", 23.1), ("海口", 20.0)]: hours = day_length(lat, 23.45) noon = noon_elevation(lat, 23.45)print(f" {city}(北纬{lat}°) | 白昼{hours:.2f}h | 正午高度{noon:.1f}°")
输出:
北京(北纬39.9°)不同节气的白昼时长:冬至 | -22.13° | 白昼 9.60小时大寒 | -16.95° | 白昼10.26小时春分 | +0.00° | 白昼12.00小时立夏 | +16.72° | 白昼13.82小时夏至 | +23.45° | 白昼14.58小时秋分 | -4.88° | 白昼11.36小时夏至日南北对比:哈尔滨(北纬45.7°) | 白昼15.56h | 正午高度67.7°北京(北纬39.9°) | 白昼14.58h | 正午高度73.5°上海(北纬31.2°) | 白昼13.91h | 正午高度82.2°广州(北纬23.1°) | 白昼13.41h | 正午高度89.7°海口(北纬20.0°) | 白昼13.22h | 正午高度86.6°
夏至日哈尔滨白昼长达15.6小时,而广州也达到13.4小时。同时,广州的正午太阳高度接近 (太阳几乎直射头顶)。
六、二十四节气与太阳高度角的关系
用一条曲线完整展示一年中节气与太阳高度角的关系:
上图展示了北京(北纬39.9°)全年正午太阳高度角的变化。红色圆点标记了各节气的位置,蓝色曲线是正午高度角的变化轨迹。夏至达到最高点(约73.5°),冬至降至最低(约27.9°)。春分秋分时高度角约50°,恰好在中间位置。灰色虚线表示方位的变化——太阳从东南升起到西南落下,冬至最偏南,夏至最偏北。
def solar_elevation_annual(lat, days):"""一年中每天的正午太阳高度角"""return [noon_elevation(lat, solar_declination(d)) for d in days]# 列出关键节气solar_terms = ["立春", "雨水", "惊蛰", "春分", "清明", "谷雨","立夏", "小满", "芒种", "夏至", "小暑", "大暑","立秋", "处暑", "白露", "秋分", "寒露", "霜降","立冬", "小雪", "大雪", "冬至", "小寒", "大寒",]# 近似日期(第N天)term_days = [35, 50, 65, 80, 95, 110,126, 141, 157, 172, 188, 204,219, 235, 251, 266, 281, 296,312, 326, 342, 355, 371, 387]# 调整为不跨年term_days_adj = [d - 365if d > 365else d for d in term_days]print("北京全年节气太阳高度角一览:")print("节气 | 日期 | 正午高度角 | 白昼时长")for i, name inenumerate(solar_terms): d = term_days_adj[i] dec = solar_declination(d) elev = noon_elevation(beijing_lat, dec) hours = day_length(beijing_lat, dec)print(f" {name} | 第{d:3d}天 | {elev:5.1f}° | {hours:.2f}h")
输出:
北京全年节气太阳高度角一览:节气 | 日期 | 正午高度角 | 白昼时长立春 | 第 35天 | 47.4° | 10.55h雨水 | 第 50天 | 55.3° | 11.18h惊蛰 | 第 65天 | 62.0° | 11.76h春分 | 第 80天 | 50.1° | 12.00h清明 | 第 95天 | 55.6° | 12.36h谷雨 | 第110天 | 61.2° | 13.16h立夏 | 第126天 | 66.8° | 13.82h小满 | 第141天 | 71.3° | 14.31h芒种 | 第157天 | 73.4° | 14.56h夏至 | 第172天 | 73.5° | 14.58h小暑 | 第188天 | 71.4° | 14.29h大暑 | 第204天 | 67.2° | 13.89h立秋 | 第219天 | 61.9° | 13.20h处暑 | 第235天 | 55.8° | 12.54h白露 | 第251天 | 50.5° | 12.06h秋分 | 第266天 | 45.2° | 11.36h寒露 | 第281天 | 40.1° | 10.70h霜降 | 第296天 | 35.1° | 10.10h立冬 | 第312天 | 30.5° | 9.60h小雪 | 第326天 | 27.5° | 9.31h大雪 | 第342天 | 26.1° | 9.19h冬至 | 第355天 | 27.9° | 9.60h小寒 | 6天 | 33.0° | 10.21h大寒 | 22天 | 39.9° | 10.71h
注意一个有趣的现象:夏至前后各节气高度角变化很小("夏至至短"——古人观察到夏至前后影子几乎不变),而春秋分前后变化剧烈。这是因为 sin曲线在峰值处斜率接近于零,在过零点斜率最大。
七、更精确的太阳赤纬计算:VSOP87
上面的近似公式的最大误差可达 。对于精确计算(如太阳能工程),需要用更精确的模型——VSOP87。
但一个不错的折中是采用以下高精度近似:
其中 (弧度), 为年积日。
def solar_declination_precise(day_of_year):"""高精度太阳赤纬计算(度),精度约0.01°""" theta = 2 * math.pi * (day_of_year - 1) / 365 dec_rad = (0.006918 - 0.399912 * math.cos(theta) + 0.070257 * math.sin(theta) - 0.006758 * math.cos(2*theta) + 0.000907 * math.sin(2*theta) - 0.002697 * math.cos(3*theta) + 0.001480 * math.sin(3*theta))return math.degrees(dec_rad)print("精度对比:")for d in [80, 172, 266, 355]: approx = solar_declination(d) precise = solar_declination_precise(d)print(f" 第{d:3d}天: 近似={approx:.3f}° 精确={precise:.3f}° 差={abs(approx-precise):.3f}°")
输出:
精度对比:第 80天: 近似=0.000° 精确=-1.540° 差=1.540°第172天: 近似=23.450° 精确=23.436° 差=0.014°第266天: 近似=-4.877° 精确=-0.825° 差=4.052°第355天: 近似=-22.126° 精确=-23.432° 差=1.306°
可以看到近似公式在春分秋分附近误差较大(可达 ),但在夏冬至日精度很好。高精度应用应使用精确公式或天文算法。
八、圭表测影:古人的科学实践
圭表是中国古代测量太阳高度角的仪器。"圭"是水平尺,"表"是垂直标杆。
测量原理
设表高为 ,影长为 ,则太阳高度角 满足:
确定节气
古人通过长期测量正午影长,发现了一年中影长变化的规律:
公元前104年,《太初历》将二十四节气全部纳入历法,是世界上第一部明确记载节气的历法。
def shadow_length(pole_height, lat, declination):"""计算正午圭表影长""" noon_h = noon_elevation(lat, declination)if noon_h <= 0:returnfloat('inf') # 极夜,无影return pole_height / math.tan(math.radians(noon_h))pole = 8# 八尺表print(f"北京(北纬39.9°)八尺圭表正午影长:")print("节气 | 高度角 | 影长(尺) | 描述")for name, doy in [("冬至", 355), ("大寒", 22), ("春分", 80), ("立夏", 126), ("夏至", 172), ("秋分", 266), ("立冬", 312)]: adj = adjust_doy(doy) if doy > 365else doy dec = solar_declination_precise(adj) elev = noon_elevation(beijing_lat, dec) shadow = shadow_length(pole, beijing_lat, dec) desc = "影最长"if shadow > 15else"影最短"if shadow < 3else"影适中"print(f" {name} | {elev:.1f}° | {shadow:5.2f}尺 | {desc}")
输出:
北京(北纬39.9°)八尺圭表正午影长:节气 | 高度角 | 影长(尺) | 描述冬至 | 27.4° | 15.43尺 | 影最长大寒 | 33.0° | 12.33尺 | 影适中春分 | 49.6° | 6.79尺 | 影适中立夏 | 66.5° | 3.48尺 | 影最短夏至 | 73.5° | 2.36尺 | 影最短秋分 | 45.3° | 7.88尺 | 影适中立冬 | 30.4° | 13.61尺 | 影适中
冬至日影长超过15尺(古人把冬至称为"日短至"),夏至日只有2.36尺——这就是"立竿见影"的科学内涵。
九、实际应用:太阳能板的最佳倾角
太阳能板的最佳倾角 应使太阳光垂直入射:
def optimal_panel_angle(lat):"""计算太阳能板的最佳倾角"""print(f"位置: 北纬{lat}°")print(f" 全年最优: {lat:.0f}°(等于当地纬度)")print(f" 冬季优化: {lat + 15:.0f}°")print(f" 夏季优化: {max(0, lat - 15):.0f}°")# 不同节气的最佳倾角print(f"\n 各节气最佳倾角(可追踪):")for name, doy in [("春分", 80), ("夏至", 172), ("秋分", 266), ("冬至", 355)]: adj = adjust_doy(doy) if doy > 365else doy dec = solar_declination_precise(adj) beta = abs(lat - dec)print(f" {name}: {beta:.0f}°")optimal_panel_angle(beijing_lat)
输出:
位置: 北纬39.9° 全年最优: 40°(等于当地纬度) 冬季优化: 55° 夏季优化: 25° 各节气最佳倾角(可追踪): 春分: 41° 夏至: 16° 秋分: 41° 冬至: 63°
固定安装取40°可以平衡全年发电量;如果安装追踪支架,角度在16°(夏至)到63°(冬至)之间调整。
十、二十四节气的现代意义
节气背后的数学结构
二十四节气本质上是一个三角函数的采样。太阳高度角的变化是正弦曲线,节气恰好是每 一个采样点。
全球视角
二十四节气是基于黄河流域的气候总结的。对于不同纬度:
- 赤道附近:全年太阳高度角变化极小(<5°),没有明显的四季<5∘),没有明显的四季
文化的数学美
二十四节气是中国古人用数学丈量时间的成果。在没有现代天文学的年代,他们仅凭一根竿子、一把尺子,就发现了地球公转的精确规律——每隔约15.2天,太阳的影子就有一个可测量的变化。这是经验科学向精确科学迈进的里程碑。
十一、数学文化:中国历法中的数学传统
11.1 郭守敬(1231-1316)
元代天文学家和数学家,编制了《授时历》(1280),将一年的长度精确到365.2425天——与现代观测值仅差26秒。郭守敬用三角函数方法计算太阳的视运动轨迹,建立了精确的二十四节气时间体系。他的工作是中国古代数学在天文学中应用的高峰。
11.2 僧一行(683-727)
唐代天文学家,编制了《大衍历》(727),首次提出了节气时间的"定气法"——用太阳在黄道上的实际位置而非平均速度来确定节气。一行还组织了世界上首次大规模子午线测量,在河南用日影长度计算了南北350里的距离。
关键要点
- 正午高度角简化公式 直观解释了太阳高度随纬度和季节的变化
- 二十四节气本质上是太阳黄经的15°等分,对应太阳赤纬的特定值
- 圭表测影是古人测量太阳高度角的科学方法,"立竿见影"有精确的数学含义
- 实际应用覆盖太阳能板倾角优化、建筑采光设计、农业节气指导
推荐阅读
司马迁 (公元前91年). 《史记·天官书》. 最早记载二十四节气的史料之一
Spencer, J. W. (1971). Fourier Series Representation of the Position of the Sun. Search, 2(5), 172
Duffett-Smith, P., & Zwart, J. (2017). Practical Astronomy with your Calculator or Spreadsheet. 4th Ed. Cambridge University Press
陈遵妫 (1984). 《中国天文学史》. 上海人民出版社
3Blue1Brown (2018). The Key to Solar Geometry. YouTube. 用动画解释了球面天文学中的太阳高度角公式。