Kennzahlen & Cockpit
Kennzahlen ohne Zusatzaufwand
Alle Kennzahlen in diesem Kapitel entstehen aus denselben Buchungen, die der Betrieb ohnehin macht: Schritte abschließen, Lose scannen, Maschinenzustände wechseln. Niemand pflegt eine zweite Datenwelt für das Cockpit. Jede Kennzahl ist eine gespeicherte Abfrage über dieselben abgeleiteten Tabellen, die auch Ansichten und Aktionen lesen: step_times für Schritt-Abschlüsse, machine_state_log für Maschinenzustände, scrap_log für Ausschuss. Woher diese Buchungen kommen, beschreibt das Datenmodell. Wie eine gespeicherte Abfrage selbst aufgebaut ist, zeigt das Kapitel Gespeicherte Abfragen.
Das hat eine Folge für die Praxis. Lose kopieren ihre Route beim Anlegen; die Kennzahlen-Abfragen lesen die Route dagegen immer live vom Auftrag. Ändert sich die Route eines Auftrags, etwa eine korrigierte Ideallaufzeit, wirkt sich das ab sofort auf jede Kennzahl aus, die diese Route liest. Es gibt keinen separaten Stammdatensatz für das Controlling, der von der Fertigung abweichen könnte.
OEE
OEE misst Verfügbarkeit mal Leistung mal Qualität. Jeder Faktor kommt aus einer eigenen Quelle.
Verfügbarkeit liest das Maschinenzustands-Protokoll: die Zeit im Zustand running im Verhältnis zur geplanten Zeit des Zeitraums. Geplante Zeit heißt Schichtzeit: Die Abfrage zählt nur Zeitfenster innerhalb einer aktiven Schicht. Wartung zählt dabei ebenfalls nicht als geplante Zeit. Wird eine Maschine drei Stunden gewartet, fließen diese drei Stunden nicht in den Nenner ein und verringern die Verfügbarkeit daher nicht.
Zeit außerhalb jeder definierten Schicht, etwa nachts oder am Wochenende ohne Schichtzuordnung, heißt in den Kennzahlen „Außerhalb“ und fließt gar nicht erst in die Verfügbarkeitsrechnung ein. Sie drückt die OEE nicht.
Leistung vergleicht Ist- gegen Idealzeit. Für jeden abgeschlossenen Schritt liest die Abfrage die Ideallaufzeit aus der Route des Auftrags (run_per_unit_s) und multipliziert sie mit der gefertigten Menge. Diese Idealzeit steht der tatsächlich gelaufenen Zeit gegenüber.
Die Qualität ist das Verhältnis der Gutmenge zur Gesamtmenge aus Gut- und Ausschussmenge. Beide Werte stammen aus denselben Schrittbuchungen.
Alle drei Faktoren multipliziert ergeben den OEE in Prozent. Sie sehen ihn gesamt über alle Maschinen oder je einzelne Maschine, je nachdem, welche Abfrage Sie verwenden. Die Leistung ist dabei nach oben begrenzt: Läuft eine Maschine schneller als ihre Ideallaufzeit, zum Beispiel weil die hinterlegte Zeit zu vorsichtig geschätzt wurde, deckelt die Abfrage den Faktor bei 100 Prozent. Ein OEE über 100 Prozent gibt es also nicht, auch wenn einzelne Faktoren rechnerisch darüber liegen könnten.
Die Herleitung bleibt für jede Gesamt- und Maschinenkennzahl gleich: Zustandszeiten liefern die Verfügbarkeit, Schrittzeiten und Auftragsroute die Leistung, und die gebuchten Mengen die Qualität.
flowchart TB
States["Maschinenzustands-Protokoll"] --> Availability["Verfügbarkeit"]
Times["Gebuchte Schrittzeiten"] --> Performance["Leistung"]
Route["Ideallaufzeit der Auftragsroute"] --> Performance
Quantities["Gutmenge und Ausschuss"] --> Quality["Qualität"]
Availability --> OEE["OEE gleich V mal L mal Q"]
Performance --> OEE
Quality --> OEE
Schichten
Schichten legen Sie unter Administration → Schichten an, Route /admin/shifts. Jede Schicht hat einen Code, eine Bezeichnung, eine Start- und Endzeit sowie die Wochentage, an denen sie gilt. Im Demoprofil sind zwei Schichten angelegt, eine Frühschicht von 06:00 bis 14:00 Uhr und eine Spätschicht von 14:00 bis 22:00 Uhr, jeweils Montag bis Freitag.
Eine Schicht darf über Mitternacht laufen. Liegt die Endzeit vor der Startzeit oder gleichauf, etwa 22:00 bis 06:00, behandelt Werkspur sie als Nachtschicht und rechnet sie ihrem Starttag zu. Die Wochentage bezeichnen deshalb immer den Starttag: Eine Nachtschicht mit dem Wochentag Freitag beginnt Freitagabend und endet Samstagfrüh. Ein durchgehender Dreischichtbetrieb ist damit ebenso abbildbar wie der Zweischichtbetrieb des Demoprofils.
Zwei Schichten dürfen nicht dieselbe Minute belegen. Beim Speichern prüft Werkspur die geänderte Schicht gegen alle anderen aktiven Schichten, über Mitternacht und über den Sonntag hinweg, und lehnt eine Überschneidung mit Angabe der kollidierenden Schicht ab. Soll eine Schicht vorübergehend nicht gelten, setzen Sie sie auf inaktiv, statt sie zu löschen: Inaktive Schichten zählen bei dieser Prüfung nicht mit und erzeugen keine Schichtfenster.
Alle Zeitangaben verwenden die für das Werk eingestellte Zeitzone, dieselbe Zeitzone, in der auch die Tages-Kennzahlen gebildet werden. Der Standardwert ist Wiener Ortszeit (Europe/Vienna); für ein Werk in einer anderen Zeitzone stellen Sie die Umgebungsvariable FOUNDRY_PLANT_TZ auf die passende IANA-Kennung um. Auf einer bestehenden Installation wirkt sich das nicht automatisch auf bereits gespeicherte Abfragen aus: Sie behalten ihre bisherige Zeitzone, bis Sie sie einmal neu speichern oder neu anlegen lassen.
Wochenenden und Nächte ohne zugeordnete Schicht drücken die OEE seit dieser Umstellung nicht mehr. Vorher zählte diese Zeit in den Nenner der Verfügbarkeit hinein und senkte den OEE-Wert, obwohl dort ohnehin niemand produzierte. Jetzt bleibt sie außen vor.
Aus denselben Schichtfenstern entstehen zwei weitere Auswertungen. Der Schichtvergleich im Cockpit stellt OEE, Stückzahl, Ausschuss und Stillstandskosten je Schicht nebeneinander, inklusive der Außerhalb-Zeile für die nicht zugeordnete Zeit. Die Ansichten Schichtleiter und Schichtübergabe zeigen dieselben Zahlen für die laufende beziehungsweise die zuletzt beendete Schicht, sodass eine Übergabe ohne Suchen in den Rohdaten auskommt.
Neben den Zahlen führt dieselbe Übergabe ein Logbuch für die Dinge, die keine Kennzahl abbildet, etwa eine ungewöhnliche Geräuschentwicklung an einer Presse oder eine Absprache für die nächste Schicht. Die Schichtleitung schreibt die Notizen über die Ansicht Schichtleiter, wahlweise mit Bezug zu einer Maschine. Die nachfolgende Schicht liest sie in der Schichtübergabe; Notizen mit Maschinenbezug erscheinen zusätzlich auf der Detailansicht der betreffenden Maschine. Ein einmal geschriebener Eintrag bleibt stehen. Ändern oder Löschen sieht das Logbuch-Prinzip nicht vor, nur das Ergänzen neuer Einträge.
Endet eine Schicht ohne direkt anschließende Folgeschicht, parkt Werkspur laufende Maschinen automatisch: Der Zustand wechselt auf idle, der Grund lautet SCHICHTENDE. Die Prüfung dafür läuft alle fünf Minuten. Maschinen in Störung oder Wartung bleiben unverändert stehen, samt Grund. Beim direkten Schichtwechsel, etwa von der Früh- in die Spätschicht, passiert nichts.
Stillstand und Ausschuss in Euro
Stillstandssekunden mal Maschinenstundensatz ergibt die Stillstandskosten in Euro. Die Abfrage summiert dafür jede Zeitspanne im Zustand down aus dem Maschinenzustands-Protokoll und multipliziert sie mit dem hinterlegten Stundensatz der jeweiligen Maschine. Je Grund-Code aufgeschlüsselt zeigt sich, welcher Stillstandsgrund im Zeitraum am meisten gekostet hat.
Ausschuss zeigt das Pareto der gebuchten Ausschussmengen je Grund-Code, sortiert nach Stückzahl: Der häufigste Grund steht oben. Eine Euro-Summe des Ausschusses gibt es zusätzlich als Gesamtwert über den Zeitraum. Beim Stillstand steht dagegen der teuerste Grund oben, weil die Abfrage die Sekunden je Grund direkt mit dem Stundensatz bewertet.
Nachkalkulation
Die Nachkalkulation vergleicht je Auftrag die geplante mit der tatsächlichen Zeit. Rüsten und Laufzeit gehen dabei getrennt ein: Die Route eines Auftrags trägt eine Ideal-Rüstzeit (setup_s) und eine Ideal-Laufzeit je Stück (run_per_unit_s), die Schritt-Buchungen (step_times) tragen die tatsächlich gebuchte Rüst- und Laufzeit. Die Abfrage summiert je Auftrag Plan- und Ist-Sekunden über alle Schritte und rechnet die Differenz mit dem Maschinenstundensatz der jeweiligen Maschine in eine Euro-Abweichung um.
Ein positiver Wert heißt, der Auftrag hat mehr gekostet als geplant, sei es durch längeres Rüsten, langsameren Lauf oder beides. Ein negativer Wert heißt, der Auftrag lief besser als geplant. Die Abfrage sortiert absteigend nach der Euro-Abweichung, sodass die teuersten Kostenüberschreitungen zuerst erscheinen.
Tageswerte und Trends
Ein nächtlicher Lauf in der für das Werk eingestellten Zeitzone verdichtet jeden Kalendertag in drei Tages-Tabellen: kpi_daily_machine für Laufzeit und Stillstand je Maschine, kpi_daily_scrap für Ausschuss je Grund-Code und kpi_daily_orders für abgeschlossene Aufträge. Die Wochentrends im Cockpit lesen ausschließlich aus diesen Tages-Tabellen, nicht aus den rohen Ereignissen. Das hält die Trendabfragen schnell, auch über viele Monate, weil eine Woche Trend dann eine Handvoll Tageszeilen liest statt aller Ereignisse dieser Woche.
Alle Kennzahlen-Abfragen in diesem Kapitel nehmen einen Zeitraum als Parameter (from und to). Lassen Sie beide leer, gelten als Standard die letzten 30 Tage.
Zählerabgleich
Der Zählerabgleich kontrolliert das MES gegen sich selbst: gebuchte Stückzahlen aus den Schritt-Abschlüssen gegen den Maschinenzähler aus der Telemetrie, Tag für Tag und Maschine für Maschine. Die Abweichung erscheint in Prozent. Ein größerer Ausschlag zeigt an, dass entweder am Terminal falsch gebucht wurde oder der Zähler nicht mehr zur Realität passt.
Der Abgleich läuft nur für Maschinen mit einer Zähleranbindung (telemetry_bindings vom Typ counter). Ohne diese Anbindung fehlt der Vergleichswert, und die Maschine erscheint nicht in der Liste.
Beispiele
-- kpi_oee, params: from, to
WITH win AS (
SELECT COALESCE((NULLIF($1,'')::date)::timestamp AT TIME ZONE plant_tz(), now() - interval '30 days') AS t0,
COALESCE((NULLIF($2,'')::date + 1)::timestamp AT TIME ZONE plant_tz(), now()) AS t1
), w AS (
SELECT sw.shift, GREATEST(sw.started_at, win.t0) AS s0, LEAST(sw.ended_at, win.t1) AS s1
FROM win, shift_windows((win.t0 AT TIME ZONE plant_tz())::date - 1,
(win.t1 AT TIME ZONE plant_tz())::date) sw
WHERE sw.ended_at > win.t0 AND sw.started_at < win.t1
), iv AS (
SELECT l.state,
EXTRACT(EPOCH FROM (LEAST(COALESCE(l.ended_at, now()), w.s1) - GREATEST(l.started_at, w.s0))) AS secs
FROM machine_state_log l
JOIN w ON l.started_at < w.s1 AND COALESCE(l.ended_at, now()) > w.s0
WHERE l.state <> 'maintenance'
), avail AS (
SELECT SUM(secs) FILTER (WHERE state = 'running') AS run_secs, SUM(secs) AS sched_secs FROM iv
), prod AS (
SELECT SUM((st.qty_good + st.qty_scrap) * COALESCE((rs.s ->> 'run_per_unit_s')::numeric, 0)) AS ideal_secs,
SUM(st.qty_good)::numeric AS good,
SUM(st.qty_good + st.qty_scrap)::numeric AS total
FROM step_times st
JOIN w ON st.completed_at > w.s0 AND st.completed_at <= w.s1
JOIN orders_current o ON o.number = st.order_number
LEFT JOIN LATERAL (
SELECT s FROM jsonb_array_elements(o.routing) s WHERE (s ->> 'seq')::int = st.step
) rs ON TRUE
) SELECT ROUND(100
* COALESCE(a.run_secs / NULLIF(a.sched_secs, 0), 0)
* LEAST(1, COALESCE(p.ideal_secs / NULLIF(a.run_secs, 0), 0))
* COALESCE(p.good / NULLIF(p.total, 0), 0), 0) AS value
FROM avail a, prod p
Die Abfrage berechnet die drei OEE-Faktoren aus drei verschiedenen Quellen: Verfügbarkeit aus dem Maschinenzustands-Protokoll (Zeit im Zustand running gegen geplante Zeit, Wartung ausgenommen), Leistung aus der Ideallaufzeit der Route gegen die tatsächlich gelaufene Zeit und Qualität aus Gut- gegen Gesamtmenge der Schritt-Buchungen. Das Produkt der drei Faktoren ergibt den OEE in Prozent für den übergebenen Zeitraum.
-- order_postcalc, params: from, to
WITH win AS (
SELECT COALESCE((NULLIF($1,'')::date)::timestamp AT TIME ZONE plant_tz(), now() - interval '30 days') AS t0,
COALESCE((NULLIF($2,'')::date + 1)::timestamp AT TIME ZONE plant_tz(), now()) AS t1
), rows AS (
SELECT st.order_number,
COALESCE(st.run_secs_actual, 0) + COALESCE(st.setup_secs_actual, 0) AS ist_secs,
(st.qty_good + st.qty_scrap) * COALESCE((rs.s ->> 'run_per_unit_s')::numeric, 0)
+ CASE WHEN st.setup_secs_actual IS NOT NULL
THEN COALESCE((rs.s ->> 'setup_s')::numeric, 0) ELSE 0 END AS plan_secs,
m.hourly_rate_cents AS rate
FROM step_times st
JOIN orders_current o ON o.number = st.order_number
JOIN machines_current m ON m.id = st.machine
LEFT JOIN LATERAL (
SELECT s FROM jsonb_array_elements(o.routing) s WHERE (s ->> 'seq')::int = st.step
) rs ON TRUE
WHERE st.completed_at > (SELECT t0 FROM win) AND st.completed_at <= (SELECT t1 FROM win)
) SELECT r.order_number AS auftrag,
ROUND(SUM(r.plan_secs) / 3600.0, 1) AS plan_h,
ROUND(SUM(r.ist_secs) / 3600.0, 1) AS ist_h,
ROUND(SUM((r.ist_secs - r.plan_secs) * r.rate) / 3600.0 / 100.0, 0) AS abweichung_eur
FROM rows r GROUP BY r.order_number ORDER BY abweichung_eur DESC LIMIT 25
Die Abfrage liest step_times je Auftrag und trennt Rüst- und Laufzeit. Sie vergleicht die geplanten Sekunden aus der Route (setup_s und run_per_unit_s mal Menge) mit den tatsächlich gebuchten Sekunden. Die Differenz rechnet sie über den Maschinenstundensatz in eine Euro-Abweichung um, absteigend sortiert nach dem teuersten Auftrag.
-- counter_check, params: from, to
WITH win AS (
SELECT COALESCE(NULLIF($1,'')::date, ((now() AT TIME ZONE plant_tz())::date - 30)) AS d0,
COALESCE(NULLIF($2,'')::date, (now() AT TIME ZONE plant_tz())::date) AS d1
), agg AS (
SELECT day, machine,
SUM(pieces_good) AS pieces_good,
SUM(pieces_scrap) AS pieces_scrap,
SUM(pieces_counted) AS pieces_counted
FROM kpi_daily_machine
GROUP BY day, machine
) SELECT to_char(k.day, 'DD.MM.YYYY') AS tag,
m.name AS maschine,
(k.pieces_good + k.pieces_scrap)::bigint AS gebucht,
k.pieces_counted AS gezaehlt,
ROUND(100.0 * (k.pieces_counted - (k.pieces_good + k.pieces_scrap))
/ NULLIF(k.pieces_good + k.pieces_scrap, 0), 1) AS abweichung_pct
FROM agg k JOIN machines_current m ON m.id = k.machine JOIN win ON k.day >= win.d0 AND k.day <= win.d1 WHERE EXISTS (SELECT 1 FROM telemetry_bindings tb WHERE tb.machine = k.machine AND tb.kind = 'counter')
AND (k.pieces_good + k.pieces_scrap > 0 OR k.pieces_counted > 0)
ORDER BY k.day DESC,
ABS(COALESCE(100.0 * (k.pieces_counted - (k.pieces_good + k.pieces_scrap))
/ NULLIF(k.pieces_good + k.pieces_scrap, 0), 0)) DESC
LIMIT 25
Die Abfrage verbindet die Tages-Tabelle kpi_daily_machine mit telemetry_bindings vom Typ counter und beschränkt sich damit auf Maschinen mit Zähler-Anbindung. Für jeden Tag und jede Maschine stellt sie die gebuchte Menge (Gut- plus Ausschussmenge) der per Telemetrie gezählten Menge gegenüber und gibt die Abweichung in Prozent aus, je Tag die größten Ausschläge zuerst.
Diese Kennzahlen stammen aus dem Demoprofil der Kaltumformung. Die zugrunde liegenden Definitionen sind reguläre gespeicherte Abfragen. Sie können sie im Bereich „Gespeicherte Abfragen“ öffnen, kopieren und an Ihren Betrieb anpassen.