4. 基于历史气象数据的日照强度序列生成与充电策略回放
为什么需要“可回放”的日照序列
浮标充电策略的优劣不能只看某一天。同一套启停逻辑在夏季连续晴天可能表现良好,但换到冬季阴雨交替的序列就可能频繁切换或长期亏电。要公平比较策略,必须把“天气输入”从策略中剥离出来,做成可重复调用的日照强度时间序列,再让策略在序列上逐时步回放。本案例用历史气象数据构造该序列,并搭建一个与策略解耦的回放框架。
数据对象与序列构造
假设浮标部署海域的历史气象数据以逐小时记录提供,字段包括时间戳、总云量(0–1)、气温与降水标记。日照强度不直接给出,需要由晴空辐照度与云量衰减共同推算。采用简化的晴空模型:
G_clear(t) = G_max · max(0, sin(π·(t - t_sunrise)/(t_sunset - t_sunrise)))
G(t) = G_clear(t) · (1 - 0.75·cloud^3.4)
其中 G_max 取 1000 W/m²,cloud 为总云量,指数 3.4 使薄云衰减平缓、厚云迅速压暗。日出日落时刻按部署海域纬度与日期用简化正弦近似,避免引入外部天文库。降水时段额外乘以 0.6 作为湿板与散射修正。这样每条历史记录都能映射为一个 0–1000 W/m² 的日照强度样本。
回放框架的接口设计
回放框架的核心是“序列驱动 + 策略回调”。序列对象只负责按时间步吐出 (timestamp, irradiance),策略对象只负责根据当前 SOC、负载与辐照度返回充电功率指令。两者通过统一接口连接,因此同一策略可以换任意季节、任意天气序列重复评估,而无需改动策略代码。
from dataclasses import dataclass
@dataclass
class Step:
ts: str
irradiance: float # W/m^2
class SolarSequence:
def __init__(self, steps):
self.steps = steps
def __iter__(self):
return iter(self.steps)
def replay(sequence, policy, soc0=0.5, capacity_wh=200.0,
panel_area=0.35, load_w=8.0, dt_h=1.0):
soc = soc0
log = []
for s in sequence:
p_pv = s.irradiance * panel_area * 0.18 # 组件效率 18%
cmd = policy(soc, p_pv, load_w) # 策略返回充电功率 W
p_charge = min(cmd, p_pv)
net_wh = (p_charge - load_w) * dt_h
soc = max(0.0, min(1.0, soc + net_wh / capacity_wh))
log.append((s.ts, s.irradiance, p_pv, p_charge, soc))
return log
回放函数只做能量守恒与 SOC 限幅,不掺入任何策略判断,保证不同策略在同一序列上的结果可比。策略以函数形式传入,例如一个简单的阈值策略:SOC 低于 0.6 且辐照度足够时全额充电,否则停止。
def threshold_policy(soc, p_pv, load_w):
if soc < 0.6 and p_pv > load_w:
return p_pv
return 0.0
季节与天气序列的构造与对比
为验证框架的可重复性,从历史数据中截取三段典型序列:夏季连续晴、冬季阴雨交替、春秋多云。每段 72 小时,用同一阈值策略回放,观察 SOC 轨迹与充电启停次数。下面的 SVG 展示了回放框架的数据流与三段序列的 SOC 响应差异。
结果判读与框架验证
回放日志每行包含时间戳、辐照度、光伏功率、实际充电功率与 SOC。判读时关注三个量:SOC 最低点是否触及下限、充电启停次数、以及序列末 SOC 相对初值的净变化。上图中夏季序列 SOC 从 0.5 升至约 0.85,启停仅 2 次;冬季序列在 0.35–0.55 间震荡,启停达 9 次,说明阈值策略在低辐照下容易反复触发;春秋序列表现居中。这些差异完全来自输入序列,策略代码未变,证明回放框架实现了“同策略、多序列”的可重复评估。