储能仿真系统-需求和设计
- 写在前面
- 1. 需求来源:我们要解决什么问题
- 1.1 仿真范围(端到端)
- 1.2 可扩展与可配置
- 1.3 联调友好
- 2. 总体架构:三层分工
- 2.1 模拟层(`EssDeviceSimModel/`)
- 2.2 接口与数据服务层
- 2.3 展示与交互层(`Display/`)
- 2.4 基础设施
- 3. 数据流与线程模型(设计要点)
- 3.1 仿真主循环
- 3.2 Modbus 侧
- 3.3 PCS 功率爬坡
- 3.4 并发安全
- 4. 配置与点表设计
- 4.1 `appsettings.json`
- 4.2 CSV 点表
- 5. 健壮性与错误处理(设计目标)
- 6. 结语
- 写在结尾
写在前面
本文对应EssSimulator的方案层描述:项目要达成什么目标、模块如何划分、数据如何流动。
1. 需求来源:我们要解决什么问题
1.1 仿真范围(端到端)
在方案层面,本系统面向储能站(ESS)端到端的可运行替身,典型包括:
- 多套电池堆(Rack)及 BMS 语义下的簇/包/单体状态演化;
- 多台 PCS:有功/无功指令、爬坡、并网/离网、直流/交流侧关键量、故障与保护检验;
- 主断路器、变压器(含主变与单元变)、计划负载;
- 对外提供Modbus TCP(以及方案中预留的 IEC61850 等)接口,便于上位机/EMS/网关联调。
1.2 可扩展与可配置
- 拓扑与通道数由配置(如
Simulator.Devices)驱动,而非写死在代码里; - 点位与内部变量通过 CSV 映射到对象路径,新增寄存器或调整地址时尽量不改核心模型代码;
- 参数化PCS 物理限值、变压器阻抗与损耗、负载计划、仿真步长与加速倍率等,便于不同站型复用同一程序骨架。
1.3 联调友好
- 可无可视化运行(
NoGui),便于 CI 或服务器侧长期挂起; - 提供控制台 GUI、命令(如
dpc/esscmd)、自动化脚本入口,缩短「改配置—观察现象」的反馈回路。
2. 总体架构:三层分工
2.1 模拟层(EssDeviceSimModel/)
职责:物理与状态行为。
EnergyStorageSystem:作为托管后台服务,按固定步长推进仿真时钟,编排 PCS、电池、断路器、变压器、负载之间的能量与电气量耦合。- 设备子模型:电池堆、PCS、断路器、变压器、计划负载等,各自封装状态更新与保护逻辑。
2.2 接口与数据服务层
职责:把内部对象暴露成外部世界能消费的协议与数据形态。
- Modbus:从站模拟、按点表读写、worker 与控制线程分工(详见方案文档中的线程模型描述)。
EssSimModelApi/:BMS、PCS/EMU、电表等数据服务与映射,将模型输出整理为对外通道所需结构。- IEC61850(方案/相关工程):对象模型、报告与事件方向的能力预留,与对象路径体系对齐。
2.3 展示与交互层(Display/)
职责:人机可读的状态与调试入口。
- 主接线、电池堆/簇/单体视图、连接信息、日志等页面;
- 命令解析与联调辅助(含基于 JSON 的自动化步骤)。
2.4 基础设施
CSV 解析、TCP 通讯抽象、对象路径解析与聚合、日志(log4net)等,为上述三层提供共用能力。
3. 数据流与线程模型(设计要点)
3.1 仿真主循环
- 以配置的仿真步长(真实休眠间隔 × 加速倍率)为 tick;
- 典型耦合关系包括:交流侧电流采样与负载叠加 → 断路器逻辑 → 变压器一次侧电压与 PCS 并网条件 → 直流侧与电池堆的电压/电流互换等(具体以
EnergyStorageSystem实现为准)。
3.2 Modbus 侧
- 按模型类型或通道划分 worker,结合优先级队列调度下一次刷新,减少无效写;
- 使用影子缓存(shadow)避免重复写、并在控制通道上记录外部写入的变化;
- 控制线程周期性读取 FC=6 等控制点,解析后写回模拟器内部变量。
3.3 PCS 功率爬坡
- 有/无功可分别由后台线程按阶段目标推进;
- 新设定到达时可打断重算,以贴近真实 PCS 的非阶跃响应;
- 爬坡参数支持全局默认 + 单台 PCS 覆盖,便于 A/B 对比同一策略下的执行差异。
3.4 并发安全
共享状态在关键路径上使用锁保护;线程优先级与睡眠策略用于在「实时感」与 CPU 占用之间折中。
4. 配置与点表设计
4.1appsettings.json
集中承载:运行期(步长、加速、无头)、协议端口规划、设备清单、PCS/变压器/负载物理与计划参数等。
{ "Simulator": { "Runtime": { "SimStepMs": 200, "Speedup": 1.0, "NoGui": false }, "Protocol": { "BaseBmsModbusPort": 1501, "BmsPortStep": 1, "BaseEmuModbusPort": 1601, "EmuPortStep": 1, "EmModbusPort": 1500 }, "Devices": [ { "Name": "Unit-1", "Pcs": [ { "Name": "PCS-1A", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } }, { "Name": "PCS-1B", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } } ], "Bms": [ { "Name": "BMS-1A", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.55, "CellInitialSocRandomRange": 0.03, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 }, { "Name": "BMS-1B", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.50, "CellInitialSocRandomRange": 0.03, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 } ] }, { "Name": "Unit-2", "Pcs": [ { "Name": "PCS-2A", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } }, { "Name": "PCS-2B", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } } ], "Bms": [ { "Name": "BMS-2A", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.60, "CellInitialSocRandomRange": 0.02, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 }, { "Name": "BMS-2B", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.45, "CellInitialSocRandomRange": 0.02, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 } ] }, { "Name": "Unit-3", "Pcs": [ { "Name": "PCS-3A", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } }, { "Name": "PCS-3B", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } } ], "Bms": [ { "Name": "BMS-3A", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.60, "CellInitialSocRandomRange": 0.02, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 }, { "Name": "BMS-3B", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.45, "CellInitialSocRandomRange": 0.02, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 } ] }, { "Name": "Unit-4", "Pcs": [ { "Name": "PCS-4A", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } }, { "Name": "PCS-4B", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } } ], "Bms": [ { "Name": "BMS-4A", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.60, "CellInitialSocRandomRange": 0.02, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 }, { "Name": "BMS-4B", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.45, "CellInitialSocRandomRange": 0.02, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 } ] }, { "Name": "Unit-5", "Pcs": [ { "Name": "PCS-5A", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } }, { "Name": "PCS-5B", "PcsRamp": { "Slope": 0.5, "IntervalMs": 100, "DelayMs": 0 } } ], "Bms": [ { "Name": "BMS-5A", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.60, "CellInitialSocRandomRange": 0.02, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 }, { "Name": "BMS-5B", "ClusterCount": 12, "PackCount": 4, "CellSeriesCount": 104, "CellParallelCount": 1, "CellNominalVoltage": 3.2, "CellNominalCapacity": 314, "CellInitialSoc": 0.45, "CellInitialSocRandomRange": 0.02, "PackInternalResistance": 0.05, "ClusterInternalResistance": 0.1, "RackInternalResistance": 0.02 } ] } ] }, "Pcs": { "RatedPower": 2508, "MaxPower": 2508, "Efficiency": 0.99, "DcVoltageRangeMin": 1000, "DcVoltageRangeMax": 1500, "AcVoltageNominal": 690, "FrequencyNominal": 50, "MaxCurrent": 2200, "GridLossCoefficient": 0.11 }, "Transformer": { "RatedPower": 2500, "PrimaryVoltage": 220000, "SecondaryVoltage": 35000, "NoLoadLoss": 50, "LoadLoss": 200, "ImpedancePercent": 4, "ReactiveVoltageInfluenceCoefficient": 1.0, "NoLoadCurrentPercent": 2 }, "UnitTransformer": { "RatedPower": 2500, "PrimaryVoltage": 35000, "SecondaryVoltage": 690, "NoLoadLoss": 50, "LoadLoss": 200, "ImpedancePercent": 4, "ReactiveVoltageInfluenceCoefficient": 1.0, "NoLoadCurrentPercent": 2 }, "Load": { "ActivePowerPlan": -500, "ReactivePowerPlan": 0 } }4.2 CSV 点表
字段通常涵盖:地址、功能码、参数名、缩放、数据类型与宽度、ModelSim到内部路径的映射等。电表的点位表(.csv)示例如下:
FunctionCode,Address,Type,Size,ParamName,Scale,Description,ModelSim 4,0,int32,32,yc0,1000,A相电压,model=4|arg1=em.PhaseAVoltage|arg2= |arg3= |arg4=100 4,2,int32,32,yc1,1000,B相电压,model=4|arg1=em.PhaseBVoltage|arg2= |arg3= |arg4=100 4,4,int32,32,yc2,1000,C相电压,model=4|arg1=em.PhaseCVoltage|arg2= |arg3= |arg4=100 4,6,int32,32,yc3,1000,AB线电压,model=4|arg1=em.LineVoltageAB|arg2= |arg3= |arg4=100 4,8,int32,32,yc4,1000,BC线电压,model=4|arg1=em.LineVoltageBC|arg2= |arg3= |arg4=100 4,10,int32,32,yc5,1000,CA线电压,model=4|arg1=em.LineVoltageCA|arg2= |arg3= |arg4=100 4,12,int32,32,yc6,1000,A相电流,model=4|arg1=em.PhaseACurrent|arg2= |arg3= |arg4=100 4,14,int32,32,yc7,1000,B相电流,model=4|arg1=em.PhaseBCurrent|arg2= |arg3= |arg4=100 4,16,int32,32,yc8,1000,C相电流,model=4|arg1=em.PhaseCCurrent|arg2= |arg3= |arg4=100 4,18,int32,32,yc9,1000,A相有功功率,model=4|arg1=em.PhaseAActivePower|arg2= |arg3= |arg4=100 4,20,int32,32,yc10,1000,B相有功功率,model=4|arg1=em.PhaseBActivePower|arg2= |arg3= |arg4=100 4,22,int32,32,yc11,1000,C相有功功率,model=4|arg1=em.PhaseCActivePower|arg2= |arg3= |arg4=100 4,24,int32,32,yc12,1000,总有功功率,model=4|arg1=em.TotalActivePower|arg2= |arg3= |arg4=100 4,26,int32,32,yc13,1000,A相无功功率,model=4|arg1=em.PhaseAReactivePower|arg2= |arg3= |arg4=100 4,28,int32,32,yc14,1000,B相无功功率,model=4|arg1=em.PhaseBReactivePower|arg2= |arg3= |arg4=100 4,30,int32,32,yc15,1000,C相无功功率,model=4|arg1=em.PhaseCReactivePower|arg2= |arg3= |arg4=100 4,32,int32,32,yc16,1000,总无功功率,model=4|arg1=em.TotalReactivePower|arg2= |arg3= |arg4=100 4,34,int32,32,yc17,1000,总视在功率,model=4|arg1=em.TotalApparentPower|arg2= |arg3= |arg4=100 4,36,int32,32,yc18,1000,功率因数,model=4|arg1=em.PowerFactor|arg2= |arg3= |arg4=100 4,38,int32,32,yc19,1000,频率,model=4|arg1=em.Frequency|arg2= |arg3= |arg4=100 4,40,int32,32,yc20,1000,正向总有功电能,model=4|arg1=em.ForwardActiveEnergy|arg2= |arg3= |arg4=100 4,42,int32,32,yc21,1000,反向总有功电能,model=4|arg1=em.ReverseActiveEnergy|arg2= |arg3= |arg4=1005. 健壮性与错误处理(设计目标)
- 影子写与防抖,降低 Modbus 写风暴;
- 分从站隔离失败影响,避免单点通讯异常拖垮整体;
- PCS 过载、电压/温度/孤岛等条件进入故障态的可预期路径;
- 指令限幅与并网前电网可用性检查,减少「非法设定导致状态发散」。
6. 结语
本系统的需求是:用可配置、可协议化的方式,在桌面上复现 ESS 关键行为,并服务多团队联调。
设计上采用「模型 / 协议与映射 / 展示」分层、显式线程与数据流、对象路径 + CSV 解耦点表,从而在扩展性与可维护性之间取得工程上可落地的平衡。
写在结尾
下一篇《储能仿真系统-功能和用途》将面向使用者,整理具体能力与典型场景。天道酬请,与君共勉!