Semesterarbeit
Raimundo Sierra, David Hausheer
bei Professor A. H. Glattfelder
Betreuer:
Konrad Stadler, Christian W. Frei
Vorgestellt am 3. Februar 2000
![\includegraphics[width=0.6\textwidth]{logo.eps}](img1.gif)
In einem ersten Schritt wird der Regler bei der Entwicklung auf dem Rechner getestet, indem z.B. das Ein-/Ausgangsverhalten des Reglers betrachtet wird. Anschliessend kann der Regler auf das bestehende Host-Target System geladen werden und intern mit einem Patientensimulator getestet werden. Um jedoch das Verhalten des Reglers mit seiner Umwelt untersuchen zu können, muss er ''von aussen'' getestet werden. Dazu wird die Simulation auf einem separaten Rechner durchgeführt und der Regler mit diesem verbunden. Dadurch kann der gesamte Regler sowie die gesamte Kommunikation zwischen dem Regler und seiner Umgebung getestet werden. Dies ist das Ziel der vorliegenden Arbeit. Eine ideale Simulation des Patienten würde mit den physikalischen Grössen eines Patienten arbeiten, d.h. in Abbildung 1 das Kästchen ''Patient'' ersetzen. Dazu müssten die Ausgänge der Gasdosierung mit Sensoren gemessen und anhand dieser Werte die physikalischen Ausgänge (Reaktionen) des Patienten berechnet werden. Diese müssten wiederum in physikalische Grössen umgewandelt, von den Überwachungsgeräten (Patientenmonitor) wie bei einem richtigen Patienten mit Sensoren gemessen und die Ergebnisse an den Regler weitergeleitet werden. Bei Umwandlungen von Signalen in physikalische Grössen können jedoch viele Fehler und Störgrössen einwirken, die das Gesamtbild und somit die Simulation stark verzerren.
In dieser Arbeit wird die Simulation (wie in Abbildung 1 angegeben) implementiert. Sie erscheint am sinnvollsten, da sie zum einen die Interaktion des Reglers mit seiner Umgebung testen kann, zum anderen die vielen Umwandlungen umgehen kann. Es ergeben sich folgende grundlegende Anforderungen an die Simulation:
Diese Anforderungen mögen etwas trivial erscheinen, sie spiegeln sich jedoch in der Funktionsweise der Simulation und den Anforderungen an die Daten wieder.
Punkt 2 impliziert, dass immer ein ''gesamter'' Patient, d.h. ein kompletter Parametersatz vorhanden sein muss und auch während der Simulation laufend berechnet wird. Um einzelne (Teil-)Regler zu testen, muss also sichergestellt werden, dass die nicht gelieferten Parameter als Standardwerte vorhanden sind. Dies hat zum Vorteil, dass der Regler an einer möglichst realen Situation getestet wird und allfällige Annahmen oder Quereinflüsse auf andere Faktoren mitgetestet werden.
Ziel von Punkt 3 ist, die Anästhesisten mit dem neuen Reglersystem vertraut zu machen. Der Anästhesist soll nicht am Patienten selbst üben, sondern durch Anschluss des virtuellen Patienten an den Anästhesieregler letzteren bedienen lernen. Der virtuelle Patient tritt somit in der Übungsphase in den Hintergrund. Da er jedoch auch über physikalische Schnittstellen mit dem Regler verbunden ist, wird das Gefühl einer realen Situation verstärkt und allfällige neue Verhaltensweisen des Reglers treten in Erscheinung.
Simulink bietet den Vorteil, dass sich Simulationen und Modelle sehr einfach und intuitiv mittels einer graphischen Oberfläche umsetzen und nachvollziehen lassen. Auch ist die Hardware etwas billiger. Problematisch ist jedoch das Schreiben von Protokollen für die Schnittstellen, v.a. für die digitalen Ein-/Ausgänge. Zum Beispiel müssen Systembibliotheken und andere HW-spezifische Codeteile um- oder neugeschrieben werden. Die Anbindung bestehender XOberon Codeteile ist nicht möglich.
Die zweite Alternative ist eine Kopie des Systems in Bern, wie es für den Regler verwendet wird. Vorteile dieser Konfiguration sind:
Um Daten zu speichern müssen diese dem Host zur Verfügung stehen. Da die Simulation auf dem Target läuft, müssen die Werte also über TCP/IP an den Host übergeben werden. Auf die genaue Funktionsweise dieses Übertragungsmechanismus wird ebenfalls im Abschnitt Benutzeroberfläche eingegangen.
In Abbildung 3 sind die verschiedenen Treibermodule dargestellt. Im folgenden wird auf die Struktur und Funktionsweise der verschiedenen Gerätetreiber näher eingegangen. Eine Übersicht über die Programmstruktur und die Abhängigkeit der einzelnen Module findet man in Abbildung 11 im Anhang.
PM8060Send* = POINTER TO PM8060SendDesc; PM8060SendDesc* = RECORD (Devices.ActuatorDesc) setCO2*: PROCEDURE(P: PM8060Send; C: CO2); setDeviceSpecific*: PROCEDURE(P: PM8060Send; D: DeviceSpecific); setNiBP*: PROCEDURE(P: PM8060Send; n: NiBP); setiBP*: PROCEDURE(P: PM8060Send; i: iBP); setEKG*: PROCEDURE(P: PM8060Send; e: EKG); setSpO2*: PROCEDURE(P: PM8060Send; s: SpO2); setGas*: PROCEDURE(P: PM8060Send; g: Gas); setO2*: PROCEDURE(P: PM8060Send; o: O2); setRespiration*: PROCEDURE(P: PM8060Send; r: Respiration); handle: PROCEDURE(P: PM8060Send); co2: CO2; deviceSpecific: DeviceSpecific; nibp: NiBP; ibp: iBP; ekg: EKG; spo2: SpO2; gas: Gas; o2: O2; respiration: Respiration; mds: MedibusDriverSend.MedibusDriverSend; sendBuffer: Buffers.MedSendBuffer; receiveBuffer: Buffers.MedReceiveBuffer; process: Process; CO2lock, O2lock, iBPlock, NiBPlock, EKGlock, SpO2lock, Gaslock, Speclock, Resplock, Alarmlock : XOK.Synchronizer; sendCO2, sendO2, sendiBP, sendNiBP, sendEKG, sendSpO2, sendGas, sendSpec, sendResp, sendAlarm: BOOLEAN; END;
PROCEDURE PM8060SendTester; VAR pm8060send: PM8060Send.PM8060Send; co2: PM8060Send.CO2; BEGIN NEW(pm8060send); PM8060Send.Init(pm8060send, "MedibusSendSerial"); NEW(co2); PM8060Send.InitCO2(co2); pm8060send.start(pm8060send); co2.InspCO2kPa := 26; pm8060send.setCO2(pm8060send, co2); END PM8060SendTester;
MedibusDriverSend* = POINTER TO MedibusDriverSendDesc;
MedibusDriverSendDesc* = RECORD (Tasks.HandlerDesc)
setDeviceID*: PROCEDURE(M: MedibusDriverSend;
deviceID: ARRAY OF CHAR);
start*, stop*: PROCEDURE(M: MedibusDriverSend);
alive-: BOOLEAN;
state*: INTEGER;
deviceID: ARRAY 64 OF CHAR;
incomming: Buffers.MedReceiveBuffer;
outgoing*, lastCommand, data*: Buffers.MedSendBuffer;
timer3sec, timer10sec: LONGINT;
sendData*, recvData*, recvDevSpec*, recvAlarms*: BOOLEAN;
MDqueue: Queues.Queue;
task: XOK.Task;
END;
DivanRecv* = POINTER TO DivanRecvDesc; DivanRecvDesc* = RECORD (Devices.SensorDesc) getPmax*, getVt*, getF*, getPEEP*, getTiTg*, getTipTi*: PROCEDURE(D: DivanRecv; VAR r: REAL); getRemoteState*: PROCEDURE(D: DivanRecv; VAR b: BOOLEAN); actPmax, actVt, actF, actPEEP, actTiTg, actTipTi: REAL; remoteState: BOOLEAN; (* TRUE falls remoteOn gesendet wurde *) queue: DivanQueues.Queue; receiveBuffer: Buffers.ReceiveBuffer; timeReceived: LONGINT; process: Process; lockPmax, lockVt, lockF, lockPEEP, lockTiTg, lockTipTi, lockRemoteState: XOK.Synchronizer; success: BOOLEAN; END;
PROCEDURE DivanRecvTester; VAR divanrecv: DivanRecv.DivanRecv; Pmax: REAL; BEGIN NEW(divanrecv); DivanRecv.Init(divanrecv, "DivanRecvSerial"); divanrecv.start(divanrecv); divanrecv.getPmax(divanrecv, Pmax); END DivanRecvTester;
IfAGadosRecv* = POINTER TO IfAGadosRecvDesc;
IfAGadosRecvDesc* = RECORD (Devices.SensorDesc)
Agas, O2Flow, N2OFlow: PIO.AnalogSensor;
getN2OFlow*, getAgasCon*, getO2Flow*: PROCEDURE(G: IfAGadosRecv;
VAR r: REAL);
actN2OFlow, actAgasCon, actO2Flow, AgasVolt: REAL;
process: Process;
handle: PROCEDURE(G: IfAGadosRecv);
N2OLock, AgasLock, O2Lock: Tasks.Synchronizer;
END;
PROCEDURE IfAGadosRecvTester;
VAR
ifagadosrecv: IfAGadosRecv.IfAGadosRecv;
AgasCon, N2OFlow, O2Flow: REAL;
BEGIN
NEW(ifagadosrecv);
IfAGadosRecv.Init(ifagadosrecv, "AnAgasRecv", "AnO2FlowRecv",
"AnN2OFlowRecv");
ifagadosrecv.start(ifagadosrecv);
ifagadosrecv.getAgasCon(ifagadosrecv, AgasCon);
ifagadosrecv.getN2OFlow(ifagadosrecv, N2OFlow);
ifagadosrecv.getO2Flow(ifagadosrecv, O2Flow);
END IfAGadosRecvTester;
XOClient.Batch Config.File ~dem Targetrechner übergeben wird. Auf das richtige Vorgehen wird nun im nächsten Abschnitt näher eingegangen.
IPCarrier.DefBoard VIPC616 AT 0EFFF6000H ~Daraufhin werden die verschiedenen Device-Driver definiert.
IPDAC.DefMod IPDAC BOARD VIPC616 AT 0H CHANNELS 6 ~ IPPrec.DefMod IPADCMod BOARD VIPC616 AT 100H CHANNELS 8 ~ IPOctalDriver.DefMod SerialIPMod BOARD VIPC616 AT 200H CHANNELS 8 ~Nun können die seriellen Channels zugeordnet werden:
Peripherals.DefSerialChannel DivanSerial ON SerialIPMod CHANNEL 0 (baud=96,parity=1,stopBit=1,dataBit=8,bufRecLen=200,bufSendLen=200) ~ Peripherals.DefSerialChannel MedibusSerial ON SerialIPMod CHANNEL 1 (baud=96,parity=1,stopBit=1,dataBit=8,bufRecLen=200,bufSendLen=200) ~ Peripherals.DefSerialChannel DivanRecvSerial ON SerialIPMod CHANNEL 5 (baud=96,parity=1,stopBit=1,dataBit=8,bufRecLen=200,bufSendLen=200) ~ Peripherals.DefSerialChannel MedibusSendSerial ON SerialIPMod CHANNEL 4 (baud=96,parity=1,stopBit=1,dataBit=8,bufRecLen=200,bufSendLen=200) ~Für die analogen Schnittstellen müssen die richtigen Skalen gewählt werden. Die Hardwareskala liegt für den D/A-Wandler zwischen 0 bis 10 Volt, für den A/D-Wandler hingegen zwischen -5 und 5 Volt. Deshalb kann nur der Bereich zwischen 0 und 5 Volt verwendet werden. Der gelesene Wert wird in 16-Bit umgewandelt, das entspricht den [-4096..-1] Ticks. Diese Skala wird dann den entsprechenden Werten in Volt (V) zugeordnet. Danach kann die physikalische Einheit (z.B. O2Flow) skaliert und zugeordnet werden. Skalenbeschränkungen können ebenfalls übergeben werden. Für die Sendeseite sieht dies dann folgendermassen aus:
Peripherals.DefScalingLinear AgasScale SCALE = [0..10] V -> [-4096..-1] Ticks SCALE = [0..20] AgasVolt -> [0..10] V LIMIT = [0..10] AgasVolt ~ Peripherals.DefScalingLinear O2FlowScale SCALE = [0..10] V -> [-4096..-1] Ticks SCALE = [0..24] O2Flow -> [0..10] V LIMIT = [0..12] O2Flow ~ Peripherals.DefScalingLinear N2OFlowScale SCALE = [0..10] V -> [-4096..-1] Ticks SCALE = [0..24] N2OFlow -> [0..10] V LIMIT = [0..12] N2OFlow ~Entsprechend sieht die Skala für die Empfängerseite aus:
Peripherals.DefScalingLinear AgasRecvScale SCALE = [0..10] AgasVolt -> [0..5] V SCALE = [-5..5] V -> [-4096..-1] Ticks LIMIT = [0..10] AgasVolt ~ Peripherals.DefScalingLinear O2FlowRecvScale SCALE = [0..12] O2Flow -> [0..5] V SCALE = [-5..5] V -> [-4096..-1] Ticks LIMIT = [0..12] O2Flow ~ Peripherals.DefScalingLinear N2OFlowRecvScale SCALE = [0..12] N2OFlow -> [0..5] V SCALE = [-5..5] V -> [-4096..-1] Ticks LIMIT = [0..12] N2OFlow ~
Nachdem dies geschehen ist, können nun die analogen Channels mit den entsprechenden Skalen zugeordnet werden. Für die Sendeseite lauten die Befehle folgendermassen:
Peripherals.DefAActuator AnAgas ON IPDAC CHANNEL 0 SCALE AgasScale ~ Peripherals.DefAActuator AnO2Flow ON IPDAC CHANNEL 1 SCALE O2FlowScale ~ Peripherals.DefAActuator AnN2OFlow ON IPDAC CHANNEL 2 SCALE N2OFlowScale ~Entsprechend sehen die Befehle für die Empfängerseite aus:
Peripherals.DefASensor AnAgasRecv ON IPADCMod CHANNEL 1 SCALE AgasRecvScale ~ Peripherals.DefASensor AnO2FlowRecv ON IPADCMod CHANNEL 2 SCALE O2FlowRecvScale ~ Peripherals.DefASensor AnN2OFlowRecv ON IPADCMod CHANNEL 3 SCALE N2OFlowRecvScale ~Diese Konfigurationen können folgendermassen getestet werden:
XOClient.Execute TestSerial.Write MedibusSendSerial "M" ~ XOClient.Execute TestSerial.ReadBuf MedibusSerial ~ XOClient.Execute Application.WriteA AnO2Flow 6.0 ~ XOClient.Execute Application.ReadA AnO2FlowRecv ~
Die Simulation modelliert den Fluss des Anästhesiegases und dessen Verteilung im Körper eines Patienten. Im folgenden wird das Patientenmodell und die Implementierung in XOberon (d.h. das Modul Simulation) erläutert sowie eine Anleitung gegeben, wie die Simulation erweitert oder verbessert werden kann.
Das Modul Simulation ist eine 1:1 Implementierung der Doktorarbeit
von Chr. W. Frei ''Fault Tolerant Control Concepts Applied to
Anesthesia'' Kapitel 4 [2]. Für ein genaues Verständnis der
physiologischen Vorgänge, sowie der Herleitung der Gleichungen und
dazugehörigen Parameter sei deshalb auf diese Arbeit
verwiesen.
Den Kern des Modells bilden die sogenannten Zustandsgleichungen
in der bekannten Form:
| (1) | |||
| (2) | |||
| (3) |
Diese Gleichungen mit den entsprechenden Parametern sollen immer auf den aktuellsten physiologischen Erkenntnissen beruhen. Für unterschiedliche Patienten werden verschiedene Parametersätze verwendet, die den Patienten charakterisieren.
Das hergeleitete Modell ist ein MIMO System, das die
Anästhesiegasflüsse sowie den chirurgischen Eingriff und den
Blutdruck mathematisch beschreibt. Die Ausgänge
,
sowie
werden aus den Eingängen
,
,
und
mit einem Set aus nichtlinearen Differentialgleichungen
berechnet. Hierbei bedeutet
die vom Patienten eingeatmete
Anästhesiegaskonzentration,
die ausgeatmete
Anästhesiegaskonzentration
und
der mittlere arterielle Blutdruck (Mean Arterial Blood
Pressure). Die Anästhesiegaskonzentration
wird dem
Frischgas, bestehend aus
und
beigemischt. Der chirurgische
Eingriff, d.h. die Reaktion auf den Einschnitt und den Beginn der
eigentlichen Operation, wird durch
modelliert. Schliesslich ist
die
Frischgaszufuhr und
die
Beatmungsfrequenz. Auf diese Eingänge wird im Abschnitt Dynamische
Parameter genauer eingegangen.
Ein Grossteil der Parameter, der zum Lösen der Differentialgleichungen benötigt wird, ist vom Patienten unabhängig. Beispielsweise ist die prozentuale Verteilung der gesamten Blutmenge invariant. Diese Parameter werden beim Aufruf der Simulation gesetzt, können von aussen nicht verändert werden und bleiben während der gesamten Simulationsdauer unverändert. Sie werden hier als invariante Parameter bezeichnet.
Im Modell sind verschiedene Parameter vom Patienten, den man simulieren
möchte, abhängig. Einfachstes Beispiel hierfür ist das
Körpergewicht
. Weiter können das Residualvolumen der Lunge
, der ''lung shunt''
, der anfängliche Blutdruck
und der anfängliche Herzschlag
als statische Patientenparameter
betrachtet werden. Wichtig ist, dass in der Simulation jeweils ''Defaultwerte''
vorhanden sind, so dass die Simulation auch lauffähig ist, wenn diese
Werte nicht gesetzt werden. Als ''Defaultpatient'' wurde eine
Person mit einem Gewicht von 70 kg, einem Residualvolumen
von 2.57 Litern, einem ''lung shunt'' von 10%, ein Blutdruck von 80
mmHg und einem Herzschlag von 60 pro Minute implementiert, was am ehesten einem
jungen Patienten entspricht.
Der ''lung shunt'' definiert den Anteil in Prozent der Alveoli in der Lunge, die nicht am Gasaustausch teilnehmen und somit den Anteil des Blutes, der ohne Sauerstoffaufnahme vom venösen in den arteriellen Blutkreislauf gelangt. Bei Rauchern oder Menschen mit Lungenproblemen kann dieser Wert höher liegen. Da jedoch ein Zusammenhang zur Zeit nicht mathematisch berechnet werden kann, muss dieser Parameter direkt eingegeben werden.
Diese Parameter werden als statisch bezeichnet, da sie den Patienten beschreiben, der sich während der Operation nicht verändert. Statische Parameter werden beim Starten der Simulation übergeben. Mögliche Erweiterungen könnten z.B. das Geschlecht, das Alter oder die Grösse mit einbeziehen, Parameter die zum jetzigen Zeitpunkt noch nicht von der Simulation berücksichtigt werden.
Neben dem eigentlichen Eingang, der Anästhesiegasdosierung
, werden
vom Anästhesisten noch eine Reihe weiterer Einstellungen
vorgenommen. Diese Einstellparameter können ebenfalls als Eingänge
betrachtet werden, da sie sich während einer Simulation
ändern können. Als Beispiele seien die Atemfrequenz
, der Frischgasfluss
und das
Tidalvolumen
der Lunge (normales Atemvolumen) erwähnt. Zu
beachten ist, dass diese Parameter im Gegensatz zum Eingang
für den Patienten ''überlebenswichtig'' sind, da er z.B. ohne
Tidalvolumen nicht leben kann. Wird deshalb ein Regler getestet, der
diese Werte nicht liefert, muss sichergestellt werden, dass diese
Parameter der Simulation trotzdem übergeben werden oder die
Simulation so geändert wird, dass ein Wert vorhanden ist. Der Eingang
hingegen muss nicht zwingend gesetzt werden; der Patient wird
in diesem Falle nicht narkotisiert.
Die vom Anästhesisten gestellten Parameter werden als dynamische
Parameter bezeichnet. Dynamische Parameter sowie der Eingang
werden über Schnittstellen eingelesen und somit periodisch
aufdatiert. Die Atemfrequenz und das Tidalvolumen können über den
DivanRecv Treiber gelesen werden. Der Frischgasfluss setzt sich aus
dem
und
Fluss zusammen, welche über den
IfAGadosRecv Treiber
eingelesen werden. In dieser Sektion können alle Eingänge ergänzt werden, die
von irgendwelchen Treibern geliefert werden. Bei einer
Erweiterung des Modells muss entschieden werden, ob der Parameter
ein normaler Eingang oder ein dynamischer
Parameter ist. Bei dynamischen Parametern muss sichergestellt werden,
dass sie über die Schnittstellen gesetzt werden.
Eine weitere Klasse von Eingängen sind Störungen. Als Störungen
werden im folgenden Eingriffe in die Simulation bezeichnet, die
entweder vom ''Chirurgen'' verursacht oder
spezifisch zum Testen der Regler eingeführt werden. Sie wirken
nicht von Anfang an auf die Simulation, sondern werden im Verlauf in
die Simulation aufgesetzt oder wieder entfernt. In der jetzigen
Implementierung kann der
Simulation ein Störwert
zur Laufzeit übergeben werden. Er
wird dem Ausgang
hinzuaddiert. Entsprechend den Ausgangswerten
von
, die im Bereich 80
mmHg liegen sollten, ist es für diese Störung sinnvoll, Werte im
Bereich von
10 mmHg zu wählen. Diese Störung wirkt sich nicht auf
die eigentliche
Simulation aus, sondern nur auf dessen Ausgang und jeweils nur so lange
wie der Wert gesetzt ist. Die Störung ist also in erster Linie zum
Testen eines Reglers gedacht, wie auch das weiter unten erwähnte
Rauschen.
Ein weiterer Parameter der zur Laufzeit verändert werden kann, ist der
chirurgische Eingriff
. Er hat keine direkte physiologische
Interpretation, sondern modelliert die Reaktion des Patienten auf den
chirurgischen Eingriff. Sinnvoll ist hier ein Wert von 1 zum Zeitpunkt
des eigentlichen Eingriffs (Beginn des Einschnitts), der nach einer
gewissen Zeit auf 0.5 herabgesetzt wird. Die Dauer sowie die Amplitude
hängen von der
Stärke des zu simulierenden Eingriffs ab. Der Wert 1 führt zu
einem starken Anstieg des Blutdrucks der so lange dauert, wie der Wert
gesetzt ist. Um Resultate, die einer echten Operation nahekommen, zu
erhalten, kann man mit Hilfe der Implementierung in Matlab
(simulation.m) verschiedene Verläufe von
ausprobieren
und so ''Mustereingriffe'' definieren.
Für die Störungen kann man einige Erweiterungen und Verbesserungen vornehmen. Vorschläge hierzu sind:
Insgesamt werden in [2] 17 Differentialgleichungen (Gleichungen 4.30 bis 4.38) aufgestellt. 13 davon repräsentieren den Konzentrationsausgleich des Anästhesiegases in den verschiedenen Körperabschnitten wie in Tabelle 3 angegeben. Weitere Gleichungen stellen die Autoregulation, die neurale Aktivität sowie je eine für die Konzentration der Epinephrine in der Lunge und der Peripherie (der gesamte Rest des Körpers) dar.
Die Differentialgleichungen werden im Programm mittels eines
periodischen Tasks diskret gelöst. Sobald alle Parameter und Eingänge
vorhanden sind, kann die Simulation die Werte
berechnen.
Die ursprüngliche Differentialgleichung
(4) wird in integrierter Form (5)
diskretisiert (6) und vor dem ersten Durchlauf initialisiert
(7).
Die Initialisierung geschieht in diesem Fall beim Starten des
Programms sowie durch Setzen der Werte über das Benutzerinterface und
die Treiber.
Am Ausgang kann optional ein Rauschen addiert werden, um die
Rauschanfälligkeit eines Reglers zu testen. Die Stärke des Rauschens kann am Anfang
der Simulation übergeben werden, wird also den statischen Parametern zugeordnet. Die
Sie wird in Prozent der Amplitude des entsprechenden
Ausgangs angegeben. 5% Rauschen bedeutet also, dass die maximale
Rauschamplitude 5% des Ausgangswertes beträgt, wobei der effektive Wert
zufällig gleichverteilt zwischen den beiden Extremen -5% .. 5% liegt.
Zusammenfassend erhalten wir folgende Bestandteile der Simulation:
Abbildung 8 zeigt den Ablauf des Programms der nun erläutert werden soll. Bei einem Aufruf durch das Modul Run wird eine neue Simulation erzeugt. Dabei wird der Bereich am Ende des Moduls Simulation nach BEGIN ausgeführt. Darin werden alle invarianten Parameter initialisiert. Mit Simulation.Init(simulation) wird die Simulation initialisiert, d.h. nacheinander alle Treiber erstellt und initialisiert sowie ein periodischer Task definiert, der die Simulation aufdatieren wird. Anschliessend werden alle Patientenparameter, d.h. alle statischen Parameter, gesetzt. Aus diesen statischen Parametern werden anschliessend in InitPatient alle zu diesem Zeitpunkt berechenbaren Hilfsvariablen berechnet sowie die Zustände initialisiert. Diese werden üblicherweise alle 0 sein, wenn nicht von Anfang an Anästhesiegas beigemischt wird. Nun können mit dem Aufruf simulation.start(simulation) alle Treiber sowie der periodische Task gestartet werden. Dadurch wird von nun an die Prozedur Run periodisch jede Sekunde ausgeführt. Hier werden als erstes die Eingänge eingelesen. Aus diesen werden in der Prozedur ActualModel alle (Hilfs-)Variablen berechnet und anschliessend die Prozedur IntegrateOneStep aufgerufen, welche die diskrete Integration durchführt, die Zustände aufdatiert und die Ausgänge berechnet. Als letztes werden die Resultate mit der Prozedur Send an die Schnittstellen, d.h. an den PM8060Send geschickt. Das Setzen der Störungen sowie die Abfrage der Zustände sind unregelmässige Ereignisse, die letztendlich über die Benutzerschnittstelle eingegeben respektive ausgelesen werden. Da deshalb gleichzeitig aus verschiedenen Tasks auf diese Variablen zugegriffen werden kann, befinden sie sich in einem kritischen Bereich und müssen entsprechend geschützt werden. Dies geschieht mit dem Modul Tasks [3], indem ein Synchronizer definiert wird.
Die Prozedur Send übergibt die Ausgänge an den PM8060Send indem die Prozeduren GetInspAgas*(S:Simulation; Var r:REAL) etc. aufgerufen werden. In diesen wird den Ausgängen ein Rauschen mit der oben erwähnten maximalen Amplitude hinzuaddiert.
Um die Ausgänge zu speichern, muss ein weiteres Modul geladen werden, das die Funktionen get<Data> möglichst periodisch aufruft und die empfangenen Daten in ein File schreibt.
Wie bereits oben erwähnt, ist die Simulation auch in Matlab
vorhanden. Mit dem Aufruf simulation(dt, duration, vap) kann der
Verlauf der inneren Zustände sowie des Ausgangs
bei einer
Integrationsschrittweite von
dt in Minuten, einer Simulationsdauer duration in
Sekunden und einer
Anästhesiegasdosierung vap in Prozent betrachtet werden. Dies ist
insbesondere bei neuen Modellen
sinnvoll, da Ergänzungen und Verbesserungen am Patientenmodell
schnell und einfach überprüft werden können. Es
empfiehlt sich sehr, die Simulation in Matlab zu testen und allenfalls zu korrigieren, bevor man sie in XOberon
implementiert. Bei der Übersetzung in XOberon muss besonders auf die
Indexierung der Matrizen geachtet werden, da diese in Matlab bei 1, in
XOberon jedoch bei 0 beginnen.
Wichtig bei einer Erweiterung ist, dass sowohl die Programmstuktur beibehalten wird, sowie die Anforderungen von XOberon erfüllt werden. Folgende Auflistung soll helfen, dass keine wesentlichen Aspekte übersehen werden.
Vor allem bei dynamischen Parametern ist auf diesen Punkt zu achten. Von diesen Parametern erwartet man, dass sie vom Anästhesisten gesetzt werden. Sie sind deshalb nicht mit Defaultwerten versehen. Sollte sich dies ändern, muss für all diese Parameter ein Defaultwert über die Schnittstellen geliefert werden.
PROCEDURE Start*;
BEGIN
(* Ein neuer Periodic-Task wird definiert *)
run.task := XOK.NewPeriodic(run, 10*XOK.Millisecond,
1000*XOK.Millisecond, 1000*XOK.Millisecond);
(* Eine neue Simulation wird generiert ... *)
NEW(run.simulation);
(* ... und initialisiert *)
Simulation.Init(run.simulation);
(* Das Modell wird der Library beigefügt *)
SimulationModell.Init(run.simulation);
(* matlabProtokol wird erzeugt und initialisiert ... *)
NEW(run.matlabProtokol);
MatlabProtokol.InitMatlabProtokol(run.matlabProtokol);
(* ... und das neue Modell hinzugefügt *)
run.matlabProtokol.addModel(run.matlabProtokol,
"Simulation.Lib", "Simulation");
(* Die Parameter werden übergeben *)
run.simulation.set<Data>(run.simulation,run.<Data>);
(* Ein neuer Patient wird initialisiert ... *)
Simulation.InitPatient(run.simulation);
(* ... und die Simulation schliesslich gestartet *)
run.simulation.start(run.simulation);
run.Started := TRUE;
(* Nun wird die Speicherung gestartet ... *)
run.matlabProtokol.start(run.matlabProtokol);
(* ... und der Task-Handler startet den Periodic-Task handle* *)
IF run.task#NIL THEN
run.task.Start;
END;
END Start;
XOClient.Execute TelnetServer.ShowCommands Run.Mod ~
XOClient.Execute Run.set<Data> &<TextFeldName>.value ~Dagegen ist die Darstellung der Zustandsgrössen der Simulation auf dem Host eine nicht triviale Aufgabe und erfordert einige Erweiterungen der bestehenden Module, ein bisschen Geschick und Geduld. Abbildung 9 zeigt eine Übersicht über die Abhängkeiten der verschiedenen Module, die zur Visualisierung gebraucht werden.
XOClient.Call Inspector.Inspect Simulation.Simulation ~Natürlich können jederzeit weitere Grössen der Simulation in das Modell hinzugefügt werden. Folgende Erweiterungen sind dazu nötig:
...
ELSIF M.name = "<Data>" THEN
M.class := Objects.Real;
O.simulation.get<Data>(O.simulation, M.x);
M.res := 0;
...
M.Enum("<Data>");
...
Um weitere Gadgets [4] hinzuzufügen sind nun folgende Schritte nötig:
Gadgets.Insert TextFields.NewTextField RemoteModels.NewObject ~Allgemein lautet der Befehl Gadgets.Insert <View> <Model>.
... BEGIN IPno[0] := CHR(129); IPno[1] := CHR(132); IPno[2] := CHR(50); IPno[3] := CHR(126); END Pump.
| ausgeatmete Anästhesiegasmenge | |
| eingeatmete Anästhesiegasmenge | |
| Anästhesiegaskonzentration | |
| Störung am Ausgang MAP | |
| Surgical stimulation; Chirurgischer Eingriff | |
| Fresh Gas Flow; Frischgasfluss | |
| Atmungsfrequenz | |
| Heart Rate; anfängliche Herzfrequenz, Puls | |
| Puls | |
| Lung Shunt | |
| Mean Arterial Blood Pressure; Blutdruck | |
| Anfänglicher Blutdruck | |
| Expiratorisches Reservevolumen + Residualvolumen | |
| Tidalvolumen; Atemvolumen | |
| Weight; Gewicht des Patienten |
Abbildung 11 zeigt die Abhängigkeiten der verschiedenen Treibermodule. Sie ist nicht vollständig, gibt aber eine gewisse Übersicht und ist v.a. als Hilfe bei der Implementierung des A2000 Moduls gedacht.
| Datei | Beschreibung | Abhängigkeiten |
| DivanRecv.Mod | Gerätetreiber für den Divan (Empfänger) | Devices.Mod Measurments.Mod Buffers.Mod DivanQueues.Mod Tasks.Mod |
| DivanRecvTester.Mod | Testmodul für den Divan (Sender und Empfänger) | Divan.Mod
DivanRecv.Mod
Out.Mod |
| IfAGadosRecv.Mod | Gerätetreiber für die Gasdosierung (Empfänger) | Devices.Mod
Logger.Mod |
| IfAGadosRecvTester.Mod | Testmodul für die Gasdosierung (Sender und Empfänger) | IfAGados.Mod
IfAGadosRecv.Mod |
| MedibusDriverSend.Mod | Gerätetreiber für das Medibus Kommunikationsprotokoll (Sender) | Queues.Mod
Buffers.Mod
Peripherals.Mod
Base.Mod |
| MedibusTester.Mod | Testmodul für das Medibus Kommunikationsprotokoll (Sender und Empfänger) | MedibusDriverSend.Mod
MedibusDriver.Mod
Out.Mod |
| PM8060Send.Mod | Gerätetreiber den Patientenmonitor (Sender) | MedibusDriverSend.Mod
Out.Mod |
| Datei | Beschreibung | Abhängigkeiten |
| PM8060Tester.Mod | Testmodul für den Patientenmonitor (Sender und Empfänger) | PM8060.Mod
PM8060Send.Mod
Out.Mod |
| Run.Mod | Startmodul für die Simulation | Simulation.Mod
SimulationModell.Mod
Out.Mod |
| Simulation.Mod | Simulationsmodul | Out.Mod |
| SimulationModell.Mod | Modell der Simulation | Simulation.Mod
Logger.Mod
XAttributes.Mod
Objects.Mod |
| Simulation.Panel | Benutzerinterface für die Simulation | - |
| ConfigReg.File | Konfigurationsdatei für die Hardwareschnittstellen auf dem Reglertarget | IPCarrier.Mod |
| ConfigSim.File | Konfigurationsdatei für die Hardwareschnittstellen auf dem Simulationstarget | IPCarrier.Mod |
| ConfigTest.File | Konfigurationsdatei für den Treibertest auf einem einzigen Target | IPCarrier.Mod |
| TreiberTest.File | Hilfsdatei mit Befehlen zum Testen der Hardwarekonfigurationen | - |
| HostThingsSim.Mod | Empfängermodul auf dem Host für die Speicherung | Texts.Mod |
| Datei | Beschreibung |
| simulation.m | Implementierung der Simulation in Matlab |
| Buffers.Mod | Devices.Mod | Divan.Mod |
| DivanQueues.Mod | FileSaver.Mod | Histories.Mod |
| HostThingsSim.Mod | IfAGados.Mod | Logger.Mod |
| MatLab.Mod | MatlabProtokol.Mod | Measurments.Mod |
| MedibusDriver.Mod | PM8060.Mod | Pump.Mod |
| RemoteModels.Mod | TestSerial.Mod |
This document was generated using the LaTeX2HTML translator Version 99.2beta6 (1.42)
Copyright © 1993, 1994, 1995, 1996,
Nikos Drakos,
Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999,
Ross Moore,
Mathematics Department, Macquarie University, Sydney.
The command line arguments were:
latex2html -split 3 bericht
The translation was initiated by Raimundo Sierra on 2001-07-18