跳到主要内容

OEE 综合设备效率服务

概述

OEE (Overall Equipment Effectiveness) 是衡量生产效率的核心 KPI, 由稼动率 × 性能率 × 合格率三项相乘得到, 单位 %。世界级工厂 OEE ≥ 85%, 普通工厂 50-60%, 连 40% 都达不到说明产线有系统性问题。

DarraRT 内置 Darra.OEE.Service 子服务, 基于 PLC 状态变量 + 计数器 + 故障码自动计算, 支持班次 / 日 / 周 / 月多层汇总, 配合 HMI 大屏实时显示。

OEE = 稼动率 (Availability) × 性能率 (Performance) × 合格率 (Quality)

公式

分项公式典型值
稼动率实际运行时间 / 计划生产时间85-95%
性能率(实际产量 × 标准节拍) / 实际运行时间80-90%
合格率合格数 / 总产量95-99%
OEE三者相乘70-85%

定义细化:

  • 计划生产时间 = 班次时长 − 计划停机 (用餐 / 换模 / 计划保养)
  • 实际运行时间 = 计划生产时间 − 非计划停机 (故障 / 待料 / 换线)
  • 标准节拍 (Ideal Cycle Time) = 设计产能对应的单件时间
  • 合格数 = 总产量 − 不良 − 返工

适用场景

场景数据源汇总粒度
单工位 OEEPLC 状态 + 计数实时 / 小时 / 班次
单设备 / 单元 OEE本机多工位瓶颈班次 / 日

车间 / 厂级的跨产线、多车间 OEE 汇总属于上层 MES 职责。DarraRT 只计算本机/本单元的 OEE, 并通过 OPC UA 把这些指标暴露给上层 MES/SCADA 做跨线汇总。

架构图

┌────────── PLC ──────────┐
│ - RunState (BOOL) │
│ - FaultCode (WORD) │
│ - ProduceCount (DINT) │ ── 每秒采样 ──► ┌─────────────┐
│ - RejectCount (DINT) │ │ OEE.Service │
│ - CycleMs (DINT) │ │ (FB调用 + SQL) │
│ - ShiftPlan (STRUCT) │ └──────┬──────┘
└─────────────────────────┘ │

┌───────────────────────┐
│ t_oee_minute (分钟级) │
│ t_oee_shift (班次级) │
│ t_oee_day (日级) │
└─────────┬─────────────┘
│ API / HMI

┌───────────────────────┐
│ <darra-dx-speedometer>│
│ <darra-trend> │
└───────────────────────┘

前置条件

  • PLC 程序已声明 RunState / FaultCode / ProduceCount / RejectCount / CycleMs
  • 班次计划表已录入 t_shift_plan
  • 标准节拍已标定 (每个产品型号不同)

详细步骤

步骤 1: PLC 侧状态机

// 运行状态枚举 (与 OEE 服务约定)
TYPE E_RunState : (
IDLE := 0, // 空闲/待机 (非计划停机)
RUN := 1, // 正常生产
FAULT := 2, // 故障
PAUSE := 3, // 计划停机 (换模/保养/餐休)
BLOCKED := 4, // 堵料 (下游满)
STARVED := 5 // 待料 (上游空)
);
END_TYPE

VAR_GLOBAL
DB_OEE : STRUCT
state : E_RunState;
fault_code : WORD;
produce_count : DINT;
reject_count : DINT;
cycle_ms : DINT; // 最近一次周期时间
ideal_cycle_ms: DINT := 1200; // 标准节拍
shift_start : DT;
shift_end : DT;
END_STRUCT
END_VAR

步骤 2: FB_OEECalculator 功能块

FUNCTION_BLOCK FB_OEECalculator
VAR_INPUT
runState : E_RunState;
faultCode : WORD;
produceCount : DINT;
rejectCount : DINT;
idealCycleMs : DINT;
sampleIntervalMs : DINT := 1000; // 调用周期
END_VAR

VAR_OUTPUT
Availability : REAL; // 0..100
Performance : REAL; // 0..100
Quality : REAL; // 0..100
OEE : REAL; // 0..100
END_VAR

VAR
// 时间累积 (ms)
plannedMs : DINT;
runMs : DINT;
faultMs : DINT;
pauseMs : DINT;
// 产量累积
totalProduced : DINT;
totalRejected : DINT;
// 上次调用的计数, 用来算 delta
lastProduce : DINT;
lastReject : DINT;
lastState : E_RunState;
END_VAR

// 1. 时间统计 (每调用一次累加 sampleIntervalMs)
CASE runState OF
RUN: runMs := runMs + sampleIntervalMs;
FAULT: faultMs := faultMs + sampleIntervalMs;
PAUSE: pauseMs := pauseMs + sampleIntervalMs;
IDLE, BLOCKED, STARVED:
// 这些算作非计划停机, 不计入运行, 但计入"计划生产时间"
;
END_CASE;

// 计划生产时间 = 所有时间 - 计划停机
plannedMs := plannedMs + sampleIntervalMs;
IF runState = PAUSE THEN
// 计划停机不计入
plannedMs := plannedMs - sampleIntervalMs;
END_IF;

// 2. 产量增量
totalProduced := totalProduced + (produceCount - lastProduce);
totalRejected := totalRejected + (rejectCount - lastReject);
lastProduce := produceCount;
lastReject := rejectCount;

// 3. 三率计算
IF plannedMs > 0 THEN
Availability := 100.0 * DINT_TO_REAL(runMs) / DINT_TO_REAL(plannedMs);
ELSE
Availability := 0.0;
END_IF;

IF runMs > 0 AND totalProduced > 0 THEN
Performance := 100.0 *
(DINT_TO_REAL(totalProduced) * DINT_TO_REAL(idealCycleMs))
/ DINT_TO_REAL(runMs);
IF Performance > 100.0 THEN Performance := 100.0; END_IF;
ELSE
Performance := 0.0;
END_IF;

IF totalProduced > 0 THEN
Quality := 100.0 * DINT_TO_REAL(totalProduced - totalRejected)
/ DINT_TO_REAL(totalProduced);
ELSE
Quality := 0.0;
END_IF;

OEE := Availability * Performance * Quality / 10000.0;

lastState := runState;

步骤 3: Service 侧汇总

Service 每分钟把 FB 累积的 plannedMs / runMs / totalProduced / totalRejected 快照落库, 同时重置 FB 计数器。

// Darra.PLC.Service / OEE / OeeAggregator.cs
public async Task FlushMinuteAsync(DateTime ts)
{
var snap = _plc.Read<OeeSnapshot>("DB_OEE.snapshot");
await _db.ExecuteAsync(@"
INSERT INTO t_oee_minute(ts, device_id, planned_ms, run_ms,
fault_ms, pause_ms,
produced, rejected,
availability, performance, quality, oee)
VALUES (@ts, @dev, @planned, @run,
@fault, @pause,
@produced, @rejected,
@a, @p, @q, @oee)
", new { ts, dev = _deviceId, /* ... */ });

_plc.ResetCounters("FB_OEE");
}

// 班次/日 汇总由定时 Job 从 t_oee_minute 聚合上卷

步骤 4: 数据库 Schema

CREATE TABLE t_oee_minute (
ts TIMESTAMPTZ NOT NULL,
device_id TEXT NOT NULL,
planned_ms BIGINT,
run_ms BIGINT,
fault_ms BIGINT,
pause_ms BIGINT,
produced INTEGER,
rejected INTEGER,
availability NUMERIC(5,2),
performance NUMERIC(5,2),
quality NUMERIC(5,2),
oee NUMERIC(5,2),
PRIMARY KEY (ts, device_id)
);

CREATE TABLE t_oee_shift (
shift_id BIGINT PRIMARY KEY,
shift_code TEXT NOT NULL, -- A班/B班/C班
device_id TEXT NOT NULL,
start_ts TIMESTAMPTZ NOT NULL,
end_ts TIMESTAMPTZ NOT NULL,
availability NUMERIC(5,2),
performance NUMERIC(5,2),
quality NUMERIC(5,2),
oee NUMERIC(5,2),
produced INTEGER,
rejected INTEGER
);

CREATE TABLE t_oee_day (
date DATE NOT NULL,
device_id TEXT NOT NULL,
oee NUMERIC(5,2),
-- ... 同上
PRIMARY KEY (date, device_id)
);

步骤 5: HMI 大屏展示

HMI 大屏用三组速度表 + 一个 OEE 仪表 + 趋势图:

<darra-dx-speedometer
bind-value="oee.availability"
min="0" max="100"
ranges='[{"start":0,"end":60,"color":"red"},
{"start":60,"end":85,"color":"orange"},
{"start":85,"end":100,"color":"green"}]'
label="稼动率 %">
</darra-dx-speedometer>

<darra-dx-speedometer bind-value="oee.performance" label="性能率 %"/>
<darra-dx-speedometer bind-value="oee.quality" label="合格率 %"/>

<darra-dx-gauge bind-value="oee.oee" label="OEE"
ranges='[{"end":50,"color":"red"},
{"end":70,"color":"orange"},
{"end":85,"color":"yellow"},
{"end":100,"color":"green"}]'/>

<darra-trend
api="/api/oee/trend?device=L1&range=24h&bucket=1h"
series='["availability","performance","quality","oee"]'
title="近 24 小时 OEE 趋势"/>

步骤 6: API

GET /api/oee/current?device=L1
→ {"availability":92.3,"performance":88.1,"quality":98.5,"oee":80.1}

GET /api/oee/shift?device=L1&date=2026-04-18
→ [{"shift":"A","oee":82.1},{"shift":"B","oee":78.4},...]

GET /api/oee/trend?device=L1&range=7d&bucket=1d
→ [{"ts":"2026-04-12","oee":79.5}, ...]

GET /api/oee/reasons?device=L1&shift=A&date=2026-04-18
→ [{"reason":"机械故障","duration_min":42,"count":3},...]

排错与解读

现象可能原因
Availability 低 (<80%)故障多 / 换线慢 / 待料频繁
Performance 低 (<80%)实际节拍慢于标准 / 微停机
Quality 低 (<95%)工艺不稳 / 来料差 / 人为
OEE 一直 100%标准节拍定得太松, 不真实
OEE 跳变计数器没清零 / 班次切换时序错

高级技巧

  1. 瓶颈识别: 多工位产线 OEE 的最低者就是瓶颈, 优先改善
  2. 六大损失归因: 故障 / 换模 / 空转 / 减速 / 启动 / 不良, 每类单独统计
  3. 标准节拍动态: 按产品型号查表, 不同批次用不同 idealCycleMs
  4. 微停机捕获: <5min 的小停机传统数采抓不到, DarraRT 1s 采样能抓
  5. SPC 联动: 合格率跌 → SPC 异常触发 → 自动排故

相关文档