跳到主内容

实时双执行域

核心能力

实时双执行域

EnerOS 采用双执行域架构:通用执行域(General Domain)承载 Agent 编排、AI 推理、业务逻辑;实时执行域(Real-time Domain)承载保护逻辑、开关操作、闭环控制,保障 P99 < 1ms 的确定性时延。两个域通过内核态共享内存通信,避免进程切换开销。

电力系统对时延有严苛要求:继电保护必须在 4 个周波(80ms@50Hz)内动作,PMU 相量计算要求 30Hz 以上输出,闭环 AVR 控制周期在 100ms 级。通用操作系统(Linux CFS 调度)的毫秒级抖动无法满足这些场景。EnerOS 通过双执行域把「快慢分离」做到内核级。

架构总览

┌─────────────────────────────────────────────────┐
│           通用执行域 (General Domain)           │
│  - Agent 编排                                   │
│  - LLM 推理                                     │
│  - 业务流程                                     │
│  - 时序分析                                     │
│  - 调度:CFS(完全公平调度器)                  │
└──────────────────┬──────────────────────────────┘
                   │ 共享内存 / 无锁队列
                   │ 延迟 < 10μs
┌──────────────────┴──────────────────────────────┐
│           实时执行域 (Real-time Domain)         │
│  - 保护逻辑 (4ms)                               │
│  - 闭环控制 (1ms)                               │
│  - 开关操作 (100μs)                             │
│  - 相量计算 (250μs)                             │
│  - 调度:SCHED_FIFO / PREEMPT_RT / Xenomai      │
└─────────────────────────────────────────────────┘

域职责划分

任务类型通用执行域实时执行域
Agent 编排-
LLM 推理-
潮流计算-
状态估计100ms 周期版本
数字孪生 What-If-
保护逻辑(距离保护)-
闭环控制(AVR / AGC)-
开关操作(GOOSE)-
相量计算(PMU)-
故障录波触发-

实时域任务定义

实时任务通过 RealtimeTask trait 定义,遵循周期触发模型:

use eneros_realtime::{RealtimeTask, RtContext, RtResult};
use std::time::Duration;

struct ProtectionLogic {
    period: Duration,
    breaker_id: u32,
    zone_reach: f64,  // Ω
}

impl RealtimeTask for ProtectionLogic {
    fn period(&self) -> Duration { self.period }

    fn priority(&self) -> i32 { 99 }  // SCHED_FIFO 优先级

    fn cpu_affinity(&self) -> Option<Vec<u32>> {
        Some(vec![0, 1])  // 绑定到 CPU 0,1
    }

    fn run(&mut self, ctx: &mut RtContext) -> RtResult<()> {
        // 读取 PMU 数据(共享内存,零拷贝)
        let pmu = ctx.pmu_snapshot();

        // 距离保护算法
        let z_seen = self.compute_impedance(&pmu);
        if z_seen < self.zone_reach {
            // 立即跳闸(无锁通道,< 100μs)
            ctx.trip_breaker(self.breaker_id);
            ctx.log_event(ProtectionEvent::Trip {
                impedance: z_seen,
                reach: self.zone_reach,
            });
        }

        Ok(())
    }
}

impl ProtectionLogic {
    fn compute_impedance(&self, pmu: &PmuSnapshot) -> f64 {
        let v = pmu.voltage_complex();
        let i = pmu.current_complex();
        (v / i).norm()
    }
}

RealtimeTask trait 方法

方法类型必填说明
period()Duration任务周期
priority()i32SCHED_FIFO 优先级(1-99)
cpu_affinity()Option<Vec>CPU 亲和性
run(&mut ctx)RtResult任务主体
init(&mut ctx)RtResult初始化
on_overrun(dur)RtResult超时回调
shutdown(&mut ctx)RtResult退出清理

任务调度

实时域采用基于优先级的抢占式调度,配合 Linux PREEMPT_RT 或 Xenomai:

use eneros_realtime::{RtScheduler, SchedPolicy, IsolationConfig};

let mut sched = RtScheduler::new()
    .policy(SchedPolicy::Fifo)
    .cpu_affinity(0..2)  // 隔离 CPU 0,1
    .isolate_from_general(true)
    .isolation(IsolationConfig {
        isolcpus: true,           // 内核启动参数 isolcpus
        nohz_full: true,          // NO_HZ_FULL
        rcu_nocbs: true,          // RCU 卸载
        huge_pages: true,         // 大页内存
        disable_irq: true,        // 禁用 IRQ
    });

sched.spawn(ProtectionLogic::new(Duration::from_micros(4000), brk_id, 5.0));
sched.spawn(ClosedLoopControl::new(Duration::from_millis(1)));
sched.spawn(BreakerOperation::new(Duration::from_micros(100)));
sched.spawn(PhasorCalculator::new(Duration::from_micros(250)));
sched.start()?;

SchedPolicy 变体

策略说明适用场景
FifoSCHED_FIFO 先进先出大多数实时任务
RoundRobinSCHED_RR 时间片轮转同优先级多任务
DeadlineSCHED_DEADLINE EDF周期任务
XenomaiXenomai Cobalt极致实时性

跨域通信

两个域通过无锁环形队列通信,避免锁竞争与缓存抖动:

use eneros_realtime::cross::{Channel, Message, ChannelConfig};

let (tx, rx) = Channel::unbounded::<ControlCmd>(
    ChannelConfig {
        capacity: 1024,
        spin_wait_us: 5,
        cache_align: true,
    },
);

// 通用域 → 实时域
tx.send(ControlCmd::SetVoltage(1.02))?;

// 实时域接收(非阻塞)
if let Some(cmd) = rx.try_recv() {
    match cmd {
        ControlCmd::SetVoltage(v) => self.target_voltage = v,
        ControlCmd::TripBreaker(id) => ctx.trip_breaker(id),
    }
}

// 实时域 → 通用域(事件上报)
let (evt_tx, evt_rx) = Channel::bounded::<RtEvent>(256);
evt_tx.send(RtEvent::BreakerTripped { id: 5, reason: "overcurrent" });

Channel 类型

类型容量阻塞行为适用场景
unbounded无限发送不阻塞通用→实时
bounded(n)n满则阻塞实时→通用
spsc1单生产单消费高速数据流
mpmcn多生产多消费一般场景

跨域消息延迟

路径延迟(P99)
通用 → 实时(无锁队列)< 5μs
实时 → 通用(事件队列)< 10μs
共享内存读取< 1μs
共享内存写入< 1μs

确定性保证

措施说明效果
CPU 隔离isolcpus=0,1 隔离实时核心避免被其他进程抢占
内存预分配启动时分配,运行时无 GC避免分配抖动
无锁数据结构SPSC/MPMC 无锁队列避免锁竞争
大页内存2MB / 1GB hugepages减少 TLB miss
中断亲和网卡中断绑定到非实时核避免 IRQ 打断
看门狗任务超时自动重置故障自愈
NO_HZ_FULL减少 timer tick减少上下文切换
RCU nocbsRCU 回调卸载减少抖动

内核启动参数示例

# /etc/default/grub
GRUB_CMDLINE_LINUX="isolcpus=0,1 nohz_full=0,1 rcu_nocbs=0,1 \
    hugepagesz=2M hugepages=512 iommu=pt intel_idle.max_cstate=0 \
    processor.max_cstate=0 idle=poll"

任务类型与周期

任务周期优先级抖动CPU
开关操作(GOOSE)100μs99< 5μs0
相量计算(PMU)250μs98< 10μs0
闭环控制(AVR)1ms95< 50μs1
闭环控制(AGC)4ms94< 100μs1
保护逻辑(距离)4ms90< 100μs0
保护逻辑(过流)4ms90< 100μs0
状态估计(快速)100ms50< 1ms1
通信(IEC 61850)1ms80< 50μs1

RtContext API

实时任务上下文提供的 API:

use eneros_realtime::RtContext;

impl RtContext {
    // 数据访问(共享内存,零拷贝)
    pub fn pmu_snapshot(&self) -> PmuSnapshot;
    pub fn rtu_snapshot(&self) -> RtuSnapshot;
    pub fn network_state(&self) -> NetworkState;

    // 控制输出
    pub fn trip_breaker(&self, id: u32);
    pub fn close_breaker(&self, id: u32);
    pub fn set_excitation(&self, gen_id: u32, v: f64);
    pub fn set_tap(&self, xfmr_id: u32, tap: i16);

    // 通信
    pub fn send_event(&self, evt: RtEvent);
    pub fn try_recv_cmd(&self) -> Option<ControlCmd>;

    // 日志(lock-free)
    pub fn log_event(&self, evt: impl Event);
    pub fn waveform_record(&self, data: &WaveformBuffer);

    // 时间
    pub fn now(&self) -> Timestamp;
    pub fn elapsed(&self) -> Duration;
}

故障切换

通用域故障不会影响实时域:实时域检测到通用域心跳超时后,自动切换到「安全模式」,按预设策略运行。

use eneros_realtime::SafetyMode;

sched.on_general_domain_timeout(|| {
    // 切换到安全模式
    SafetyMode::island_operation()
        .hold_frequency(50.0)
        .hold_voltage(1.0)
        .disable_remote_control()
        .enable_local_protection()
        .activate();
});

// 心跳配置
sched.heartbeat_config(HeartbeatConfig {
    interval: Duration::from_millis(100),
    timeout: Duration::from_millis(500),
    on_missed: HeartbeatAction::Warn,
    on_timeout: HeartbeatAction::EnterSafetyMode,
});

SafetyMode 行为

行为含义
hold_frequency维持频率在设定值
hold_voltage维持电压在设定值
disable_remote_control拒绝远程控制命令
enable_local_protection启用本地保护
activate激活安全模式

性能指标

指标数值测试方法
任务调度抖动(P99)< 50μs1 万次周期任务
任务调度抖动(P99.9)< 100μs1 万次周期任务
跨域消息延迟< 10μs无锁队列
GPIO 响应(开关操作)< 100μs示波器测量
端到端保护动作(P99)< 1ms故障注入
端到端保护动作(最坏)< 4ms故障注入
最大连续无抖动运行> 30 天7×24 测试
CPU 利用率(实时核)< 60%满负荷
内存占用(实时域)< 100MB预分配

测试环境:Intel Xeon 4 核 / 8GB / Ubuntu 22.04 + PREEMPT_RT。

配置参数

eneros.toml 中实时域相关配置:

[realtime]
# 调度策略:fifo / round_robin / deadline / xenomai
policy = "fifo"
# 实时 CPU 核(与 isolcpus 一致)
cpus = [0, 1]
# 大页内存(MB)
huge_pages_mb = 1024
# 是否启用看门狗
watchdog = true
# 看门狗超时(ms)
watchdog_timeout_ms = 100
# 心跳间隔(ms)
heartbeat_interval_ms = 100
# 心跳超时(ms)
heartbeat_timeout_ms = 500
# 故障切换安全模式
safety_mode_on_timeout = true
# 实时任务最大数
max_tasks = 256
参数类型默认值说明
policyenumfifo调度策略
cpusVec[0,1]实时 CPU 核
huge_pages_mbu321024大页内存大小
watchdogbooltrue启用看门狗
watchdog_timeout_msu32100看门狗超时
heartbeat_interval_msu32100心跳间隔
heartbeat_timeout_msu32500心跳超时
safety_mode_on_timeoutbooltrue超时切换安全模式
max_tasksu32256实时任务最大数

与其他能力的关系

关联能力互动方式
安全守卫实时域命令也经过网关(精简版)
数字孪生引擎与实时域同步镜像
设备模型库实时域使用精简设备模型
多智能体协作保护类 Agent 运行在实时域
时序原生操作PMU 数据流式写入
物理约束决策实时域约束校验在微秒级完成
电网拓扑一等公民拓扑变更实时同步到实时域

相关文档