Interface mellan Simulink och Gestpan. - DiVA

64
2003:E007 EXAMENSARBETE Interface mellan Simulink och Gestpan En S-funktion för simuleringar med RM12 multipurpose model Anders Höglund 2003-03-21 Högskolan Trollhättan/Uddevalla institutionen för teknik Box 957, 461 29 Trollhättan Tel: 0520-47 50 00 Fax: 0520-47 50 99 E-post: [email protected]

Transcript of Interface mellan Simulink och Gestpan. - DiVA

2003:E007

EXAMENSARBETE

Interface mellan Simulink och Gestpan En S-funktion för simuleringar med RM12 multipurpose model

Anders Höglund

2003-03-21

Högskolan Trollhättan/Uddevalla institutionen för teknik

Box 957, 461 29 Trollhättan Tel: 0520-47 50 00 Fax: 0520-47 50 99

E-post: [email protected]

i

EXAMENSARBETE

Interface mellan Simulink och Gestpan En S-funktion för simuleringar i rm12 multipurpose model

Sammanfattning Vid regler- och prestandastudier på avdelningen Motorsystem på Volvo Aero i Trollhättan har tidigare två olika motormodeller använts. Dessa har nu divergerat så pass mycket att det blivit svårt att skilja mätfel från modellfel. Man har sedan en tid tillbaka insett värdet av en gemensam modell. En sådan modell har nu tagits fram och kallas RM12 Multiporpose Model. Detta är en statisk och dynamisk modell för RM12, motorn i JAS 39 Gripen. För att kunna utföra regler- och prestandaberäkningar på denna modell genom MATLABs simuleringsverktyg Simulink har en ny komponent för att binda samman Multipurpose-modellen med Simulink utvecklats inom detta examensarbete. Denna komponent är en så kallad S-funktion. Denna är skriven i programmeringsspråket C och sköter kommunikationen med motormodellen.

Nyckelord: S-funktion, C, Fortran, MATLAB, Simulink, motormodell, RM12, interface, MEX-fil

Utgivare: Högskolan Trollhättan/Uddevalla, institutionen för teknik Box 957, 461 29 Trollhättan Tel: 0520-47 50 00 Fax: 0520-47 50 99 E-post: [email protected]

Författare: Anders Höglund Examinator: Anna-Karin Christiansson Handledare: Dan Ring, Tomas Grönstedt, Volvo Aero Corporation AB Poäng: 10 Nivå: C Huvudämne: Elektroteknik Inriktning: Informationssystem Språk: Svenska Nummer: 2003:E007 Datum: 2003-03-21

ii

DISSERTATION

Interface between Simulink and Gestpan An S-function for simulations on the RM12 Multipurpose Model

Summary At the department Performance and Control Systems at Volvo Aero Corporation in Trollhättan Sweden, two different RM12 models have previously been used for control- and performance studies. These two models have now diverged to the extent that it is difficult to separate modeling errors from measurement errors due to differences in the two models. The department has, for quite some time, realised the importance of a common model. Such a model has now been developed and is called the RM12 Multipurpose Model. It is a static and dynamic model of the RM12 engine found in the Swedish fighter aircraft JAS 39 Gripen. In order to perform control- and performance studies on this model using the simulation tool Simulink in MATLAB, a new component has been developed. The development of this component is what this thesis is about. The result is a new S-function that makes it possible to simulate the model using Simulink. The S-function is written in the programming language C.

Keywords: S-function, C, Fortran, MATLAB, Simulink, engine model, RM12, interface, MEX-file

Publisher: University of Trollhättan/Uddevalla, Department of Technology Box 957, S-461 29 Trollhättan, SWEDEN Phone: + 46 520 47 50 00 Fax: + 46 520 47 50 99 E-mail: [email protected]

Author: Anders Höglund Examiner: Anna-Karin Christiansson Advisor: Dan Ring, Tomas Grönstedt, Volvo Aero Corporation AB Subject: Electrical Engineering, Information Systems Language: Swedish Number: 2003:E007 Date: March 21, 2003

Interface mellan Simulink och Gestpan

Förord Jag skulle vilja tacka alla som hjälp mig i mitt arbete med att ta fram denna rapport och i mitt arbete att genomföra mitt examensarbete. Det har både varit spännande, intressant och lärorikt, och i vissa stunder tungt och besvärligt. Jag hoppas att denna rapport kommer att lägga grunden för ett fortsatt samarbete på avdelningen Motorsystem.

Speciellt tack till:

Dan Ring

Tomas Grönstedt

Anna-Karin Christiansson

Elisabeth Rydh

Lars Mossberg

Richard Avellán

Henrik Alvebrink

Mikael Johansson

Roland Rundberg

iii

Interface mellan Simulink och Gestpan

Innehållsförteckning Sammanfattning ...............................................................................................................i Summary ......................................................................................................................... ii Förord............................................................................................................................. iii Innehållsförteckning.......................................................................................................iv Symbolförteckning ..........................................................................................................v 1 Inledning......................................................................................................................1

1.1 Bakgrund................................................................................................................1 1.2 Syfte och mål..........................................................................................................1 1.3 Avgränsningar .......................................................................................................1

2 Förstudier ....................................................................................................................2 2.1 RM12 – Motorn till JAS 39 Gripen .......................................................................2

2.1.1 Motorns uppbyggnad .................................................................................2 2.2 MATLAB ................................................................................................................3

2.2.1 MEX-filer...................................................................................................4 2.3 Simulink .................................................................................................................5

2.3.1 S-funktioner ...............................................................................................6 2.4 Fortran.................................................................................................................10

2.4.1 Moduler i Fortran.....................................................................................10 2.5 RM12 Multipurpose model/Gestpan....................................................................11

3 Framtagning av interface.........................................................................................11 3.1 Testinterface ........................................................................................................11

3.1.1 Externa funktionsanrop från C till Fortran ..............................................12 3.1.2 Cellmatris i MATLAB.............................................................................13 3.1.3 Typer och precision, C kontra Fortran.....................................................16 3.1.4 Debugga C-MEX S-funktionen ...............................................................17

3.2 Statiskt interface ..................................................................................................18 3.2.1 Initiering av parametrar ...........................................................................19 3.2.2 Länkning med hjälp av mex.....................................................................19

4 Simuleringar..............................................................................................................20 5 Resultat ......................................................................................................................20 6 Slutsatser ...................................................................................................................21

6.1 Analys av resultat ................................................................................................22 6.2 Rekommendationer till fortsatt arbete.................................................................22

7 Bilagor........................................................................................................................25

iv

Interface mellan Simulink och Gestpan

Symbolförteckning

Förkortning Förklaring

C Programmeringsspråket C

dll Dynamic Link Library

EBK Efterbrännkammare

FADEC Full Authority Digital Engine Control

GE General Electric

HT-turbin Högtrycksturbin

LT-turbin Lågtrycksturbin

VAC Volvo Aero Corporation

För att öka läsbarheten i rapporten har all kod skrivits med typsnittet Courier New. Detta gäller både kod i Fortran, C och MATLAB.

Då symbolerna ”>>” står framför en kodrad markerar detta att det är ett kommando som är skrivet i MATLABs kommandofönster.

v

Interface mellan Simulink och Gestpan

1 Inledning Volvo Aero utvecklar och tillverkar delkomponenter för civila flyg- och raketmotorer, men även till militära motorer som RM12. Företaget har även en servicesida som säljer och hyr ut motorer och reservdelar till motorer. Affärsavdelningen LMGT utvecklar och tillverkar kraftgeneratorer byggda på gasturbinteknik samt tillhandahåller service på densamma.

Avdelningen motorsystem som tillhör divisionen militärt flyg, tillhandahåller kunskap om motorns reglering, prestanda, säkerhet och funktion. Avdelningen arbetar även med utveckling av system för att testa motorfunktioner i flygplanet eller i provrigg. Även utveckling av funktioner i flygplanets regler- och övervakningssystem görs på avdelningen.

För att på ett effektivt sätt kunna simulera motorers prestanda finns ett antal verktyg. Dessa har nu fått ett tillskott då en ny generell motormodell tagits fram. För att denna skall kunna användas till simuleringar krävs det ett interface mot simuleringsverktyget Simulink och det är detta interface som denna rapport försöker redogöra för.

1.1 Bakgrund Två modeller har tidigare använts för prestanda- och reglerstudier på avdelningen motorsystem på Volvo Aero. Dessa har mer och mer divergerat och skiljer sig nu åt på ett antal punkter. För att undvika bland annat detta problem och kunna utföra både prestanda- och reglerstudier i samma modell har en ny modell tagits fram. Denna modell är skriven i Fortran 90 och kallas RM12 Multipurpose Model. Den nya modellen utvecklad av Tomas Grönstedt på Volvo Aero är modulariserad, vilket ger en ökad flexibilitet. För att kunna genomföra vissa typer av studier med modellen måste den kopplas till ett simuleringsverktyg, i detta fallet MATLAB/SIMULINK.

1.2 Syfte och mål För att kunna använda motormodellen RM12 Multipurpose Model skriven i Fortran 90 tillsammans med simuleringsverktyget MATLAB/SIMULINK behövs ett interface däremellan. Detta interface skall möjliggöra simulering av RM12 multipurpose model i MATLAB Simulink och därmed kan både prestandautvärdering, reglersystemsstudier och design för RM12 utföras i MATLAB.

1.3 Avgränsningar Interfacet är utvecklat i Windowsmiljö och fungerar bara i en sådan. Detta beror bland annat på filändelser.

1

Interface mellan Simulink och Gestpan

Hittils har bara protokoll för statiska studier implementerats, dvs arbete med att utveckla ett interface för kommunikation av data under dynamiska simuleringar återstår.

2 Förstudier Vid sammanlänkning av flera programmeringsmiljöer, här MATLAB, C och Fortran, krävs studier av hur detta sker på effektivaste sätt. Då Fortran har en stark tradition inom tekniska beräkningar finns det förberett en hel del i MATLAB [6,8] för denna integration. Programmet som skall integreras med MATLAB är en motormodell av RM12 (RM12 Multipurpose Model) skriven i Fortran 90. Den är utvecklad av Tomas Grönstedt på Volvo Aero och kommer att ersätta två äldre modeller för regler- och prestandastudier. För att bättre förstå Multipurpose-modellens uppbyggnad i moduler har även en inledande del som beskriver motorn i JAS 39 Gripen - RM12 - tagits med.

Den sammanlänkande filen mellan MATLAB och motormodellen är skriven i programmeringsspråket C.

2.1 RM12 – Motorn till JAS 39 Gripen Turbofläktmotorn RM12 (ReaktionsMotor 12) är en dubbelströmsmotor konstruerad av General Electric Company [1] (GE). Utvecklingen av RM12 sker i samarbete mellan GE och Volvo Aero Corporation (VAC). RM12 är en version av GE’s motor F404-GE-400. Motorn har ett elektroniskt reglersystem med en FADEC-enhet (Full Authority Digital Engine Control) som normalt reglerar och övervakar motorn. I händelse av fel i detta system finns ett hydromekaniskt reservreglersystem. Reglersystemet styr bränsleflödet till motorn (huvudbrännkammare och EBK, dvs Efterbrännkammare), arean för utlopps-munstycket samt inställningen av ledskenorna i fläkt och kompressor.

2.1.1 Motorns uppbyggnad

Motorn är uppbyggd av sju utbytbara moduler, fläkt, kompressor, växellåda, brännkammare, HT-turbin, LT-turbin och efterbrännkammare (EBK), se Figur 1.

2

Interface mellan Simulink och Gestpan

Figur 1 Motorns moduler

Motorn har två rotorer, en lågtrycks(LT-) rotor och en högtrycks(HT-) rotor. LT-rotorn utgörs av en trestegs fläkt kopplad till och driven av en enstegs LT-turbin. HT-rotorn består av en sjustegs kompressor kopplad till och driven av en enstegs HT-turbin. De båda rotorerna är mekaniskt oberoende av varandra.

Luften tas in i motorn genom inloppsdelen, passerar genom fläktmodulen och delas upp i två olika stora flöden när den når främre stativet. Konstruktionen är vald så att en mindre del av luften leds via fläktkanalen till en efterbrännkammare (EBK) medan resterande del av luftflödet leds in i kompressorn. Denna konstruktion gör motorn till en så kallad turbofläktmotor.

2.2 MATLAB MATLAB är ett högnivåspråk för tekniska beräkningar. Det integrerar beräkning, presentation och programmering i en relativt lättanvänd miljö. Språket använder en notation som liknar det matematiska och är därför intuitivt tilltalande för tekniska tillämpningar. Till MATLAB hör simuleringsverktyget Simulink som beskrivs mer i detalj nedan.

För att utöka MATLABs inbyggda funktionsbibliotek kan man skriva egna funktioner. Detta görs enklast med hjälp av m-filer. Men om man vill använda sig av en befintlig kod skriven i ett annat programspråk tex Fortran måste man skapa en MEX-fil [2] som länkar samman den externa koden med en så kallad "gatewayfil" som är skriven så att MATLAB förstår. Detta kallas att skapa en MEX-fil. Man kan på ett liknande sätt i Simulink länka samman extern kod med ett Simulinkblock, detta görs då i en S-funktion [3]. Detta beskrivs närmare i avsnittet "Länka med hjälp av mex" (2.3.1.3). Både vid skapandet av MEX-filer och S-funktioner använder man sig av samma kommando, mex, skrivet i MATLABs kommandofönster eller i en m-fil. Detta

3

Interface mellan Simulink och Gestpan

kommando länkar samman de externa filerna och filen som kommunicerar med MATLAB eller Simulink. Ett exempel på detta kommando kan vara:

>> mex MinCFil.c MinFortranFil.obj

som länkar samman filerna MinCFil.c och MinFortranFil.obj till en ny fil uppkallad efter namnet på den första filen efter mex, i detta fallet MinCFil. Den nya filen kommer heta MinCFil.dll enligt Tabell 1 på sidan 6 om man använder sig av operativsystemet Windows. Det går att använda mex-kommandot på flera filer skrivna i samma språk då samma kompilator då används, men det går inte att blanda okompilerade filer av olika språk då kompilatorn man valt då man körde mex –setup bara pekar på en specifik kompilator. Detta kommando fungerar t. ex. inte:

>>mex MinCFil.c MinFortranFil.f90

Kompilera istället filen MinFortranFil.f90 till en objektsfil och kör kommandot:

>>mex MinCFil.c MinFortranFil.obj

2.2.1 MEX-filer

Man kan i MATLAB anropa egna C- eller Fortransubrutiner som om de vore inbyggda funktioner eller m-filer. Filer där dessa egna subrutiner ligger kallas MEX-filer. Dessa är dynamiskt länkade bibliotek (.dll) som kan exekveras inifrån MATLAB. De är uppbyggda på ett annat sätt än S-funktionen.

Mex-filen har två skilda delar, en kommunikationsdel och en beräkningsdel, se Figur 2.

MATLAB Fortran

Beräkningsdel

KommunikationsdelmexFunction()

Figur 2 MEX-filens interaktion med MATLAB och extern Fortrankod

Beräkningsdelen kan innehålla kod för beräkningar i mex-filen samt in- och utmatning av data till eventuella externa filer, som t.ex. Fortranfiler. Kommunikationsdelen sköter

4

Interface mellan Simulink och Gestpan

kommunikationen mellan beräkningsdelen och MATLAB genom funktionen mexFunction och dess parametrar prhs, nrhs, plhs och nlhs. Prhs är en sträng av ”högerhandsargument” (PointerRightHandSide) dvs inparametrar i funktionsanropet i MATLAB som kan se ut som nedan:

>>[A,B] = mexfunktionen(C,D)

I detta fallet innehåller prhs C och D. Plhs innehåller på samma sätt en sträng av utparametrar, dessa läggs i A och B. Nrhs och nlhs innehåller antalet in- och utparametrar respektive. Trots att mexFunction ser ut att vara en funktion anropar MATLAB den som en subrutin. Såhär skall funktionshuvudet i C se ut:

void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])

Med hjälp av en speciellt strängstruktur – mxArray – tas värden in i kommunikationsdelen, behandlas i beräkningsdelen och skickas tillbaka som returdata till MATLAB.

MEX-filer har flera användningsområden [2]:

• Stora existerande C och Fortranprogram kan anropas från MATLAB utan att behöva bli omskrivna som m-filer.

• Långsamma beräkningar som for-loopar kan kodas i C eller Fortran för att öka effektiviteten.

Då det fanns två sätt att skapa ett interface mot motormodellen, dels genom att skapa en MEX-fil som beskrivits ovan samt genom en S-funktion som beskrivs nedan, valdes vägen att titta närmare på S-funktionen då det fanns en tidigare applikation på VAC uppbyggt på detta sätt. Det skulle dock gått lika bra att fortsätta att titta på en applikation baserad på en MEX-fil.

2.3 Simulink Simulink är ett verktyg i MATLAB för simulering och modellkonstruktion [4]. Det baseras på ett grafiskt gränssnitt som ger en lättöverskådlig bild av modellen man byggt. Man kan på ett enkelt sätt bygga en modell med komponenter ur ett standardbibliotek. Om dessa komponenter inte räcker till kan man även skapa egna, baserade på extern kod skriven i t.ex. C eller Fortran. Då kallas de S-funktioner. En speciell komponent kallad S-funktion, se Figur 3, kan då anropa den egendefinierade programkoden.

5

Interface mellan Simulink och Gestpan

Figur 3 Komponenten S-Function i Simulink

2.3.1 S-funktioner

En S-funktion är ett Simulinkblock med funktionaliteten skriven i ett annat programspråk, t.ex. Ada, C, C++, Fortran eller MATLAB. Då en S-funktion skriven i C kompileras blir den en så kallad C-MEX-S-funktion-fil. En MEX-fil har olika filändelse beroende på operativsystem [2]. I Windows får MEX-filen filändelsen ".dll", dvs Dynamic Link Library, se Tabell 1 nedan. Denna dll-fil är körbar inifrån Simulink.

Tabell 1 MEX-filers filändelser i olika operativsystem

Plattform MEX-fils filändelse

Alpha .mexaxp

HP, version 10.20 .mexhp7

HP, version 11.x .mexhpux

IBM RS/6000 .mexrs6

Linux .mexglx

SGI, SGI64 .mexsg

Solaris .mexsol

Windows .dll

S-funktioner använder en speciell anropssyntax som tillåter samverkan med Simulinks inbyggda ekvationslösare, se avsnitt "S-funktionens struktur" (2.3.1.2). Denna samverkan är mycket lik den som sker mellan ekvationslösare och inbyggda

6

Interface mellan Simulink och Gestpan

Simulinkblock. S-funktionen har en mycket allmän form och kan tillgodose kontinuerliga, diskreta och hybrida system.

2.3.1.1 Maskning

För att anpassa användargränssnittet på S-funktionen kan man använda sig av maskning för att skapa ett eget gränssnitt, en egen mask över Simulinks eget gränssnitt. Med hjälp av en inbyggd editor, se Figur 4 nedan, skapar man ett eget gränssnitt mellan Simulink och S-funktionen. Här kan man designa utseendet på Simulinkblocket, samt koppla parametrar som skall skickas med till S-funktionen tillsammans med insignalen/insignalerna. Dessa parametrar kan vara styrparametrar som man bara skickar en gång. Med hjälp av maskning kan man på ett enkelt sätt styra parameterinmatning och samtidigt få ett blockutseende som passar till S-funktionen man skapat.

Figur 4 Maskningseditorn, här skapas utseende och länkar till S-funktionen

Under fliken ”Icon” ger man S-funktionsblocket dess utseende. Här kan man tex lägga in en illustrativ bild eller skriva en text som förklarar innehållet i S-funktionen.

7

Interface mellan Simulink och Gestpan

Figur 5 S-funktionsblock med bild som ikon

Om man använder sig av S-funktionsparametrar som skickas till S-funktionen behandlar man dem under fliken ”Parameters”. Här skapar man även utseendet på den dialogbox som kommer upp då man dubbelklickar på S-funktionsblocket, se Figur 6 nedan.

Figur 6 Dialogbox för inställning av S-funktionsparametrar i en maskad S-funktion

Under maskeditorns flik ”Documentation” lägger man text som syns i ”Block Parameters”, tex namnet på S-funktionen och en kort beskrivning. Även hjälptext om S-funktionen kan man lägga till. Denna visas då man klickar på knappen Help.

Fliken ”Initialization” låter användaren med hjälp av MATLAB-kommandon initialisera den maskade S-funktionen. Dessa kommandon utförs när:

• modellen öppnas.

• en simulering startas eller om blockdiagrammen uppdateras.

• den maskade modellan roteras.

• utseendet på masken ändras, tex kan utseendet bero på initieringsvariabler.

8

Interface mellan Simulink och Gestpan

2.3.1.2 S-funktionens struktur

För att anropssyntaxen skall fungera krävs att den är uppbyggd med en speciell struktur, se mer i bilaga 1, som beskrivs nedan. Strukturen är densamma för alla språk men syntaxen ser naturligtvis olika ut.

• Initiering

S-funktionen initierar SimStruct, en simuleringsstruktur som innehåller information om S-funktionen. Den sätter nummer och dimensioner på in- och utgångar samt sätter ”block sample time”. Även allokering av minne och den sk ”sizes”-strängen allokeras.

• Beräkning av nästa sampel

Sätter tiden till nästa sampel.

• Beräkning av utgångarna

Här tas värdet från ingångar in, bearbetas och skickas tillbaka på utgången. Det är även här som anrop till eventuella externa funktioner ligger, som i detta fallet anrop mot motormodellen.

• Uppdatera eventuella diskreta tillstånd

Om det finns tillstånd i modellen.

• Integration

Alla delar i denna struktur är inte obligatoriska, man kan alltså hoppa över vissa delar beroende på karaktären på sin modell. De som inte kan undvikas är initieringen, beräkningen av nästa sampel och utgångsberäkningen.

2.3.1.3 Länka med hjälp av mex

Då man vill utnyttja möjligheterna med en S-funktion av level 2, som ger funktionalitet med nyare versioner av Simulink med Fortrankod, måste man skriva ett skelett i C som tjänstgör som ett interface mellan Simulink och Fortranprogrammet. Att använda C-MEX S-funktioner är relativt enkelt om man inte skrivit sitt Fortranprogram innan. Om Fortrankoden redan existerar kan det bli mer komplicerat. Vissa delar av koden kan behöva registreras av Simulink för att S-funktionen skall fungera.

För att mex-kommandot skall fungera måste det först konfigureras. Detta för att det skall känna till vilka kompilatorer som finns installerade på datorn och för att sätta sökvägar till filer som kommandot sedan använder. Konfigurationen av mex-kommandot görs genom att köra mex med flaggan ”-setup”. Inga andra flaggor får sättas då denna sätts.

>> mex -setup

9

Interface mellan Simulink och Gestpan

Då detta kommando körs letar mex upp de kompilatorer som installerats och ber användaren välja ut en. Om man redan kompilerat sina Fortranfiler i en extern kompilator behöver man bara kompilera sin C-fil. I detta fallet väljer man en lämplig C-kompilator som mex hittat och denna kommer då att användas vid skapandet av S-funktionen.

För att Simulink skall kunna använda sig av den funktionalitet man skapat med sin S-funktion måste man länka samman de filer man skapat. Detta görs med hjälp av mex-kommandot. Man börjar med att kompilera Fortranfilerna till objektsfiler, dvs filer med filändelsen ".obj". Detta kan göras inifrån MATLAB eller med en extern kompilator. Dessa länkas sedan samman med S-funktionen genom följande syntax som skrivs i MATLAB:s kommandofönster eller i en m-fil.

>> mex MinCfil.c MinFortranfil.obj MinFortranModul.obj

Detta är mex-kommandot i sin enklaste form. Ofta är man tvungen att lägga till vissa länkflaggor, som behandlas i avsnittet slutsatser (6).

Då S-funktionen anropas från MATLAB måste den följa vissa regler och namnkonventioner för att det skall fungera. Den måste därför vara uppbyggd enligt en mall för S-funktioner. Denna mall finns att tillgå och ligger i MATLAB:s undermapp [MATLAB]\simulink\src\. Filen heter sfuntmpl_basic.c (bilaga 1) och det finns även en grundläggande förklaring till mallen i filen sfuntmpl_doc.c (bilaga 2). En speciell mall för S-funktioner från C till Fortran är filen sfuntmpl_gate_fortran.c (bilaga 3).

2.4 Fortran Fortran [5] är ett programmeringsspråk för teknisk och vetenskaplig databehandling. Namnet kommer av engelskans formula och translation, dvs formelöversättning. Språket konstruerades på IBM 1954 och var det första språk som tillät en syntax som liknade det matematiska med formler. Språket spred sig snabbt till företagens beräkningsavdelningar. Den första standarden kom 1966 och sedan har nya utkommit 1977, -90 och -95. Då Fortran är relativt maskinnära är det tidseffektivt och minnessnålt. En strikt standard har gynnat språket trots dess något ålderdomliga struktur.

2.4.1 Moduler i Fortran

Då man bygger stora och komplexa program i Fortran använder man sig av moduler [6]. En modul är en del av ett program som sköter en specifik uppgift. Man kan lägga både subrutiner och funktioner i moduler. Man väljer sedan vilka moduler man vill använda sig av med hjälp av kommandot ”use ModulNamn”. På detta sätt byggs en struktur av moduler upp och man behöver inte göra alla moduler ”globala” utan de begränsas till det stället de behövs. En modul kan alltså använda en eller flera moduler som i sin tur använder andra moduler. Funktioner och subrutiner i en modul kan både vara synliga

10

Interface mellan Simulink och Gestpan

och osynliga för användaren. Detta sköts med kommandona private/public. Genom att ange private innan de innehållande subrutinerna sätts alla dessa till att bara vara synliga för modulen, sedan ”låser man upp” de subrutiner man vill göra synliga för anrop utifrån modulen med public.

2.5 RM12 Multipurpose model/Gestpan Motormodellen RM12 Multipurpose Model [8] är en motormodell av motorn RM12. Modellen är i dagsläget (030321) en modell för statiska beräkningar. Modellen är en del av Gestpan, ett analysverktyg för lösning av olinjära ekvationssystem och ordinära differentialekvationer (ODE). Statiska motormodeller leder till olinjära ekvationssystem och dynamiska modeller till ODE:er. I Gestpan ligger förutom moduler för ekvationslösare även moduler som implementerar ett användargränssnitt. Detta gränssnitt administrerar indata och utdata samt anropar de ovan nämda lösarna. Därigenom anropas också de moduler som implementerar den motorfysik kring vilken RM12 Multiporpose Model är uppbyggd. Både Gestpan och den del av Gestpan som utgör motormodellen är skrivna i Fortran 90 och är uppbyggda av ett stort antal moduler.

3 Framtagning av interface För att nå fram till delmålet att få ett statiskt interface till Multipurpose modellen, vilket var målet med detta exjobb, byggdes ett antal "mini-interface". Dessa testade delfunktionalitet för att sedan sättas samman till ett större interface. Allt gjordes enligt modellen "en-ändring-i-taget" för att isolera problem och skapa så enkla delproblem som möjligt, samt för att inte riskera inblandning från okända problem. Först kommer en beskrivning hur testinterface togs fram för att sedan gå in på det verkliga interfacet som arbetade mot hela Multipurpose modellen.

3.1 Testinterface Till att börja med skapades ett så enkelt testinterface som möjligt, se Figur 7. Utgående från ett program från Simulinks eget demonstrationsbibliotek, bl.a. timestwo och sfun_atmos, skapades en S-funktion i C som anropade ett enkelt Fortranprogram som bara satte utsignalen till tre gånger insignalen och skickade detta tillbaka till S-funktionen. Då det framtida interfacet skulle anropa Fortrankod uppbyggt av ett stort antal moduler byggdes det första testinterfacet upp på samma sätt, dvs S-funktionen anropar en subrutin i ett Fortranprogram som bara skickar parametrarna vidare till en Fortranmodul som tar emot parametrarna, gör beräkningen och sedan skickar tillbaka svaret som till sist når ända tillbaka till Simulink.

11

Interface mellan Simulink och Gestpan

S-funktion C

Subrutin Fortran

Modul Fortran Simulink

Figur 7 Uppbyggnad av det första testinterfacet

Detta interface modifierades sedan till flera liknande interface för att testa funktionalitet på diverse funktioner. Bland annat skulle parametrar av olika typ, bla heltal, flyttal och teckensträngar kunna skickas. Dels från Simulink till S-funktionen men också från S-funktionen till Fortranmodulen. För att minimera risken för fel gjordes dessa små program så enkla som möjligt.

En av de konstateranden som kunde göras med dessa elementära kodsnuttar var att det var nödvändigt att gå via Fortran-subrutinen, i enligthet med Figur 7, dvs en direkt kopplingen mellan S-funktionen och Fortranmodulen var inte möjlig.

3.1.1 Externa funktionsanrop från C till Fortran

Då S-funktionen anropar en subrutin som ligger i en annan fil och till och med är skriven i ett annat programspråk måste man deklarera detta anrop. Detta görs i deklarationsdelen av S-funktionen. Här anger man namnet på den externa rutinen och vilken typ av parametrar som skall skickas och tas emot, se nedan.

Deklaration av extern Fortanfunktion kan se ut som följande, skrivet i C:

extern void gestpan_subr_(char *, int, // model_name

int *, // n_input

char *[], int, // input_names+length

double *[], // input_vector

int *, // n_output

char *[], int, // output_names+length

double *[]); // output_vector

12

Interface mellan Simulink och Gestpan

Då Fortran internt skickar ”osynliga” längdangivelser på strängparametrar av typen char(len=*), dvs teckensträngar, måste man skicka med dessa speciellt då man anropar Fortrankod från C. Detta syns vid parametrarna ”input_names” och ”output_names” som efterföljs av ett heltal. Den anropade Fortransubrutinen gestpan_subr() har alltså bara sju (synliga) argument men man skickar nio.

Anropet från C på den externa subrutinen som ligger i Fortranfilen ser ut på följande sätt:

gestpan_subr_(&model_name, model_name_len,

&n_input,

&input_names[0], input_names_len,

&input_vector[0],

&n_output,

&output_names[0], output_names_len,

&output_vector[0]);

där parametrarna med ett ”&”-tecken före skickas ”by-reference” dvs som referenser till adresser och parametrarna utan ”&”-tecken skickas som värden (by-value).

3.1.2 Cellmatris i MATLAB

För att på ett enkelt sätt komma åt de parametrar som skall skickas från Simulink till C-filen används en cellmatris i MATLAB. En cellmatris [7] är en speciell MATLAB-matris vars element är celler, dvs de kan innehålla andra MATLAB matriser. En cell i en cellmatris kan t. ex. innehålla en sträng av flyttal medan en annan innehåller ett heltal och en tredje en textsträng, de kan alla ha olika typ och är oberoenda av varandra förutom att de ligger i samma cellmatris. En cellmatris kan skapas på två sätt, dels genom att för-allokera en cellmatris med önskad storlek eller genom att tilldela en cell i en cellmatris ett innehåll, mha ”krullparanteser” {}, som då automatiskt allokeras till rätt storlek.

• Förallokering av cellmatris

• Tilldelning av innehåll

Kommandot:

>> a = cell(2, 2);

förallokerar en cellmatris med två rader och två kolumner, dvs fyra celler. Cellerna är efter detta kommando allokerade men inte fyllde med något innehåll.

Om man istället tilldelar en cell värden direkt skriver man på följande sätt:

>> b{1,1} = [1 2; 3 4];

13

Interface mellan Simulink och Gestpan

Detta skapar och allokerar en endimensionell cellmatris där den enda cellen innehåller en matris av storlek (2x2). Tilldelar man sedan cellen b{1, 2} i cellmatrisen utökas b:s storlek till att bli (2x2). Det kan efter flera tilldelningar sedan se ut på följande sätt.

17

3-4j

1 2

3 4

6 8 10 12 14

Figur 8 Exempel på en cellmatris med fyra celler

För att på ett enkelt sätt kunna skicka parametrarna till S-funktionen skapades en cellmatris i MATLAB där alla parametrar lagrades. Denna matris såg ut på detta sätt:

input.names input.vector

output.names output.vector

model_name

Gestpan_par

Figur 9 Cell-matrisen Gestpan_par som initialiserar parametervärden

Denna initialisering skapades i en m-fil (bilaga 5) med följande kommandon:

Gestpan_par.model_name = {'rm12_mp.txt'};

Gestpan_par.input.names = {'altitude';'M';'delta_t_amb';'pla'};

Gestpan_par.input.vector = {0;0;0;30};

14

Interface mellan Simulink och Gestpan

Gestpan_par.output.names = {'t41'};

Gestpan_par.output.vector = {[]};

Dessa rader sätter parametrarna som skickas till Gestpan. Den första raden talar om vilken initieringsfil som skall användas. Gestpan_par.input.names anger vilka inparametrar som skall användas och Gestpan_par.input.vector anger dess värden. Gestpan_par.output.names anger vilken parameter/parametrar i modellen man vill titta på som utsignal och den sista raden allokerar utrymme för detsamma.

3.1.2.1 Åtkomst av cellmatrisparametrar från C-filen

För att komma åt parametrar från C-filen som ligger i en cellmatris i MATLAB och skickas som parametrar från S-funktionen går man tillväga på ett speciellt sätt. Först måste man skapa en länk till parametern man vill åt, detta görs med kommandot ssGetSFcnParam(S, nr), där nr anger ordningsnumret på parametern i parameterlistan (se Figur 4 på sidan 3). För att lättare kunna arbeta med parametern kan man ge den ett namn, genom en define-sats. Följande exempel hämtar den första parametern, med indexvärde 0, och ger den namnet MODEL_NAME.

#define MODEL_NAME(S) ssGetSFcnParam(S, 0)

Man kan sedan definiera sin parametrar på lämplig sätt. För att sedan i C-filen komma åt innehållet i parametern måste man ta hänsyn till innehållet i parametern. Är det en teckensträng eller en vektor av teckensträngar använder man sig av kommandot mxGetString. Är det en vektor med bara skalärer använder man istället mxGetCell.

3.1.2.1.1 Åtkomst av teckensträngar

Följande kodsnutt hämtar parametern INPUT_NAMES(S) som innehåller fyra teckensträngar och lägger innehållet i vektorn input_names[i].

for (i=0; i<4; i++) {

cell_element_ptr = mxGetCell(INPUT_NAMES(S),i);

mxGetString(cell_element_ptr,input_names[i],1+mxGetN(cell_element_ptr))

}

där följande deklarationer gjorts innan:

int i;

char input_names[4][32];

const mxArray *cell_element_ptr;

15

Interface mellan Simulink och Gestpan

Kommandot mxGetString tar innehållet i första argumentet (cell_element_ptr) och lägger över i det andra argumentet (input_names[i]) med det antal tecken som anges i det tredje argumentet (1+mxGetN(cell_element_ptr)).

3.1.2.1.2 Åtkomst av skalärer Då man vill komma åt en parameter som är en skalär eller en vektor av skalärer är det lite lättare. Istället för att använda kommandot mxGetString kan man med kommandot mxGetScalar direkt lägga innehållet i cellen där man vill ha det. Det kan se ut som följer: for (j=0; j<4; j++) { cell_element_ptr = mxGetCell(INPUT_VECTOR(S),j); input_vector[j] = mxGetScalar(cell_element_ptr); }

där cell_element_ptr och j är deklarerad som ovan men input_vector som nedan.

double input_vector[4];

Här läggs innehållet i INPUT_VECTOR[j] i input_vector[j], skalär för skalär.

3.1.3 Typer och precision, C kontra Fortran

Då man skapar en applikation bestående av filer skrivna i olika språk måste man tänka på hur man hanterar datatyperna i de olika språken. Det kan finnas ett större eller mindre antal standardtyper som skall matchas i de olika språken för att det skall fungera. Oftast är det relativt lätt med skalärer men mer komplicerat att hantera t. ex. teckensträngar. I Tabell 2 visas hur ett antal typer skall användas mellan språken C och Fortran.

Tabell 2 Ekvivalenta datatyper i Fortran och C

Fortran datatyp C datatyp

INTEGER(1) char

INTEGER(2) short

INTEGER(4) int

REAL(4) float

16

Interface mellan Simulink och Gestpan

REAL(8) double

CHARACTER(1) unsigned char

CHARACTER*(*) Char[], se även 3.1.3.1 nedan

3.1.3.1 Datatypen CHARACTER*(*) i Fortran

Då man vill skicka teckensträngar eller vektorer av teckensträngar från C till Fortran måste man skicka med ett ”gömt” argument, se även 3.1.1. Detta skall ligga precis efter teckensträngen och innehålla längden på teckensträngen. Detta för att Fortran internt skickar med detta argument vid funktionsanrop och därför förväntar sig ett sådant trots att anropet kommer från en extern C-kod.

3.1.3.2 Precision i Fortran

I Fortran finns möjligheten att sätta precisionen [6] på sina beräkningar genom kommandona KIND och SELECTED_REAL_KIND(). Genom följande rader sätts precisionen på variabeln tal till 12 värdesiffror.

rp = SELECTED_REAL_KIND(12)

REAL(KIND=rp) :: tal

Kompilatorn kommer sedan använda detta när den väljer vilken av typerna REAL() den skall använda beroende på vilken plattform man kompilerar på. Detta gör konstruktionen mycket dynamisk då den är förberedd för framtida förbättringar i plattformarna.

Denna kontruktion används i motormodellen och det har därför eftersträvats att skapa samma dynamiska tankesätt i C-koden. Det har dock varit svårt att hitta en liknande kontruktion. Detta sköts i dagsläget av C-kompilatorn.

3.1.4 Debugga C-MEX S-funktionen

Då man vill debugga sin S-funktion kan man göra detta på ett enkelt sätt om man använder sig av Microsoft Visual C++. Man kanske vill se hur en parameter uppför sig efter vissa kommandon eller vad innehållet i parametern är och att den t. ex. allokeras korrekt. Man börjar då med att länka ihop sina filer mha mex till en dll-fil. Denna öppnas sedan i MS Visual C++. Dess namn kommer då att stå innan Microsoft Visual C++ högst upp i programramen. Om man har ett program öppet i editorn kommer kommer detta eventuellt att stängas ner. Man öppnar sedan sin C-Mex S-funktion, dvs C-filen, och väljer ”Settings…” i menyn ”Projects”.

17

Interface mellan Simulink och Gestpan

Figur 10 Dialogbox för inställning av debugfil

Här väljer man fliken Debug och i rutan ”Executable for debug session:” skriver man sökvägen till ikonen man använder för att starta MATLAB (dvs till MATLAB.exe). Man kan även bläddra sig fram till rätt ikon. Man kan sedan sätta breakpoints och debugga genom att välja ”Build”, ”Start Debug” och ”Go”, alternativt trycka F5. MS Visual C++ kommer då att öppna MATLAB och där startar man simuleringen i den modell man vill använda. Man kommer sedan tillbaka till MS Visual C++ och det ställe i koden där man satt sin breakpoint.

Debuggning är ett mycket kraftfullt vapen för att hitta fel som uppkommit i koden. Man kan på detta sätt enkelt kontrollera att man skrivit rätt. Men det skall också nämnas att man då man skriver applikationer i blandade språk inte alltid helt kan lita på vad man ser. Dagens moderna programvaror förenklar ibland vissa saker för användaren som är till nackdel då man inte alltid har full kontroll på vad som sker. Man får då ta till ”råare” metoder för att återta kontrollen.

3.2 Statiskt interface När testinterfacet var klart och fungerade mot en "mini-modell", som bara hade en bråkdel av funktionaliteten av den riktiga modellen men ändå kunde testa överföringen av parametrarna, kompilerades S-funktionen, bilaga 4, och länkades ihop med hela motormodellen. Då motormodellen är skriven och testad mot Compaqs Visual Fortran kompilator måste den kompileras med en kompilator av samma typ, dvs versionen på kompilatorn har betydelse. Det framkom att den endast kunde kompileras med versionen 6.1 och 6.5. Nyare och äldre kompilatorer gav ett felaktigt resultat.

18

Interface mellan Simulink och Gestpan

Då vissa problem med parametrarna upptäcktes gjordes vissa ändringar i motormodellen för att underlätta skickandet av parametrarna, detta beskrivs nedan (3.2.1).

I ett statiskt interface tar man inte hänsyn till tiden utan bortser från tidsvarianta förlopp och insvängningsförlopp. Man tittar alltså på signalen efter oändligt lång tid. I ett interface för dynamiska simuleringar måste man ta hänsyn till tidsvariabeln också. Detta hanns inte med i detta arbete utan lämnades till en eventuell fortsättning.

De parametrar som skickas in i det statiska interfacet är altitude (höjd över havet i meter), M (hastigheten i mach), delta_t_amb (omgivningstemperaturen i Kelvin) och pla (gaspådraget). Man kan sedan titta på en signal i modellen som utsignal för att se hur den uppför sig vid olika förhållanden.

3.2.1 Initiering av parametrar

Då parametrar skickas mellan de olika rutinerna är det viktigt att de bara innehåller vad som avses. Det är lätt att det kommer med tecken som inte bör finnas där. För att stävja detta problem måste man vara noggrann vid initieringen av sina parametrar samt även då de fylls med innehåll. Då en teckensträng deklareras i C utan att initialiseras fylls den med skräptecken, dvs nedanstående deklarering är inte så bra:

char input_names[4][32];

Ett steg längre är att försöka med följande deklarering med en initialisering:

char input_names[4][32] = {{""},{""},{""},{""}};

Denna initialisering skapar samma skräptecken i alla positioner och är alltså inte heller den så bra. Genom följande konstruktion kan man tömma alla positioner i strängen.

char input_names[4][32] = {{" "},

{" "},

{" "},

{" "}};

Ovan är varje ”tom-rad” 32 tecken lång.

Då man sedan fyller strängen med innehåll kommer det att läggas ett strängslutstecken efter varje strängrad. För att komma förbi detta problem konstruerade Tomas i sin modell en funktion som rensar bort tecken som inte skall vara med i parametrarna. Denna snurra läser bakifrån i strängen tills den hittar ett tecken den känner igen och fyller då detta utrymme med blanktecken.

3.2.2 Länkning med hjälp av mex

Vid länknigen av de filer som skulle ingå i dll-filen sattes vissa länkflaggor. Länkningen gjordes i en m-fil. De länkflaggor som sattes var hänvisningar till ett antal

19

Interface mellan Simulink och Gestpan

biblioteksfiler från Fortran, utan dessa kunde inte länkningen genomföras på ett korrkt sätt. Dessa var: dformd.lib, dfconsol.lib och dfport.lib. Även sökvägen till dessa bifogades: /LIBPATH:$DF_ROOT\DF98\LIB. Denna sökväg förutsäter att man konfigurerat mex-kommandot på ett korekt sätt.

Då ett ”default-bibliotek” störde de tidigare bibioteken togs detta bort med hjälp av följande kommando: /NODEFAULTLIB:libc.lib.

Det fullständiga länkkommandot var alltså som följer, där allt skall stå på en rad: mex LINKFLAGS#"$LINKFLAGS dformd.lib dfconsol.lib dfport.lib /LIBPATH:$DF_ROOT\DF98\LIB /NODEFAULTLIB:libc.lib" sfun2for.c ../gestpan_matlab_libfile/lib/gestpan/Debug/*.obj

4 Simuleringar Ett antal simuleringar gjordes under arbetes gång för att verifiera kod och idéer. Dessa kommer inte att redovisas då resultatet av dessa är förklarat tidigare i texten. Mot slutet av arbetet blev simuleringarna mer intensiva och då körningen av det statiska intefacet ansågs klart kördes detta ett antal gånger, dock med negativt resultat. Simuleringen i Simulink och den följande körningen av modellen utfördes men fel uppkom på vägen som gjorde att ingen utsignal skickades tillbaka till Simulink. Om detta fel låg i Gestpan eller i C eller i Simulink har ännu inte kunnat upptäckas. Troligtvis ligger felet i övergången mellan C-filen och Simulink. Den slutliga produkten har därför inte kunnat verifieras utan arbetet måste här fortsätta för att få fram en fungerande S-funktion, verifiera denna mot ett annat interface i Gestpan som redan finns tillgängligt.

5 Resultat Arbetet resulterade i en ny S-funktion som var ett statiskt interface mot Multipurpose modellen. Den nya S-funktionen initialiseras med fyra insignaler, altitude, M, delta_t_amb och pla. Altitude betecknar flyghöjden i meter över markytan, M anger hastigheten i mach, delta_t_amb avvikelsen från omgivningstemperaturen i Kelvin och slutligen pla som anger gaspådraget. Alla parametrar måste ges rimliga värden för att modellen skall fungera. Dessa anges i Tabell 4, och skall endast ses som en grov uppskattning för att kunna skicka parametrar som ej är orimliga. En uppsättning rimliga parametervärden för insignalerna i modellen kan alltså vara:

Tabell 3 Använda parametervärden

altitude 0.0 M 0.0 delta_t_amb 0.0 pla 30.0

20

Interface mellan Simulink och Gestpan

Dessa värden har använts vid simuleringarna av programmet men enligt Tabell 4 och Figur 11 nedan kan andra värden användas.

Tabell 4 Rimliga parametervärden

Parameter ~ Min ~ Max

altitude 0-11000, beror på M 6000-18000, beror på M

M 0-0.8, beror på altitude 1.2-2, beror på altitude

delta_t_amb -20 20

pla 17 130

Sambandet mellan altitude och M kan grovt uttryckas med följande skiss:

18km

11km

1,2 2,0

altitude

M

Figur 11 Sambandet mellan altitude och M, en flygenvelopp

Området innanför den heldragna linjen och axlarna kallas flygenveloppen och illustrerar det område där värdena tillåts ligga.

Den parameter man vill titta på inne i motormodellen anger man i output_names, i initieringsfilen. Modellen tar sedan fram det statiska värdet på denna parameter baserat på värdet på insignalerna.

6 Slutsatser Då man skapar en applikation som innehåller kod från olika programmeringsspråk och dessa behandlas i olika programmiljöer är det lätt att det uppkommer fel som just beror av komplexiteten av en ”blandspråksapplikation”. Vissa hjälpmedel finns för att

21

Interface mellan Simulink och Gestpan

underlätta arbetet, t. ex. möjligheten att debugga. Men ibland hjälper inte ens detta för att hitta fel. Det gäller också att man vet hur kompileringen av filerna sker, om det finns kompileringsflaggor som skall sättas mm. Även länkningen av filerna kan ställa till med problem då det även här finns flaggor och länkbibliotek som måste tas med i beräkningen.

Då olika versioner av samma programvara kan uppföra sig på olika sätt gäller det också att ta hänsyn till detta. Även kompatibiliteten mellan olika programvaror som används kan ställa till med problem då de inte fungerar ihop på bästa sätt från början utan måste anpassas på ett eller annat sätt för att de skall fungera ihop.

Även datorn man arbetar på måste förberedas på rätt sätt för att t. ex. sökvägar och annat skall vara rätt konfigurerade.

6.1 Analys av resultat Då den slutliga versionen av interfacet inte kunnat testats på ett tillräckligt tillfredsställande sätt är det svårt att analysera resultatet. Förhoppningsvis kommer det nu påbörjade arbetet att fortsätta och leda fram till framtida framgångsrika tester och resultat inom detta område.

6.2 Rekommendationer till fortsatt arbete Då det var svårt att uppskatta tidsåtgången för den första versionen av interfacet sattes målet lågt men skarpt, dvs att först och främst få fram ett statiskt interface och om detta kunde framställas på kort tid gå vidare med ett dynamiskt interface. Diverse problem på vägen gjorde att endast målet med ett statiskt interface nåddes. Det skulle dock vara önskvärt att gå vidare i detta projekt och även skapa ett dynamiskt interface. Detta skulle då kunna bygga på kod från detta projekt samt kräva en del tillägg och nykodning.

Då precisionen i Gestpandelen är satt med plattformsoberoende kommandon kommer denna del att fungera väl i framtida uppgraderade och starkare plattformar t. ex. 64-bitars. Detta är inte fallet i delen skriven i C utan där sker all precisionshantering av kompilatorn. Ett fortsatt arbete skulle kunna vara att titta närmare på om det i C är möjligt att även här skapa en liknande konstruktion som i Gestpandelen. Kan man alltså koda in precisionen även i C-kod? Just nu används dubbel precision i C-koden som vid kompilering på ett 32-bitars system kommer fungera väl tillsammans med Gestpan och motormodellen.

Vid länkningen av filerna i applikationen som sköts med hjälp av mex-kommandot i MATLAB länkas ett antal biblioteksfiler med. Detta rekommenderas av Mathworks och

22

Interface mellan Simulink och Gestpan

görs även i deras exempel. Dessa har till avsikt att förbättra och underlätta samarbetet mellan C- och Fortran- applikationer i en ”blandspråksapplikation”, eller som det vanligen brukar uttryckas på engelska, ”mixed-language-programming”.

23

Interface mellan Simulink och Gestpan

Referensförteckning

Bok:

1 VOLVO RM12, Motorn i JAS 39 Gripen, motorkurs för Saabs typkurs fpl 39, december 2002

2 The MathWorks. 2002. MATLAB, External Interfaces. Version 6. Natick, Massachusetts. The MathWorks, Inc.

3 The MathWorks. 2002. Simulink, Writing S-Functions. Version 5. Natick, Massachusetts. The MathWorks, Inc.

4 The MathWorks. 2002. Simulink, Using Simulink. Version 5. Natick, Massachusetts. The MathWorks, Inc.

Elektronisk källa:

5 Nationalencyklopedien. Uppslagsord: Fortran. www.ne.se. 030115.

Bok:

6 Chapman, S, J. 1998. Fortran 90/95, For Scientists and Engineers. Boston, Massachusetts. McGraw-Hill.

7 Chapman, S, J. 2002. MATLAB® Programming for Engineers. 2:a upplagan. Pacific Grove, Kalifornien. Brooks/Cole

Internt Volvodokument:

8 Grönstedt, T. RM12 multipurposemodell - verifierings- och implementeringsrapport, Rapportnr. 2002VAC001970.

24

Interface mellan Simulink och Gestpan

7 Bilagor Ett antal bilagor finns med i rapporten för att öka förståelsen och ge en mer detaljerad bild av vissa detaljer.

Tabell 5 Bifogade bilagor

Bilaga nr

Innehåll

1 sfuntmpl_basic.c

2 sfuntmpl_doc.c

3 sfuntmpl_gate_Fortran.c

4 sfun2for.c

5 init.m

25

Bilaga 1

/* * sfuntmpl_basic.c: Basic 'C' template for a level 2 S-function. * * ------------------------------------------------------------------------- * | See matlabroot/simulink/src/sfuntmpl_doc.c for a more detailed template | * ------------------------------------------------------------------------- * * Copyright 1990-2000 The MathWorks, Inc. * $Revision: 1.24 $ */ /* * You must specify the S_FUNCTION_NAME as the name of your S-function * (i.e. replace sfuntmpl_basic with the name of your S-function). */ #define S_FUNCTION_NAME sfuntmpl_basic #define S_FUNCTION_LEVEL 2 /* * Need to include simstruc.h for the definition of the SimStruct and * its associated macro definitions. */ #include "simstruc.h" /* Error handling * -------------- * * You should use the following technique to report errors encountered within * an S-function: * * ssSetErrorStatus(S,"Error encountered due to ..."); * return; * * Note that the 2nd argument to ssSetErrorStatus must be persistent memory. * It cannot be a local variable. For example the following will cause * unpredictable errors: * * mdlOutputs() * { * char msg[256]; {ILLEGAL: to fix use "static char msg[256];"} * sprintf(msg,"Error due to %s", string); * ssSetErrorStatus(S,msg); * return; * } * * See matlabroot/simulink/src/sfuntmpl_doc.c for more details. */ /*====================* * S-function methods * *====================*/ /* Function: mdlInitializeSizes =============================================== * Abstract: * The sizes information is used by Simulink to determine the S-function * block's characteristics (number of inputs, outputs, states, etc.). */ static void mdlInitializeSizes(SimStruct *S) { /* See sfuntmpl_doc.c for more details on the macros below */ ssSetNumSFcnParams(S, 0); /* Number of expected parameters */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { /* Return if number of expected != number of actual parameters */ return; } ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 0); if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, 1); ssSetInputPortRequiredContiguous(S, 0, true); /*direct input signal access*/ ssSetInputPortDirectFeedThrough(S, 0, 1);

1

Bilaga 1

if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, 1); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); ssSetOptions(S, 0); } /* Function: mdlInitializeSampleTimes ========================================= * Abstract: * This function is used to specify the sample time(s) for your * S-function. You must register the same number of sample times as * specified in ssSetNumSampleTimes. */ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); } #define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */ #if defined(MDL_INITIALIZE_CONDITIONS) /* Function: mdlInitializeConditions ======================================== * Abstract: * In this function, you should initialize the continuous and discrete * states for your S-function block. The initial states are placed * in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S). * You can also perform any other initialization activities that your * S-function may require. Note, this routine will be called at the * start of simulation and if it is present in an enabled subsystem * configured to reset states, it will be call when the enabled subsystem * restarts execution to reset the states. */ static void mdlInitializeConditions(SimStruct *S) { } #endif /* MDL_INITIALIZE_CONDITIONS */ #define MDL_START /* Change to #undef to remove function */ #if defined(MDL_START) /* Function: mdlStart ======================================================= * Abstract: * This function is called once at start of model execution. If you * have states that should be initialized once, this is the place * to do it. */ static void mdlStart(SimStruct *S) { } #endif /* MDL_START */ /* Function: mdlOutputs ======================================================= * Abstract: * In this function, you compute the outputs of your S-function * block. Generally outputs are placed in the output vector, ssGetY(S). */ static void mdlOutputs(SimStruct *S, int_T tid) { const real_T *u = (const real_T*) ssGetInputPortSignal(S,0); real_T *y = ssGetOutputPortSignal(S,0); y[0] = u[0]; }

2

Bilaga 1

#define MDL_UPDATE /* Change to #undef to remove function */ #if defined(MDL_UPDATE) /* Function: mdlUpdate ====================================================== * Abstract: * This function is called once for every major integration time step. * Discrete states are typically updated here, but this function is useful * for performing any tasks that should only take place once per * integration step. */ static void mdlUpdate(SimStruct *S, int_T tid) { } #endif /* MDL_UPDATE */ #define MDL_DERIVATIVES /* Change to #undef to remove function */ #if defined(MDL_DERIVATIVES) /* Function: mdlDerivatives ================================================= * Abstract: * In this function, you compute the S-function block's derivatives. * The derivatives are placed in the derivative vector, ssGetdX(S). */ static void mdlDerivatives(SimStruct *S) { } #endif /* MDL_DERIVATIVES */ /* Function: mdlTerminate ===================================================== * Abstract: * In this function, you should perform any actions that are necessary * at the termination of a simulation. For example, if memory was * allocated in mdlStart, this is the place to free it. */ static void mdlTerminate(SimStruct *S) { } /*======================================================* * See sfuntmpl_doc.c for the optional S-function methods * *======================================================*/ /*=============================* * Required S-function trailer * *=============================*/ #ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration function */ #endif

3

Bilaga 2

/* * File: sfuntmpl_doc.c * Abstract: * A 'C' template for a level 2 S-function. * * See matlabroot/simulink/src/sfuntmpl_basic.c * for a basic C-MEX template file that uses the * most common methods. * * Copyright 1990-2000 The MathWorks, Inc. * $Revision: 1.44 $ */ /* * You must specify the S_FUNCTION_NAME as the name of your S-function. */ #define S_FUNCTION_NAME your_sfunction_name_here #define S_FUNCTION_LEVEL 2 /* * Need to include simstruc.h for the definition of the SimStruct and * its associated macro definitions. * * The following headers are included by matlabroot/simulink/include/simstruc.h * when compiling as a MEX file: * * matlabroot/extern/include/tmwtypes.h - General types, e.g. real_T * matlabroot/extern/include/mex.h - MATLAB MEX file API routines * matlabroot/extern/include/matrix.h - MATLAB MEX file API routines * * The following headers are included by matlabroot/simulink/include/simstruc.h * when compiling your S-function with RTW: * * matlabroot/extern/include/tmwtypes.h - General types, e.g. real_T * matlabroot/rtw/c/libsrc/rt_matrx.h - Macros for MATLAB API routines * */ #include "simstruc.h" /* Error handling * -------------- * * You should use the following technique to report errors encountered within * an S-function: * * ssSetErrorStatus(S,"error encountered due to ..."); * return; * * Note that the 2nd argument to ssSetErrorStatus must be persistent memory. * It cannot be a local variable in your procedure. For example the following * will cause unpredictable errors: * * mdlOutputs() * { * char msg[256]; {ILLEGAL: to fix use "static char msg[256];"} * sprintf(msg,"Error due to %s", string); * ssSetErrorStatus(S,msg); * return; * } * * The ssSetErrorStatus error handling approach is the suggested alternative * to using the mexErrMsgTxt function. MexErrMsgTxt uses "exception handling" * to immediately terminate S-function execution and return control to * Simulink. In order to support exception handling inside of S-functions, * Simulink must setup exception handlers prior to each S-function invocation. * This introduces overhead into simulation. * * If you do not call mexErrMsgTxt or any other routines that cause exceptions, * then you should use SS_OPTION_EXCEPTION_FREE_CODE S-function option. This * is done by issuing the following command in the mdlInitializeSizes function: * * ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE); * * Setting this option, will increase the performance of your S-function by * allowing Simulink to bypass the exception handling setup that is usually

1

Bilaga 2

* performed prior to each S-function invocation. Extreme care must be taken * to verify that your code is exception free when using the * SS_OPTION_EXCEPTION_FREE_CODE option. If your S-function generates * an exception when this option is set, unpredictable results will occur. * * Exception free code refers to code which never "long jumps". Your S-function * is not exception free if it contains any routine which when called has * the potential of long jumping. For example mexErrMsgTxt throws an exception * (i.e. long jumps) when called, thus ending execution of your S-function. * Use of mxCalloc may cause unpredictable problems in the event of a memory * allocation error since mxCalloc will long jump. If memory allocation is * needed, you should use the stdlib.h calloc routine directly and perform * your own error handling. * * All mex* routines have the potential of long jumping (i.e. throwing an * exception). In addition several mx* routines have the potential of * long jumping. To avoid any difficulties, only the routines which get * a pointer or determine the size of parameters should be used. For example * the following will never throw an exception: mxGetPr, mxGetData, * mxGetNumberOfDimensions, mxGetM, mxGetN, mxGetNumberOfElements. * * If all of your "run-time" methods within your S-function are exception * free, then you can use the option: * ssSetOptions(S, SS_OPTION_RUNTIME_EXCEPTION_FREE_CODE); * The other methods in your S-function need not be exception free. The * run-time methods include any of the following: * mdlGetTimeOfNextVarHit, mdlOutputs, mdlUpdate, and mdlDerivatives * * Warnings & Printf's * ------------------- * You can use ssWarning(S,msg) to display a warning. * - When the S-function is compiled via mex for use with Simulink, * ssWarning equates to mexWarnMsgTxt. * - When the S-function is used with Real-Time Workshop, * ssWarning(S,msg) equates to * printf("Warning: in block '%s', '%s'\n", ssGetPath(S),msg); * if the target has stdio facilities, otherwise it becomes a comment and * is disabled. * * You can use ssPrintf(fmt, ...) to print a message. * - When the S-function is compiled via mex for use with Simulink, * ssPrintf equates to mexPrintf. * - When the S-function is used with Real-Time Workshop, * ssPrintf equates to printf, if the target has stdio facilities, * otherwise it becomes a call to a empty function (rtPrintfNoOp). * - In the case of Real-Time Workshop which may or may not have stdio * facilities, to generate the most efficient code use: * #if defined(SS_STDIO_AVAILABLE) * ssPrintf("my message ..."); * #endif * - You can also use this technique to do other standard I/O related items, * such as: * #if defined(SS_STDIO_AVAILABLE) * if ((fp=fopen(file,"w")) == NULL) { * ssSetErrorStatus(S,"open failed"); * return; * } * ... * #endif */ /*====================* * S-function methods * *====================*/ /* * Level 2 S-function methods * -------------------------- * Notation: "=>" indicates method is required. * [method] indicates method is optional. * * Note, many of the methods below are only available for use in level 2 * C-MEX S-functions. * * Model Initialization in Simulink * -------------------------------- *=> mdlInitializeSizes - Initialize SimStruct sizes array *

2

Bilaga 2

* [mdlSetInputPortFrameData] - Optional method. Check and set input and * output port frame data attributes. * * NOTE: An S-function cannot use mdlSetInput(Output)PortWidth and * mdlSetInput(Output)PortDimensionInfo at the same time. It can use * either a width or dimension method, but not both. * * [mdlSetInputPortWidth] - Optional method. Check and set input and * optionally other port widths. * [mdlSetOutputPortWidth] - Optional method. Check and set output * and optionally other port widths. * * [mdlSetInputPortDimensionInfo] * - Optional method. Check and set input and * optionally other port dimensions. * [mdlSetOutputPortDimensionInfo] * - Optional method. Check and set output * and optionally other port dimensions. * [mdlSetDefaultPortDimensionInfo] * - Optional method. Set dimensions of all * input and output ports that have unknown * dimensions. * * [mdlSetInputPortSampleTime] - Optional method. Check and set input * port sample time and optionally other port * sample times. * [mdlSetOutputPortSampleTime]- Optional method. Check and set output * port sample time and optionally other port * sample times. *=> mdlInitializeSampleTimes - Initialize sample times and optionally * function-call connections. * * [mdlSetInputPortDataType] - Optional method. Check and set input port * data type. See SS_DOUBLE to SS_BOOEAN in * simstruc_types.h for built-in data types. * [mdlSetOutputPortDataType] - Optional method. Check and set output port * data type. See SS_DOUBLE to SS_BOOLEAN in * simstruc_types.h for built-in data types. * [mdlSetDefaultPortDataTypes] - Optional method. Set data types of all * dynamically typed input and output ports. * * [mdlInputPortComplexSignal] - Optional method. Check and set input * port complexity attribute (COMPLEX_YES, * COMPLEX_NO). * [mdlOutputPortComplexSignal] - Optional method. Check and set output * port complexity attribute (COMPLEX_YES, * COMPLEX_NO). * [mdlSetDefaultPortComplexSignals] * - Optional method. Set complex signal flags * of all input and output ports who * have their complex signals set to * COMPLEX_INHERITED (dynamic complexity). * * [mdlSetWorkWidths] - Optional method. Set the state, iwork, * rwork, pwork, dwork, etc sizes. * * [mdlStart] - Optional method. Perform actions such * as allocating memory and attaching to pwork * elements. * * [mdlInitializeConditions] - Initialize model parameters (usually * states). Will not be called if your * S-function does not have an initialize * conditions method. * * ['constant' mdlOutputs] - Execute blocks with constant sample * times. These are only executed once * here. * * Model simulation loop in Simulink * --------------------------------- * [mdlCheckParameters] - Optional method. Will be called at * any time during the simulation loop when * parameters change. * SimulationLoop: * [mdlProcessParameters] - Optional method. Called during * simulation after parameters have been * changed and verified to be okay by

3

Bilaga 2

* mdlCheckParameters. The processing is * done at the "top" of the simulation loop * when it is safe to process the changed * parameters. * [mdlGetTimeOfNextVarHit] - Optional method. If your S-function * has a variable step sample time, then * this method will be called. * [mdlInitializeConditions]- Optional method. Only called if your * S-function resides in an enabled * subsystem configured to reset states, * and the subsystem has just enabled. * => mdlOutputs - Major output call (usually updates * output signals). * [mdlUpdate] - Update the discrete states, etc. * * Integration (Minor time step) * [mdlDerivatives] - Compute the derivatives. * Do * [mdlOutputs] * [mdlDerivatives] * EndDo - number of iterations depends on solver * Do * [mdlOutputs] * [mdlZeroCrossings] * EndDo - number of iterations depends on zero crossings signals * EndIntegration * EndSimulationLoop * => mdlTerminate - End of model housekeeping - free memory, * etc. * * Model initialization for code generation (rtwgen) * ------------------------------------------------- * <Initialization. See "Model Initialization in Simulink" above> * * [mdlRTW] - Optional method. Only called when * generating code to add information to the * model.rtw file which is used by the * Real-Time Workshop. * * mdlTerminate - End of model housekeeping - free memory, * etc. * * Noninlined S-function execution in Real-Time Workshop * ----------------------------------------------------- * 1) The results of most initialization methods are 'compiled' into * the generated code and many methods are not called. * 2) Noninlined S-functions are limited in several ways, for example * parameter must be real (non-complex) double vectors or strings. More * capability is provided via the Target Language Compiler. See the * Target Language Compiler Reference Guide. * * => mdlInitializeSizes - Initialize SimStruct sizes array * => mdlInitializeSampleTimes - Initialize sample times and optionally * function-call connections. * [mdlInitializeConditions] - Initialize model parameters (usually * states). Will not be called if your * S-function does not have an initialize * conditions method. * [mdlStart] - Optional method. Perform actions such * as allocating memory and attaching to pwork * elements. * ExecutionLoop: * => mdlOutputs - Major output call (usually updates * output signals). * [mdlUpdate] - Update the discrete states, etc. * * Integration (Minor time step) * [mdlDerivatives] - Compute the derivatives. * Do * [mdlOutputs] * [mdlDerivatives] * EndDo - number of iterations depends on solver * Do * [mdlOutputs] * [mdlZeroCrossings] * EndDo - number of iterations depends on zero crossings signals * EndExecutionLoop * mdlTerminate - End of model housekeeping - free memory,

4

Bilaga 2

* etc. */ /*====================================================================* * Parameter handling methods. These methods are not supported by RTW * *====================================================================*/ #define MDL_CHECK_PARAMETERS /* Change to #undef to remove function */ #if defined(MDL_CHECK_PARAMETERS) && defined(MATLAB_MEX_FILE) /* Function: mdlCheckParameters ============================================= * Abstract: * mdlCheckParameters verifies new parameter settings whenever parameter * change or are re-evaluated during a simulation. When a simulation is * running, changes to S-function parameters can occur at any time during * the simulation loop. * * This method can be called at any point after mdlInitializeSizes. * You should add a call to this method from mdlInitalizeSizes * to check the parameters. After setting the number of parameters * you expect in your S-function via ssSetNumSFcnParams(S,n), you should: * #if defined(MATLAB_MEX_FILE) * if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) { * mdlCheckParameters(S); * if (ssGetErrorStatus(S) != NULL) return; * } else { * return; Simulink will report a parameter mismatch error * } * #endif * * When a Simulation is running, changes to S-function parameters can * occur either at the start of a simulation step, or during a * simulation step. When changes to S-function parameters occur during * a simulation step, this method is called twice, for the same * parameter changes. The first call during the simulation step is * used to verify that the parameters are correct. After verifying the * new parameters, the simulation continues using the original * parameter values until the next simulation step at which time the * new parameter values will be used. Redundant calls are needed to * maintain simulation consistency. Note that you cannot access the * work, state, input, output, etc. vectors in this method. This * method should only be used to validate the parameters. Processing * of the parameters should be done in mdlProcessParameters. * * See matlabroot/simulink/src/sfun_errhdl.c for an example. */ static void mdlCheckParameters(SimStruct *S) { } #endif /* MDL_CHECK_PARAMETERS */ #define MDL_PROCESS_PARAMETERS /* Change to #undef to remove function */ #if defined(MDL_PROCESS_PARAMETERS) && defined(MATLAB_MEX_FILE) /* Function: mdlProcessParameters =========================================== * Abstract: * This method will be called after mdlCheckParameters, whenever * parameters change or get re-evaluated. The purpose of this method is * to process the newly changed parameters. For example "caching" the * parameter changes in the work vectors. Note this method is not * called when it is used with the Real-Time Workshop. Therefore, * if you use this method in an S-function which is being used with the * Real-Time Workshop, you must write your S-function such that it doesn't * rely on this method. This can be done by inlining your S-function * via the Target Language Compiler. */ static void mdlProcessParameters(SimStruct *S) { } #endif /* MDL_PROCESS_PARAMETERS */ /*=====================================* * Configuration and execution methods * *=====================================*/ /* Function: mdlInitializeSizes ===============================================

5

Bilaga 2

* Abstract: * The sizes information is used by Simulink to determine the S-function * block's characteristics (number of inputs, outputs, states, etc.). * * The direct feedthrough flag can be either 1=yes or 0=no. It should be * set to 1 if the input, "u", is used in the mdlOutput function. Setting * this to 0 is akin to making a promise that "u" will not be used in the * mdlOutput function. If you break the promise, then unpredictable results * will occur. * * The NumContStates, NumDiscStates, NumInputs, NumOutputs, NumRWork, * NumIWork, NumPWork NumModes, and NumNonsampledZCs widths can be set to: * DYNAMICALLY_SIZED - In this case, they will be set to the actual * input width, unless you are have a * mdlSetWorkWidths to set the widths. * 0 or positive number - This explicitly sets item to the specified * value. */ static void mdlInitializeSizes(SimStruct *S) { int_T nInputPorts = 1; /* number of input ports */ int_T nOutputPorts = 1; /* number of output ports */ int_T needsInput = 1; /* direct feed through */ int_T inputPortIdx = 0; int_T outputPortIdx = 0; ssSetNumSFcnParams(S, 0); /* Number of expected parameters */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { /* * If the the number of expected input parameters is not equal * to the number of parameters entered in the dialog box return. * Simulink will generate an error indicating that there is a * parameter mismatch. */ return; } ssSetNumContStates( S, 0); /* number of continuous states */ ssSetNumDiscStates( S, 0); /* number of discrete states */ /* * Configure the input ports. First set the number of input ports. */ if (!ssSetNumInputPorts(S, nInputPorts)) return; /* * Set input port dimensions for each input port index starting at 0. * The following options summarize different ways for setting the input * port dimensions. * * (1) If the input port dimensions are unknown, use * ssSetInputPortDimensionInfo(S, inputPortIdx, DYNAMIC_DIMENSION)) * * (2) If the input signal is an unoriented vector, and the input port * width is w, use * ssSetInputPortVectorDimension(S, inputPortIdx, w) * w (or width) can be DYNAMICALLY_SIZED or greater than 0. * This is equivalent to ssSetInputPortWidth(S, inputPortIdx, w). * * (3) If the input signal is a matrix of dimension mxn, use * ssSetInputPortMatrixDimensions(S, inputPortIdx, m, n) * m and n can be DYNAMICALLY_SIZED or greater than zero. * * (4) Otherwise use: * ssSetInputPortDimensionInfo(S, inputPortIdx, dimsInfo) * This function can be used to fully or partially initialize the port * dimensions. dimsInfo is a structure containing width, number of * dimensions, and dimensions of the port. */ if(!ssSetInputPortDimensionInfo(S, inputPortIdx, DYNAMIC_DIMENSION)) return; /* * Set direct feedthrough flag (1=yes, 0=no). * A port has direct feedthrough if the input is used in either * the mdlOutputs or mdlGetTimeOfNextVarHit functions. */ ssSetInputPortDirectFeedThrough(S, inputPortIdx, needsInput);

6

Bilaga 2

/* * Configure the output ports. First set the number of output ports. */ if (!ssSetNumOutputPorts(S, nOutputPorts)) return; /* * Set output port dimensions for each output port index starting at 0. * See comments for setting input port dimensions. */ if(!ssSetOutputPortDimensionInfo(S,outputPortIdx,DYNAMIC_DIMENSION)) return; /* * Set the number of sample times. This must be a positive, nonzero * integer indicating the number of sample times or it can be * PORT_BASED_SAMPLE_TIMES. For multi-rate S-functions, the * suggested approach to setting sample times is via the port * based sample times method. When you create a multirate * S-function, care needs to be taking to verify that when * slower tasks are preempted that your S-function correctly * manages data as to avoid race conditions. When port based * sample times are specified, the block cannot inherit a constant * sample time at any port. */ ssSetNumSampleTimes( S, 1); /* number of sample times */ /* * Set size of the work vectors. */ ssSetNumRWork( S, 0); /* number of real work vector elements */ ssSetNumIWork( S, 0); /* number of integer work vector elements*/ ssSetNumPWork( S, 0); /* number of pointer work vector elements*/ ssSetNumModes( S, 0); /* number of mode work vector elements */ ssSetNumNonsampledZCs( S, 0); /* number of nonsampled zero crossings */ /* * All options have the form SS_OPTION_<name> and are documented in * matlabroot/simulink/include/simstruc.h. The options should be * bitwise or'd together as in * ssSetOptions(S, (SS_OPTION_name1 | SS_OPTION_name2)) */ ssSetOptions( S, 0); /* general options (SS_OPTION_xx) */ } /* end mdlInitializeSizes */ #define MDL_SET_INPUT_PORT_FRAME_DATA /* Change to #undef to remove function */ #if defined(MDL_SET_INPUT_PORT_FRAME_DATA) && defined(MATLAB_MEX_FILE) /* Function: mdlSetInputPortFrameData ======================================== * Abstract: * This method is called with the candidate frame setting (FRAME_YES, or * FRAME_NO) for an input port. If the proposed setting is acceptable, * the method should go ahead and set the actual frame data setting using * ssSetInputPortFrameData(S,portIndex,frameData). If * the setting is unacceptable an error should generated via * ssSetErrorStatus. Note that any other dynamic frame input or * output ports whose frame data setting are implicitly defined by virtue * of knowing the frame data setting of the given port can also have their * frame data settings set via calls to ssSetInputPortFrameData and * ssSetOutputPortFrameData. */ static void mdlSetInputPortFrameData(SimStruct *S, int portIndex, Frame_T frameData) { } /* end mdlSetInputPortFrameData */ #endif /* MDL_SET_INPUT_PORT_FRAME_DATA */ #define MDL_SET_INPUT_PORT_WIDTH /* Change to #undef to remove function */ #if defined(MDL_SET_INPUT_PORT_WIDTH) && defined(MATLAB_MEX_FILE) /* Function: mdlSetInputPortWidth =========================================== * Abstract: * This method is called with the candidate width for a dynamically * sized port. If the proposed width is acceptable, the method should * go ahead and set the actual port width using ssSetInputPortWidth. If * the size is unacceptable an error should generated via

7

Bilaga 2

* ssSetErrorStatus. Note that any other dynamically sized input or * output ports whose widths are implicitly defined by virtue of knowing * the width of the given port can also have their widths set via calls * to ssSetInputPortWidth or ssSetOutputPortWidth. */ static void mdlSetInputPortWidth(SimStruct *S, int portIndex, int width) { } /* end mdlSetInputPortWidth */ #endif /* MDL_SET_INPUT_PORT_WIDTH */ #define MDL_SET_OUTPUT_PORT_WIDTH /* Change to #undef to remove function */ #if defined(MDL_SET_OUTPUT_PORT_WIDTH) && defined(MATLAB_MEX_FILE) /* Function: mdlSetOutputPortWidth ========================================== * Abstract: * This method is called with the candidate width for a dynamically * sized port. If the proposed width is acceptable, the method should * go ahead and set the actual port width using ssSetOutputPortWidth. If * the size is unacceptable an error should generated via * ssSetErrorStatus. Note that any other dynamically sized input or * output ports whose widths are implicitly defined by virtue of knowing * the width of the given port can also have their widths set via calls * to ssSetInputPortWidth or ssSetOutputPortWidth. */ static void mdlSetOutputPortWidth(SimStruct *S, int portIndex, int width) { } /* end mdlSetOutputPortWidth */ #endif /* MDL_SET_OUTPUT_PORT_WIDTH */ #undef MDL_SET_INPUT_PORT_DIMENSION_INFO /* Change to #define to add function */ #if defined(MDL_SET_INPUT_PORT_DIMENSION_INFO) && defined(MATLAB_MEX_FILE) /* Function: mdlSetInputPortDimensionInfo ==================================== * Abstract: * This method is called with the candidate dimensions for an input port * with unknown dimensions. If the proposed dimensions are acceptable, the * method should go ahead and set the actual port dimensions. * If they are unacceptable an error should be generated via * ssSetErrorStatus. * Note that any other input or output ports whose dimensions are * implicitly defined by virtue of knowing the dimensions of the given * port can also have their dimensions set. * * See matlabroot/simulink/src/sfun_matadd.c for an example. */ static void mdlSetInputPortDimensionInfo(SimStruct *S, int_T portIndex, const DimsInfo_T *dimsInfo) { } /* mdlSetInputPortDimensionInfo */ #endif /* MDL_SET_INPUT_PORT_DIMENSION_INFO */ #undef MDL_SET_OUTPUT_PORT_DIMENSION_INFO /* Change to #define to add function*/ #if defined(MDL_SET_OUTPUT_PORT_DIMENSION_INFO) && defined(MATLAB_MEX_FILE) /* Function: mdlSetOutputPortDimensionInfo =================================== * Abstract: * This method is called with the candidate dimensions for an output port * with unknown dimensions. If the proposed dimensions are acceptable, the * method should go ahead and set the actual port dimensions. * If they are unacceptable an error should be generated via * ssSetErrorStatus. * Note that any other input or output ports whose dimensions are * implicitly defined by virtue of knowing the dimensions of the given * port can also have their dimensions set. * * See matlabroot/simulink/src/sfun_matadd.c for an example. */ static void mdlSetOutputPortDimensionInfo(SimStruct *S, int_T portIndex, const DimsInfo_T *dimsInfo) { } /* mdlSetOutputPortDimensionInfo */ #endif /* MDL_SET_OUTPUT_PORT_DIMENSION_INFO */ #undef MDL_SET_DEFAULT_PORT_DIMENSION_INFO /* Change to #define to add fcn */ #if defined(MDL_SET_DEFAULT_PORT_DIMENSION_INFO) && defined(MATLAB_MEX_FILE)

8

Bilaga 2

/* Function: mdlSetDefaultPortDimensionInfo ================================== * Abstract: * This method is called when there is not enough information in your * model to uniquely determine the port dimensionality of signals * entering or leaving your block. When this occurs, Simulink's * dimension propagation engine calls this method to ask you to set * your S-functions default dimensions for any input and output ports * that are dynamically sized. * * If you do not provide this method and you have dynamically sized ports * where Simulink does not have enough information to propagate the * dimensionality to your S-function, then Simulink will set these unknown * ports to the 'block width' which is determined by examining any known * ports. If there are no known ports, the width will be set to 1. * * See matlabroot/simulink/src/sfun_matadd.c for an example. */ static void mdlSetDefaultPortDimensionInfo(SimStruct *S) { } /* mdlSetDefaultPortDimensionInfo */ #endif /* MDL_SET_DEFAULT_PORT_DIMENSION_INFO */ #define MDL_SET_INPUT_PORT_SAMPLE_TIME #if defined(MDL_SET_INPUT_PORT_SAMPLE_TIME) && defined(MATLAB_MEX_FILE) /* Function: mdlSetInputPortSampleTime ======================================= * Abstract: * This method is called with the candidate sample time for an inherited * sample time input port. If the proposed sample time is acceptable, the * method should go ahead and set the actual port sample time using * ssSetInputPortSampleTime. If the sample time is unacceptable an error * should generated via ssSetErrorStatus. Note that any other inherited * input or output ports whose sample times are implicitly defined by * virtue of knowing the sample time of the given port can also have * their sample times set via calls to ssSetInputPortSampleTime or * ssSetOutputPortSampleTime. * * When inherited port based sample times are specified, we are guaranteed * that the sample time will be one of the following: * [sampleTime, offsetTime] * continuous [0.0 , 0.0 ] * discrete [period , offset ] where 0.0 < period < inf * 0.0 <= offset < period * Constant, triggered, and variable step sample times will not be * propagated to S-functions with port based sample times. * * Generally the mdlSetInputPortSampleTime or mdlSetOutputPortSampleTime * is called once with the input port sample time. However, there can be * cases where this function will be called more than once. This happens * when the simulation engine is converting continuous sample times to * continuous but fixed in minor steps sample times. When this occurs, the * original values of the sample times specified in mdlInitializeSizes * will be restored before calling this method again. * * The final sample time specified at the port may be different (but * equivalent to) from what was specified in this method. This occurs * when: * o) Using a fixed step solver and the port has a continuous but fixed * in minor step sample time. In this case the sample time will * be converted to the fundamental sample time for the model. * o) We are adjusting sample times for numerical correctness. For * example [0.2499999999999, 0] is converted to [0.25, 0]. * S-functions are not explicitly notified of "converted" sample times. * They can examine the final sample times in mdlInitializeSampleTimes. */ static void mdlSetInputPortSampleTime(SimStruct *S, int_T portIdx, real_T sampleTime, real_T offsetTime) { } /* end mdlSetInputPortSampleTime */ #endif /* MDL_SET_INPUT_PORT_SAMPLE_TIME */ #define MDL_SET_OUTPUT_PORT_SAMPLE_TIME #if defined(MDL_SET_OUTPUT_PORT_SAMPLE_TIME) && defined(MATLAB_MEX_FILE) /* Function: mdlSetOutputPortSampleTime ====================================== * Abstract:

9

Bilaga 2

* This method is called with the candidate sample time for an inherited * sample time output port. If the proposed sample time is acceptable, the * method should go ahead and set the actual port sample time using * ssSetOutputPortSampleTime. If the sample time is unacceptable an error * should generated via ssSetErrorStatus. Note that any other inherited * input or output ports whose sample times are implicitly defined by * virtue of knowing the sample time of the given port can also have * their sample times set via calls to ssSetInputPortSampleTime or * ssSetOutputPortSampleTime. * * Normally, sample times are propagated forwards, however if sources * feeding this block have an inherited sample time, then Simulink * may choose to back propagate known sample times to this block. * When back propagating sample times, we call this method in succession * for all inherited output port signals. * * See mdlSetInputPortSampleTimes for more information about when this * method is called. */ static void mdlSetOutputPortSampleTime(SimStruct *S, int_T portIdx, real_T sampleTime, real_T offsetTime) { } /* end mdlSetOutputPortSampleTime */ #endif /* MDL_SET_OUTPUT_PORT_SAMPLE_TIME */ /* Function: mdlInitializeSampleTimes ========================================= * Abstract: * * This function is used to specify the sample time(s) for your S-function. * You must register the same number of sample times as specified in * ssSetNumSampleTimes. If you specify that you have no sample times, then * the S-function is assumed to have one inherited sample time. * * The sample times are specified as pairs "[sample_time, offset_time]" * via the following macros: * ssSetSampleTime(S, sampleTimePairIndex, sample_time) * ssSetOffsetTime(S, offsetTimePairIndex, offset_time) * Where sampleTimePairIndex starts at 0. * * The valid sample time pairs are (upper case values are macros defined * in simstruc.h): * * [CONTINUOUS_SAMPLE_TIME, 0.0 ] * [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET] * [discrete_sample_period, offset ] * [VARIABLE_SAMPLE_TIME , 0.0 ] * * Alternatively, you can specify that the sample time is inherited from the * driving block in which case the S-function can have only one sample time * pair: * * [INHERITED_SAMPLE_TIME, 0.0 ] * or * [INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET] * * The following guidelines may help aid in specifying sample times: * * o A continuous function that changes during minor integration steps * should register the [CONTINUOUS_SAMPLE_TIME, 0.0] sample time. * o A continuous function that does not change during minor integration * steps should register the * [CONTINUOUS_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET] * sample time. * o A discrete function that changes at a specified rate should register * the discrete sample time pair * [discrete_sample_period, offset] * where * discrete_sample_period > 0.0 and * 0.0 <= offset < discrete_sample_period * o A discrete function that changes at a variable rate should * register the variable step discrete [VARIABLE_SAMPLE_TIME, 0.0] * sample time. The mdlGetTimeOfNextVarHit function is called to get * the time of the next sample hit for the variable step discrete task. * Note, the VARIABLE_SAMPLE_TIME can be used with variable step * solvers only.

10

Bilaga 2

* o Discrete blocks which can operate in triggered subsystems. For your * block to operate correctly in a triggered subsystem or a periodic * system it must register [INHERITED_SAMPLE_TIME, 0.0]. In a triggered * subsystem after sample times have been propagated throughout the * block diagram, the assigned sample time to the block will be * [INHERITED_SAMPLE_TIME, INHERITED_SAMPLE_TIME]. Typically discrete * blocks which can be periodic or reside within triggered subsystems * need to register the inherited sample time and the option * SS_DISALLOW_CONSTANT_SAMPLE_TIME. Then in mdlSetWorkWidths, they * need to verify that they were assigned a discrete or triggered * sample time. To do this: * mdlSetWorkWidths: * if (ssGetSampleTime(S, 0) == CONTINUOUS_SAMPLE_TIME) { * ssSetErrorStatus(S, "This block cannot be assigned a " * "continuous sample time"); * } * * If your function has no intrinsic sample time, then you should indicate * that your sample time is inherited according to the following guidelines: * * o A function that changes as its input changes, even during minor * integration steps should register the [INHERITED_SAMPLE_TIME, 0.0] * sample time. * o A function that changes as its input changes, but doesn't change * during minor integration steps (i.e., held during minor steps) should * register the [INHERITED_SAMPLE_TIME, FIXED_IN_MINOR_STEP_OFFSET] * sample time. * * To check for a sample hit during execution (in mdlOutputs or mdlUpdate), * you should use the ssIsSampleHit or ssIsContinuousTask macros. * For example, if your first sample time is continuous, then you * used the following code-fragment to check for a sample hit. Note, * you would get incorrect results if you used ssIsSampleHit(S,0,tid). * if (ssIsContinuousTask(S,tid)) { * } * If say, you wanted to determine if the third (discrete) task has a hit, * then you would use the following code-fragment: * if (ssIsSampleHit(S,2,tid) { * } * */ static void mdlInitializeSampleTimes(SimStruct *S) { /* Register one pair for each sample time */ ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); } /* end mdlInitializeSampleTimes */ #define MDL_SET_INPUT_PORT_DATA_TYPE /* Change to #undef to remove function */ #if defined(MDL_SET_INPUT_PORT_DATA_TYPE) && defined(MATLAB_MEX_FILE) /* Function: mdlSetInputPortDataType ========================================= * Abstract: * This method is called with the candidate data type id for a dynamically * typed input port. If the proposed data type is acceptable, the method * should go ahead and set the actual port data type using * ssSetInputPortDataType. If the data type is unacceptable an error * should generated via ssSetErrorStatus. Note that any other dynamically * typed input or output ports whose data types are implicitly defined by * virtue of knowing the data type of the given port can also have their * data types set via calls to ssSetInputPortDataType or * ssSetOutputPortDataType. * * See matlabroot/simulink/include/simstruc_types.h for built-in * type defines: SS_DOUBLE, SS_BOOLEAN, etc. * * See matlabroot/simulink/src/sfun_dtype_io.c for an example. */ static void mdlSetInputPortDataType(SimStruct *S, int portIndex,DTypeId dType) { } /* mdlSetInputPortDataType */ #endif /* MDL_SET_INPUT_PORT_DATA_TYPE */ #define MDL_SET_OUTPUT_PORT_DATA_TYPE /* Change to #undef to remove function */ #if defined(MDL_SET_OUTPUT_PORT_DATA_TYPE) && defined(MATLAB_MEX_FILE) /* Function: mdlSetOutputPortDataType ========================================

11

Bilaga 2

* Abstract: * This method is called with the candidate data type id for a dynamically * typed output port. If the proposed data type is acceptable, the method * should go ahead and set the actual port data type using * ssSetOutputPortDataType. If the data type is unacceptable an error * should generated via ssSetErrorStatus. Note that any other dynamically * typed input or output ports whose data types are implicitly defined by * virtue of knowing the data type of the given port can also have their * data types set via calls to ssSetInputPortDataType or * ssSetOutputPortDataType. * * See matlabroot/simulink/src/sfun_dtype_io.c for an example. */ static void mdlSetOutputPortDataType(SimStruct *S,int portIndex,DTypeId dType) { } /* mdlSetOutputPortDataType */ #endif /* MDL_SET_OUTPUT_PORT_DATA_TYPE */ #define MDL_SET_DEFAULT_PORT_DATA_TYPES /* Change to #undef to remove function*/ #if defined(MDL_SET_DEFAULT_PORT_DATA_TYPES) && defined(MATLAB_MEX_FILE) /* Function: mdlSetDefaultPortDataTypes ===================================== * Abstract: * This method is called when there is not enough information in your * model to uniquely determine the input and output data types * for your block. When this occurs, Simulink's data type propagation * engine calls this method to ask you to set your S-function default * data type for any dynamically typed input and output ports. * * If you do not provide this method and you have dynamically typed * ports where Simulink does not have enough information to propagate * data types to your S-function, then Simulink will assign the * data type to the largest known port data type of your S-function. * If there are no known data types, then Simulink will set the * data type to double. * * See matlabroot/simulink/src/sfun_dtype_io.c for an example. */ static void mdlSetDefaultPortDataTypes(SimStruct *S) { } /* mdlSetDefaultPortDataTypes */ #endif /* MDL_SET_DEFAULT_PORT_DATA_TYPES */ #define MDL_SET_INPUT_PORT_COMPLEX_SIGNAL /* Change to #undef to remove */ #if defined(MDL_SET_INPUT_PORT_COMPLEX_SIGNAL) && defined(MATLAB_MEX_FILE) /* Function: mdlSetInputPortComplexSignal ==================================== * Abstract: * This method is called with the candidate complexity signal setting * (COMPLEX_YES or COMPLEX_NO) for an input port whos complex signal * attribute is set to COMPLEX_INHERITED. If the proposed complexity is * acceptable, the method should go ahead and set the actual complexity * using ssSetInputPortComplexSignal. If the complex setting is * unacceptable an error should generated via ssSetErrorStatus. Note that * any other unknown ports whose complexity is implicitly defined by virtue * of knowing the complexity of the given port can also have their * complexity set via calls to ssSetInputPortComplexSignal or * ssSetOutputPortComplexSignal. * * See matlabroot/simulink/src/sfun_cplx.c for an example. */ static void mdlSetInputPortComplexSignal(SimStruct *S, int portIndex, CSignal_T cSignalSetting) { } /* mdlSetInputPortComplexSignal */ #endif /* MDL_SET_INPUT_PORT_COMPLEX_SIGNAL */ #define MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL /* Change to #undef to remove */ #if defined(MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL) && defined(MATLAB_MEX_FILE) /* Function: mdlSetOutputPortComplexSignal =================================== * Abstract: * This method is called with the candidate complexity signal setting * (COMPLEX_YES or COMPLEX_NO) for an output port whos complex signal * attribute is set to COMPLEX_INHERITED. If the proposed complexity is * acceptable, the method should go ahead and set the actual complexity * using ssSetOutputPortComplexSignal. If the complex setting is

12

Bilaga 2

* unacceptable an error should generated via ssSetErrorStatus. Note that * any other unknown ports whose complexity is implicitly defined by virtue * of knowing the complexity of the given port can also have their * complexity set via calls to ssSetInputPortComplexSignal or * ssSetOutputPortComplexSignal. * * See matlabroot/simulink/src/sfun_cplx.c for an example. */ static void mdlSetOutputPortComplexSignal(SimStruct *S, int portIndex, CSignal_T cSignalSetting) { } /* mdlSetOutputPortComplexSignal */ #endif /* MDL_SET_OUTPUT_PORT_COMPLEX_SIGNAL */ #define MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS /* Change to #undef to remove */ #if defined(MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS) && defined(MATLAB_MEX_FILE) /* Function: mdlSetDefaultPortComplexSignals ================================ * Abstract: * This method is called when there is not enough information in your * model to uniquely determine the complexity (COMPLEX_NO, COMPLEX_YES) * of signals entering your block. When this occurs, Simulink's * complex signal propagation engine calls this method to ask you to set * your S-function default complexity type for any input and output ports * who's complex signal attribute is set to COMPLEX_INHERITED. * * If you do not provide this method and you have COMPLEX_INHERITED * ports where Simulink does not have enough information to propagate * the complexity to your S-function, then Simulink will set * these unkown ports to COMPLEX_YES if any of your S-function * ports are currently set to COMPLEX_YES, otherwise the unknown * ports will be set to COMPLEX_NO. * * See matlabroot/simulink/src/sfun_cplx.c for an example. */ static void mdlSetDefaultPortComplexSignals(SimStruct *S) { } /* mdlSetDefaultPortComplexSignals */ #endif /* MDL_SET_DEFAULT_PORT_COMPLEX_SIGNALS */ #define MDL_SET_WORK_WIDTHS /* Change to #undef to remove function */ #if defined(MDL_SET_WORK_WIDTHS) && defined(MATLAB_MEX_FILE) /* Function: mdlSetWorkWidths =============================================== * Abstract: * The optional method, mdlSetWorkWidths is called after input port * width, output port width, and sample times of the S-function have * been determined to set any state and work vector sizes which are * a function of the input, output, and/or sample times. This method * is used to specify the nonzero work vector widths via the macros * ssNumContStates, ssSetNumDiscStates, ssSetNumRWork, ssSetNumIWork, * ssSetNumPWork, ssSetNumModes, and ssSetNumNonsampledZCs. * * If you are using mdlSetWorkWidths, then any work vectors you are * using in your S-function should be set to DYNAMICALLY_SIZED in * mdlInitializeSizes, even if the exact value is know at that. The * actual size to be used by the S-function should then be specified * in mdlSetWorkWidths. */ static void mdlSetWorkWidths(SimStruct *S) { } #endif /* MDL_SET_WORK_WIDTHS */ #define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */ #if defined(MDL_INITIALIZE_CONDITIONS) /* Function: mdlInitializeConditions ======================================== * Abstract: * In this function, you should initialize the continuous and discrete * states for your S-function block. The initial states are placed * in the state vector, ssGetContStates(S) or ssGetDiscStates(S). * You can also perform any other initialization activities that your * S-function may require. Note, this method will be called at the * start of simulation and if it is present in an enabled subsystem * configured to reset states, it will be call when the enabled subsystem * restarts execution to reset the states.

13

Bilaga 2

* * You can use the ssIsFirstInitCond(S) macro to determine if this is * is the first time mdlInitializeConditions is being called. */ static void mdlInitializeConditions(SimStruct *S) { } #endif /* MDL_INITIALIZE_CONDITIONS */ #define MDL_START /* Change to #undef to remove function */ #if defined(MDL_START) /* Function: mdlStart ======================================================= * Abstract: * This function is called once at start of model execution. If you * have states that should be initialized once, this is the place * to do it. */ static void mdlStart(SimStruct *S) { } #endif /* MDL_START */ #define MDL_GET_TIME_OF_NEXT_VAR_HIT /* Change to #undef to remove function */ #if defined(MDL_GET_TIME_OF_NEXT_VAR_HIT) && (defined(MATLAB_MEX_FILE) || \ defined(NRT)) /* Function: mdlGetTimeOfNextVarHit ========================================= * Abstract: * This function is called to get the time of the next variable sample * time hit. This function is called once for every major integration time * step. It must return time of next hit by using ssSetTNext. The time of * the next hit must be greater than ssGetT(S). * * Note, the time of next hit can be a function of the input signal(s). */ static void mdlGetTimeOfNextVarHit(SimStruct *S) { time_T timeOfNextHit = ssGetT(S) /* + offset */ ; ssSetTNext(S, timeOfNextHit); } #endif /* MDL_GET_TIME_OF_NEXT_VAR_HIT */ #define MDL_ZERO_CROSSINGS /* Change to #undef to remove function */ #if defined(MDL_ZERO_CROSSINGS) && (defined(MATLAB_MEX_FILE) || defined(NRT)) /* Function: mdlZeroCrossings =============================================== * Abstract: * If your S-function has registered CONTINUOUS_SAMPLE_TIME and there * are signals entering the S-function or internally generated signals * which have discontinuities, you can use this method to locate the * discontinuities. When called, this method must update the * ssGetNonsampleZCs(S) vector. */ static void mdlZeroCrossings(SimStruct *S) { } #endif /* MDL_ZERO_CROSSINGS */ /* Function: mdlOutputs ======================================================= * Abstract: * In this function, you compute the outputs of your S-function * block. Generally outputs are placed in the output vector(s), * ssGetOutputPortSignal. */ static void mdlOutputs(SimStruct *S, int_T tid) { } /* end mdlOutputs */ #define MDL_UPDATE /* Change to #undef to remove function */ #if defined(MDL_UPDATE) /* Function: mdlUpdate ====================================================== * Abstract: * This function is called once for every major integration time step. * Discrete states are typically updated here, but this function is useful

14

Bilaga 2

* for performing any tasks that should only take place once per * integration step. */ static void mdlUpdate(SimStruct *S, int_T tid) { } #endif /* MDL_UPDATE */ #define MDL_DERIVATIVES /* Change to #undef to remove function */ #if defined(MDL_DERIVATIVES) /* Function: mdlDerivatives ================================================= * Abstract: * In this function, you compute the S-function block's derivatives. * The derivatives are placed in the derivative vector, ssGetdX(S). */ static void mdlDerivatives(SimStruct *S) { } #endif /* MDL_DERIVATIVES */ /* Function: mdlTerminate ===================================================== * Abstract: * In this function, you should perform any actions that are necessary * at the termination of a simulation. For example, if memory was allocated * in mdlStart, this is the place to free it. * * Suppose your S-function allocates a few few chunks of memory in mdlStart * and saves them in PWork. The following code fragment would free this * memory. * { * int i; * for (i = 0; i<ssGetNumPWork(S); i++) { * if (ssGetPWorkValue(S,i) != NULL) { * free(ssGetPWorkValue(S,i)); * } * } * } */ static void mdlTerminate(SimStruct *S) { } #define MDL_RTW /* Change to #undef to remove function */ #if defined(MDL_RTW) && (defined(MATLAB_MEX_FILE) || defined(NRT)) /* Function: mdlRTW ========================================================= * Abstract: * * This function is called when the Real-Time Workshop is generating * the model.rtw file. In this method, you can call the following * functions which add fields to the model.rtw file. * * 1) The following creates Parameter records for your S-functions. * nParams is the number of tunable S-function parameters. * * if ( !ssWriteRTWParameters(S, nParams, * * SSWRITE_VALUE_[type],paramName,stringInfo, * [type specific arguments below] * * ) ) { * return; (error reporting will be handled by SL) * } * * Where SSWRITE_VALUE_[type] can be one of the following groupings * (and you must have "nParams" such groupings): * * SSWRITE_VALUE_VECT, * const char_T *paramName, * const char_T *stringInfo, * const real_T *valueVect, * int_T vectLen * * SSWRITE_VALUE_2DMAT, * const char_T *paramName, * const char_T *stringInfo,

15

Bilaga 2

* const real_T *valueMat, * int_T nRows, * int_T nCols * * SSWRITE_VALUE_DTYPE_VECT, * const char_T *paramName, * const char_T *stringInfo, * const void *valueVect, * int_T vectLen, * int_T dtInfo * * SSWRITE_VALUE_DTYPE_2DMAT, * const char_T *paramName, * const char_T *stringInfo, * const void *valueMat, * int_T nRows, * int_T nCols, * int_T dtInfo * * SSWRITE_VALUE_DTYPE_ML_VECT, * const char_T *paramName, * const char_T *stringInfo, * const void *rValueVect, * const void *iValueVect, * int_T vectLen, * int_T dtInfo * * SSWRITE_VALUE_DTYPE_ML_2DMAT, * const char_T *paramName, * const char_T *stringInfo, * const void *rValueMat, * const void *iValueMat, * int_T nRows, * int_T nCols, * int_T dtInfo * * Notes: * 1. nParams is an integer and stringInfo is a string describing * generalinformation about the parameter such as how it was derived. * 2. The last argument to this function, dtInfo, is obtained from the * DTINFO macro (defined in simstruc.h) as: * dtInfo = DTINFO(dataTypeId, isComplexSignal); * where dataTypeId is the data type id and isComplexSignal is a * boolean value specifying whether the parameter is complex. * * See simulink/include/simulink.c for the definition (implementation) * of this function and simulink/src/sfun_multiport.c for an example * of using this function. * * 2) The following creates SFcnParameterSetting record for S-functions * (these can be derived from the non-tunable S-function parameters). * * if ( !ssWriteRTWParamSettings(S, nParamSettings, * * SSWRITE_VALUE_[whatever], settingName, * [type specific arguments below] * * ) ) { * return; (error reporting will be handled by SL) * } * * Where SSWRITE_VALUE_[type] can be one of the following groupings * (and you must have "nParamSettings" such groupings): * Also, the examples in the right hand column below show how the * ParamSetting appears in the .rtw file * * SSWRITE_VALUE_STR, - Used to write (un)quoted strings * const char_T *settingName, example: * const char_T *value, Country USA * * SSWRITE_VALUE_QSTR, - Used to write quoted strings * const char_T *settingName, example: * const char_T *value, Country "U.S.A" * * SSWRITE_VALUE_VECT_STR, - Used to write vector of strings * const char_T *settingName, example: * const char_T *value, Countries ["USA", "Mexico"] * int_T nItemsInVect

16

Bilaga 2

* * SSWRITE_VALUE_NUM, - Used to write numbers * const char_T *settingName, example: * const real_T value NumCountries 2 * * * SSWRITE_VALUE_VECT, - Used to write numeric vectors * const char_T *settingName, example: * const real_T *settingValue, PopInMil [300, 100] * int_T vectLen * * SSWRITE_VALUE_2DMAT, - Used to write 2D matrices * const char_T *settingName, example: * const real_T *settingValue, PopInMilBySex Matrix(2,2) * int_T nRows, [[170, 130],[60, 40]] * int_T nCols * * SSWRITE_VALUE_DTYPE_NUM, - Used to write numeric vectors * const char_T *settingName, example: int8 Num 3+4i * const void *settingValue, written as: [3+4i] * int_T dtInfo * * * SSWRITE_VALUE_DTYPE_VECT, - Used to write data typed vectors * const char_T *settingName, example: int8 CArray [1+2i 3+4i] * const void *settingValue, written as: * int_T vectLen CArray [1+2i, 3+4i] * int_T dtInfo * * * SSWRITE_VALUE_DTYPE_2DMAT, - Used to write data typed 2D * const char_T *settingName matrices * const void *settingValue, example: * int_T nRow , int8 CMatrix [1+2i 3+4i; 5 6] * int_T nCols, written as: * int_T dtInfo CMatrix Matrix(2,2) * [[1+2i, 3+4i]; [5+0i, 6+0i]] * * * SSWRITE_VALUE_DTYPE_ML_VECT, - Used to write complex matlab data * const char_T *settingName, typed vectors example: * const void *settingRValue, example: int8 CArray [1+2i 3+4i] * const void *settingIValue, settingRValue: [1 3] * int_T vectLen settingIValue: [2 4] * int_T dtInfo * written as: * CArray [1+2i, 3+4i] * * SSWRITE_VALUE_DTYPE_ML_2DMAT, - Used to write matlab complex * const char_T *settingName, data typed 2D matrices * const void *settingRValue, example * const void *settingIValue, int8 CMatrix [1+2i 3+4i; 5 6] * int_T nRows settingRValue: [1 5 3 6] * int_T nCols, settingIValue: [2 0 4 0] * int_T dtInfo * written as: * CMatrix Matrix(2,2) * [[1+2i, 3+4i]; [5+0i, 6+0i]] * * Note, The examples above show how the ParamSetting is written out * to the .rtw file * * See simulink/include/simulink.c for the definition (implementation) * of this function and simulink/src/sfun_multiport.c for an example * of using this function. * * 3) The following creates the work vector records for S-functions * * if (!ssWriteRTWWorkVect(S, vectName, nNames, * * name, size, (must have nNames of these pairs) * : * ) ) { * return; (error reporting will be handled by SL) * } * * Notes: * a) vectName must be either "RWork", "IWork" or "PWork"

17

Bilaga 2

* b) nNames is an int_T (integer), name is a const char_T* (const * char pointer) and size is int_T, and there must be nNames number * of [name, size] pairs passed to the function. * b) intSize1+intSize2+ ... +intSizeN = ssGetNum<vectName>(S) * Recall that you would have to set ssSetNum<vectName>(S) * in one of the initialization functions (mdlInitializeSizes * or mdlSetWorkVectorWidths). * * See simulink/include/simulink.c for the definition (implementation) * of this function, and ... no example yet :( * * 4) Finally the following functions/macros give you the ability to write * arbitrary strings and [name, value] pairs directly into the .rtw * file. * * if (!ssWriteRTWStr(S, const_char_*_string)) { * return; * } * * if (!ssWriteRTWStrParam(S, const_char_*_name, const_char_*_value)) { * return; * } * * if (!ssWriteRTWScalarParam(S, const_char_*_name, * const_void_*_value, * DTypeId_dtypeId)) { * return; * } * * if (!ssWriteRTWStrVectParam(S, const_char_*_name, * const_char_*_value, * int_num_items)) { * return; * } * * if (!ssWriteRTWVectParam(S, const_char_*_name, const_void_*_value, * int_data_type_of_value, int_vect_len)){ * return; * } * * if (!ssWriteRTW2dMatParam(S, const_char_*_name, const_void_*_value, * int_data_type_of_value, int_nrows, int_ncols)){ * return; * } * * The 'data_type_of_value' input argument for the above two macros is * obtained using * DTINFO(dTypeId, isComplex), * where * dTypeId: can be any one of the enum values in BuitlInDTypeID * (SS_DOUBLE, SS_SINGLE, SS_INT8, SS_UINT8, SS_INT16, * SS_UINT16, SS_INT32, SS_UINT32, SS_BOOLEAN defined * in simstuc_types.h) * isComplex: is either 0 or 1, as explained in Note-2 for * ssWriteRTWParameters. * * For example DTINFO(SS_INT32,0) is a non-complex 32-bit signed * integer. * * If isComplex==1, then it is assumed that 'const_void_*_value' array * has the real and imaginary parts arranged in an interleaved manner * (i.e., Simulink Format). * * If you prefer to pass the real and imaginary parts as two seperate * arrays, you should use the follwing macros: * * if (!ssWriteRTWMxVectParam(S, const_char_*_name, * const_void_*_rvalue, const_void_*_ivalue, * int_data_type_of_value, int_vect_len)){ * return; * } * * if (!ssWriteRTWMx2dMatParam(S, const_char_*_name, * const_void_*_rvalue, const_void_*_ivalue, * int_data_type_of_value, * int_nrows, int_ncols)){ * return; * }

18

Bilaga 2

* * See simulink/include/simulink.c and simstruc.h for the definition * (implementation) of these functions and simulink/src/ml2rtw.c for * examples of using these functions. * */ static void mdlRTW(SimStruct *S) { } #endif /* MDL_RTW */ /*=============================* * Required S-function trailer * *=============================*/ #ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration function */ #endif

19

Bilaga 3

/* * File: sfuntmpl_gate_fortran.c * * Abstract:: * * C->Fortran gateway TEMPLATE for a level 2 S-function. * Copy, rename and then edit this file to call your Fortran * code in the solver mode you want, then build it. * * To build the mex file, first compile the Fortran file(s), * then include their object file names in the mex command. * For example, if your Fortran compiler is invoked with the * 'g77' command, a mex session looks like this at the command * prompt: * * >> !g77 -c myfortranfile.f * >> mex my_sfuntmpl_gate_fortran.c myfortranfile.o * * --------------------------------------------------------- * | See matlabroot/simulink/src/sfuntmpl_doc.c for a more | * | detailed description of the C-MEX template. | * --------------------------------------------------------- * * Copyright 1990-2000 The MathWorks, Inc. * $Revision: 1.2 $ */ /* * You must specify the S_FUNCTION_NAME as the name of your S-function * (i.e. replace sfungate with the name of your S-function, which has * to match the name of the final mex file, e.g., if the S_FUNCTION_NAME * is my_sfuntmpl_gate_fortran, the mex filename will have to be * my_sfuntmpl_gate_fortran.dll on Windows and * my_sfuntmpl_gate_fortran.mexXXX on unix where XXX is the 3 letter * mex extension code for your platform). */ #define S_FUNCTION_LEVEL 2 #define S_FUNCTION_NAME sfuntmpl_gate_fortran /* * Need to include simstruc.h for the definition of the SimStruct and * its associated macro definitions. */ #include "simstruc.h" /* * As a convenience, this template has options for both variable * step and fixed step algorithm support. If you want fixed step * operation, change the #define below to #undef. * * If you want to, you can delete all references to VARIABLE_STEP * and set up the C-MEX as described in the "Writing S-functions" * manual. */ #define VARIABLE_STEP /* * The interface (function prototype) for your Fortran subroutine. * Change the name to the name of the subroutine and the arguments * to the actual argument list. * * Note that datatype REAL is 32 bits in Fortran and are passed * by reference, so the prototype arguments must be 'float *'. * INTEGER maps to int, so those arguments are 'int *'. Be * wary of IMPLICIT rules in Fortran when datatypes are not * explicit in your Fortran code. To use the datatype double * the Fortran variables need to be declared DOUBLE PRECISION * either explicitly or via an IMPLICIT DOUBLE PRECISION * statement. * * Your Fortran compiler may decorate and/or change the * capitalization of 'SUBROUTINE nameOfSub' differently * than the prototype below. Check your Fortran compiler's * manual for options to learn about and possibly control * external symbol decoration. See also the text file named

1

Bilaga 3

* sfuntmpl_fortran.txt in this file's directory. * * Additionally, you may want to use CFORTRAN, a tool for * automating interface generation between C and Fortran. * Search the web for 'cfortran'. * */ #ifdef VARIABLE_STEP extern void nameofsub_(float *sampleArgs, float *states, int *numstates, float *sampleOutput); #else extern void nameofsub_(float *sampleArgs, float *sampleOutput); #endif /* Error handling * -------------- * * You should use the following technique to report errors encountered within * an S-function: * * ssSetErrorStatus(S,"Error encountered due to ..."); * return; * * Note that the 2nd argument to ssSetErrorStatus must be persistent memory. * It cannot be a local variable. For example the following will cause * unpredictable errors: * * mdlOutputs() * { * char msg[256]; {ILLEGAL: to fix use "static char msg[256];"} * sprintf(msg,"Error due to %s", string); * ssSetErrorStatus(S,msg); * return; * } * * See matlabroot/simulink/src/sfunctmpl_doc.c for further details. */ /*====================* * S-function methods * *====================*/ /* Function: mdlInitializeSizes =============================================== * Abstract: * The sizes information is used by Simulink to determine the S-function * block's characteristics (number of inputs, outputs, states, etc.). */ static void mdlInitializeSizes(SimStruct *S) { /* See sfuntmpl.doc for more details on the macros below */ ssSetNumSFcnParams(S, 0); /* Number of expected parameters */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { /* Return if number of expected != number of actual parameters */ return; } ssSetNumContStates(S, 1); /* how many continuous states? */ ssSetNumDiscStates(S, 0); if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, 1); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, 1); ssSetNumSampleTimes(S, 1); /* * If your Fortran code uses REAL for the state, input, and/or output

2

Bilaga 3

* datatypes, use these DWorks as work areas to downcast continuous * states from double to REAL before calling your code. You could * also put the work vectors in hard-coded local (stack) variables. * * For fixed step code, keep a copy of the variables to be output * in a DWork vector so the mdlOutputs() function can provide output * data when needed. You can use as many DWork vectors as you like * for both input and output (or hard-code local variables). */ if(!ssSetNumDWork( S, 3)) return; ssSetDWorkWidth( S, 0, ssGetOutputPortWidth(S,0)); ssSetDWorkDataType( S, 0, SS_SINGLE); /* use SS_DOUBLE if needed */ ssSetDWorkWidth( S, 1, ssGetInputPortWidth(S,0)); ssSetDWorkDataType( S, 1, SS_SINGLE); ssSetDWorkWidth( S, 2, ssGetNumContStates(S)); ssSetDWorkDataType( S, 2, SS_SINGLE); ssSetNumNonsampledZCs(S, 0); ssSetOptions(S, 0); } /* Function: mdlInitializeSampleTimes ========================================= * Abstract: * This function is used to specify the sample time(s) for your * S-function. You must register the same number of sample times as * specified in ssSetNumSampleTimes. */ static void mdlInitializeSampleTimes(SimStruct *S) { #ifdef VARIABLE_STEP /* * For Fortran code with either no states at * all or with continuous states that you want * to support with variable time steps, use * a sample time like this: */ ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); #else /* * If the Fortran code implicitly steps time * at a fixed rate and you don't want to change * the code, you need to use a discrete (fixed * step) sample time, 1 second is chosen below. */ ssSetSampleTime(S, 0, 0.01); /* Choose the sample time here if discrete */ ssSetOffsetTime(S, 0, 0.0); #endif } #define MDL_INITIALIZE_CONDITIONS /* Change to #undef to remove function */ #if defined(MDL_INITIALIZE_CONDITIONS) /* Function: mdlInitializeConditions ======================================== * Abstract: * In this function, you should initialize the continuous and discrete * states for your S-function block. The initial states are placed * in the state vector, ssGetContStates(S) or ssGetRealDiscStates(S). * You can also perform any other initialization activities that your * S-function may require. Note, this routine will be called at the * start of simulation and if it is present in an enabled subsystem * configured to reset states, it will be call when the enabled subsystem * restarts execution to reset the states. */ static void mdlInitializeConditions(SimStruct *S) { /* * #undef MDL_INITIALIZE_CONDITIONS if you don't have any

3

Bilaga 3

* continuous states. */ real_T *x = ssGetContStates(S); /* set the values of the states (x) to start with */ } #endif /* MDL_INITIALIZE_CONDITIONS */ #define MDL_START /* Change to #undef to remove function */ #if defined(MDL_START) /* Function: mdlStart ======================================================= * Abstract: * This function is called once at start of model execution. If you * have states that should be initialized once, this is the place * to do it. */ static void mdlStart(SimStruct *S) { } #endif /* MDL_START */ /* Function: mdlOutputs ======================================================= * Abstract: * In this function, you compute the outputs of your S-function * block. The default datatype for signals in Simulink is double, * but you can use other intrinsic C datatypes or even custom * datatypes if you wish. See Simulink document "Writing S-functions" * for details on datatype topics. */ static void mdlOutputs(SimStruct *S, int_T tid) { #ifdef VARIABLE_STEP /* * For Variable Step Code WITH CONTINUOUS STATES * --------------------------------------------- * For Fortran code that implements continuous states and uses * the mdlDerivatives interface, call your Fortran code's output * routines from here. If it alters the states, you have to * reset the solver. Remember, in Simulink the continuous states * must be of type double, so be prepared to copy them to float * if your Fortran code uses REAL as the datatype for the states. * * ... or, NO STATES * ----------------- * If your code has no states and you want it to execute in * a continuous model, keep the uPtrs, sampleArgs, y, and * sampleOutput variables and delete x, xf, and nx. Adjust * the function call accordingly. */ InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); float *sampleArgs = (float *) ssGetDWork(S,1); double *y = ssGetOutputPortRealSignal(S,0); float *sampleOutput = (float *) ssGetDWork(S,0); double *x = ssGetContStates(S); float *xf = (float *) ssGetDWork(S,2); int nx = ssGetNumContStates(S); int k; /* * If the datatype in the Fortran code is REAL * then you have to downcast the I/O and states from * double to float as copies before sending them * to your code (or change the Fortran code). */ for (k=0; k < ssGetDWorkWidth(S,1); k++) { sampleArgs[k] = (float) (*uPtrs[k]); } /*

4

Bilaga 3

* It is recommended to use a DWork vector to * allocate the space for the float copy of * the states (if needed). */ for (k=0; k < nx; k++) { xf[k] = (float) x[k]; } /* ==== Call the Fortran routine (args are pass-by-reference) */ /* nameofsub_(sampleArgs, xf, &nx, sampleOutput ); */ /* * If needed, convert the float outputs to the * double (y) output array */ for (k=0; k < ssGetOutputPortWidth(S,0); k++) { y[k] = (double) sampleOutput[k]; } #else /* * For Fixed Step Code * ------------------- * If the Fortran code implements discrete states (implicitly or * registered with Simulink, it doesn't matter), call the code * from mdlUpdates() and save the output values in a DWork vector. * The variable step solver may call mdlOutputs() several * times in between calls to mdlUpdate, and you must extract the * values from the DWork vector and copy them to the block output * variables. * * Be sure that the ssSetDWorkDataType(S,0) declaration in * mdlInitializeSizes() uses SS_DOUBLE for the datatype when * this code is active. */ double *copyOfOutputs = (double *) ssGetDWork(S, 0); double *y = ssGetOutputPortRealSignal(S,0); int k; for (k=0; k < ssGetOutputSignalWidth(S,0); k++ ) { y[k] = copyOfOutputs[k]; } #endif } #define MDL_UPDATE /* Change to #undef to remove function */ #if defined(MDL_UPDATE) /* Function: mdlUpdate ====================================================== * Abstract: * This function is called once for every major integration time step. * Discrete states are typically updated here, but this function is useful * for performing any tasks that should only take place once per * integration step. */ static void mdlUpdate(SimStruct *S, int_T tid) { #ifndef VARIABLE_STEP /* * For Fixed Step Code Only * ------------------------ * If your Fortran code runs at a fixed time step that advances * each time you call it, it is best to call it here instead of * in mdlOutputs(). The states in the Fortran code need not be * continuous if you call your code from here. */ InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); float *sampleArgs = (float *) ssGetDWork(S,1);

5

Bilaga 3

double *y = ssGetOutputPortRealSignal(S,0); float *sampleOutput = (float *) ssGetDWork(S,0); int k; /* * If the datatype in the Fortran code is REAL * then you have to downcast the I/O and states from * double to float as copies before sending them * to your code (or change the Fortran code). */ for (k=0; k < ssGetDWorkWidth(S,1); k++) { sampleArgs[k] = (float) (*uPtrs[k]); } /* ==== Call the Fortran routine (args are pass-by-reference) */ /* nameofsub_(sampleArgs, sampleOutput ); */ /* * If needed, convert the float outputs to the * double (y) output array */ for (k=0; k < ssGetOutputPortWidth(S,0); k++) { y[k] = (double) sampleOutput[k]; } #endif } #endif /* MDL_UPDATE */ #define MDL_DERIVATIVES /* Change to #undef to remove function */ #if defined(MDL_DERIVATIVES) /* Function: mdlDerivatives ================================================= * Abstract: * In this function, you compute the S-function block's derivatives. * The derivatives are placed in the derivative vector, ssGetdX(S). */ static void mdlDerivatives(SimStruct *S) { #ifdef VARIABLE_STEP /* * For Variable Step Code Only * --------------------------- * If your Fortran code needs to support continuous states * with variable timestep solvers, you need to call into * your Fortran routine (or perhaps one that shares a * common block but only calculates derivatives) here to * extract/calculate state derivatives WITHOUT ADVANCING TIME. */ #endif } #endif /* MDL_DERIVATIVES */ /* Function: mdlTerminate ===================================================== * Abstract: * In this function, you should perform any actions that are necessary * at the termination of a simulation. For example, if memory was * allocated in mdlStart, this is the place to free it. */ static void mdlTerminate(SimStruct *S) { } /*========================================================* * See sfuntmpl_doc.c for the optional S-function methods * *========================================================*/

6

Bilaga 3

/*=============================* * Required S-function trailer * *=============================*/ #ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration function */ #endif

7

Bilaga 4

/* * File: sfun2for.c * * Abstract: * * Revision: */ #define S_FUNCTION_LEVEL 2 #define S_FUNCTION_NAME sfun2for #include "simstruc.h" #if defined (_MSC_VER) #define gestpan_subr_ GESTPAN_SUBR #endif #if defined(__xlc__) || defined(__hpux) #define gestpan_subr_ gestpan_subr #endif /* S-function parameters */ #define MODEL_NAME(S) ssGetSFcnParam(S,0) #define INPUT_NAMES(S) ssGetSFcnParam(S,1) #define INPUT_VECTOR(S) ssGetSFcnParam(S,2) #define OUTPUT_NAMES(S) ssGetSFcnParam(S,3) #define NPARAMS 4 extern void gestpan_subr_(char *, int, // model_name int *, // n_input char *[], int, // input_names double *[], // input_vector int *, // n_output char *[], int, // output_names double *[]); // output_vector /* Function: mdlInitializeSizes ===============================================*/ static void mdlInitializeSizes(SimStruct *S) { ssSetNumSFcnParams(S, NPARAMS); /* Number of expected parameters */ if (ssGetNumSFcnParams(S) != ssGetSFcnParamsCount(S)) { return; /* Parameter mismatch will be reported by Simulink */ } ssSetNumContStates(S, 0); ssSetNumDiscStates(S, 0); if (!ssSetNumInputPorts(S, 1)) return; ssSetInputPortWidth(S, 0, 1); ssSetInputPortDirectFeedThrough(S, 0, 1); if (!ssSetNumOutputPorts(S, 1)) return; ssSetOutputPortWidth(S, 0, DYNAMICALLY_SIZED); ssSetNumSampleTimes(S, 1); ssSetNumRWork(S, 0); ssSetNumIWork(S, 0); ssSetNumPWork(S, 0); ssSetNumModes(S, 0); ssSetNumNonsampledZCs(S, 0); if(!ssSetNumDWork( S, 2)) return; ssSetDWorkWidth( S, 0, ssGetOutputPortWidth(S,0)); ssSetDWorkDataType( S, 0, SS_DOUBLE); ssSetDWorkWidth( S, 1, ssGetInputPortWidth(S,0)); ssSetDWorkDataType( S, 1, SS_DOUBLE); /* Take care when specifying exception free code - see sfuntmpl_doc.c */ ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE); } /* Function: mdlInitializeSampleTimes =========================================*/ static void mdlInitializeSampleTimes(SimStruct *S) { ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); ssSetOffsetTime(S, 0, 0.0); }

1

Bilaga 4

#undef MDL_INITIALIZE_CONDITIONS #if defined(MDL_INITIALIZE_CONDITIONS) /* Function: mdlInitializeConditions ========================================*/ static void mdlInitializeConditions(SimStruct *S) { } #endif /* MDL_INITIALIZE_CONDITIONS */ #define MDL_START #if defined(MDL_START) /* Function: mdlStart =======================================================*/ static void mdlStart(SimStruct *S) { printf("\n"); printf("_________________________________\n"); printf(" GESTPAN Matlab Interface \n"); printf(" V 0.1 \n"); printf("_________________________________\n\n"); } #endif /* MDL_START */ /* Function: mdlOutputs =======================================================*/ static void mdlOutputs(SimStruct *S, int_T tid) { InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); float *sampleArgs = (float *) ssGetDWork(S,1); real_T *y = ssGetOutputPortRealSignal(S,0); float *sampleOutput = (float *) ssGetDWork(S,0); int k; int n_input, n_output; char model_name[11]; double input_vector[4] = {{0},{0},{0},{0}}; double output_vector[1]; char input_names[4][32] = {{" "}, {" "}, {" "}, {" "}}; // "clean" array char output_names[1][32] = {" "}; // "clean" array unsigned int input_names_len = 0; // hidden argument sent to gestpan_subr unsigned int output_names_len = 0; // hidden argument sent to gestpan_subr unsigned int model_name_len = 0; // hidden argument sent to gestpan_subr const mxArray *cell_element_ptr; int i, j, l; for (k=0; k < ssGetDWorkWidth(S,1); k++) { sampleArgs[k] = (float) (*uPtrs[k]); } /* ** Getting S-function parameters ** */ /* Parameter: model_name (char) */ cell_element_ptr = mxGetCell(MODEL_NAME(S),0); mxGetString(cell_element_ptr, model_name, 1+mxGetN(cell_element_ptr)); model_name_len = mxGetN(cell_element_ptr); /* Parameter: input_names (char[4]) */ n_input = mxGetNumberOfElements(INPUT_NAMES(S));// Setting n_input for (i=0; i<n_input; i++) {

cell_element_ptr = mxGetCell(INPUT_NAMES(S),i); mxGetString(cell_element_ptr, input_names[i], 1+mxGetN(cell_element_ptr)); input_names_len = input_names_len + mxGetN(cell_element_ptr); } /* Parameter: input_vector (double[4]) */ for (j=0; j<n_input; j++) { cell_element_ptr = mxGetCell(INPUT_VECTOR(S),j); input_vector[j] = mxGetScalar(cell_element_ptr); } /* Parameter: output_names (char[4]) */ n_output = mxGetNumberOfElements(OUTPUT_NAMES(S));// Setting n_output for (l=0; l<n_output; l++) { cell_element_ptr = mxGetCell(OUTPUT_NAMES(S),l); mxGetString(cell_element_ptr, output_names[l], 1+mxGetN(cell_element_ptr));

2

Bilaga 4

output_names_len = output_names_len + mxGetN(cell_element_ptr); } /* ==== Call the Fortran routine (args are pass-by-reference) */ gestpan_subr_(&model_name, model_name_len, &n_input, &input_names[0], input_names_len, &input_vector[0], &n_output, &output_names[0], output_names_len, &output_vector[0]); printf("output_vector=%.12f", output_vector[0]); printf("output_vector"); for (k=0; k < ssGetOutputPortWidth(S,0); k++) { y[k] = output_vector[0]; } } #undef MDL_UPDATE /* Change to #undef to remove function */ #if defined(MDL_UPDATE) /* Function: mdlUpdate ======================================================*/ static void mdlUpdate(SimStruct *S, int_T tid) { } #endif /* MDL_UPDATE */ #undef MDL_DERIVATIVES /* Change to #undef to remove function */ #if defined(MDL_DERIVATIVES) /* Function: mdlDerivatives =================================================*/ static void mdlDerivatives(SimStruct *S) { } #endif /* MDL_DERIVATIVES */ /* Function: mdlTerminate =====================================================*/ static void mdlTerminate(SimStruct *S) { } /*=============================* * Required S-function trailer */ #ifdef MATLAB_MEX_FILE /* Is this file being compiled as a MEX-file? */ #include "simulink.c" /* MEX-file interface mechanism */ #else #include "cg_sfun.h" /* Code generation registration function */ #endif

3

Bilaga 5

% % file: init.m % % % Programmer: Anders Höglund % % Revision: 2003-02-26: Written. % % Create cell Gestpan_par.model_name = {'rm12_mp.txt'}; Gestpan_par.input.names = {'altitude m';'M';'delta_t_amb K';'pla'}; Gestpan_par.input.vector = {0;0;0;30}; Gestpan_par.output.names = {'t41'}; Gestpan_par.output.vector = {[]}; % disp('Initializing S-function parameters complete') % END of FILE

1