case3.2_more_complex_pv_battery_load_pcc.py)本文档说明 case3.2_more_complex_pv_battery_load_pcc.py 的系统组成、控制目标、功率符号、复杂测试波形、双时间尺度运行机制、遥测采样、CSV 数据输出及结束处理。
本案例由光伏(PV)、电池、负载和公共耦合点(Point of Common Coupling,PCC)四类节点组成。脚本以 1 Hz 标称频率更新控制命令,以 10 Hz 标称频率采集四节点功率与虚拟荷电状态(State of Charge,SOC),并在主循环正常结束后保存 CSV 表格。
本文档严格依据脚本静态代码编制。文中“内部命令”“遥测值”“回退值”和“虚拟 SOC”分别说明,不将计算量或回退量描述为设备实测结果。
| 节点角色 | 脚本变量 | 默认节点编号 | 当前控制或采样内容 |
|---|---|---|---|
| 光伏 | pv_node |
1 |
根据复杂光伏波形更新功率命令,并采集功率遥测。 |
| 电池 | battery_node |
2 |
根据功率差额更新功率命令、虚拟能量和 SOC,并采集功率遥测。 |
| 负载 | load_node |
3 |
根据复杂负载波形更新功率命令,并采集功率遥测。 |
| PCC | pcc_node |
4 |
每个控制周期写入 v = 20.0,采集功率遥测;当前不下发 PCC 有功功率命令。 |
节点角色依据脚本变量命名确定。实际设备拓扑、节点映射以及 p、v 属性的物理含义,应以现场接口配置为准。
脚本采用以下内部功率符号:
功率控制模式的目标为:
脚本将负载请求转换为内部负载功率:
电池内部命令按差额直接计算:
因此,内部命令和 bus_sum_set_w 由代数构造满足:
该关系描述内部设定值,不代表四节点实测功率必然平衡。
脚本规定 CAN 功率设定点 node.p 与内部功率符号相反:
实际下发为:
api.node[pv_node].p = -pv_cmd_w
api.node[load_node].p = -load_cmd_w
api.node[battery_node].p = -battery_cmd_w
因此,内部注入或放电功率对应负的 node.p;内部吸收或充电功率对应正的 node.p。PCC 节点当前仅在控制更新时执行 api.node[pcc_node].v = 20.0,没有写入 PCC 的 p 属性。
脚本中保留了一段“电池 SOC 上下限保护、功率限制、负载削减”的注释代码,但当前不执行。实际启用的策略具有以下边界:
battery_max_discharge_w 和 battery_max_charge_w 不参与当前控制;5 s 后发送 CAN 控制,可从用户界面停止脚本;api.sleep(5.0);Sending...;t0 和 last_tick_s;电池模型的初始化值为:
这些值用于脚本内部简化模型,不是设备读取值。
脚本设置:
控制更新间隔采样数为:
外层循环以 sample_period_s 为周期。仅当:
时更新控制命令;每次采样迭代都会读取四节点功率并追加一行结果。因此,默认配置下标称控制更新频率为 1 Hz,标称遥测采样频率为 10 Hz。首次控制更新对应的具体迭代编号取决于运行接口 loop() 提供的 sample_tick 序列。
控制更新分支按以下顺序执行:
使用本次采样时间计算 elapsed_s;
计算电池能量积分步长:
计算负载请求、光伏可用功率和 PCC 目标;
向 PCC 节点写入 v = 20.0;
生成光伏、负载与电池内部命令;
计算内部命令功率和;
对内部命令取反,并向光伏、负载、电池节点写入 p;
根据电池内部命令更新虚拟能量和 SOC;
输出控制日志;
递增 repeat。当前启用逻辑未使用 repeat 控制日志频率。
电池能量更新关系为:
虚拟 SOC 为:
当内部电池功率为正时,能量模型下降;为负时,能量模型上升。由于 energy_wh 被限制在 0.8 Wh 至 4.0 Wh,记录的虚拟 SOC 位于 20% 至 100%。
clamp() 只作用于 energy_wh。即使虚拟能量已经达到上下限,当前代码仍可能继续计算并下发同方向的 battery_cmd_w。
每个 0.1 s 标称采样周期均依次调用 get_latest_power_w() 读取光伏、电池、负载和 PCC 节点:
api.node[node].get_data(timeout=0),即非阻塞读取;p1 为数值,采用 p1;p 为数值,采用 p;fallback;online 布尔值,但调用处使用 _ 丢弃该状态;sum_meas_w;power_soc_table_rows。需要注意,CSV 中命名为测量功率的值可能来自真实字段 p1、兼容字段 p,也可能是内部命令回退值。脚本没有在输出表中记录数据来源或在线状态。因此,不能仅根据 CSV 字段名称认定每一行都是有效设备实测值。
此外,get_latest_power_w() 不对读取到的 p1 或 p 执行符号转换。遥测字段的功率方向应以运行接口定义为准。
每次采样循环开始时,脚本执行:
if run_duration_s > 0.0 and sample_elapsed_s > run_duration_s:
break
默认阈值为 18000.0 s,约 5 h,不包含启动前 5 s 延时。判断条件为严格大于而非大于等于。当 run_duration_s <= 0.0 时,脚本不通过该条件限制时长。
正常退出采样循环后,脚本按:
repo_root = Path(__file__).resolve().parents[3]
确定仓库根目录,并将 CSV 保存到:
<repo_root>/data/output/
输出目录由 save_power_soc_table() 以 parents=True, exist_ok=True 创建。文件名格式为:
case5_2_power_soc_table_YYYYMMDD_HHMMSS.csv
文件名中的 case5_2 为脚本硬编码文本,与当前脚本文件名 case3.2_more_complex_pv_battery_load_pcc.py 不一致。时间戳通过 datetime.fromtimestamp(api.now()) 生成,其时间语义取决于 api.now() 的接口定义。
保存成功后,脚本输出文件路径和行数,然后依次对节点 1、2、3、4 调用 shutdown(),最后输出:
All node shutdown, EXPERIMENT finished
脚本没有使用 try/finally。若控制、采样、路径解析或文件写入过程中发生未处理异常,CSV 保存或末尾 shutdown() 可能无法执行。
| 参数名 | 默认值 | 作用 |
|---|---|---|
CASE_NAME |
"EXPERIMENT" |
启动与结束日志中的案例名称。 |
run_duration_s |
18000.0 s |
运行时长判断阈值,约 5 h;不大于零时禁用该判断。 |
send_hz |
1.0 Hz |
标称控制更新频率。 |
period_s |
1.0 s |
控制周期,由 1.0 / send_hz 计算。 |
sample_hz |
10.0 Hz |
标称遥测采样频率。 |
sample_period_s |
0.1 s |
采样周期,由 1.0 / sample_hz 计算。 |
control_tick_samples |
10 |
每次控制更新对应的采样间隔数。 |
pv_node |
1 |
光伏节点编号。 |
battery_node |
2 |
电池节点编号。 |
load_node |
3 |
负载节点编号。 |
pcc_node |
4 |
PCC 节点编号。 |
| 启动延时 | 5.0 s |
开始循环前的固定等待时间。 |
PCC 的 v 设定 |
20.0 |
每次控制更新写入 PCC 节点;单位与设备行为以接口定义为准。 |
dt_s 下限 |
0.2 s |
电池虚拟能量积分的最小步长。 |
| 参数名 | 默认值 | 当前作用 | 是否约束电池命令 |
|---|---|---|---|
battery_voltage_v |
20.0 V |
计算虚拟满电能量。 | 否 |
battery_capacity_ah |
0.2 Ah |
计算虚拟满电能量。 | 否 |
battery_full_wh |
4.0 Wh |
虚拟满电能量。 | 否 |
battery_init_soc_pct |
50.0% |
初始化虚拟能量。 | 否 |
battery_soc_min_pct |
20.0% |
计算虚拟能量下限。 | 否,仅约束记录值 |
battery_soc_max_pct |
100.0% |
在当前启用逻辑中不参与判断。 | 否 |
battery_max_discharge_w |
50.0 W |
为可能回滚的旧策略保留。 | 否 |
battery_max_charge_w |
50.0 W |
为可能回滚的旧策略保留。 | 否 |
上述数值为脚本模型设定,不代表设备额定能力或现场安全边界。
光伏基础功率周期为 1200 s:
每个周期前 600 s 为半正弦波,后 600 s 为零,基础范围为 0 W 至 30 W。
脚本叠加四个确定性正弦扰动:
分别对应脚本中的云层缓慢波动、大气湍流、高频噪声和云团经过分量。合成扰动被限制为:
虽然代码注释使用“噪声”和“随机”等描述,这些分量均由确定性正弦函数生成,没有调用随机数生成器。
| 起始时间(s) | 结束时间(s) | 最大跌落深度 | 平台剩余比例 |
|---|---|---|---|
450 |
550 |
70% |
30% |
980 |
1040 |
80% |
20% |
1520 |
1680 |
60% |
40% |
2100 |
2180 |
85% |
15% |
2750 |
2820 |
75% |
25% |
3200 |
3350 |
65% |
35% |
每个事件在开始和结束边缘采用 10 s 线性过渡。事件外 sudden_drop = 0。最终光伏功率为:
其中 为平滑后的跌落深度。根据基础功率、扰动限幅和非负处理,可确定代码输出包络不超过 39 W:
该数值是代码公式的理论上界,不是实测峰值,也不表示轨迹一定达到 39 W。
脚本将 3600 s 作为模拟一天,并构造:
其中:
evening_peak 由平方正弦计算,本身非负,因此其后的 max(0, evening_peak) 不改变数值。
中频分量为:
高频分量为:
另有小幅波动:
这些分量均是确定性正弦波,并非随机采样值。
令 ,脚本采用:
边界点采用代码的严格不等号:t_d = 600、2000 或 2800 时均进入“其他时段”,因而取 0.95。
| 起始时间(s) | 结束时间(s) | 平台功率变化(W) |
|---|---|---|
320 |
380 |
+5.0 |
850 |
900 |
-4.0 |
1450 |
1510 |
+4.5 |
2100 |
2150 |
-3.5 |
2780 |
2830 |
+5.5 |
3300 |
3360 |
-5.0 |
每个事件在开始和结束边缘采用 5 s 线性过渡。负载合成为:
最终严格限制为:
因此,代码输出的负载请求范围为 5 W 至 40 W,内部负载命令范围为 -40 W 至 -5 W。
pcc_wave_w() 当前固定返回:
函数内的 T = 1200 未参与当前返回值,20.0 W 分支已被注释。在当前 PCC 目标下:
仅依据光伏和负载各自的代码包络,可得到电池内部命令的保守理论范围:
这是由独立上下界推导的包络,不代表实际组合轨迹一定达到两个端点。
| 字段名 | 内容 | 数据性质 |
|---|---|---|
elapsed_s |
自 t0 起的采样相对时间 |
计算值 |
pv_power_w |
光伏 p1、兼容 p 或内部命令回退值 |
混合来源 |
battery_power_w |
电池 p1、兼容 p 或内部命令回退值 |
混合来源 |
load_power_w |
负载 p1、兼容 p 或内部命令回退值 |
混合来源 |
pcc_power_w |
PCC p1、兼容 p 或内部目标回退值 |
混合来源 |
soc_pct |
当前虚拟能量模型计算的 SOC | 计算值 |
sum_meas_w |
上述四个返回功率之和 | 计算值,输入可能含回退值 |
sum_meas_w 的名称沿用脚本,但当任一节点回退到内部命令时,该字段并非纯实测功率之和。CSV 不包含节点在线状态、回退标志、内部命令和 sum_cmd。
默认标称采样频率为 10 Hz、运行阈值为 18000 s,理论上约产生 180000 个采样行,实际行数受 loop() 调度、严格大于的结束判断及运行中断影响。所有行先保存在内存列表中,循环结束后一次性写入 CSV。
本案例可用于展示以下脚本级行为:
1 Hz 控制更新与 10 Hz 遥测采样的双时间尺度结构;脚本本身不能证明设备跟踪精度、通信实时性或实测功率平衡。相关结论需要结合 CSV 中数据来源、节点在线信息和外部测量结果另行验证。
1 至 4 与光伏、电池、负载、PCC 的现场映射。node.p 的符号方向以及遥测 p1、p 字段的符号定义。v = 20.0,并确认单位和控制模式。run_duration_s、send_hz 和 sample_hz,并确认两种频率组合得到的 control_tick_samples 符合预期。<repo_root>/data/output/ 可创建和写入。5 s;如需中止,可按启动日志提示从用户界面操作。SOC、cmd[P/L/B]、sum_cmd 和 state。Power+SOC table saved 日志中的 CSV 路径与行数。建议先在隔离环境缩短 run_duration_s,分阶段演示:
600 s,覆盖第一个负载事件、第一次光伏跌落及光伏基础半波;1 Hz 控制日志与 10 Hz CSV 采样行之间的时间尺度差异;sum_cmd 的代数平衡;shutdown()。若需完整展示所有预设事件,运行时间需覆盖最后一个负载事件结束时间 3360 s。默认 18000 s 可覆盖这些事件并重复周期波形,但现场演示是否使用该时长应根据设备条件确定。
| 观察项 | 判读建议 |
|---|---|
cmd[P/L/B] |
按光伏波形、负载负号及电池差额公式核对内部命令。 |
sum_cmd |
由代数构造应接近零;该值不是实测功率和。 |
SOC |
为命令积分并限幅后的虚拟值,不是电池管理系统反馈。 |
| CSV 四节点功率 | 可能来自 p1、兼容 p 或内部命令回退,需结合外部状态判断来源。 |
sum_meas_w |
是 CSV 中四个功率返回值之和;若含回退值,则不是纯实测和。 |
| CSV 行数 | 应结合实际运行时长和采样调度判断,不能仅按 10 Hz 理论值要求完全一致。 |
| 结束日志 | 表示代码已保存表格并顺序调用四次 shutdown();仍需现场确认设备状态。 |
5 h,另有启动前 5 s 延时。run_duration_s <= 0.0 时不通过脚本条件自动结束。50 W 充放电限值和负载削减均未在当前逻辑中启用。20% 或 100% 后,电池命令仍可能继续朝同一方向下发。get_latest_power_w() 无有效数据时静默使用回退值,不输出警告,也不在 CSV 标记回退。online 状态,CSV 中没有节点在线字段。3600 s 模拟周期。0 W;定义但未使用的 T = 1200 不形成 PCC 波形。case5_2,与当前案例文件名不一致。datetime.fromtimestamp(api.now()),其正确性依赖 api.now() 返回可解释为 Unix 时间戳的值。try/finally,未处理异常可能导致 CSV 保存和四节点关机未执行。shutdown() 的设备行为以接口实现为准。Path(__file__).resolve().parents[3] 依赖脚本目录层级,移动脚本后应核对输出根目录解析结果。本文档依据 case3.2_more_complex_pv_battery_load_pcc.py 的静态代码生成,未执行硬件、仿真或通信测试。节点编号、电压、容量、SOC、功率与时间参数均为案例设定,不代表设备额定能力或现场安全边界。实际部署前,应依据设备手册、通信接口定义、节点映射、保护策略、文件系统权限和项目操作规程完成审核与验证。