Objektorientierte Programmierung (OOP) ist ein Konzept, das die Entwicklung komplexer Systeme erleichtern soll, indem neue Konzepte eingeführt werden, die der realen Welt näher sind als funktionale und prozedurale Programmiersprachen. Wie Wikipedia schreibt, "spiegelt die gewöhnliche menschliche Sprache als Ganzes die Ideologie von OOP wider, beginnend mit der Verkapselung der Idee eines Objekts in Form seines Namens und endend mit dem Polymorphismus, das Wort im übertragenen Sinne zu verwenden, der letztendlich den Ausdruck der Repräsentation durch den Namen des Objekts zu einer vollwertigen Konzeptklasse entwickelt."

Aber aus der Sicht aller, die zum ersten Mal auf diese Abstraktionen gestoßen sind, scheint das Gegenteil nach den klassischen prozeduralen Sprachen nicht klarer geworden zu sein.
Auf der anderen Seite gibt es grafische Notationen des Programms, die nicht der menschlichen Sprache nahe kommen, aber viel verständlicher sind als jeder Code, der nicht wie OOP ist. Es ist möglich, dass mir dies klarer ist, verwöhnt durch eine Ingenieurausbildung, aber es gibt viele Leute wie mich und diesen Text für dieselben verwöhnten Physiker, die hohe Abstraktionen nicht verstehen.
Hier ist zum Beispiel eine reale Beschreibung in der grafischen Notation des NPP-Absperrschieber-Algorithmus:
Abbildung 1. Beispiel eines KKW-Steuerungsprogramms in grafischer NotationLinks sind Eingangssignale, rechts Befehle.
Es scheint mir, dass sogar ein Kind einen solchen Algorithmus lesen kann:
- Wenn die Pumpe 60 Sekunden lang eingeschaltet ist und die Durchflussmenge weniger als 10 beträgt, öffnen Sie das Umwälzventil.
- Wenn die Pumpe eingeschaltet ist, geben Sie den Befehl, die Ventile 001 und 002 innerhalb von 5 Sekunden zu öffnen.
- Wenn die Durchflussmenge größer als 20 ist und die Pumpe eingeschaltet ist, muss innerhalb von 5 Sekunden das Verschlussventil 003 geschlossen werden.
Als Student arbeitete ich in Teilzeit, indem ich eine Komponentenbibliothek für Delphi erstellte, und war mit OOP aus erster Hand vertraut. Als ich dann auf echte Steuerungsprogramme für Kernkraftwerke stieß, war ich sehr überrascht, dass es keine Abstraktion, Verkapselung und, verzeih mir, Polymorphismus gab, nur reines C, und die Empfehlung von MISRA C, die durch die Regeln gekürzt wurde, damit alles zuverlässig , tragbar und sicher war.
Der Peak des C-Cutoffs in meiner Praxis war FIL für RBMK-Reaktorsteuerungssysteme. Darin wurden Funktionen in C vorab geschrieben, kompiliert und dann auf Basis einer Textdatei aufgerufen, wo sie in der FIL-Sprache beschrieben wurden. Infolgedessen war es möglich, nur einen begrenzten, aber sorgfältig getesteten und debuggten Satz von Funktionen aufzurufen. Und das alles im Namen von Sicherheit und Zuverlässigkeit.
Gleichzeitig sind das Reaktorsteuerungssystem und das KKW-Steuerungssystem insgesamt nur dann der Fall, wenn die Prinzipien der OOP in vollem Umfang angewendet werden sollten. In der Tat gibt es viele ähnliche Geräte - Ventile, Pumpen, Sensoren, alles ist leicht zu klassifizieren, es gibt fertige Objekte, die realen Geräten entsprechen. Es scheint, dass es hier ist - verwenden Sie OOP, Klassen, Vererbung, Abstraktion und Polymorphismus. Aber nein, Sie benötigen reines C und dies sind Sicherheitsanforderungen.
Und dann - noch interessanter. Tatsächlich wird das Programm zur Verwaltung des Kernkraftwerks nicht vom Programmierer geschrieben, sondern vom Technologen - nur er weiß, was und wann er schließen, öffnen, einschalten und vor allem - er weiß, wann er das Kanu ausschalten muss, um nicht abzustürzen. Und der Programmierer muss dies alles sorgfältig in C-Code implementieren. Und noch besser, es würde überhaupt keinen Programmierer geben, und der Technologe selbst zeichnete die technologischen Algorithmen von Steuerungsprogrammen in grafischer Form, erzeugte automatisch C-Code und lud ihn in die Steuerungsausrüstung. Internationale Sicherheitsstandards empfehlen dies, in diesem Fall wird kein Programmierer - wie ein Geiger - benötigt. Er führt nur zusätzliche Fehler und Verzerrungen bei der Umsetzung der Gedanken des Technologen ein.

Was mich überraschte, als ich herausfand, dass die NPP-Technologen und -Designer unabhängig von den Programmierern objektorientierte Programmierung und sogar in grafischen Notationen entwickelt und erfolgreich eingesetzt haben, der resultierende Code jedoch die Sicherheitsanforderungen vollständig erfüllt und keine Artefakte der OOP-Methodik enthält .
Wenn Sie sich den Code ansehen, der aus der Schaltung in Abbildung 1 generiert wird, sehen Sie dort reines C ohne Klassen.
Zum Beispiel die Algorithmuseintragstabelle:
state_vars->kbaalgsv0_out_1_ = kba31ap001_xb01; state_vars->kbaalgsv0_out_4_ = kba31cf001_xq01;
Nur Variablen zuweisen.
Jeder Block wird als Berechnung der Ausgabe durch Eingabe unter Berücksichtigung der in der Liste der Konstanten angegebenen Parameter beschrieben. Zum Beispiel sieht der Block "Mehr" im Code folgendermaßen aus:
locals->v5_out_0_ = state_vars->kbaalgsv0_out_4_ > consts->kbaalgsv3_a_;
Der Blockausgang ist das Ergebnis des Vergleichs des Eingangssignals mit einem Wert in einer Konstanten.
Somit werden in anderen Blöcken die lokalen Variablen aus den Eingangsvariablen nacheinander berechnet, und am Ende des Programmzyklus werden die Variablen in die Ausgangsvariablen geschrieben.
if((action==f_InitState)||(action==f_GoodStep)||(action==f_RestoreOuts)){ kba31ey001_yb01 = locals->v8_out_0_; kba31ey001_yb11 = state_vars->kbaalgsv9_out_0_; kba31ey001_yb12 = state_vars->kbaalgsv12_out_0_; kba31ey001_yb02 = locals->v13_out_0_; };
Wo sind die Klassen hier, fragst du?
Die gesamte mit OOP verbundene Methodik besteht aus Variablennamen. Es scheint, dass dies im Variablennamen sein könnte? Und es kann einen ganzen Abgrund geben. Der Variablenname lautet beispielsweise kba31ap001_xb01, nur eine Variable im C-Code, die die Anforderungen für den Namen der Variablen erfüllt. Für einen Konstrukteur sieht es jedoch ungefähr so aus: „Reaktorraum, Brauchwasserversorgungssystem, erste Pumpe, Inbetriebnahme“. All diese Konvertierungsmagie geschieht dank des wunderbaren deutschen Kraftwerk-Kennzeichensystems KKS, Zitat:
„Dieses Codierungsklassifizierungssystem ist für Kraftwerke konzipiert und hat ein großes Potenzial. Es berücksichtigt auch die Merkmale frei programmierbarer Mikroprozessorhardware.
Neben der Kennzeichnung von technologischen Geräten, Leitungsgremien (Absperr-, Sicherheits-, Absperr- usw. Ventile, Hilfsmechanismen), Messpunkten, Montageeinheiten, Automatisierungsgeräten, Gebäuden und Strukturen ermöglicht das KKS-System Kennzeichnungsalgorithmen und -programme verschiedener Art und Zwecke (Verarbeitungsalgorithmen für gemessene technologische Parameter, Signalisierung, automatische Regelung, technologischer Schutz, logische Steuerung: Sperren, ABP, Schritt-für-Schritt-Programme, - Berechnung von t hniko-ökonomische Indikatoren und Diagnose von technischen Anlagen), Eingangs-, Ausgangs- und Zwischensignale von Algorithmen und Programmen, Videoaufnahmen von allen Ebenen auf Video-Terminals angezeigt, Kabel, etc ... "
Das interessanteste im letzten Teil des Namens ist jedoch _xb01 , das durch den Unterstrich angegeben wird. Wenn Sie sich die Signalbasis für das Managementprojekt ansehen, werden wir dort Klassen sehen, die für jeden verständlich und vertraut sind, der sich einmal, irgendwo und irgendwo für OOP interessiert hat (siehe Abb. 2).
Abbildung 2. Ein Beispiel für eine Signalbasisstruktur für ein Steuerungssystem für Kernkraftwerke.Wir haben Klassen oder Tabellen, in der Abbildung ist dies die Spalte "Kategorien". Zum Beispiel "KD1" mit einer Tabelle von Mustersignalen, Feldern der Klasse Obere Messgrenze, untere Messgrenze, Sensorablesung usw. Ist eine Abstraktion.
Und es gibt auch eine Implementierung dieser Klasse - einen spezifischen Sensor, zum Beispiel TK21F02B1, der sich im Kreislauf befindet, wie Sie anhand seines Namens im „Reaktorraum, industrielles Wasserversorgungssystem, an der ersten Pumpe“ erraten können, und die Tatsache, dass es sich um einen Durchflusssensor handelt ist in diesem Titel enthalten, aber nicht korrekt.
Und diese Instanz dieser Klasse hat im Verlauf des Programms bestimmte Signale und deren Werte, auf die über die Namen der Felder der Klasse zugegriffen werden kann. Beispielsweise wird ein Sensorwert durch die Variable TK21F02B1_XQ04 angezeigt.
An diesem Punkt können wir sagen, warten Sie, dies ist überhaupt kein OOP oder gar kein OOP, es ist nur eine Datenstruktur, es ist in Standard C. Und wo ist die Kapselung der Methoden in der Klasse? Die Datenverarbeitung sollte in der Klasse sein, dann ist dies die echte koschere OOP-Methode.
Lassen Sie uns sehen, wie das Unterprogramm zur Steuerung der Sensorzuverlässigkeit in grafischer Form aussieht. Fig. 3 ist ein Teil der Signalverarbeitungsschaltung:
Abbildung 3. Ein Beispiel für ein Signalverarbeitungsprogramm.Es ist ersichtlich, dass in der Verarbeitungsunterroutine die Variablennamen TK21F02B1_XQ04 verwendet werden, die gemäß den KKS-Regeln gebildet werden und auf der Klassenfeldtabelle basieren. Im obigen Beispiel werden die Sensorwerte in Prozent TK21F02B1_XQ03 gemäß den eingestellten Werten der Felder der Klasseninstanz wie TK21F02B1_Xmin und TK21F02B1_Xmax berechnet.
Wenn wir uns dem aus diesem Schema generierten Code zuwenden, sehen wir eine einfache Zuordnung eines Werts zu einer Variablen, reinem C und ohne Pluspunkte und OOP.
state_vars->su100v12_out_0_ = tk21f02b1_ai;
Und Zuordnung des Berechnungsergebnisses, auch als einfache Zuordnung einer Variablen (mit Überprüfung der Gültigkeit der Nummer, um das System nicht fallen zu lassen, wenn wir aufgrund der Signalverarbeitung einen Fehler erhalten haben)
if(isfinite(locals->v63_out_0_)){ tk21f02b1_xq04 = locals->v63_out_0_; };
Und zu welchem Zeitpunkt erscheint die Vereinigung dieser Felder der Klasse der Verarbeitungsmethoden? Tatsächlich kenne ich zwei Optionen für diesen Fokus. Jetzt werden wir einen von ihnen analysieren. (Die zweite Option wird hier analysiert. )
Lassen Sie uns sehen, wie der Block, in dem sich die Verarbeitungsprogrammschaltung befindet, im Diagramm konfiguriert ist (siehe Abb. 4).
Wir haben eine Schaltung, auf der wir Blöcke eines Submodells einer grafischen Programmiersprache platzieren. Innerhalb dieser Blöcke befindet sich eine grafische Schaltung, von der ein Teil in Abbildung 3 gezeigt ist, ein Programm zur Verarbeitung von Signalen von Sensoren.
In den Eigenschaften dieses Blocks sehen wir die Felder der Signaldatenbank und eine Dropdown-Liste, die bereits in der Datenbank vorhandene Signale, Instanzen der Klasse und bestimmte Sensoren dieses Typs enthält. Es reicht aus, den gewünschten Sensor, eine Instanz der Klasse mit Namen, auszuwählen, und ein Wunder geschieht. In dem Schema erhalten alle Lese- und Schreibblöcke Namen vom Typ TK21F02B1_XQ03 (Name des Klasseninstanzsensors + Feldname).
Beim Generieren des C-Codes erhalten nun alle Variablen die Werte des gewünschten Sensors. Und der Programmierer wird nicht benötigt, der Technologe hat alles selbst gemacht, als er das Schema in der grafischen Programmiersprache für den NPP-Steuerungsalgorithmus entwickelte.
Abbildung 4. Ein Beispiel für die Einrichtung einer Sensorverarbeitungsschaltung.Um die Namen zuzuweisen, wird in der Entwurfsumgebung des Steuerungssystems ein spezielles Automatisierungsskript verwendet, das ungefähr dem in Abbildung 5 entspricht. Allen Leseblöcken im Diagramm werden Namen zugewiesen, die aus dem Namen des Objekts und dem Namen des Felds in der Klasse bestehen (siehe Abb. 5).
Abbildung 5. Festlegen des Namens von Variablen in Leseblöcken.Es ist klar, dass auf ähnliche Weise eine unbegrenzte Anzahl von Signalverarbeitungsoptionen erstellt werden kann, im Wesentlichen Methoden für die Klasse in der OOP-Methodik. Auf die gleiche Weise können sie für den Sensor gebildet werden, dessen Summierung, wenn er auf den Videobildern des SCADA-Systems angezeigt wird, oder zum Beispiel die Verarbeitung von Prozeduren zum Ändern von Einstellungen. Ein Diagramm wird in grafischer Form erstellt, als Block gespeichert und bei Bedarf verwendet.
Zusammenfassend lässt sich sagen, dass in grafischen Programmiersprachen auch OOP-Methoden verwendet werden und von Vorteil sind. Und nach dem Generieren des Quellcodes der Steuerungsprogramme verschwinden alle Artefakte der OOP-Methodik und bleiben sauber C, sicher, zuverlässig und verifiziert.
Es ist klar, dass eine solche Anwendung von Automatisierungstools neben der Beschleunigung der Entwicklung auch die Entwicklungszeit und die Anzahl der Fehler in Steuerungsprogrammen erheblich verkürzen kann.