跳到主内容

物理约束决策

核心能力

物理约束决策

EnerOS 遵循「约束即法律」原则:任何 Agent 决策在落地前都必须通过内核约束引擎的校验,违反物理规律的命令会被直接拦截并投影到最近可行解。这一机制确保 Agent 智能永远在电力系统物理可行域内运行。

这是 EnerOS 区别于通用 AgentOS 的根本特征之一。在通用 AI Agent 系统中,模型输出的「不可行」决策最多导致业务失败;而在电力系统中,一次违反物理规律的开关操作可能引发大面积停电、设备损毁甚至人身事故。约束引擎以微秒级开销为代价,把所有 Agent 决策锁进物理可行域。

设计哲学

「约束即法律」包含三层含义:

  • 强制执行:约束校验不是可选步骤,而是内核命令通道的必经环节,Agent 无法绕过
  • 物理可行:所有约束基于电力系统物理规律(潮流方程、热稳定极限、稳定边界),而非业务规则
  • 可行投影:违反约束的命令不会被简单拒绝,而是投影到最近可行解,避免 Agent 陷入死循环

约束引擎架构

约束引擎位于内核态,分为三层:声明层(DSL)、校验层(同步)、投影层(异步)。

┌──────────────────────────────────────────────────┐
│  声明层 ConstraintBuilder (DSL)                  │
│  - 类型化约束构造器                              │
│  - 编译期类型检查                                │
└───────────────────┬──────────────────────────────┘
                    │ register()
┌───────────────────┴──────────────────────────────┐
│  校验层 ConstraintEngine.validate() (同步)       │
│  - 单约束 < 5μs                                  │
│  - 全量约束 < 200μs                              │
│  - 返回 ValidationResult                         │
└───────────────────┬──────────────────────────────┘
                    │ 若违反
┌───────────────────┴──────────────────────────────┐
│  投影层 ConstraintEngine.project() (异步)        │
│  - QP/LP 求解器                                  │
│  - 加权最小二乘                                  │
│  - 返回最近可行解                                │
└──────────────────────────────────────────────────┘

约束引擎初始化

use eneros_constraint::{ConstraintEngine, Constraint, ConstraintBuilder};

let mut engine = ConstraintEngine::new();

// 声明约束
engine.register(ConstraintBuilder::voltage_limit(0.95, 1.05));
engine.register(ConstraintBuilder::thermal_limit(bus_id, 100.0)); // MW
engine.register(ConstraintBuilder::line_flow_limit(branch_id, 50.0));
engine.register(ConstraintBuilder::frequency_band(49.5, 50.5));
engine.register(ConstraintBuilder::power_balance(tolerance: 0.1));
engine.register(ConstraintBuilder::reserve_requirement(0.05)); // 5% 负荷

ConstraintBuilder 方法一览

方法入参含义严格度
voltage_limitmin, max (p.u.)母线电压幅值上下限硬约束
thermal_limitelement_id, MVA元件热稳定极限硬约束
line_flow_limitbranch_id, MW支路有功上限硬约束
frequency_bandmin, max (Hz)系统频率允许范围硬约束
power_balancetolerance (MW)总发=总用+损耗硬约束
reserve_requirementpercent最小备用比例软约束
phase_angle_diffbus_a, bus_b, deg两节点相角差上限硬约束
short_circuit_capacitybus_id, MVA母线短路容量上限硬约束
contingencybase, contingency, postN-1 故障后满足约束计划约束
stability_marginpercent暂态稳定裕度软约束

约束 DSL

约束采用类型化 DSL,避免字符串解析的运行时风险,且支持编译期检查。

use eneros_constraint::{Constraint, Contingency};

// 电压约束
let v = Constraint::voltage()
    .bus(1)
    .min(0.95)
    .max(1.05)
    .build();

// 热稳定约束
let thermal = Constraint::thermal()
    .element(branch_id)
    .limit_mva(50.0)
    .emergency_limit_mva(60.0)
    .duration_secs(15 * 60)
    .build();

// N-1 约束
let n_minus_1 = Constraint::contingency()
    .base_case(v.clone())
    .contingency(Contingency::branch_out(5))
    .post_contingency(v.clone())
    .build();

// 频率约束
let freq = Constraint::frequency()
    .min(49.5)
    .max(50.5)
    .rocof_max(0.5)  // Hz/s 频率变化率
    .build();

// 备用约束(软约束)
let reserve = Constraint::reserve()
    .load_following(50.0)    // MW
    .spinning(100.0)         // MW
    .non_spinning(200.0)     // MW
    .severity(Severity::Soft)
    .build();

Constraint 字段说明

字段类型含义
idConstraintId约束唯一标识
kindConstraintKind电压/热稳定/频率/备用/N-1 等
scopeScope作用范围:母线、支路、系统
severitySeverityHard(硬)/ Soft(软)/ Planning(计划)
penaltyf64软约束违反时的罚因子
enabledbool是否启用
tagsVec用户标签,便于分组查询

决策校验

Agent 产生的命令在执行前必须经过 validate

use eneros_constraint::{ValidationResult, DispatchDecision};

let decision = DispatchDecision::new()
    .set_generator(gen_id, 80.0)  // MW
    .open_branch(branch_id)
    .adjust_tap(xfmr_id, 5)
    .set_load(bus_id, 50.0);      // MW

match engine.validate(&decision, &network) {
    ValidationResult::Ok => {
        ctx.execute(decision).await?;
    }
    ValidationResult::Violated(violations) => {
        log::warn!("决策违反约束: {:?}", violations);
        // 投影到最近可行解
        let projected = engine.project(&decision, &network)?;
        ctx.execute(projected).await?;
    }
    ValidationResult::Fatal(fatal) => {
        log::error!("致命违反: {:?}", fatal);
        ctx.emergency_block().await?;
    }
}

ValidationResult 变体

变体含义处理方式
Ok所有约束满足直接执行
Violated软/硬约束违反,可投影调用 project() 投影
Fatal致命违反(如频率失稳)紧急闭锁,停止 Agent

Violation 结构

pub struct Violation {
    pub constraint_id: ConstraintId,
    pub kind: ConstraintKind,
    pub element: ElementId,
    pub actual: f64,
    pub limit: f64,
    pub deviation: f64,
    pub severity: Severity,
    pub message: String,
}

可行性投影

当原始决策违反约束时,投影层会基于 QP/LP 求解器将其投影到约束可行域的最近边界,避免简单拒绝导致的 Agent 陷入死循环。

use eneros_constraint::ProjectionStrategy;

// 投影策略:加权最小二乘
let strategy = ProjectionStrategy::WeightedLeastSquares {
    weights: weights_map,
    max_iter: 100,
    tolerance: 1e-6,
};

let projected = engine.project_with(&decision, &network, strategy)?;
// projected 满足所有硬约束,且与原始决策距离最小

ProjectionStrategy 变体

策略适用场景求解器典型耗时
WeightedLeastSquares一般调度决策QP(OSQP)< 20ms
LeastSquares等权重投影QP(OSQP)< 15ms
LinearProgram纯线性约束LP(HiGHS)< 5ms
MinShift最小调整量MILP< 50ms
PriorityBased按优先级调整启发式< 1ms

自定义投影示例

use eneros_constraint::{Projector, Decision};

struct EconomicProjector {
    gen_costs: Vec<f64>,
}

impl Projector for EconomicProjector {
    fn project(
        &self,
        decision: &Decision,
        constraints: &[Constraint],
        network: &NetworkGraph,
    ) -> ProjectResult {
        // 按发电成本升序调整,优先降成本高的机组
        let mut sorted_gens = decision.gen_changes.clone();
        sorted_gens.sort_by(|a, b| {
            self.gen_costs[a.gen_id as usize]
                .partial_cmp(&self.gen_costs[b.gen_id as usize])
                .unwrap()
        });

        let mut projected = decision.clone();
        for c in constraints {
            if c.is_violated(&projected, network) {
                self.adjust_for(&mut projected, c, &sorted_gens)?;
            }
        }
        Ok(projected)
    }
}

let projected = engine.project_with_strategy(&decision, &network, EconomicProjector { gen_costs })?;

约束类型矩阵

类别约束严格度检查时机
电压V_min ≤ V_i ≤ V_max硬约束实时 + 决策前
热稳定I_ij ≤ I_max硬约束实时 + 决策前
频率f_min ≤ f ≤ f_max硬约束实时
频率变化率df/dt≤ RoCoF_max
功率平衡ΣP_gen = ΣP_load + Loss硬约束决策前
备用Reserve ≥ 5% Load软约束计划
N-1单一故障后满足上述计划约束计划
短路容量I_sc ≤ I_sc_max硬约束规划
暂态稳定稳定裕度 ≥ 阈值软约束在线
电压稳定裕度 ≥ 阈值软约束在线

内核强制执行

约束引擎作为内核模块,挂在命令执行通道上,所有 ctx.execute(decision) 调用都会自动经过约束校验,Agent 无法绕过:

use eneros_constraint::KernelHook;

// 内核启动时挂载约束钩子
KernelHook::mount(&constraint_engine)?;

// 此后所有 ctx.execute() 自动调用:
//   1. engine.validate(&decision, &network)
//   2. 若 Violated → 自动调用 project()
//   3. 若 Fatal → 拦截并触发 emergency_block

N-1 校验

针对关键场景的 N-1 安全校核:

use eneros_constraint::{ContingencySet, Contingency};

let contingencies = ContingencySet::new()
    .add(Contingency::branch_out(5))
    .add(Contingency::branch_out(12))
    .add(Contingency::generator_out(gen_id))
    .add(Contingency::bus_split(bus_id));

let report = engine.n_minus_1_check(&network, &contingencies)?;
for case in &report.cases {
    if !case.feasible {
        println!("故障 {:?} 后违反: {:?}", case.contingency, case.violations);
    }
}
println!("通过率: {}/{}", report.passed, report.total);

性能指标

操作延迟备注
单约束校验< 5μs缓存命中
全量约束校验(1000 节点)< 200μs含潮流结果
全量约束校验(10万 节点)< 5ms含潮流结果
可行性投影(LP, 1000 变量)< 5msHiGHS
可行性投影(QP, 1000 变量)< 20msOSQP
N-1 校验(100 故障集)< 50ms并行
约束注册< 10μs-
约束热更新< 100μs不中断校验

测试环境:4 核 / 8GB / Ubuntu 22.04,节点数 1000。

配置参数

eneros.toml 中约束相关配置:

[constraint]
# 约束校验严格度:strict / permissive / audit_only
mode = "strict"
# 是否自动投影违反决策
auto_project = true
# 默认投影策略:wls / ls / lp / min_shift / priority
default_projection = "wls"
# N-1 校验并行度
n_minus_1_parallelism = 4
# 软约束罚因子(默认)
soft_penalty = 1000.0
# 致命违反是否触发紧急闭锁
fatal_emergency_block = true
# 约束缓存大小
cache_size = 4096
参数类型默认值说明
modeenumstrict校验模式
auto_projectbooltrue自动投影违反决策
default_projectionenumwls默认投影策略
n_minus_1_parallelismu324N-1 校验并行度
soft_penaltyf641000.0软约束默认罚因子
fatal_emergency_blockbooltrue致命违反触发闭锁
cache_sizeu324096约束结果缓存条数

与其他能力的关系

关联能力互动方式
电网拓扑一等公民约束基于拓扑计算
安全守卫约束引擎是安全网关的核心组件
数字孪生引擎What-If 推演调用约束校验
多智能体协作Agent 决策必经约束校验
实时双执行域实时域约束校验在微秒级完成
设备模型库热稳定极限来自设备参数
时序原生操作约束违反事件入库

相关文档