Datenaustausch in der Schutztechnik
über IEC 61850
Diplomarbeit
Ausgeführt zum Zwecke der Erlangung des akademischen Grades eines
Diplom-Ingenieurs
unter der Leitung von
Univ.Prof. Dr.-Ing. Wolfgang Gawlik
Univ.Ass. Dipl.-Ing. Benjamin Cox
eingereicht an der
Technischen Universität Wien
Fakultät für Elektrotechnik und Informationstechnik
Institut für Energiesysteme und Elektrische Antriebe
von
Martin Kaintz, BSc
Matrikelnummer: 01125478
Wien, am 1. April 2021
Danksagung
An dieser Stelle möchte ich mich bei Univ.Prof. Wolfgang Gawlik und Dipl.-Ing. Benjamin
Cox für die gute Betreuung bedanken. Ganz speziell möchte ich mich dafür bedanken,
dass mir in schwierigen Zeiten im Wintersemester 2020/21 alle Möglichkeiten geboten
wurden, diese Arbeit erfolgreich abzuschließen.
Mein ganz persönlicher Dank gilt meiner Familie, speziell meinen Eltern Martina und
Gerald, für den Rückhalt während meiner Studienzeit. Meinen Geschwistern Linda und
Bernhard danke ich für die abwechslungsreiche Zeit neben dem Studium. Außerdem bedanke ich mich bei meinem Bruder für seine hilfreichen Anmerkungen zu dieser Arbeit.
Meinen größten Dank möchte meiner Freundin Magdalena für ihre Unterstützung und
Geduld in arbeitsintensiven Zeiten aussprechen. Ihre Kompetenz im Korrigieren wissenschaftlicher Arbeiten hat dieser Diplomarbeit außerdem den nötigen Feinschliff verliehen.
Schlussendlich bedanke ich mich bei allen Entwicklern freier Software. Ohne die freie
Verfügbarkeit von libiec61850, LATEX, Tik Z und vielen anderen Programmen, wäre diese
Arbeit nicht in dieser Form entstanden.
3
Kurzfassung
Das Ziel dieser Arbeit ist die Verbesserung eines Prüfstandes für Schutzgeräte durch den
Einsatz des Kommunikationsstandards IEC 61850. Zu überprüfen ist, ob im Vergleich zu
den bisher eingesetzten Methoden ein Laufzeitvorteil erzielt werden kann.
Der Prüfstand besteht aus dem Prüfling, einem SIPROTEC 5 -Schutzgerät der Firma
Siemens, dem Schutzprüfgerät CMC 356 der Firma Omicron und einem Computer, dem
die Steuerung und Datenverarbeitung obliegt. Für die Untersuchung von Laufzeitverbesserungen wird der in Python implementierte Programmcode mithilfe der frei verfügbaren
C-Bibliothek libiec61850 und diverser Hilfsklassen um IEC 61850-Funktionen erweitert.
Die Sammlung von Daten zu Fehlerfällen wird mithilfe von IEC 61850-Reports realisiert.
Um die Leistungsfähigkeit des Prüfstandes ohne und mit IEC 61850-Integration vergleichen zu können, werden Laufzeitmessungen bei ausreichend großen Testreihen durchgeführt.
Der erweiterte Prüfstand ermöglicht eine deutliche Laufzeitverkürzung und sofortige
Verfügbarkeit der Daten nach Erkennen eines Fehlers. Die Erkenntnisse und Verbesserungen erlauben effizientere Testungen und neue Ansätze für weitere Forschungsprojekte
am Prüfstand.
4
Abstract
This thesis aims to improve a test bench for protection relays through implementation
of communication standard IEC 61850. Investigations focus on the possibility to achieve
an improvement in runtime compared to the currently applied methods.
The test bench is composed of the test object, a Siemens SIPROTEC 5 protection
relay, an Omicron CMC 356 relay testing tool and a computer responsible for control
and data processing. To investigate possible improvements in runtime, the open source
C-library libiec61850 and various python helper classes are added to the python source
code. Data on faults is collected via IEC 61850 Reports. To enable comparison between a
test bench with and without integration of IEC 61850, run time measurements are carried
out on sufficiently large test data sets.
Upgrading of the test bench leads to a considerable decrease in run time while at the
same time enabling immediate access to report data after fault recognition. Insights and
improvements achieved through the thesis at hand facilitate more efficient testing and
new approaches for research on the test bench.
5
Inhaltsverzeichnis
1 Einleitung
6
1.1 Motivation für den Einsatz von IEC 61850 . . . . . . . . . . . . . . . . . . 6
1.1.1 Historische Entwicklungen . . . . . . . . . . . . . . . . . . . . . . . 6
1.1.2 Vorteile der standardisierten Kommunikation . . . . . . . . . . . . 7
1.1.3 Ausblick auf mögliche zukünftige Entwicklungen . . . . . . . . . . 8
1.2 Struktur des Standards IEC 61850 . . . . . . . . . . . . . . . . . . . . . . 8
1.2.1 Begriffsdefinitionen und Modellbeschreibung . . . . . . . . . . . . . 8
1.2.2 Komponenten für die Übertragung von Meldungen . . . . . . . . . 10
1.3 Aufgabenstellung . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2 Materialen und Methoden
2.1 Aufbau des Prüfstandes im Labor . . . . . . . . . . . . . . . . . . . . . . .
2.2 Konfiguration des IEC 61850-Servers auf dem Schutzgerät . . . . . . . . .
2.2.1 Grundlegende Einstellungen und Funktionen . . . . . . . . . . . .
2.2.2 DataSet und ReportControl . . . . . . . . . . . . . . . . . . . . . .
2.3 C-Bibliothek libiec61850 . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.1 Elemente der Bibliothek . . . . . . . . . . . . . . . . . . . . . . . .
2.3.2 Python-Schnittstelle zu libiec61850 . . . . . . . . . . . . . . . . . .
2.4 Hilfsklassen in Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.4.1 Konstanten und Methoden zur Verbindungsverwaltung . . . . . . .
2.4.2 Konvertierung von MMS-Größen . . . . . . . . . . . . . . . . . . .
2.4.3 Konfiguration und Verarbeitung von Meldungen . . . . . . . . . . .
2.5 Integration der IEC 61850-Funktionalitäten in den Prüfstand . . . . . . . .
12
12
15
15
17
19
19
23
27
27
30
30
40
3 Ergebnisse
3.1 Erkenntnisse durch die Integration der IEC 61850-Funktionalitäten in Python und in den Prüfstand . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.2 Verbesserung der Laufzeit . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.3 Überprüfung und Vergleich der Fehler-Daten für beide Übertragungsmethoden . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
47
4 Diskussion und Ausblick
55
47
48
52
7
1 Einleitung
Einführend wird in diesem Kapitel kurz auf die geschichtlichen Entwicklungen und daraus
folgenden Anforderungen an einen Kommunikationsstandard eingegangen. Anschließend
werden die für diese Arbeit relevanten Teile von IEC 61850 beschrieben.
1.1 Motivation für den Einsatz von IEC 61850
Der Wechsel von Direktverkabelungen in der Schutztechnik hin zu Bus-Systemen bietet
eine Vielzahl neuer Möglichkeiten und Vorteile, wirft jedoch auch Fragen bezüglich Zuverlässigkeit und Schnelligkeit auf. In diesem Abschnitt soll daher ein kurzer Überblick über
die Bedürfnisse der digitalen Schutztechnik am Feld, sowie über die daraus resultierenden
Vorteile der Norm IEC 61850 für Untersuchungen im Labor gegeben werden.
1.1.1 Historische Entwicklungen
Die Entwicklung der Datenkommunikation in der Netzschutz- und Leittechnik wird
hauptsächlich durch die Entwicklung der digitalen Schutztechnik bestimmt. Erste Ansätze für digitale Schutztechnik gibt es seit 1969 durch George Rockefeller, jedoch konnten
sich diese anfangs aufgrund von Wirtschaftlichkeit und Zuverlässigkeit nicht durchsetzen. Fortschritte in der Mikroprozessortechnik und Weiterentwicklung von benötigten
Komponenten wie Speicher, Schnittstellen und Bussystemen führten schießlich in den
1980er bis 1990er Jahren zum Durchbruch der digitalen Schutztechnik. [1]
Um Störfälle aufzuzeichnen kamen anfangs Metallpapierschreiber zum Einsatz, die
überschaubare Datenmengen aufzeichneten, welche selbst bei Hochspannungs-Distanzschutz nur Signale von 10 bis 20 Meldekontakten elektromechanischer Schutzgeräte umfassten. Durch bessere Mikroprozessoren und Speicher konnten auch Störschriebe mit
rund 50 kB aufgezeichnet und für die Analyse von Fehlerfällen herangezogen werden.
Laufend anfallende Betriebsmeldungen und Abfragen von Betriebszuständen erhöhten
zusätzlich die auftretenden Datenmengen. [2]
Die Kommunikation mit digitalen Schutzeinrichtungen auf Feldebene entwickelte sich
hin zu seriellen Schnittstellen, die Schutzgeräte mit Computern verbanden. Als technischer Standard etablierte sich RS 232 mit einer maximal vorgesehenen Datenrate von
19200 Baud, wobei jedoch häufig nur eine Kommunikation mit 9600 Baud eingesetzt wurde. Die Schnittstelle zwischen Computern auf Stationsleitebene und Knoten der Netzleitebene erfolgte über Punkt-zu-Punkt-Verbindungen. Um Betriebszustände- und Meldungen zentral abfragen und erhalten zu können, kam häufig Ethernet nach den Protokollen
ISO 8072 und ISO 8073 zum Einsatz. [1]
9
Wegbereitende Entwicklungen für IEC 61850
Unabhängig vom Energieversorgungssektor entwickelten sich durch Fortschritte der Mikroprozesstechnik, des Ethernet-Protokolls und des LAN (Local Area Network ) neue Konzepte in der Automatisierungstechnik. Die Konzerne General Motors und Boeing forcierten zur besseren Kommunikation in Fertigungsanlagen die Ausarbeitung des Manufacturing Automation Protocol/Technical Office Protocol (MAP/TOP). Ihre Motivation dafür
war, über unterschiedliche Netzwerkteilnehmer Echtzeit-Daten und Informationen über
die Struktur der Daten zu übertragen. Diese Anforderungen wurden in der Manufacturing
Message Specification (MMS) erfüllt. Die Definition von Standard-Objekten und Regeln
zur Codierung der Daten sowie die Übertragung der syntaktischen Informationen dieser
Daten ermöglicht einerseits einen symbolorientierten Zugriff als auch das Durchsuchen
von Server-Objekten. Obwohl MAP/TOP sich nicht als Standard durchsetzen konnte,
wurde MMS als zentraler Teil in IEC 61850 integriert.
Die Veröffentlichung des OSI-Schichtmodells 1984 führte zur Dokumentation von verbindungslosen OSI-Profilen. Diese Arbeiten brachten das Profil Generic Object-Oriented
Substation Event (GOOSE) hervor, das in IEC 61850 als Generic Substation Status Event
(GSSE) spezifiziert ist. [3]
1.1.2 Vorteile der standardisierten Kommunikation
Die Vereinheitlichung der Datenabbildung und -kommunikation eröffnet für Untersuchungen im Labor neue Möglichkeiten. Der Vergleich von Schutzgeräten unterschiedlicher Hersteller ist damit einerseits bereits beim Versuchsaufbau leichter möglich, andererseits müssen die ausgelesenen Daten nicht mehr nachbereitet, sondern können direkt
verglichen werden. Die Verwendung von Ethernet-Hardware ermöglicht die Integration
in bestehende Labor-Netze und erübrigt zusätzlichen Kostenaufwand.
Proprietäre Kommunikationsprotokolle würden den Testaufwand bei der Entwicklung
eines Prüfstandes deutlich erhöhen. Der Einsatz von IEC 61850 ermöglicht hingegen die
Simulation von Schutzgeräten in Form einer Computerapplikation. Für die Arbeit wurde
eine Programmbibliothek gewählt, die für die Verarbeitung von Konfigurationsdateien
der zu testenden Geräte die nötigen Funktionen bereitstellt. Damit kann ein IEC 61850Server auf einem Computer gestartet werden, der für Testzwecke das reale Schutzgerät
repräsentiert.
Die Unabhängigkeit von kommerziellen Applikationen und der mit diesen häufig einhergehenden Bindung an Architekturen und Betriebssysteme führt zu deutlich mehr Flexibilität. In der Entwicklungsphase des IEC 61850-unterstützten Prüfstandes für diese
Arbeit wurde sowohl ein ARM -basierter Raspberry Pi mit Linux als auch ein Intel basierter Apple-Computer mit dem Betriebssystem MacOS eingesetzt, obwohl der Prüfstand im Labor der TU Wien auf einem Windows-Rechner ausgeführt wird. Hersteller
von Schutzgeräten bieten meist nur eine Endapplikation für ein Betriebssystem an, die
für den Einsatz in Stationen gedacht ist und nicht die Bedürfnisse eines Versuchslabors
abdeckt.
10
1.1.3 Ausblick auf mögliche zukünftige Entwicklungen
Im Jahr 2019 hatten in fünf G8-Ländern und zahlreichen anderen Ländern die Netzbetreiber bereits weitgehend auf IEC 61850-Kommunikation umgestellt. Mit Ausnahme
von Kanada und den USA (wo stattdessen das Distributed Network Protocol zum Einsatz kommt) werden in den nächsten Jahren die meisten Industrieländer folgen. [3] Die
am Markt dominierenden Hersteller von Geräten für die Netzschutz- und leittechnik setzen immer stärker auf IEC 61850 statt auf hauseigene Bussysteme. Trends in Richtung
Smart Grids begünstigen die stärkere Vernetzung mit einheitlichen Kommunikationsstandards. Auch für Forschungsprojekte im Bereich der Schutztechnik ist es daher wichtig, die
Vorteile der standardisierten Kommunikation zu nutzen um Ergebnisse auf aktuellstem
Entwicklungsstand liefern zu können.
1.2 Struktur des Standards IEC 61850
Der gesamte Standard besteht aus mehr als 130 Dokumenten und ist in zehn Teile strukturiert [3].
Teil 1 und 2: Einleitung, Überblick und Glossar
Teil 3 bis 5: allgemeine Anforderungen, Anforderungen an System- und Projektverwaltung, Kommunikationsanforderungen
Teil 6: formale Beschreibung der Konfigurationssprache zwischen Geräten
Teil 7-1: Prinzipien und Modell der Kommunikationsstruktur
Teil 7-2: Beschreibung der abstrakten Schnittstelle für die Kommunikation
Teil 7-3 und 7-4: Beschreibung von Datenklassen und logischen Knoten
Teil 8 und 9: MMS-Zuordnungen und Sampled Values
Teil 10: Techniken zur Konformitätsprüfung
Für die technische Umsetzung der Kommunikation mit dem für diese Arbeit verwendeten Schutzgerät im Labor der TU Wien sind ausschließlich die Teile 7-2 und 7-3 relevant.
Sie beschreiben wie der IEC 61850-Server am Gerät aufgebaut ist und wie ein Client die
verfügbaren Dienste nutzen kann.
1.2.1 Begriffsdefinitionen und Modellbeschreibung
Im Standard wird ein elektronisches Gerät, auf dem ein IEC 61850-Server betrieben wird,
als Intelligent Electronic Device (IED) bezeichnet, da grundsätzlich nicht nur Schutzgeräte sondern eine Gruppe von Geräten abgedeckt werden. Ein IED muss einen Namen
besitzen, der im Verbundsystem einzigartig (unique) ist und zur Identifikation dient. Der
Begriff Device wird in den Dokumenten auch in einem anderen Kontext verwendet und
bezeichnet z.B. auch einen Dienst auf dem physischen Gerät.
11
IED
SIP
LD
LD
LD
Ln1_21RMDistance1
Ln1
Rec_FaultRecorder
LN
LN
SE_RFLO
DEF_RDRE
DO
DO
DO
FltDis
FltDisPct
FltNum
DA
DA
DA
DA
instMag
mag
instMag
mag
Abbildung 1.1: Baumstruktur des IEC 61850-Informationsmodells. Die Hierarchie der
Klassen ist IED > LD > LN > DO > DA. Beispielhaft sind Namen
von konkreten Knoten auf dem verwendeten Schutzgerät angeführt.
In Teil 7-2 wird das grundlegende Informationsmodell beschrieben. Es besteht im einfachsten Fall aus den Klassen
• Server,
• Logical-Device (LD),
• Logical-Node (LN),
• Data Object (DO) und
• Data Attribute (DA).
Jede Instanz dieser Klassen kann beliebig viele untergeordnete Elemente besitzen. Die
Struktur ist hierarchisch aufgebaut und kann als Baum dargestellt werden. Abbildung
1.1 zeigt einen kleinen Teil der Server-Struktur und soll das Prinzip veranschaulichen.
Die Daten selbst besitzen in der Norm definierte Datentypen und sind in Form einer
Datenstruktur Elementen der Klasse DA zugeordnet. Diese Datenstruktur kann entweder
durch eine Liste (array) oder eine Baumstruktur (struct) mehrere Daten beinhalten.
Grundlegende Datentypen sind
12
• BOOLEAN
• INT8 und weitere Ganzzahl-Typen bis 128 Bit Länge
• FLOAT32 und FLOAT64
• ENUMERATED
• CODED ENUM
• OCTET STRING
• VISIBLE STRING
• UNICODE STRING
Jedes Attribut DA besitzt die Eigenschaft, einen speziellen Nutzen zu haben. Diese
Eigenschaft wird mittels Functional Constraints (FC) festgelegt und mit zwei Buchstaben beschrieben. Beispielsweise wird für Analog-Messwerte einem Objekt FC=MX zugewiesen und FC=ST für Statusinformationen. Über die Eigenschaft wird also auch beschrieben, welche Dienste mit einem DO interagieren. [4]
Neben Datenobjekten gibt es weitere Elemente im Modell, von denen DataSet und
Report besonders relevant für den Prüfstand sind. Daher wird im folgenden Unterkapitel
kurz auf die Eigenschaften dieser beiden Klassen eingegangen.
1.2.2 Komponenten für die Übertragung von Meldungen
Ein DataSet ist eine geordnete Liste von Referenzen auf Datenobjekte. Es dient dazu,
eine Sammlung von Daten aus unterschiedlichen Datenobjekten zu erstellen, die nicht
dem gleichen LN oder LD angehören müssen. Damit kann eine Menge an Daten in einer
einzigen Netzwerkanfrage abgefragt werden, um höhere Effizienz zu erreichen. Haupteinsatzgebiet von DataSets ist jedoch, eine Datensammlung für Meldungen (Report), Prokollierung (Log) und GOOSE-Funktionen bereitzustellen. DataSets gehören Logical Nodes
an. Jeder Eintrag eines DataSets besitzt eine Referenz zum eigentlichen DO und eine
FC. Damit werden rekursiv alle Daten inkludiert, die dem DO untergeordnet sind und
die entsprechende FC besitzen.
Control Blocks beschreiben eine Gruppe weiterer Einheiten, die jedoch im Gegensatz zu
einfachen Datenobjekten und DataSets funktionelle Aufgaben besitzen. Sie verarbeiten
Daten aus DataSets und können vom Client konfiguriert werden. Ein Report Control
Block (RCB) hat die Aufgabe bei einem bestimmten Ereignis eine Meldung mit den
Daten an einen Client zu übermitteln. Nach dem Auftreten eines Ereignisses werden die
Daten aus dem assoziierten DataSet aggregiert und als Meldung an den Client geschickt
(siehe Abbildung 1.2). Für das Auslösen eines Ereignisses und die Verarbeitung der Daten
sind im RCB Attribute zum Konfigurieren dieser Funktionen definiert. Details zu den
verwendeten Attributen sind bei der Implementierung des Clients in Abschnitt 2.4.3 zu
finden.
13
Reporting
Real
data
DataSet
linked to
Report
control
get and set
config
DO
DO
DO
controls
Event
monitor
Event
controls
Client
Report
handler
Reports
Abbildung 1.2: Konzept eines Report Control Blocks (RCB). DataSets zugeordnete
Daten werden überwacht und im Falle von Änderungen löst der Event
monitor ein Event aus. Je nach Konfiguration des RCB werden vom
Report handler Meldungen an den Client übermittelt.
Als Anmerkung sei erwähnt, dass es sich bei Report Control Blocks genau genommen
um abstrakte Modelle handelt, die als Instanz auf dem IED ihre Funktionalität erlangen.
Der Begriff wird auch bei der Programmierung des Clients verwendet und ohne klare
Unterscheidung in den nachfolgenden Abschnitten ist damit je nach Kontext entweder
das Modell selbst, dessen Instanz am Server oder dessen Abbild am Client gemeint.
1.3 Aufgabenstellung
Für das Durchführen einer großen Zahl an Tests zur Prüfung von Schutzgeräten für elektrische Übertragungsleitungen ist im Schutztechnik-Labor der TU Wien ein Prüfstand
aufgebaut. Die Auswertung der Ergebnisse dieser Tests stellt ein großes Problem dar, da
auf im Detail unbekannte Hardware- und Softwarefunktionen der Hersteller zurückgegriffen wird und diese Funktionen nicht für diesen Anwendungsfall ausgelegt sind. Das Laden
von mehreren tausend Fehlerfällen führt zu großen Laufzeiten und beschränkt somit die
Zahl der durchführbaren Tests.
Im Zuge dieser Arbeit soll überprüft werden, ob die Kommunikation mit dem Prüfling
durch IEC 61850 ersetzt werden kann. Dabei stellt sich neben der grundsätzlichen Realisierbarkeit die Frage, ob diese Funktionalitäten in den bestehenden Prüfstand mithilfe der
Programmiersprache Python integriert werden können und ob eine signifikante Verbesserung der Laufzeitproblematik erzielt werden kann. Die Qualität der erhaltenen Daten soll
dabei nicht beeinträchtigt werden, sodass bisherige Auswertungen der Ergebnisse nicht
angepasst werden müssen.
14
2 Materialen und Methoden
In diesem Abschnitt wird auf die Komponenten des Prüfstandes eingegangen und beschrieben, wie diese zu konfigurieren sind. Der überwiegende Teil der Arbeit behandelt
den Empfang von IEC 61850-Meldungen und deren Verarbeitung in Python, sowie die
Erweiterung der bestehenden Prüfstand-Applikation um diese Funktionalitäten.
2.1 Aufbau des Prüfstandes im Labor
Für die Durchführung definierter Tests wird auf aufgezeichnete Sequenzen zurückgegriffen, die in einer SQL-Datenbank abgelegt sind. Eine Testsequenz besteht aus abgetasteten
Werten von Spannungs- und Stromverläufen. Die Dauer ist im Allgemeinen nicht festgelegt, sehr wohl aber der Beginn und das Ende der Sequenz. Die ersten 1000 ms dienen dazu, die Speicher im Schutzgerät vor dem Fehler vollständig zu füllen und das Schutzgerät
in einen fehlerfreien Betriebszustand überzuführen. Um den Fehler zuverlässig erkennen
zu können, endet die Sequenz frühestens 500 ms nach Fehlereintritt. Dadurch wird außerdem dem Fehlerorter zur genauen Bestimmung der Fehlerdistanz ein größeres Zeitfenster
zur Verfügung gestellt als für die Entscheidung über Anregung oder Auslösung benötigt
wird. Im Beispiel in Abbildung 2.1 tritt der Fehler kurz nach 1 s auf. In der Menge der
Testsequenzen gibt es relativ zum Nullphasenwinkel der Spannung des Stranges L1 vier
mögliche Fehlerzeitpunkte, die jeweils gleich oft geprüft werden. Der Fehler tritt entweder 0°, 30°, 60° oder 90° nach dem positiven Nulldurchgang der Außenleiterspannung UL1
auf.
Die Größe der Spannungen und Ströme am Schutzgerät wird in der Praxis von den
Messwandlern bestimmt. Im Labor werden die abgespeicherten Primärgrößen per Software auf Sekundärgrößen umgerechnet und so dem Schutzgerät zugeführt. Die Struktur
der Testumgebung ist in Abbildung 2.2 dargestellt.
Schutzgerät
Das Schutzgerät SIPROTEC 5 (Typ 7SL87) der Firma Siemens unterstützt Distanzund Leitungsdifferentialschutz sowie Schaltermanagement. Seine Hauptaufgabe ist es, eine elektrische Leitung durch Erfassung von Messgrößen und deren digitaler Verarbeitung
zu überwachen und im Fehlerfall Kommandos an Leistungsschalter zu geben. Für die
Kommunikation mit Leistungsschaltern und anderen Komponenten der Netzschutz- und
Leittechnik besitzt diese Gerät eine Vielzahl teilweise redundanter optischer und elektrischer Schnittstellen. Für die Konfiguration des Schutzgerätes ist ein Computer mit
der Software DiGSi 5 (Version 7.80) über die integrierte Ethernet-Schnittstelle (Port J)
verbunden.
15
Primärspannung UL1
Spannung in kV
100
0
−100
Primärspannung UL2
100
0
−100
100
0
−100
Primärspannung UL3
0
0.2
0.4
0.8
Zeit in s
1
1.2
1.4
1
1.2
1.4
Primärstrom IL1
400
0
−400
Strom in A
Primärstrom IL2
400
0
−400
400
0
−400
0.6
Primärstrom IL3
0
0.2
0.4
0.6
0.8
Zeit in s
Abbildung 2.1: Exemplarischer Zeitverlauf einer Testsequenz. Der Fehler tritt kurz
nach 1 s auf.
16
Für IEC 61850-Datenübertragung steht für elektrische Ethernet-Kommunikation das
Modul ETH-BA-2EL mit zwei redundanten Anschlüssen zur Verfügung und für optische
Kommunikation das Modul ETH-BB-2FO. Im Labor-Computer kommt zusätzlich zur
Verbindung zum Port J eine zweite Ethernet-Schnittstelle für den Anschluss an den Port
ETH-BA-2EL zum Einsatz [5].
Schutzprüfgerät
Um im Labor dem zu testenden Schutzrelais die Spannungen und Ströme zu übergeben, kommt das Schutzprüfgerät CMC 356 der Firma Omicron zum Einsatz. Über die
Ethernet-Schnittstelle wird das Gerät gesteuert und erhält die Abtastwerte zur Wandlung auf analoge Größen an den Ausgängen. Da auf dem Schutzrelais ausschließlich
Distanzschutz-Funktionen getestet werden, werden drei Spannungsausgänge für die drei
Außenleiter und der Sternpunkt sowie drei Stromausgänge für die drei Außenleiter und
ein Neutralleiter mit dem Schutzgerät verbunden. Das Gerät kann Prüfspannungen bis
300 V und Prüfströme bis 64 A bereitstellen. Über weitere Stromausgänge ist auch eine
Prüfung von Differentialschutzfunktionen möglich. [6]
SQL-Datenbank
C6
18
50
Analog/DigitalKommunikation
IE
CMC 356
(Omicron)
Netz-Ströme
testbench.py,
iec61850helper.py,
libiec61850, ...
Schutzprüfgerät
N
LA
NetzSpannungen
Computer
(Schutzrechner)
Schutzgerät
SIPROTEC 5
(Siemens)
Abbildung 2.2: Aufbau des Prüfstandes: Das Schutzprüfgerät wird vom Schutzrechner gesteuert und gibt die Spannungs- und Stromverläufe aus, die aus
der SQL-Datenbank geladen werden. Die Auswertung der Fehlerfälle
erfolgt über IEC 61850.
17
Python-Applikation testbench.py
Der Schutzrechner ist ein Desktop-Computer, der den Kern des Prüfstandes darstellt. Die
Applikation testbench.py lädt Testsequenzen aus der Datenbank, steuert das Schutzprüfgerät und wertet die Testergebnisse aus. Neben diesen Hauptaufgaben ist vor allem die
Messung von Laufzeiten eine wichtige Funktion für den Vergleich der Leistungsfähigkeit
mit und ohne Implementierung der IEC 61850-Kommunikation.
2.2 Konfiguration des IEC 61850-Servers auf dem
Schutzgerät
Um verfügbare Funktionen zu definieren und Einstellungen zu setzen, wird die XMLbasierte Sprache SCL (System Configuration Language) eingesetzt. Damit ist es möglich,
ein IED vollständig mit einem Baum zu beschreiben und das zu prüfende Gerät zu konfigurieren. Praktisch ist somit eine einzige Datei ausreichend, die über die entsprechenden
Konfigurationsprogramme der Hersteller dem Gerät übergeben wird. Die in den folgenden
Abschnitten angeführten Auszüge aus dieser Datei sind um Elternknoten erweitert, um
die Position im Baum und nicht in der Datei selbst zu verdeutlichen. Diese Ausschnitte
sollen eine Reproduktion der Ergebnisse durch einen gleichwertigen IEC 61850-Server,
beispielsweise auch durch ein Simulationsprogramm wie in Abschnitt 1.1.2 beschrieben,
ermöglichen.
2.2.1 Grundlegende Einstellungen und Funktionen
Als Wurzelknoten definiert in Code-Block 2.1 das Element <SCL> die verwendete
Sprache. Im Unterknoten <Header> (Zeile 11 bis 16) wird als Erstes die Station
IEC station 1 festgelegt. Dieser Name darf unter allen vernetzten IEC 61850-Geräten
nicht mehrfach vorkommen. Der Knoten <Communication> (ab Zeile 17) dient zur
Konfiguration der Netzwerkschnittstellen und kann mehrere Access Points (AP) definieren. Im vorliegenden Fall wird ein AP mit dem Ethernet-Anschluss E verknüpft
(Zeile 20) und mit der IP-Adresse 10.0.0.60 in einem 24-Bit-Subnetz konfiguriert
(Zeilen 22 und 23). Das Attribut iedName weist der Schnittstelle einen Namen zu,
der bei jeder Referenz auf ein LD, LN, DO oder DA als Präfix angegeben wird (z.B.
SIPRec_FaultRecorder/DEF_RDRE1.FltNum für den Zugriff auf das DA mit der
Fehlernummer FltNum, die dem LN DEF_RDRE1 und dem LD Rec_FaultRecorder
untergeordnet ist).
<?xml version="1.0" encoding="UTF-8"?>
<SCL xmlns="http://www.iec.ch/61850/2003/SCL"
3
xmlns:scl="http://www.iec.ch/61850/2003/SCL"
4
xsi:schemaLocation="http://www.iec.ch/61850/2003/SCL SCL.xsd"
5
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6
xmlns:IEC_60870_5_104="http://www.iec.ch/61850-80-1/2007/SCL"
7
xmlns:siebase=
8
"http://www.siemens.com/energy/2009/09/siprotec5/SieBase"
9
xmlns:siedig="http://www.siemens.com/energy/2011/11/Siedig">
1
2
18
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<!-- Zeilen entfernt -->
<Header id="IEC station 1" version="1" revision="4"
toolID="IEC 61850 System Configurator, Version: V5.80 "
nameStructure="IEDName">
<Text>IEC station 1</Text>
<!-- Zeilen entfernt -->
</Header>
<Communication>
<SubNetwork name="Default_subnet" type="8-MMS">
<Private type="Siemens-Start-Address">172.16.0.1</Private>
<ConnectedAP iedName="SIP" apName="E">
<Address>
<P type="IP" xsi:type="tP_IP">10.0.0.60</P>
<P type="IP-SUBNET" xsi:type="tP_IP-SUBNET">255.255.255.0</P>
<!-- Zeilen entfernt -->
</Address>
26
</ConnectedAP>
27
</SubNetwork>
28
</Communication>
29 </SCL>
25
Code-Block 2.1: Aufbau der XML-Datei und Netzwerkkonfiguration in der Konfigurationssprache SCL.
Die Verfügbaren Funktionen des IED werden wie in Code-Block 2.2 im Knoten
<Services> (ab Zeile 11) festgelegt. Da der Prüfstand die Daten zu Fehlerfällen mittels Reports und deren verknüpfte DataSets vom Schutzgerät erhält, ist es zwingend
erforderlich, dass wie im folgenden XML-Code zumindest die Elemente
• <GetDirectory />
• <GetDataObjectDefinition />
• <DataObjectDirectory /> und
• <GetDataSetValue />
inkludiert sind (Zeilen 16-19). Um die Einstellungen für die Fehlermeldungen während
der Laufzeit anpassen zu können, müssen außerdem im Element <ReportSettings>
die Attribute
• datSet
• rptID
• bufTime und
• trgOps
den Wert Dyn (dynamisch) besitzen (Zeilen 26 und 27).
19
<?xml version="1.0" encoding="UTF-8"?>
<SCL>
3
<IED desc="7SL87" name="SIP" type="7SL87"
4
manufacturer="SIEMENS" configVersion="V07.80.17">
<Private type="Siemens-MasterId">
5
6
378b250f-835b-4b14-822b-4b2d9c6c0c3e
7
</Private>
8
<Private type="Siemens-s7ManagerName">7SL87</Private>
9
<Private type="Siemens-ICD-Language">de-DE</Private>
1
2
<!-- Zeilen entfernt -->
10
<Services>
12
<DynAssociation />
13
<SettingGroups>
<SGEdit />
14
15
</SettingGroups>
16
<GetDirectory />
17
<GetDataObjectDefinition />
18
<DataObjectDirectory />
19
<GetDataSetValue />
20
<DataSetDirectory />
21
<ConfDataSet max="50" maxAttributes="100" />
22
<DynDataSet max="30" maxAttributes="60" />
23
<ReadWrite />
24
<ConfReportControl max="30" />
25
<GetCBValues />
26
<ReportSettings cbName="Conf" datSet="Dyn" rptID="Dyn"
27
optFields="Dyn" bufTime="Dyn" trgOps="Dyn" intgPd="Dyn" />
28
<GSESettings cbName="Conf" datSet="Conf"
29
appID="Conf" dataLabel="Fix" />
30
<ConfLNs fixPrefix="false" fixLnInst="false" />
31
<GOOSE max="16" />
32
<FileHandling />
33
</Services>
34
</IED>
35 </SCL>
11
Code-Block 2.2: Zwingend erforderliche Report- und DataSet-Konfigurationen für den
IEC 61850-Server.
2.2.2 DataSet und ReportControl
DataSets sind üblicherweise keiner konkreten Funktion des Schutzgeräts zugeordnet und
werden somit meist keinem spezifischen LN, sondern dem Standardknoten LLN0 untergeordnet der als LN innerhalb jedes LD definiert sein muss. In ihm werden allgemeine
Einstellungen und Eigenschaften gesammelt, wie z.B. auch DataSets und ControlBlocks.
Das übergeordnete LD auf dem SIPROTEC-Schutzgerät heißt Application.
Ein DataSet ist eine Liste an Referenzen auf Attribute mit einer bestimmten FC,
sog. Functionally Constrained Data Attributes (FCDA) mit dem entsprechenden XMLAttribut <FCDA />. Im Ausschnitt aus der Konfigurationsdatei in Code-Block 2.3 ist
beispielsweise im DataSet DSTestbench in Zeile 21 und 22 ein <FCDA />-Knoten für
20
die Fehlerreaktanz definiert: Das Datenobjekt FltReact repräsentiert einen Messwert
(fc="MX" für Measurement Information) und liegt im Knoten SE_RFLO innerhalb der
Leitungsüberwachung (ldInst="Ln1" für Line 1 ).
Für die Konfiguration von Meldungen ist der Knoten <ReportControl> (ab Zeile 34
in Code-Block 2.3) vorgesehen. Er besitzt eine Referenz auf das DataSet, das im gleichen
LN vorhanden sein muss (dataSet="DSTestbench"). ReportControl-Knoten müssen
eine eindeutige ID besitzen, die sich wie ein Dateipfad aus den übergeordneten Knoten zusammensetzt, wie z.B. rptID="SIP/Application/LLN0$RP$RPTestbench". Zwischen den $-Zeichen wird angegeben, ob es sich um einen Buffered Report (BR) oder um
den im Prüfstand eingesetzten Unbuffered Report (RP) handelt. Die beiden Varianten besitzen geringfügige Unterschiede bei der Sicherstellung der Datenübertragung, die für die
Anwendung im Labor nicht relevant sind. Weitere Einstellungen wie z.B. die Buffer-Zeit
bufTime oder Optionen zur Auslösung einer Meldung (<TrgOps />) werden während
der Laufzeit verändert und in Abschnitt 2.5 näher beschrieben.
<?xml version="1.0" encoding="UTF-8"?>
<SCL>
3
<IED>
4
<AccessPoint desc="Port E" name="E"
5
router="false" clock="false">
6
<Server timeout="0">
<Authentication none="true" />
7
8
<LDevice desc="Anwendung" inst="Application">
9
<LN0 lnClass="LLN0" inst="" desc="Allgemein"
10
lnType="SIPROTEC5_LNType_LLN0_Application">
11
<DataSet name="DSTestbench">
12
<Private type="Siemens-SysConItem" />
13
<FCDA ldInst="Rec_FaultRecorder" prefix="DEF_"
14
lnClass="RDRE" lnInst="1" doName="FltNum" fc="ST" />
15
<FCDA ldInst="Ln1" prefix="" lnClass="PTRC"
lnInst="1" doName="Op" fc="ST" />
16
17
<FCDA ldInst="Ln1" prefix="" lnClass="PTRC"
18
lnInst="1" doName="Str" fc="ST" />
19
<FCDA ldInst="Ln1" prefix="SE_" lnClass="RFLO"
20
lnInst="1" doName="FltRis" fc="MX" />
21
<FCDA ldInst="Ln1" prefix="SE_" lnClass="RFLO"
22
lnInst="1" doName="FltReact" fc="MX" />
23
<FCDA ldInst="Ln1" prefix="SE_" lnClass="RFLO"
24
lnInst="1" doName="FltRisSc" fc="MX" />
25
<FCDA ldInst="Ln1" prefix="SE_" lnClass="RFLO"
26
lnInst="1" doName="FltReactSc" fc="MX" />
27
<FCDA ldInst="Ln1" prefix="SE_" lnClass="RFLO"
28
lnInst="1" doName="FltDis" fc="MX" />
29
<FCDA ldInst="Ln1" prefix="SE_" lnClass="RFLO"
30
lnInst="1" doName="FltDisPct" fc="MX" />
31
<FCDA ldInst="Ln1" prefix="SE_" lnClass="RFLO"
32
lnInst="1" doName="FltLoop" fc="ST" />
33
</DataSet>
34
<ReportControl datSet="DSTestbench"
35
rptID="SIP/Application/LLN0$RP$RPTestbench" confRev="10001"
36
buffered="false" bufTime="100" name="RPTestbench">
1
2
21
<TrgOps dchg="true" qchg="true" dupd="true" period="true" />
<OptFields seqNum="true" timeStamp="true" dataSet="true"
39
reasonCode="true" dataRef="false"
entryID="false" configRef="true" />
40
41
<RptEnabled max="1" />
42
</ReportControl>
43
</LN0>
44
</LDevice>
45
</Server>
46
</AccessPoint>
47
</IED>
48 </SCL>
37
38
Code-Block 2.3: Konfiguration des DataSet DSTestbench und des Report Block
RPTestbench für das Auslösen von Meldungen.
2.3 C-Bibliothek libiec61850
Bei Recherchen zu bereits verfügbaren Programmen und Bibliotheken wurde nach den
Kriterien der guten Integrierbarkeit mit Python, der Flexibilität durch Erweiterbarkeit
und der Verfügbarkeit des Quelltextes unter einer freien Lizenz die Bibliothek libiec61850
ausgewählt. Die Software wird von der Firma MZ Automation GmbH auf der Plattform
GitHub 1 unter der Lizenz GPL-3.0 zur Verfügung gestellt und laufend weiterentwickelt.
Die Programmierung in der Sprache C führt zu sehr guter Leistungsfähigkeit aufgrund
von vorkompiliertem Code und zu einfacher Integration in Python. Dadurch ist einerseits flexible und effiziente Programmierung von Endanwendungen in Python möglich,
während das vorkompilierte C-Programm gleichzeitig für schnelle Ausführung sorgt. Die
Bibliothek besitzt keine Abhängigkeiten zu anderen Bibliotheken. Das erleichtert die Einrichtung einer Arbeitsumgebung, da keine Zusatzprogramme installiert werden müssen
und keine Probleme mit Programm-Abhängigkeiten auftreten.
2.3.1 Elemente der Bibliothek
Grundsätzlich werden sowohl Server- als auch Client-Funktionen bereitgestellt, jedoch
wird im Folgenden nur die Client-seitige Anwendung betrachtet (Abbildung 2.3).
Auf unterster Ebene (der Hardware am nähesten) befindet sich die Schnittstelle zum
Betriebssystem. Die Unterstützung für Linux, Windows und MacOS wird vom Entwickler
bereitgestellt, jedoch ist die Bibliothek für den Einsatz unter anderen Systemen erweiterbar. Aufgabe dieser Schnittstelle ist es, die Hardware-Abstraktionsebene (HAL) einheitlich gestalten zu können. Höhere Ebenen können so Grundfunktionen wie Threading, das
Dateisystem oder Ethernet-Verbindungen unabhängig vom Betriebssystem nutzen.
Der MMS Client Stack ist eine erweiterte Implementierung von MMS nach ISO 9506.
Als Kern der Bibliothek umfasst dieser Teil die eigentliche Datenübertragung (Internet Protocol IP und Transmission Control Protocol TCP), die Codierung und Decodie1
https://github.com/mz-automation/libiec61850
22
IEC 61850 C Client API
IEC 61850 Client Service Layer (report handling, control, data access, ...)
MMS Client Stack
GOOSE
Subscriber
Hardware Abstraction Layer (HAL)
Sockets, Threads, Time, Ethernet, Files
Linux HAL
WIN32 HAL
MacOS HAL
Abbildung 2.3: Client-Struktur der C-Bibliothek libiec61850.
rung von Daten, Bereitstellung der Daten in Form von Datenstrukturen sowie Funktionen zur Serversteuerung. Auf oberster Anwendungsebene werden aus dieser Schicht nur
Funktionen zur Auflösung von Datenstrukturen eingesetzt (Funktionen beginnend mit
MmsValue_).
Die Applikation selbst wird auf eine Vielzahl von anwendungsorientierten Funktionen
aufgebaut, deren Aufgaben beispielsweise
• die Verbindungsabwicklung (z.B. der Verbindungsaufbau
mit IedConnection_connect),
• die Abfrage von Datenobjekten (beginnend mit IedConnection_get),
• die Konfiguration von Meldungen (beginnend
mit ClientReportControlBlock_) oder
• die Verarbeitung von erhaltenen Meldungen (beginnend mit ClientReport_)
sind. Vorkompilierte Programme wie dieses können nicht ohne weiteres in Python verwendet werden und um die Bibliothek direkt in den Prüfstand einzubinden ist eine entsprechende Schnittstelle notwendig.
2.3.2 Python-Schnittstelle zu libiec61850
Für die Schnittstelle zwischen der C-Bibliothek und Python-Programmen kommt SWIG 2
zum Einsatz. Dieses Entwicklerwerkzeug erstellt Bibliotheken für andere (meist interpretierte) Sprachen, wie z.B. Python, MATLAB oder R. In Python kann damit ein Paket
importiert werden, mit dem direkt Funktionen und Variablen aus C bzw. C++ angesprochen werden. SWIG sorgt dafür, dass Datentypen korrekt übersetzt werden und der
Aufruf von Funktionen nach Python-Konventionen möglich ist.
2
http://www.swig.org
23
Der C-Code in Code-Block 2.4 beschreibt eine Funktionsdefinition, die als Rückgabewert eine Variable vom Typ IedConnection besitzt:
1
// C - Code
IedConnection IedConnection_create() {
3
return createNewConnectionObject(NULL, true);
4 }
2
Code-Block 2.4: Definition der Funktion IedConnection_create in C.
Der Python-Beispielcode in Code-Block 2.5 importiert das von SWIG erstellte Modul
iec61850 und erstellt ein Verbindungsobjekt. Der Rückgabewert ist ein Swig Object,
das den C-Datentyp IedConnection repräsentiert (Zeile 5). Dieses kann einer Funktion
als Parameter übergeben werden, die als C-Datentyp IedConnection erwartet.
1
# Python - Code
import iec61850
3 connection = iec61850.IedConnection_create()
4 print(connection)
2
5
# < S w i g O b j e c t of t y p e ’ I e d C o n n e c t i o n ’ a t 0 x 1 0 8 c f 8 1 5 0 >
Code-Block 2.5: Exemplarischer Aufruf der C-Funktion IedConnection_create in
Python.
Eine Besonderheit in Python im Vergleich zu C ist, dass eine Funktion mehrere
Rückgabewerte unterschiedlicher Typen in Form einer Liste besitzen kann. In C wird
üblicherweise vor dem Funktionsaufruf eine Variable deklariert und als Zeiger der
Funktion übergeben. Dazu wird in der SWIG-Konfigurationsdatei libiec61850.i
die Anweisung %apply int *OUTPUT {IedClientError* error}; hinzugefügt, um
den Fehler-Code als zusätzlichen Rückgabewert in Python zu erhalten, beispielsweise
für folgende Funktion:
LinkedList IedConnection_getLogicalDeviceList(IedConnection self,
IedClientError* error)
In Python wird eine Liste mit zwei Einträgen zurückgegeben (Code-Block 2.6): einerseits der eigentliche Rückgabewert der Funktion (LinkedList in Zeile 7) und andererseits der Fehler-Code 0 (Zeile 9).
1
# Python - Code
import iec61850
3 connection = iec61850.IedConnection_create()
4 iec61850.IedConnection_connect(connection, ’localhost’, 102)
5 [deviceList, error] = iec61850.IedConnection_getLogicalDeviceList(
connection)
6 print(deviceList)
2
7
# < i e c 6 1 8 5 0 . s L i n k e d L i s t ; proxy of < Swig Object of type ’ L i n k e d L i s t ’
at 0 x1037ea300 > >
8
print(error)
9
# 0
Code-Block 2.6: Verarbeitung mehrerer Rückgabewerte
IedConnection_create in Python.
24
aus
der
C-Funktion
Das Verarbeiten von Meldungen stellt eine besondere Herausforderung dar, da hierfür
nicht aktiv von der Applikation eine Anfrage an das Schutzgerät geschickt wird, sondern
umgekehrt. Bei der Konfiguration der Meldungen wird in C eine Callback -Funktion in
Form eines Zeigers hinterlegt. Jedoch ist es nicht möglich, während der Laufzeit des Prüfstandes aus Python heraus eine C-Funktion zu deklarieren, die dann weiteren PythonCode ausführt. Als Hilfskonstrukt werden daher C++-Klassen erstellt (Code-Block 2.7).
In der Klasse RCBSubscriber wird in der Methode subscribe (Zeile 5) die C-Funktion
IedConnection_installReportHandler aufgerufen, um die Callback-Funktion zu registrieren. Als Callback wird jedoch eine statische Funktion dieser Klasse übergeben (Zeile
11). Für die Zuordnung der Meldungen verschiedener Report Control Blocks (RCB) auf
die richtige Instanz der Klasse EventSubscriber wird jede Instanz in der Liste ESMap
mit dem Namen des RCB als Schlüssel gespeichert. Nach dem Kopieren der übermittelten
Daten in eine Objekt-Variable mittels setReceivedData (Zeile 26) wird die Methode
trigger ausgeführt (Zeile 27), die in einer abgeleiteten Klasse selbst definiert werden
kann.
1
/ / C ++ - C o d e
class RCBSubscriber: public EventSubscriber {
3
public:
2
4
5
virtual void subscribe() {
// i n s ta l l the
6
7
8
9
10
11
12
13
}
libiec61850
callback :
IedConnection_installReportHandler(
m_ied_connection,
m_rcb_reference.c_str(),
m_rcb_rpt_id.c_str(),
RCBSubscriber::triggerRCBHandler,
NULL);
14
15
16
17
18
// Static
m e t h o d : it is t h e c a l l b a c k f o r
l i b i e c 6 1 8 5 0 in C
static void triggerRCBHandler(void *parameter, ClientReport
report)
{
PyThreadStateLock PyThreadLock;
19
20
21
std::string rcbName = ClientReport_getRcbReference(report);
EventSubscriber* event_subscriber = ESMap[rcbName];
22
23
24
25
26
27
28
29
30
if (event_subscriber) {
EventHandler *l_event_handler_p = event_subscriber->
getEventHandler();
if (l_event_handler_p) {
l_event_handler_p->setReceivedData(&report);
l_event_handler_p->trigger();
}
}
}
25
31
// S e t t e r s
32
33
34
35
36
37
38
39
40
41
42
43
};
void setIedConnection(const IedConnection &i_ied_connection) {
m_ied_connection = i_ied_connection;
}
void setRcbReference(const char *i_rcb_reference) {
m_rcb_reference = i_rcb_reference;
ESMap.insert(std::make_pair(m_rcb_reference, this));
}
void setRcbRptId(const char *i_rcb_rpt_id) {
m_rcb_rpt_id = i_rcb_rpt_id;
}
44
class EventHandler {
public:
47
virtual ~EventHandler() {}
48
virtual void setReceivedData(void *i_data_p) = 0;
49
virtual void trigger() = 0;
50 };
45
46
51
class RCBHandler: public EventHandler {
virtual void setReceivedData(void *i_data_p)
54
{
52
53
// copy the r e c e i v e d
55
57
58
59
60
data
ClientReport *l_my_data_p = static_cast<ClientReport*>(i_data_p);
_client_report = *l_my_data_p;
56
}
}
ClientReport _client_report;
Code-Block 2.7: Definition mehrerer C++-Klassen zur Verarbeitung von CallbackFunktionen infolge von Meldungen des Schutzgerätes.
Mithilfe der director -Funktion von SWIG kann ein Abbild dieser Klassen auf Python
übertragen werden und auch auf Klassen vererbt werden. In Code-Block 2.8 wird die
Klasse RCBHandlerHelper als abgeleitete Klasse von iec61850.RCBHandler erstellt.
Damit wird die Methode trigger in Python definiert und SWIG bildet diese als C++Methode ab.
Abbildung 2.4 zeigt die wesentlichen Zusammenhänge der beschriebenen Komponenten.
1
# Python - Code
class RCBHandlerHelper(iec61850.RCBHandler):
3
customTrigger = None
4
rpt = None
2
5
def setCustomTrigger(self, function):
self.customTrigger = function
6
7
8
26
9
10
11
def trigger(self):
# execute
previously
assigned
function
self.customTrigger(self._client_report)
Code-Block 2.8: Python-Klasse als abgeleitete Klasse einer C++-Klasse zur Ausführung einer Python-Funktion nach Erhalt einer Meldung.
libiec61850
IedConnection_installReportHandler()
Callback
ausführen
API-Zugriffe
statische CallbackFunktion installieren
C++-Hilfsklassen
subscribe()
RCBSubscriber
RCBHandler
trigger()
abgeleitete Klasse
in Python
RCBHandlerHelper(iec61850.RCBHandler)
Abbildung 2.4: Beziehungen zwischen der C-Bibliothek libiec61850, den Hilfsklassen in
C++ und der Python-Applikation für die Abwicklung von Meldungen.
2.4 Hilfsklassen in Python
Um die Kommunikation über IEC 61850 effizient und möglichst übersichtlich in den
Prüfstand einbauen zu können, werden einige Hilfsklassen erstellt, die als Modul importiert werden. Damit wird eine weitere Schicht zwischen der Anwendungsebene und
der libiec61850-Schnittstelle eingezogen. Die Prüfstand-Applikation selbst soll nur um ein
absolutes Mindestmaß an Komplexität durch die IEC 61850-Integration erweitert werden.
Die Handhabung von kritischen Verbindungsvariablen und der Aufruf von C-Funktionen
würde zu unübersichtlichem Code führen und zahlreiche Fehlerquellen bieten. Hilfsklassen ermöglichen übersichtlichen Code, der leicht getestet werden kann und somit weniger
fehleranfällig ist. Im Folgenden sollen die wichtigsten Teile des implementierten Funktionsumfangs beschrieben werden. Neben Funktionen zur Server-Verbindung, zum Dekodieren von MMS-Paketen und zur Konfiguration von Meldungen wird eine Datenstruktur
zur Handhabung der erhaltenen Daten erstellt.
2.4.1 Konstanten und Methoden zur Verbindungsverwaltung
In der Norm IEC 61850 werden bestimmte Betriebszustände, Fehlerfälle, physikalische
Dimensionen von Größen oder deren Vorsatzzeichen (Zehnerpotenzen) als Ganzzahlen
27
kodiert übertragen. Für die Dekodierung ist in der Klasse Iec61850Helper die Klassenvariable enum definiert. Ein Auszug ist in Code-Block 2.9 ab Zeile 10 zu sehen.
FCs werden in Objekt-Referenzen sowohl als Zeichenketten als auch als Funktionsparameter in Form von C-Variablen verwendet. Für eine Konvertierung wird daher in Zeile
30 dictFC definiert.
In der Methode connect wird die Klassenvariable con initialisiert, die eine C-Variable
vom Typ IedConnection beinhaltet und für jeden Netzwerkzugriff als Parameter übergeben wird. Diese Variable wird nach dem Beenden der Verbindung in der Methode
close (Zeile 58) wieder auf None gesetzt. Die Methode _checkError (Zeile 65) sollte
nach jedem Netzwerkzugriff aufgerufen werden und löst im Fall eines Fehlers die Ausnahme (Exception) IOError aus. Mit der vom Python-Interpreter automatisch ausgeführten
Methode __del__ (Zeile 72) wird garantiert, dass die Verbindung ordnungsgemäß beendet wird, bevor die Instanz der Klasse gelöscht wird.
1
2
# Python - Code
import iec61850
3
class Iec61850Helper(object):
hostname = "localhost"
6
tcpPort = 102
7
con = None
4
5
8
# IEC 61850 -7 -4 Annex H
9
enum = {
"FltLoop": {
1: "Phase A to Ground",
2: "Phase B to Ground",
3: "Phase C to Ground",
4: "Phase A to B",
5: "Phase B to C",
6: "Phase C to A",
7: "Other"
},
10
11
12
13
14
15
16
17
18
19
# IEC 61850 -7 -3 Table 18
20
21
22
23
24
25
26
}
27
"dir": {
0: "unknown",
1: "forward",
2: "backward",
3: "both"
}
28
# IEC 61850 -7 -2
29
dictFC = {
’ST’: iec61850.IEC61850_FC_ST,
’MX’: iec61850.IEC61850_FC_MX,
’CO’: iec61850.IEC61850_FC_CO,
’SP’: iec61850.IEC61850_FC_SP,
30
31
32
33
34
28
35
36
37
38
39
40
41
42
43
44
45
46
47
}
’SV’: iec61850.IEC61850_FC_SV,
’CF’: iec61850.IEC61850_FC_CF,
’DC’: iec61850.IEC61850_FC_DC,
’SG’: iec61850.IEC61850_FC_SG,
’SE’: iec61850.IEC61850_FC_SE,
’EX’: iec61850.IEC61850_FC_EX,
’BR’: iec61850.IEC61850_FC_BR,
’RP’: iec61850.IEC61850_FC_RP,
’LG’: iec61850.IEC61850_FC_LG,
’GO’: iec61850.IEC61850_FC_GO,
’MS’: iec61850.IEC61850_FC_MS,
’US’: iec61850.IEC61850_FC_US,
48
49
50
51
def __init__(self, hostname="localhost", tcpPort=102):
self.hostname = hostname
self.tcpPort = tcpPort
52
53
54
55
56
def connect(self):
self.con = iec61850.IedConnection_create()
error = iec61850.IedConnection_connect(self.con, self.hostname,
self.tcpPort)
self._checkError(error)
57
58
59
60
61
62
63
def close(self):
if iec61850.IedConnection_getState(self.con) == iec61850.
IED_STATE_CONNECTED:
iec61850.IedConnection_close(self.con)
if self.con is not None:
iec61850.IedConnection_destroy(self.con)
self.con = None
64
65
66
67
68
69
70
def _checkError(self, error):
if (error != iec61850.IED_ERROR_OK):
print(error)
print("Failed to connect to %s:%i (%i)" % (self.hostname, self.
tcpPort, error))
self.close()
raise IOError
71
72
73
74
75
def __del__(self):
if self.con is not None:
print("closing IEC61850 connection")
self.close()
Code-Block 2.9: Auszug aus der Python-Klasse Iec61850Helper mit Auflistung
einiger in IEC 61850 festgelegter Kodierungen, ein dict mit den FCs
sowie der Methoden zur Verbindungshandhabung.
29
2.4.2 Konvertierung von MMS-Größen
Alle über den Bus übertragenen Daten werden als MMS-Größen kodiert gesendet. Am
Labor-Prüfstand werden Daten ausschließlich empfangen und es ist nicht notwendig,
MMS-Datenpakete zu erstellen. Für die Konvertierung auf Python-Variablen lässt sich
der Vorteil der dynamischen Datentypen nutzen und mit nur einer Methode (convert in
Code-Block 2.10) werden beliebige MMS-Typen dekodiert. Für den Typ MMS_STRUCTURE
gibt die Methode eine Zeichenkette mit dem Inhalt (auch tiefer verzweigter Strukturen)
zurück, wodurch die eigentlichen Typ-Informationen verloren gehen. Diese Funktionalität
ist für Tests praktisch, jedoch sollten Datenstrukturen vor dem Aufruf der convertMethode aufgelöst werden (z.B. wie in Code-Block 2.15 ab Zeile 33).
Die Funktion iec61850.MmsValue_printToBuffer in Zeile 16 erwartet in C als zweites Argument eine Referenz einer deklarierten Variablen. Diese wird von SWIG erstellt
und tritt in Python nur noch als Rückgabevariable buf auf (siehe Erläuterungen zu
Code-Block 2.6).
1
2
# Python - Code
# Member of class
Iec61850Helper ( object ):
@staticmethod
4 def convert(obj):
5
objType = iec61850.MmsValue_getType(obj)
6
if objType == iec61850.MMS_INTEGER:
7
return iec61850.MmsValue_toInt64(obj)
8
elif objType == iec61850.MMS_UNSIGNED:
9
return iec61850.MmsValue_toUint32(obj)
10
elif objType == iec61850.MMS_BOOLEAN:
11
return iec61850.MmsValue_getBoolean(obj)
12
elif objType == iec61850.MMS_FLOAT:
13
return iec61850.MmsValue_toFloat(obj)
14
elif objType == iec61850.MMS_OCTET_STRING or objType == iec61850.
MMS_BIT_STRING or objType == iec61850.MMS_UTC_TIME or objType ==
iec61850.MMS_STRUCTURE:
15
buf = str()
16
[val, buf] = iec61850.MmsValue_printToBuffer(obj, 1024)
17
return buf
18
elif objType == iec61850.MMS_VISIBLE_STRING:
19
return iec61850.MmsValue_toString(obj)
3
Code-Block 2.10: Statische Methode convert der Python-Klasse Iec61850Helper
zur Dekodierung von MMS-Größen auf Python-Variablen.
2.4.3 Konfiguration und Verarbeitung von Meldungen
Meldungen werden mithilfe des Report Control Blocks (RCB) konfiguriert (siehe Abschnitt 1.2.2). Um ein Abbild der Einstellungen in Python zu erhalten, wird die Klasse
RCBHelper erstellt. Ein Auszug aus dem Quelltext ist in Code-Block 2.11 angeführt. Die
Variable con ist eine Kopie der gleichnamigen Variablen der Klasse Iec61850Helper
30
und es wird keine neue Verbindung aufgebaut. rcb beinhaltet eine Referenz auf die CVariable für diesen RCB. Beim Senden der Einstellungen an den Server werden nicht
alle Konfigurationen des Blocks übertragen, sondern nur vorher festgelegte. Die Variable mask beschreibt eine Bit-Maske dieser gesetzten RCB-Einstellungen und wird durch
Oder-Verknüpfung beim Ändern von Einstellungen in den entsprechenden Methoden festgelegt (z.B. in Zeile 52 im Code-Block 2.11 für die Einstellung BufTm). Sie gibt damit
an, welche Einstellungen an den Server übertragen werden.
Die Kriterien, wann ein Event für die Übertragung einer Meldung ausgelöst wird,
werden mit der Option TrgOp (Trigger Option) angepasst. In der Norm werden folgende
fünf Optionen definiert:
• data-change (dchg): Die Änderung bezieht sich auf den Wert eines DA. Meist
handelt es sich um Status-Werte mit dem Attribut stVal, durch welches z.B. die
Änderung der Fehlernummer am Schutzgerät eine Meldung auslöst.
• quality-change (qchg): Hierbei löst die Änderung des Attributes q eine Meldung
aus. Neben einer Vielzahl anderer Attribute ist auch den DA für die Anregung und
Auslösung des Schutzgerätes das Unterattribut q zugeordnet.
• data-update (dupd): Diese Option betrifft berechnete Werte, wie z.B. die Fehlerdistanz. Wenn der Wert neu berechnet und gesetzt wird, wird auch dann ein Event
ausgelöst, wenn das Ergebnis der Berechnung das gleiche ist und sich der Wert im
Grunde nicht ändert.
• integrity: Betrifft die periodische Auslösung von Meldungen. Die Option IntgPd
legt das Zeitintervall fest.
• general-interrogation: Damit können Meldungen durch eine Anfrage des Clients
ausgelöst werden. Alle Daten, die im DataSet vorhanden sind, werden übertragen.
Diese Optionen können unabhängig voneinander einen booleschen Wert annehmen.
Zum Setzen der Option TrgOp werden die einzelnen Werte kodiert und Oder-verknüpft
(Code-Block 2.11 Zeile 29-38).
1
# Python - Code
class RCBHelper(object):
3
con = None
2
4
5
# Referenz
rcb = None
6
7
8
9
10
11
12
mask = 0
callback = None
# Subscriber
subs = None
subsHandler = None
dataSetDirectory = None
13
14
def __init__(self, rcb, con):
31
self.con = con
self.rcb = rcb
15
16
17
def getObjectReference(self):
return iec61850.ClientReportControlBlock_getObjectReference(self.
rcb)
18
19
20
def getRptID(self):
return iec61850.ClientReportControlBlock_getRptId(self.rcb)
21
22
23
def getDataSetReference(self):
return iec61850.ClientReportControlBlock_getDataSetReference(self
.rcb)
24
25
26
def setTrgOps(self, data_change=False, quality_change=False,
data_update=False, integrity=False, general_interrogation=False):
trgMask = 0
if data_change:
trgMask = trgMask | iec61850.TRG_OPT_DATA_CHANGED
if quality_change:
trgMask = trgMask | iec61850.TRG_OPT_QUALITY_CHANGED
if data_update:
trgMask = trgMask | iec61850.TRG_OPT_DATA_UPDATE
if integrity:
trgMask = trgMask | iec61850.TRG_OPT_INTEGRITY
if general_interrogation:
trgMask = trgMask | iec61850.TRG_OPT_GI
iec61850.ClientReportControlBlock_setTrgOps(self.rcb, trgMask)
self.mask = self.mask | iec61850.RCB_ELEMENT_TRG_OPS
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def setRptEna(self, value):
iec61850.ClientReportControlBlock_setRptEna(self.rcb, value)
self.mask = self.mask | iec61850.RCB_ELEMENT_RPT_ENA
42
43
44
45
def setBufTm(self, value):
iec61850.ClientReportControlBlock_setBufTm(self.rcb, value)
self.mask = self.mask | iec61850.RCB_ELEMENT_BUF_TM
46
47
48
49
def setGI(self, value):
iec61850.ClientReportControlBlock_setGI(self.rcb, value)
self.mask = self.mask | iec61850.RCB_ELEMENT_GI
50
51
52
53
def triggerGI(self):
return iec61850.IedConnection_triggerGIReport(self.con, self.
getObjectReference())
54
55
Code-Block 2.11: Auszug aus der Python-Klasse RCBHelper zur Konfiguration von
Report Control Blocks.
32
In Code-Block 2.12 sind weitere Methoden der Klasse RCBHelper angegeben. Der Methode setSubscriberCallback wird als Argument die Callback-Funktion (oder Klasse) übergeben, die zunächst als Objektvariable self.callback gespeichert wird und so
später beim Auslösen der Trigger-Funktion verfügbar ist. In Zeile 5 wird eine Instanz
der C++-Klasse RCBSubscriber erstellt, die zum abonnieren der Meldungen dient.
Ihr wird die Verbindungsvariable, die Referenz zum RCB und dessen ID übergeben.
Die Referenz (z.B. SIPApplication/LLN0.RP.RPTestbench01) und die ID (z.B.
SIP/Application/LLN0$RP$RPTestbench) besitzen eine in der Norm festgelegte
Formatierung und werden in diesem Fall aus der Konfiguration abgefragt.
1
2
# Python - Code
# Member of class
RCBHelper ( object ):
def setSubscriberCallback(self, function):
self.callback = function
4
5
self.subs = iec61850.RCBSubscriber()
6
self.subs.setIedConnection(self.con)
7
self.subs.setRcbReference(self.getObjectReference())
8
self.subs.setRcbRptId(self.getRptID())
9
self.subsHandler = RCBHandlerHelper()
10
self.subsHandler.setCustomTrigger(self.trigger)
11
self.subs.setEventHandler(self.subsHandler)
12
self.subs.subscribe()
13
[self.dataSetDirectory, error] = iec61850.
IedConnection_getDataSetDirectory(self.con, self.
getDataSetReference().replace("$", "."), None)
3
14
def trigger(self, clientReport):
if self.callback is not None:
17
self.callback(self, ClientReport(clientReport, self.con, self.
dataSetDirectory))
18
else:
19
print("Received report, but callback function is not defined")
15
16
20
def __del__(self):
del self.subsHandler
23
self.subs.__disown__()
24
del self.subs
21
22
Code-Block 2.12: Methoden der Python-Klasse RCBHelper zum Setzen und
Ausführen von Callback-Funktionen nach dem Empfangen einer
Meldung.
Zum
Registrieren
der
Callback-Funktion
wird
eine
Instanz
der
Klasse
RCBHandlerHelper erstellt, die, wie in Code-Block 2.8 gezeigt, von der C++-Klasse
RCBHandler erbt und somit die Methode trigger besitzt. Als Trigger-Funktion
wird dem Objekt self.subsHandler jedoch nicht self.callback übergeben,
sondern eine zusätzlich definierte Methode trigger der Klasse RCBHelper
(Code-Block 2.12, Zeile 15). Damit obliegt die Verarbeitung der C-Variablen
33
RCBHandlerHelper._client_report nicht der Applikation, sondern wird in dieser
Hilfsklasse vorgenommen. In Zeile 17 wird ein Objekt vom Typ ClientReport erstellt,
das die empfangenen Daten aus der C-Variable in eine Python-Datenstruktur überführt.
Beim Löschen einer Instanz der Klasse RCBHelper muss unbedingt auch die Instanz
der C++-Klasse iec61850.RCBSubscriber gelöscht werden. Aufgrund der Verwendung
von directors in SWIG muss davor die Methode __disown__ ausgeführt werden [7].
Baumstruktur für empfangene Daten
Eine Meldung enthält keine Attribut-Namen der übertragenen Daten. Daher können aus
einer Meldung nicht direkt über Attribut-Referenzen die gewünschten Daten extrahiert
werden. Über das DataSet, das dem Report zugeordnet ist, ist die Struktur der inkludierten DOs jedoch bekannt. Um eine möglichst effiziente Verarbeitung zu gewährleisten,
werden beim Initialisieren des Prüfstands einmalig alle Attribute aus den DOs des DataSets als Baum abgebildet, der als Schablone für später empfangene Daten dient. In
Abbildung 2.5 ist ein Ausschnitt eines solchen Baumes dargestellt, bei dem beispielweise
das Attribut mit der Referenz SIPLn1/SE_RFLO1.FltDisPct.mag.f und dem Wert
17.51987 als Endpunkt im Baum die Fehlerdistanz in Prozent beinhaltet.
Für jeden Zugriff auf Knoten des Baumes wird ein Suchpfad in Form einer Python-Liste
übergeben. Untergeordnete Knoten sind in der Liste children als Objekte der Klasse
ReportData gespeichert. In der Variablen childrenNames wird dem Namen jedes Unterknoten der Index in dieser Liste zugewiesen. So ist ein Zugriff auf Knotenpunkte sowohl
direkt über den Index und auch indirekt über dessen Namen in Form einer Zeichenkette
möglich.
Der Quelltext der Klasse ReportData ist in Code-Block 2.13 angegeben. Mithilfe der
Methode addNode wird ein Knoten im Baum eingefügt. Der Suchpfad in der Variablen
path wird verkürzt und durch Rekursion im entsprechenden Unterbaum eingefügt, wenn
das Ende des Pfades erreicht ist (len(path) == 1 in Zeile 17).
Die Methode getIndex akzeptiert als Parameter entweder eine Zeichenkette, die in der
Variablen self.childrenNames als Schlüssel existieren muss, oder eine Ganzzahl, die
ein gültiger Index der Liste children sein muss. Sie gibt immer eine Ganzzahl zurück,
die für den Zugriff auf Unterknoten herangezogen wird.
Mit den Methoden insertValue und getValue wird in analoger Weise der Wert im
Unterbaum mit rekursiv verkürztem Pfad gespeichert bzw. abgefragt.
34
name = ’root’
index = -1
children = [ReportData, ...]
childrenNames = {
’SIPRec_FaultRecorder/DEF_RDRE1’: 0,
’SIPLn1_21RMDistance1/DISB_PTRC1’: 1,
’SIPLn1/SE_RFLO1’: 2}
data = None
fc = None
name = ’SIPLn1/SE_RFLO1’
index = 2
children = [ReportData, ...]
childrenNames = {
’FltLoop’: 0,
’FltZ’: 1,
’Inactive’: 2,
...
’FltReactSc’: 10,
’FltDis’: 11,
’FltDisPct’: 12,
’FLInvalid’: 13}
data = None
fc = None
name = ’FltDisPct’
index = 12
children = [ReportData, ...]
childrenNames = {
’instMag’: 0,
’mag’: 1,
’q’: 2,
’t’: 3}
data = None
fc = ’MX’
name = ’mag’
index = 1
children = [ReportData]
childrenNames = {’f’: 0}
data = None
fc = ’MX’
...
more
children
...
more
children
name =
’SIPRec_FaultRecorder/DEF_RDRE1’
index = 0
children = [ReportData, ...]
childrenNames = {’FltNum’: 0}
data = None
fc = None
name =
’SIPLn1_21RMDistance1/DISB_PTRC1’
index = 1
children = [ReportData, ...]
childrenNames = {
’NamPlt’: 0,
’Op’: 1,
’Str’: 2,
’SelLoopAG’: 3,
...}
data = None
fc = None
name = ’FltRis’
index = 7
children = [ReportData, ...]
childrenNames = {
’instMag’: 0,
’mag’: 1,
’q’: 2,
’t’: 3}
data = None
fc = ’MX’
...
more
children
...
more
children
...
more
children
name = ’f’
index = 0
children = []
childrenNames = {}
data = 17.51987
fc = ’MX’
Abbildung 2.5: Ausschnitt aus einem Baum, der aus einem DataSet erstellt und beim
Empfang von Meldungen mit Daten befüllt wird. Jeder abgebildete
Knoten entspricht einer Instanz der Klasse ReportData. Der Wurzelknoten wird mit dem Namen ’root’ bezeichnet und besitzt den für
Listen ungültigen Index -1.
35
1
# Python - Code
class ReportData(object):
3
name = None
4
index = -1
5
children = []
6
childrenNames = {}
7
data = None
8
fc = None
2
9
def __init__(self, name=None, index=-1, data=None, fc=None):
self.name = name
self.index = index
self.data = data
self.fc = fc
10
11
12
13
14
15
def addNode(self, path, fc):
if len(path) == 1:
size = len(self.children)
self.childrenNames[path[0]] = size
self.children.append(ReportData(path[0], size, None, fc))
elif len(path) > 1:
name = path[0]
path.pop(0)
if name not in self.childrenNames.keys():
size = len(self.children)
self.children.append(ReportData(name, size, None, fc))
self.childrenNames[name] = size
index = self.childrenNames[name]
self.children[index].addNode(path, fc)
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def getIndex(self, search):
if type(search) is str and search in self.childrenNames.keys():
return self.childrenNames[search]
elif type(search) is int and search < len(self.children):
return search
else:
print(type(search))
raise Exception("Index or name not found: {}".format(search))
return None
31
32
33
34
35
36
37
38
39
40
def insertValue(self, path, value):
if len(path) < 1:
if self.data is None:
self.data = value
return True
search = path.pop(0)
41
42
43
44
45
46
47
index = self.getIndex(search)
return self.children[index].insertValue(path, value)
48
49
36
50
51
52
53
54
55
56
57
def getValue(self, path, resetValue=False):
if len(path) < 1 and len(self.children) == 0:
v = self.data
if resetValue:
self.data = None
return v
search = path.pop(0)
58
59
60
index = self.getIndex(search)
return self.children[index].getValue(path, resetValue)
61
62
63
64
def getSubTree(self, search):
index = self.getIndex(search)
return self.children[index]
Code-Block 2.13: Auszug aus der Python-Klasse ReportData, die
Datenstruktur für die Daten aus Meldungen bereitstellt.
eine
Für die Initialisierung des Baumes wird eine Liste der DO eines DataSets geladen
(Code-Block 2.12 Zeile 13) und liegt als C-Variable des Typs LinkedList in der Variable
self.dataSetDirectory vor. In Code-Block 2.14 wird mit der Funktion
iec61850.LinkedList_getNext in der while-Schleife jedes DO verarbeitet. Die Variable entryName beinhaltet eine Zeichenkette mit der Referenz zum DO und der FC
(z.B. ’SIPLn1/SE_RFLO1.FltDisPct[MX]’). Mithilfe von Regular Expressions werden die Komponenten der Referenz bestimmt, um den Pfad im Baum zu ermitteln.
Die untergeordneten Attribute eines DO werden mithilfe der Funktion
iec61850.IedConnection_getVariableSpecification
ermittelt
und
als
MmsVariableSpecification zurückgegeben. Die Struktur dieser MMS-Variablen wird
rekursiv mit der Methode fillMmsSpec aufgelöst. Die Unterattribute werden über den
Index i aus der MMS-Variablen abgefragt und exakt so in den Baum eingefügt. So wird
gewährleistet, dass beim Empfang von Meldungen über den Index i die Daten der richtigen Knoten geändert werden.
1
# Python - Code
2
# Member of class
RCBHelper ( object ):
def fillReportTree(self, tree):
4
entry = iec61850.LinkedList_getNext(self.dataSetDirectory)
5
while entry:
6
entryName = iec61850.LinkedList_getString(entry)
7
m = re.match(r’(?P<node>[A-Za-z0-9_/.]+)(\[(?P<constraint>[A-Z
]{2})\])?’, entryName)
8
rx = m.groupdict()
9
insList = rx[’node’].split(".")
3
10
11
12
13
# type : MmsVariableSpecification
[obspec, error] = iec61850.IedConnection_getVariableSpecification
(self.con, rx[’node’], Iec61850Helper.dictFC[rx[’constraint’]])
tree = self.fillMmsSpec(obspec, insList, tree, rx[’constraint’])
entry = iec61850.LinkedList_getNext(entry)
37
return tree
14
15
def fillMmsSpec(self, mms, path, tree, fc):
obj = iec61850.MmsVariableSpecification_getStructureElements(mms)
18
if obj is None:
19
tree.addNode(path, fc)
20
return tree
16
17
21
item = iec61850.LinkedList_getNext(obj)
22
23
i = 0
24
# type : MmsVariableSpecification
25
inner = iec61850.
MmsVariableSpecification_getChildSpecificationByIndex(mms, i)
while inner:
i += 1
deepPath = path.copy()
deepPath.append(iec61850.LinkedList_getString(item))
tree = self.fillMmsSpec(inner, deepPath, tree, fc)
inner = iec61850.
MmsVariableSpecification_getChildSpecificationByIndex(mms, i)
item = iec61850.LinkedList_getNext(item)
26
27
28
29
30
31
32
33
34
return tree
35
Code-Block 2.14: Methoden der Python-Klasse RCBHelper zum Erstellen der
Datenstruktur für später empfangene Daten aus Meldungen.
Einfügen der Daten in den Baum
Wie in Code-Block 2.12 in Zeile 17 gezeigt, wird beim Auslösen des Triggers eine Instanz
der Klasse ClientReport erstellt, deren primäre Aufgabe es ist, die erhaltenen Daten
in den Baum einzufügen. Die Methode getDataSetValues (Code-Block 2.15, Zeile 17)
erhält als Argument den vordefinierten Baum als Schablone. Die Daten werden mit der
Funktion iec61850.ClientReport_getDataSetValues wieder als LinkedList geladen und in einer for-Schleife durchlaufen. Auf die gleiche Weise wie beim Erstellen des
Baumes wird der Pfad wieder mittels Regular Expressions aus der Referenz zum DO
ermittelt und mit der Methode fillReportData in den Baum eingefügt (Code-Block
2.15, Zeile 28).
Handelt es sich beim übergebenen MMS-Wert um eine structure, wird über den Index
i der Pfad erweitert (Zeile 40). Damit wird die Datenstruktur rekursiv durchlaufen bis
es sich beim MMS-Wert nicht mehr um eine structure handelt. Dann wird der Wert in
eine Python-Variable konvertiert und in den Baum eingetragen (Zeile 44).
1
# Python - Code
class ClientReport(object):
3
con = None
4
crp = None
2
38
5
6
dataSetDirectory = None
dataSetName = None
7
8
9
10
11
12
def __init__(self, crp, con, dataSetDirectory):
self.con = con
self.crp = crp
self.dataSetDirectory = dataSetDirectory
self.dataSetName = self.getDataSetName()
13
14
15
def getDataSetName(self):
return iec61850.ClientReport_getDataSetName(self.crp)
16
17
18
19
20
21
22
23
24
25
26
27
28
def getDataSetValues(self, tree):
if self.dataSetDirectory:
values = iec61850.ClientReport_getDataSetValues(self.crp)
if values:
for i in range(0, iec61850.LinkedList_size(self.
dataSetDirectory)):
value = iec61850.MmsValue_getElement(values, i)
if value:
entry = iec61850.LinkedList_get(self.dataSetDirectory, i)
entryName = iec61850.LinkedList_getString(entry)
m = re.match(r’(?P<node>[A-Za-z0-9_/]+)\.(?P<object
>[^\[]*)’, entryName)
rx = m.groupdict()
tree = ClientReport.fillReportData(tree, [rx["node"], rx["
object"]], value)
29
30
return tree
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@staticmethod
def fillReportData(tree, path, struct):
if iec61850.MmsValue_getTypeString(struct) == "structure":
size = iec61850.MmsValue_getArraySize(struct)
if size > 0:
for i in range(0, size):
structValue = iec61850.MmsValue_getElement(struct, i)
subPath = path.copy()
subPath.append(i)
tree = ClientReport.fillReportData(tree, subPath,
structValue)
else:
tree.insertValue(path, Iec61850Helper.convert(struct))
return tree
Code-Block 2.15: Auszug aus der Klasse ClientReport zur Verarbeitung von
erhaltenen Meldungen.
39
Konfiguration des RCB auf Anwendungsebene
Durch den Einsatz der vorgestellten Klassen wird die Zahl der notwendigen Methoden auf
Anwendungsebene stark reduziert. Nach dem Verbindungsaufbau werden von der Klasse
Iec61850Helper die Methoden getSubscriberURCB und setURCBData zum Erstellen
eines RCB und Senden der Einstellungen an den IEC 61850-Server benötigt (Code-Block
2.16).
1
2
3
# Python - Code
# Member of class
Iec61850Helper ( object ):
def getSubscribeURCB(self, deviceName, logicalNodeName, reportName,
myHandler=None):
# Unbuffered
4
Report
Control
B l o c k ( RP )
[rcb, error] = iec61850.IedConnection_getRCBValues(self.con,
deviceName+"/"+logicalNodeName+".RP."+reportName, None)
self._checkError(error)
myRCB = RCBHelper(rcb, self.con)
myRCB.setSubscriberCallback(myHandler)
5
6
7
8
9
return myRCB
10
11
12
# Member of class
Iec61850Helper ( object ):
def setURCBData(self, myRCB):
14
error = iec61850.IedConnection_setRCBValues(self.con, myRCB.rcb,
myRCB.mask, True)
15
self._checkError(error)
16
myRCB.mask = 0
13
Code-Block 2.16: Methoden der Klasse Iec61850Helper zur Konfiguration von
Report Control Blocks.
2.5 Integration der IEC 61850-Funktionalitäten in den
Prüfstand
Alle vorgestellten Klassen sind in der Datei iec61850helper.py definiert und die
Klassen Iec61850Helper und ReportData werden aus dem gleichnamigen Paket in
Code-Block 2.17 in Zeile 2 importiert. Für das Duplizieren des unbefüllten Baumes wird
die Funktion deepcopy aus dem Python-Paket copy verwendet.
Um möglichst flexibel zwischen den bisher implementierten Funktionen zum Auslesen
der Fehlerdaten und den neuen IEC 61850-Funktionen wechseln zu könnnen, wird mit der
booleschen Variablen useIec61850Reporting an den entsprechenden Stellen im Code
unterschieden.
Wie in Code-Block 2.1 beim Konfigurieren des IEC 61850-Servers festgelegt, wird auch
im Prüfstand in Code-Block 2.17 in Zeile 6 die IP-Adresse auf 10.0.0.60 gesetzt. Die
Variable iec ist ein Objekt der Klasse Iec61850Helper. In Zeile 20 wird die Instanz
erstellt und in Zeile 22 die Verbindung zum Server aufgebaut.
40
Report
Event
Event
Report
Event
Event
Event
Der Baum für die Meldungsdaten wird zunächst nur als Wurzelknoten in Zeile 9 definiert und erst nach dem Initialisieren des RCB in Zeile 35 vollständig erstellt. Der RCB
wird mit der in Code-Block 2.16 gezeigten Methode getSubscribeURCB initialisiert. Als
Argumente werden LD, LN, Name des Reports (wie in Code-Block 2.3 definiert) und eine
Callback-Funktion bzw. -Klasse angegeben. Die Trigger-Optionen (Zeile 27) werden so
gesetzt, dass mit Ausnahme von integrity-Meldungen in jedem Fall eine Meldung übertragen wird (siehe 2.4.3). In Zeile 28 werden Meldungen allgemein aktiviert. Der Aufruf
setGI(False) ist nicht zu verwechseln mit dem Setzen der Trigger-Option general interrogation. Die Zeile besagt lediglich, dass an dieser Stelle keine Meldung geschickt werden
soll. Die Option selbst bleibt aktiv. Mit der Einstellung setResv(True) wäre es möglich,
den RCB für diesen Client zu reservieren. Im Labor gibt es jedoch keine weiteren Clients
und der Wert wird auf False gesetzt.
Die Buffer-Zeit, die in Zeile 31 festgelegt wird, beschreibt, wann nach dem Auftreten
eines Events eine Meldung an den Client übertragen wird3 . Abbildung 2.6 zeigt den Zusammenhang auf einer Zeitachse. Sollte sich innerhalb der Buffer-Zeit ein Statuswert ein
weiteres Mal ändern und einen weiteren Event auslösen, wird sofort ein Report verschickt
und der Timer beginnt neu zu zählen.
time
BufTm
BufTm
Abbildung 2.6: Reports werden nach Ablauf des Timers BufTm, der ab dem Auftreten eines Events läuft, verschickt und beinhalten alle dazwischen
aufgetretenen Änderungen durch andere Events.
Nachdem die Einstellungen für den RCB gesetzt sind, werden die Änderungen mit der
Methode setURCBData in Zeile 33 auf den Server übertragen.
1
# Python - Code
from iec61850helper import Iec61850Helper, ReportData
3 from copy import deepcopy
2
4
useIec61850Reporting = True
iecServerIP = "10.0.0.60"
7 iec = None
5
6
8
9
10
reportBufTm = 100
iecthread = None
11
3
Der Begriff Buffer in diesem Kontext ist nicht mit der Bezeichnung Unbuffered RCB zu verwechseln.
Diese Eigenschaft bezieht sich nämlich auf die Übertragung der Ethernet-Pakete und das Verhalten
bei Übertragungsfehlern.
41
12
tree = ReportData(’root’)
13
def initIec61850Reporting():
global iec
16
global myRCB
17
global tree
14
15
18
if iec is None:
iec = Iec61850Helper(iecServerIP)
if not iec.isConnected():
iec.connect()
19
20
21
22
23
myRCB = iec.getSubscribeURCB("SIPApplication", "LLN0", "
RPTestbench01", iec61850ReportHandler)
print("Configured IEC 61850 DataSet: {}".format(myRCB.
getDataSetReference()))
24
25
26
myRCB.setTrgOps(data_change=True, data_update=True, quality_change=
True, general_interrogation=True, integrity=False)
myRCB.setRptEna(True)
myRCB.setGI(False)
myRCB.setResv(False)
myRCB.setBufTm(reportBufTm)
27
28
29
30
31
32
iec.setURCBData(myRCB)
33
34
tree = myRCB.fillReportTree(tree)
35
Code-Block 2.17: Integration
der
implementierten
IEC 61850Funktionalitäten in den bestehenden Prüfstand. Neben dem Import
der benötigten Klassen werden globale Variablen und die Funktion
initIec61850Reporting definiert.
Callback-Funktion in eigenem Thread
In Code-Block 2.17 wird in Zeile 24 als Callback die Variable iec61850ReportHandler
übergeben. Dabei handelt es sich nicht um eine Funktion, sondern um eine Klasse wie
in Code-Block 2.18 angegeben. Beim Instanzieren wird die Methode __init__ ausgeführt und startet die Methode run in einem neuen Thread. Die Variable filledTree ist
global definiert und somit auch im Hauptprogramm abrufbar, nachdem die Meldungen
empfangen wurden und die Daten im Baum verfügbar sind.
Beim Start eines neuen Threads muss beachtet werden, dass auf die globale Variable
filledTree immer nur ein Thread zugreift. Ansonsten kommt es zum unerwünschten
Überschreiben von Daten. Diese Problematik wird gelöst, indem immer nur ein Thread
aktiv sein darf. Dazu wird in der Methode __init__ in Zeile 4 überprüft, ob ein Thread
aktiv ist und gegebenenfalls mit der Methode join auf das Beenden gewartet. Erst dann
wird ein neuer Thread gestartet.
42
class iec61850ReportHandler(object):
def __init__(self, myRCB, clientReport):
3
global iecthread
4
while iecthread is not None and iecthread.is_alive():
5
iecthread.join()
6
iecthread = threading.Thread(target=self.run, args=(myRCB,
clientReport))
7
iecthread.daemon = False
8
iecthread.start()
1
2
9
10
11
12
def run(self, myRCB, clientReport):
global filledTree
global lastFltNum
13
14
newTest = filledTree.getValue(["SIPRec_FaultRecorder/DEF_RDRE1",
"FltNum", "stVal"]) is None
15
16
17
18
19
20
filledTree = clientReport.getDataSetValues(filledTree)
if newTest and lastFltNum is not None and lastFltNum >=
filledTree.getValue(["SIPRec_FaultRecorder/DEF_RDRE1", "FltNum", "
stVal"]):
filledTree = deepcopy(tree)
else:
lastFltNum = filledTree.getValue(["SIPRec_FaultRecorder/
DEF_RDRE1", "FltNum", "stVal"])
21
22
del clientReport
Code-Block 2.18: Definition des Callbacks als Klasse, die die Methode zur
Verarbeitung der empfangenen Daten in einem neuen Thread
ausführt.
Mit der Variablen lastFltNum wird überprüft, ob sich seit der letzten Meldung die
Fehlernummer geändert hat. In Zeile 14 wird überprüft, ob die aktuell verarbeitete Meldung die erste dieses Tests ist. Sollte in Zeile 17 die Abfrage ergeben, dass es sich um
einen neuen Test handelt, während die Fehlernummer jedoch noch jene des vorherigen
Tests beinhaltet, so kann sich diese Meldung nicht auf den noch nicht aufgetretenen Fehler beziehen und wird verworfen. Diese Problematik wird in den Ergebnissen in Abschnitt
3.1 näher behandelt.
Abfragen der Werte nach der Testdurchführung
Für jede Testserie wird die Funktion run_tests_CMC ausgeführt (Code-Block 2.19), die
als Aufgaben die Ansteuerung des Schutzprüfgerät (CMC) und die Auswertung der Fehlerdaten besitzt. Die Daten zu den Zeitverläufen wie in Abbildung 2.1 werden bereits vor
dem Aufruf dieser Funktion in den internen Speicher des CMC geladen. Die Anzahl der
Testwiederholungen wird mit rpt angegeben. Vor der Testdurchführung wird in Zeile 11
43
sichergestellt, dass beim Eintreffen von Meldungen ein unbefüllter Baum vorhanden ist,
der als Kopie des Ursprungsbaumes tree erstellt wird. Nach dem Test liegen die Daten
durch die Ausführung des Callbacks in der Variablen filledTree vor und die Funktion get_report_IEC gibt die relevanten Daten als dict zurück (gekürzter Quelltext ab
Zeile 21). Für jeden Test wird ein Eintrag in der Liste iecCollectedReports erstellt
und am Ende der Funktion run_test_CMC gesammelt zurückgegeben.
1
def run_tests_CMC(engineApp, devId, rpt, cmc_bin, print_details=False
):
# ...
2
3
4
global filledTree
iecCollectedReports = []
5
fpu = 0
# number of forw ar d p i ck u p s
bpu = 0
# number of b a c k w a r d p ic k u p s
trip = 0
# number of trips
for att in range(rpt): # t e s t a t t e m p t
if useIec6180Reporting:
filledTree = deepcopy(tree)
6
7
8
9
10
11
12
# configure CMC and run test
# ...
13
14
15
16
17
if useIec6180Reporting:
iecCollectedReports.append(get_report_IEC())
18
return fpu, bpu, trip, iecCollectedReports
19
20
21 def get_report_IEC() -> dict:
global filledTree
22
23
24
PTRC_Str = filledTree.getValue(["SIPLn1/PTRC1", "Str"])
25
PTRC_Op = filledTree.getValue(["SIPLn1/PTRC1", "Op"])
26
27
return {
28
’FltNum’: filledTree.getValue(["SIPRec_FaultRecorder/DEF_RDRE1",
"FltNum", "stVal"]),
29
’Pickup_General’: PTRC_Str[0],
30
’Pickup_L1’: PTRC_Str[2],
31
’Pickup_L2’: PTRC_Str[4],
32
’Pickup_L3’: PTRC_Str[6],
33
’Pickup_N’: PTRC_Str[8],
34
’Pickup_Dir_General’: Iec61850Helper.enum["dir"][PTRC_Str[1]],
35
’Pickup_Dir_L1’: Iec61850Helper.enum["dir"][PTRC_Str[3]],
36
’Pickup_Dir_L2’: Iec61850Helper.enum["dir"][PTRC_Str[5]],
37
’Pickup_Dir_L3’: Iec61850Helper.enum["dir"][PTRC_Str[7]],
38
’Pickup_Dir_N’: Iec61850Helper.enum["dir"][PTRC_Str[9]],
39
’Trip_General’: PTRC_Op[0],
40
’Trip_L1’: PTRC_Op[1],
44
41
42
43
44
’Trip_L2’: PTRC_Op[2],
’Trip_L3’: PTRC_Op[3],
}
# ...
Code-Block 2.19: Auszug
aus
den
Methoden
run_tests_CMC
und
get_report_IEC. Vor jedem Test wird ein leerer Baum
initialisiert und nach dem Test werden extrahierte Daten der
Liste iecCollectedReports angehängt. Neu eingefügte Zeilen
besitzen eine hervorgehobene Nummerierung. Der Code für die
Ansteuerung des CMC ist nicht angegeben (Zeile 14).
45
3 Ergebnisse
Nachdem durch die Methodik implizit gezeigt wurde, dass eine Umsetzung der Kommunikation nach IEC 61850 im Labor realisierbar ist, soll in diesem Teil zuerst auf Probleme
und deren Lösung bei der Integration eingegangen werden. Weiters soll die Frage beantwortet werden, ob bei gleicher Datenqualität eine Verbesserung der Laufzeit erzielt
werden kann.
3.1 Erkenntnisse durch die Integration der
IEC 61850-Funktionalitäten in Python und in den
Prüfstand
Meldung 5
Fehler 2
Meldung 4
Sequenz 2
Zeit
Ende
Start
Ende
Start
Start
Sequenz 1
Meldung 3
Meldung 2
Fehler 1
Meldung 1
Das Abfragen von Werten von einem IEC 61850-Server und das Setzen von Konfigurationen am Server ist aufgrund der Tatsache, dass der Client die Anfragen tätigt und auf
eine Antwort wartet einfach umsetzbar. Die gewählte C-Bibliothek ermöglicht dafür eine
ausgezeichnete Integration in Python. Wird die Übertragung jedoch vom Server initiiert,
treten die in Abschnitt 2.3.2 behandelten Probleme mit Callback-Funktionen auf. Die
meisten jener Schwierigkeiten konnten durch die im Methodik-Teil beschriebene Koordinierung von Threads auf Anwendungsebene beseitigt werden. Dabei hat sich auch gezeigt,
dass die sequenzielle Abarbeitung dieser Threads keine längeren Laufzeiten verursacht.
Die Beobachtung der zeitlichen Verteilung erhaltener Meldungen gibt Aufschluss über
die Reaktion des Schutzgerätes auf unterschiedliche Fehler. Abbildung 3.1 zeigt schematisch die zeitliche Abfolge der relevanten Ereignisse. In etwa 1 s nach Start der ersten
Sequenz tritt Fehler 1 auf. Der Fehler wird vom Schutzgerät erkannt und nach kürzestmöglicher Zeit wird Meldung 1 übermittelt. Einige Routinen im Schutzgerät wer-
Abbildung 3.1: Schematische Darstellung der zeitlichen Abfolge von Fehlern und Meldungen innerhalb einer Testreihe bestehend aus Sequenzen.
47
den mit niedriger Priorität ausgeführt und es ist unbestimmt, zu welchem Zeitpunkt
die berechneten Daten übermittelt werden. Ein Beispiel dafür ist der Fehlerorter, der
keine Schutzfunktion übernimmt. Im schlechtesten Fall wird diese vom Fehlerorter verursachte Meldung so wie die in Abbildung 3.1 gezeigte Meldung 2 erst nach Ende der
Sequenz übermittelt. Meldung 2 kann auch geschickt werden, weil sich beim Abschalten
der Spannungen und Ströme am Ende der Sequenz bestimmte Statuswerte ändern. Diese
Art von Meldungen stellt kein Problem dar, da neue Werte nur dann in den Datenbaum
übernommen werden, wenn die Knoten der entsprechenden Attribute noch keine Daten
beinhalten. Nach dem Fehlerfall ist jedoch der gesamte Baum mit Daten befüllt und
die Meldungen nach Rücksetzung bestimmter Attribute nach Abschaltung ersetzen die
bereits vorhandenen Daten nicht.
Genau wie beim Abschaltvorgang kann auch beim Einschaltvorgang eine Statusänderung zu einer Meldung führen. Meldungen dieser Art können verworfen werden. Die
Erkennung basiert auf dem Vergleich von Fehlernummern und ist wie in Code-Block 2.18
(Zeile 17-20) implementiert. Eine Meldung, die nach dem Start einer Sequenz keine inkrementierte Fehlernummer besitzt, wird ignoriert. Im überwiegenden Teil der beobachteten
Fälle werden zwei oder drei Meldungen zwischen Fehlerzeitpunkt und Ende der Sequenz
empfangen, wie in Abbildung 3.1 nach Fehler 2.
3.2 Verbesserung der Laufzeit
Zur Messung der Laufzeiten wird auf bereits in den Prüfstand integrierte Funktionen
zurückgegriffen. Wie in Code-Block 3.1 gezeigt wird beim Start der Simulation eine Zeitmessung gestartet. Nach Abschluss jedes Arbeitsschritts wird die Zeit relativ zum Start
und die benötigte Zeit für diesen Arbeitsschritt in der Log-Datei ausgegeben. Der zeitlich problematische Schritt ohne Integration von IEC 61850 ist das Laden der Meldungen
(Zeile 27) vom Schutzgerät. Im Gegensatz dazu läuft das Empfangen von IEC 61850Reports während 1 dem Ausführen der Tests ab und ist in Zeile 26 bereits abgeschlossen.
Das Laden der Ergebnisse erübrigt sich damit und die in Zeile 27 angegebene Laufzeit
wird nicht benötigt.
Für jede Testsimulation wird in der Log-Datei eine Auflistung wie in Code-Block
3.1 ausgegeben. Um zwei Testreihen ohne und mit IEC 61850-Integration zu vergleichen, werden die Gesamtzeiten, die pro Test benötigt werden, mit dem Bash-Befehl
sed -nr ’s/.*results saved: *([0-9.]+)s.*/\1/p’ times.log > times.dat
aus der Log-Datei extrahiert.
[
[
[
[
[
[
1
2
3
4
5
6
1
sim start:
db connected:
sims loaded:
signals found:
CMC reset:
traces loaded:
0.00000s]
0.03125s (+
0.39063s (+
0.39063s (+
0.92189s (+
1.70316s (+
0.03125s)]
0.35938s)]
0.00000s)]
0.53126s)]
0.78127s)]
Auch wenn die Meldungen in eigenen Threads abgearbeitet werden, ist hier nicht Gleichzeitigkeit bzw.
parallele Ausführung gemeint.
48
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
[
sig1 scaled:
[
sig1 uploaded:
[ sig1 CMC configured:
[
sig2 scaled:
[
sig2 uploaded:
[ sig2 CMC configured:
[
sig3 scaled:
[
sig3 uploaded:
[ sig3 CMC configured:
sig4 scaled:
[
[
sig4 uploaded:
[ sig4 CMC configured:
[
sig5 scaled:
sig5 uploaded:
[
[ sig5 CMC configured:
[
sig6 scaled:
[
sig6 uploaded:
[ sig6 CMC configured:
[
seq defined:
[
test done:
[ downloaded new rec:
[
results saved:
[
records saved:
1.73441s (+
2.42193s (+
2.42193s (+
2.45317s (+
3.12507s (+
3.12507s (+
3.15631s (+
3.83370s (+
3.84071s (+
3.87121s (+
4.54331s (+
4.55031s (+
4.57981s (+
5.25241s (+
5.25892s (+
5.28942s (+
5.97202s (+
5.97902s (+
6.03753s (+
23.41474s (+
68.15009s (+
68.21259s (+
68.46260s (+
0.03125s)]
0.68752s)]
0.00000s)]
0.03125s)]
0.67189s)]
0.00000s)]
0.03125s)]
0.67739s)]
0.00701s)]
0.03050s)]
0.67210s)]
0.00700s)]
0.02950s)]
0.67260s)]
0.00651s)]
0.03050s)]
0.68260s)]
0.00700s)]
0.05851s)]
17.37721s)]
44.73536s)]
0.06250s)]
0.25001s)]
Code-Block 3.1: Beispielausgabe des Prüfstandes zur Zeitmessung einer Testreihe mit
10 Fehlerfällen und Aufschlüsselung der einzelnen Arbeitsschritte.
In der mittleren Spalte sind die absolut gemessenen Zeiten ab dem
Start angegeben. Die rechte Spalte gibt die benötigte Zeit für den
entsprechenden Arbeitsschritt an.
Abbildung 3.2 zeigt die Streudiagramme der extrahierten Datenpunkte für den Fall ohne IEC 61850-Integration (blaue Punkte) und mit IEC 61850-Integration (gelbe Kreuze).
Beide Verläufe bilden einen näherungsweise linearen Zusammenhang zwischen der TestNummer und der Laufzeit für den jeweiligen Test ab. Für weitere analytische Abschätzungen bietet sich eine einfache lineare Regression an. Dafür wird das Python-Modul
sklearn.linear_model eingesetzt und mithilfe der Klasse LinearRegression
werden mit der Methode der Minimierung der Fehlerquadrate die Koeffizienten bestimmt [8]. Das Ergebnis ist in Abbildung 3.2 veranschaulicht und kann wie folgt angegeben werden:
tohne (n) = (1, 4361 · n + 106.3578) s
(3.1)
tmit (n) = ((0, 0038 · n) + 23.1681) s.
(3.2)
Der Verlauf mit IEC 61850-Integration (Gleichung 3.2) besitzt eine vernachlässigbare
Steigung durch numerische Effekte bei der Regression und kann somit als konstant angenommen werden. Die Laufzeit beträgt in der analytischen Näherung pro durchgeführtem
Test 23,1681 s.
49
700
Zeitmessungen ohne IEC 61850
Regressionsgerade ohne IEC 61850
Zeitmessungen mit IEC 61850
Regressionsgerade mit IEC 61850
600
Zeit in Sekunden pro Test
500
400
300
200
100
0
0
50
100
150
200
Test-Nummer
250
300
Abbildung 3.2: Streudiagramme der gemessenen Laufzeiten pro Test und deren Regressionsgeraden. Die Datenpunkte sind aus den von testbench.py erstellten Log-Dateien extrahiert. Für die Messreihe ohne IEC 61850 wurden
300 Tests durchgeführt. Die Messreihe mit IEC 61850 wurde nach 100
Tests gestoppt, da keine Zusatzinformation zu erwarten war.
50
Um die Gesamtlaufzeit abzuschätzen, werden die einzelnen Laufzeiten aufsummiert
und in Abbildung 3.3 graphisch dargestellt:
n
Tohne (n) =
tohne (n) =
1
n
Tmit (n) =
1, 4361 2
· n + 106, 3578 · n
2
(3.3)
s
tmit (n) ≈ (23, 1681 · n) s
(3.4)
1
Gesamtdauer in Stunden
Diese Abschätzung wird durch Vergleich der Uhrzeiten bei Start und Ende der Simulationen überprüft. Der Testlauf ohne IEC 61850-Integration umfasst n = 302 Tests. Als
Startzeit ist in der Log-Datei 11:19 und als Endzeit 15:04 am Folgetag eingetragen. Die
Laufzeit beträgt 27 Stunden und 45 Minuten. Durch Einsetzen der Testzahl in Gleichung
3.3 ergibt sich eine Laufzeit von Tohne (302) = 27,11 h. Diese Näherung der Laufzeit ist
mit einem Fehler von 2,3 % plausibel und Gleichung 3.3 eignet sich für den Vergleich der
Laufzeiten.
Die Messreihe mit IEC 61850-Integration umfasst 102 Datenpunkte. Als Startzeit ist
in der Log-Datei 13:31 und als Endzeit 14:11 eingetragen. Die Laufzeit beträgt somit
40 Minuten. Einsetzen in Gleichung 3.4 liefert Tmit (102) ≈ 39,4 min. Damit ist auch
Gleichung 3.4 für den Laufzeitvergleich geeignet.
Kumulierte Laufzeit ohne IEC 61850
Kumulierte Laufzeit mit IEC 61850
25
20
15
10
5
0
0
50
100
150
200
Anzahl der Tests
250
300
Abbildung 3.3: Abgeschätzte Gesamtlaufzeit in Abhängigkeit der durchgeführten
Tests. Für den Zeitverlauf ohne IEC 61850-Integration ergibt sich eine
quadratische Steigerung.
Daraus lässt sich schlussfolgern, dass ab dem ersten Test ein Zeitvorteil mit IEC 61850Integration erzielt wird und mit steigender Testzahl die Gesamtlaufzeit linear steigt.
Der im Vergleich quadratische Verlauf der Laufzeit ohne IEC 61850-Integration ist als
51
Kern der Problematik identifiziert und kann mit den beschriebenen Methoden vermieden
werden.
3.3 Überprüfung und Vergleich der Fehler-Daten für beide
Übertragungsmethoden
Für den Vergleich der Daten wird die Rückgabe der Methode get_report_IEC in CodeBlock 2.19 und repräsentativ für die Methode ohne IEC 61850 eine aus dem Programm
DiGSi (siehe Abschnitt 2.1) exportierte CSV-Datei herangezogen.
Funktionseinheit
Attribut
Wert
Aufzeichnung:Störschreiber:
Steuerung
Fehler-Nummer
611
Leitung 1:RM Distanzschutz 1:Z 1
Auslösemeldung
L1 L2 L3
Leitung 1:RM Distanzschutz 1:
Sammelmeldung
Anregung
Leitung 1:RM Distanzschutz 1:
Sammelmeldung
Ausgew. Schleife L23
Leitung 1:RM Distanzschutz 1:Z 1
Auslösemeldung
gehend
Leitung 1:RM Distanzschutz 1:
Sammelmeldung
Anregung
gehend
Leitung 1:RM Distanzschutz 1:
Sammelmeldung
Ausgew. Schleife L23
gehend
Leitung 1:Fehlerorter
Fehlerresistanz prim.
0,029 Ω
Leitung 1:Fehlerorter
Fehlerreaktanz prim.
−0,051 Ω
Leitung 1:Fehlerorter
Fehlerresistanz sek.
0,026 Ω
Leitung 1:Fehlerorter
Fehlerreaktanz sek.
−0,046 Ω
Leitung 1:Fehlerorter
Fehlerdistanz
-0,4 km
Leitung 1:Fehlerorter
Fehlerdistanz in %
−0,8 %
Leitung 1:Fehlerorter
Fehlerschleife
L2 L3 Richt. unbek.
kommend Richt. unbek.
L23
Tabelle 3.1: Zusammenfassung der Ergebnisse eines Fehlerfalls ohne IEC 61850Integration nach CSV-Export aus DiGSi.
52
Attribut
Wert
Attribut
Wert
FltNum
611
Trip_General
True
Pickup_General
True
Trip_L1
True
Pickup_L1
False
Trip_L2
True
Pickup_L2
True
Trip_L3
True
Pickup_L3
True
FltRis
0,028 547 6 Ω
Pickup_N
False
FltReact
−0,050 717 Ω
Pickup_Dir_General
unknown
FltRisSc
0,025 952 4 Ω
Pickup_Dir_L1
unknown
FltReactSc
−0,046 106 7 Ω
Pickup_Dir_L2
unknown
FltDis
−0,422 609 6 km
Pickup_Dir_L3
unknown
FltDisPct
−0,845 219 2 %
Pickup_Dir_N
unknown
FltLoop
Phase B to C
Tabelle 3.2: Rückgabe der Methode get_report_IEC mit den ermittelten Werten
für einen Fehlerfall. Physikalische Dimensionen wurden nach dem Export
hinzugefügt.
In den Tabellen 3.1 und 3.2 sind die ermittelten Daten zum gleichen Fehlerfall (gleiche
Fehler-Nummer) für je eine der beiden Methoden angegeben. Für alle drei Stränge wird
eine Auslösung (Trip) bewirkt und ein Vergleich zeigt, dass beide Methoden zum selben
Resultat kommen. Eine Anregung wird an den Strängen L2 und L3 festgestellt und ist
im IEC 61850-Standard in eigene Attribute aufgeschlüsselt (Pickup). Gleiches gilt für
die Richtung (Pickup_Dir), die in diesem Fehlerfall unbekannt ist. Die vom Fehlerorter
berechneten Werte für Resistanz, Reaktanz und Distanz stimmen überein. Die Fehlerschleife wird in IEC 61850 als Ganzzahl kodiert übertragen und ist in Tabelle 3.2 durch
die Zeichenkette “Phase B to C” ersetzt.
Beim Vergleich von einigen hundert Fehlerfällen konnte beobachtet werden, dass bei
weniger als 5 % der Fälle bei der Fehlerschleife des Fehlerorters (FltLoop) der Wert Off
gesendet wird. Unter allen anderen Attributen konnten keine Unterschiede festgestellt
werden.
53
4 Diskussion und Ausblick
Zusammenfassend lässt sich sagen, dass eine Integration des Kommunikationsstandards
IEC 61850 in den bestehenden Prüfstand technisch möglich und aus unterschiedlichen
Gründen sinnvoll ist. Das primäre Ziel, nicht optimierte und daher ungeeignete Datenübertragungsmethoden der Hersteller-Software zu ersetzen und damit eine Laufzeitverbesserung zu bewirken, kann mit den beschriebenen Methoden erreicht werden. Der Zeitvorteil ist ab dem ersten durchgeführten Test gegeben und wird durch die Verbesserungen
von einer von der Testzahl abhängigen quadratischen Laufzeiterhöhung in eine lineare
übergeführt. Für Versuchsplanungen kann auf Basis dieser Erkenntnisse die Laufzeit für
eine bestimmte Testzahl mit hoher Genauigkeit berechnet werden.
Durch die Integration von IEC 61850-Reports sind die Daten de facto am Ende einer
Testsequenz und somit innerhalb einer Testreihe mit beispielsweise 10 Einzeltests verfügbar. Es ist daher möglich, bereits während einer Testreihe Entscheidungen aufgrund
der Ergebnisse zu treffen und beispielsweise die Testzahl dynamisch anzupassen, bis statistisch signifikante Ergebnisse vorliegen. Für zukünftige Forschungsfragen ergeben sich
damit neue Ansätze.
Die zeitliche Verteilung der empfangenen Meldungen und damit die Zuordnung zu dem
richtigen Fehlerfall in einer Reihe von Tests ist eine zentrale Herausforderung. Meldungen, die aufgrund von Ein- und Abschaltvorgängen auftreten, sowie Meldungen die durch
langsame Routinen am Schutzgerät ausgelöst werden, müssen identifiziert werden, damit
keine falsche Zuordnung oder Datenverlust durch Verwechslung auftritt. Wenn beispielsweise der Fehlerorter erst nach Ende einer Sequenz die berechneten Daten zur Verfügung
stellt, könnte als Lösung vor dem Beginn der nachfolgenden Sequenz eine Totzeit eingeführt werden. In vielen Fällen lässt sich so ein Kompromiss zwischen Datenqualität und
Laufzeit finden. Dieser Aspekt muss für zukünftige Tests berücksichtigt werden.
Die Implementierung mit Unterstützung der quelloffenen Bibliothek libiec61850 und
mithilfe von weiteren quelloffenen Paketen in Python bietet speziell für akademische Anwendungen Vorteile. Die Unabhängigkeit von proprietärer Software und das Wegfallen
von Lizenzkosten, sowie der einfache Einsatz auf unterschiedlichen Plattformen und Betriebssystemen bietet ein hohes Maß an Flexibilität. Die Einbettung in Python ist auch
aufgrund der immer stärkeren Verbreitung der Sprache im akademischen Bereich sinnvoll.
Das möglichst schnelle Finden von Ergebnissen wird durch die Einfachheit von Python
und die Verfügbarkeit von Paketen für eine Vielzahl von Anwendungen erleichtert.
Zu guter Letzt spricht die Etablierung des Standards und dessen Verbreitung in weiten Teilen der Welt für dessen Einsatz in der Forschung. Schutzgeräte unterschiedlicher
Hersteller unterstützen die Kommunikation über IEC 61850 seit vielen Jahren und diese
55
Modernisierung hat sich bewährt. Die Möglichkeit, dadurch im Labor auch Schutzgeräte
verschiedener Hersteller direkt vergleichen zu können, öffnet die Tür für neue Forschungsfragen.
56
Literaturverzeichnis
[1] H.-J. Herrmann, Digitale Schutztechnik : Grundlagen, Software, Ausführungsbeispiele.
Berlin [u.a.]: VDE-Verl., 1997.
[2] G. Götzelmann, “Sicherer Netzbetrieb durch digitale Schutzeinrichtungen,” Elektrotechnik und Informationstechnik, vol. 121, no. 10, pp. 380–382, 2004.
[3] H. Falk, IEC 61850 demystified. Boston London: Artech House, 2019. [Online].
Available: http://us.artechhouse.com/CloudPublish/book.aspx?isbn=9781630816612
[4] IEC, “Communication networks and systems in substations,” International Electrotechnical Commission, Geneva, Switzerland, ISO IEC 61850-7:2003, 2003.
[5] SIPROTEC 5 Beschreibung Hardware, Siemens AG, 8 2020.
[6] CMC 356, OMICRON electronics GmbH, 5 2020.
[7] “Swig and python - 31.5.3 ownership and object destruction,” accessed on 11.02.2021.
[Online]. Available: http://www.swig.org/Doc1.3/Python.html#Python_nn35
[8] “sklearn.linear_model.linearregression — scikit-learn 0.24.1 documentation,”
accessed on 18.03.2021. [Online]. Available: https://scikit-learn.org/stable/
modules/generated/sklearn.linear_model.LinearRegression.html#sklearn.linear_
model.LinearRegression
57
Abkürzungsverzeichnis
LAN Local Area Network
MAP Manufacturing Automation Protocol
TOP Technical Office Protocol
MMS Manufacturing Messaging Specification
GOOSE Generic Object Oriented Substation (or System) Event
GSSE Generic Substation Status Event
SV Sampled Values
IP Internet Protocol
TCP Transmission Control Protocol
IED Intelligent Electronic Device
LD Logical Device
LN Logical Node
DO Data Object
DA Data Attribute
FC Functional Constraint
SCL System Configuration Language
RCB Report Control Block
FCDA Functionally Constrained Data Attribute
59
Hiermit erkläre ich, dass die vorliegende Arbeit gemäß dem Code of Conduct – Regeln
zur Sicherung guter wissenschaftlicher Praxis (in der aktuellen Fassung des jeweiligen
Mitteilungsblattes der TU Wien), insbesondere ohne unzulässige Hilfe Dritter und ohne
Benutzung anderer als der angegebenen Hilfsmittel, angefertigt wurde. Die aus anderen
Quellen direkt oder indirekt übernommenen Daten und Konzepte sind unter Angabe der
Quelle gekennzeichnet. Die Arbeit wurde bisher weder im In– noch im Ausland in gleicher
oder in ähnlicher Form in anderen Prüfungsverfahren vorgelegt.
Wien, am 1. April 2021
Martin Kaintz, BSc
61
0
You can add this document to your study collection(s)
Sign in Available only to authorized usersYou can add this document to your saved list
Sign in Available only to authorized users(For complaints, use another form )