• No results found

Simulation in S84

N/A
N/A
Protected

Academic year: 2021

Share "Simulation in S84"

Copied!
82
0
0

Bezig met laden.... (Bekijk nu de volledige tekst)

Hele tekst

(1)

Simulation in S84

Citation for published version (APA):

Rooda, J. E., Joosten, S. M. M., Rossingh, T. J., & Smedinga, R. (1984). Simulation in S84. (TH Eindhoven. Afd. Werktuigbouwkunde, Vakgroep Produktietechnologie : WPB; Vol. WPB0242). Technische Hogeschool

Eindhoven.

Document status and date: Published: 01/01/1984

Document Version:

Publisher’s PDF, also known as Version of Record (includes final page, issue and volume numbers)

Please check the document version of this publication:

• A submitted manuscript is the version of the article upon submission and before peer-review. There can be important differences between the submitted version and the official published version of record. People interested in the research are advised to contact the author for the final version of the publication, or visit the DOI to the publisher's website.

• The final author version and the galley proof are versions of the publication after peer review.

• The final published version features the final layout of the paper including the volume, issue and page numbers.

Link to publication

General rights

Copyright and moral rights for the publications made accessible in the public portal are retained by the authors and/or other copyright owners and it is a condition of accessing publications that users recognise and abide by the legal requirements associated with these rights. • Users may download and print one copy of any publication from the public portal for the purpose of private study or research. • You may not further distribute the material or use it for any profit-making activity or commercial gain

• You may freely distribute the URL identifying the publication in the public portal.

If the publication is distributed under the terms of Article 25fa of the Dutch Copyright Act, indicated by the “Taverne” license above, please follow below link for the End User Agreement:

www.tue.nl/taverne

Take down policy

If you believe that this document breaches copyright please contact us at: openaccess@tue.nl

providing details and we will investigate your claim.

(2)

Auteur,;: p:cof. dr. ir. J. E. Rooda

Ir. S. M. M. JOClb t:~:n Ir. T.J. Rossingh Drs. R. Smedinga

WPA ):apportJH. 0242 october 1984 .

(3)

This project has partly been sponsored by

(4)

TABLE OF CONTENTS 1.0 INTRODUCTION 1.1 General Info 1.2 Compiling S84 Programs 1.3 Running S84 2.0 ELEMENTS 2.1 Element types 2.2 Items 2.3 Processes

2.4 General Information functions 2.5 Elem Exceptions 3.0 QUEUES 3.1 Ordinary Queues 3.2 Priority Queues 3.3 Queue exceptions 4.0 SYNCHRONISATION 4.1 Sema 4.2 Sync 4.3 Mutex 4.4 Mesg 4.5 Coop 4.6 Trig 4.7 Synchronisation Exceptions 5.0 CONTINUOUS PROCESSES IN S84 5.1 Coprocs in S84 5.2 Watchdog 5.3 Examples 5.4 Exceptions 6.0 DATA COLLECTION 6.1 Count 6.2 Accu 6.3 Risto 6.4 Tally 6.5 DCD operations 6.6 DCD exceptions

7.0 PSEUDO INPUT GENERATORS (DISTRIBUTIONS) 7.1 Random number generation

7.2 Distributions 7.3 Consta:lt 7.4 Erlang 7.5 Negexp 7.6 Normal 7.7 Poisson 7.8 Uniform 7.9 Dist Exceptions 8.0 INTERACTIVE FACILITY 9.0 MAIN PROGRAl'1 10.0 HANDlES 11.0 TRACING 12.0 GRAPHICS

12.1 Representation of simulation objects 12.2 The graphic editor

13.0 LITERATURE 1 1 2 2 3 3 3 5 9 10 11 11 11 12 13 13 15 17 18 20 21 23 24 24 26 27 31 33 33 34 35 36 37 38 39 39 39 40 40 41 41 41 41 41 42 43 • 44 45 47 48 49 53

(5)

B IMPLEMENTATION DETAILS

B.I TSIZE

B.2 SYSTEM CRASHES

B.3 TERMINATING PROCESSES

B.4 LIMITATION TO PROCESS PARAMETER LIST

B.5 TYPE CASTING C MATHEMATICAL FUNCTIONS D SUMMARY 60 60 61 62 62 62 64 65 •

.

(6)

1.0 INTRODUCTIO~

This booklet is intended to be a programmers manual for the Simulation Package S84. It does not tell what S84 is, nor why one would use it, nor what can be done with it. This paper only tells how to use it. For the subject of simulation of discrete systems, see [Shannon, 1975; Fishman, 1978; Birtwistle, 1979; Nance, 1981].

584 is implemented in Modular Pascal, and the user of 584 is expected to make his programs in Modular Pascal. A good book to learn standard Pascal is [Schneider, 1978J. The language is described formally in [Jensen, 1975]. Modular Pascal is a dialect of standard Pascal, described by [Bron, 1982b]. Some information on Modular Pascal Operating Systems and the running of Modular Pascal programs can be found in [Joosten, 1981; Bron, 1982a; Rossingh, 1983J.

A suitable introduction to S84 is given by [Rooda, 1982]. When the german language is a bit of a problem, [Rooda, 1981] will do.

The rest of this text assumes that the reader is familiar with Modular Pascal.

1.1 General Info

The chapters of this booklet have been designed to deal with one specific S84 issue each. Some chapters contain declarations. These declarations are exported by two modules: S84DEF exports the type declarations and S84 exports the procedures and functions. To use S84, botn modu1es must be imported: S84DEF first, followed by S84. Within this manual, all the exported declarations can be found with the help of the index.

Some conventions have been adopted concerning the names of routines. Procedures having a name that starts with 'ini' are procedures that initialise a declared variable. The 'ini' procedure must be called before any action on the variable is performed. A function having a name that starts with 'new' does not act upon an existing variaole, but it creates a new variable and initialises it properly. Its result is always a pointer to the newly created variable.

At the end of each chapter, a short discussion on exceptions can be found. Whenever an exception occurs in a program, its description can be found with the aid of the index (look under 'Exceptions'). This goes for 584 exceptions only. Other exceptions can occur in the file system, or in the operating system. S84 exceptions can be recognised from the fact that they are all of the form 'Exception nr. x in S84ERR'.

To illustrate the discussed topics, many examples have beeft inserted throughout the manual.

Appendix D has been added to this manual as a 'quick reference manual'. The experienced user can find all the information that is necessary when programming in a concise form.

(7)

1.2 Compiling 584 Programs

584 programs may be written completely in the programming language Modular Pascal. However. in 584 a notation is used for describing parallel processes. It uses the (reserved) words PROCESS, BEGINPROC and ENDPROC. This notation is used throughout this a8nual. Before compilation of the program, is must be precompiled by the program 584PRE. This program transforms the notation into Modular Pascal, which can be compiled the usual way.

Appendix A gives a full description of what the precompiler does.

1.3 Running 584

This section is applicable only to 584 packages running under the Modular Pascal operating system family (MUPOS, 5UP05).

Before a simulation program can be run, the 584 package must be loaded into the system. This is achieved by running the program S84. After running 584, the simulation package will become part of the operating system. Therefore, it has to be run only once, no matter how many simulation programs are run afterwards.

When 584 is loaded, the user is prompted with two questions: the hard stacK size and the soft stack size. These represent the stacksizes of a process. The hard stack contains only the return information for procedure calls. Therefore, 100 words of hard stack space per process is usually enough. The size of the hard stack cannot be altered in a simulation program. On the soit stack, a process maintains its data and performs calculations. Hence. the soft stack usually occupies more space than the hard stack. 500 words of soft stack space is enough for most applications. The soft stack size can be given another value in simulation programs. The figure supplied here is used as default.

When 584 has been loaded successfully. the following message appears on the terminal:

S84 package version ••• etc. type HALT to remove package.

After 584 has been loaded into the system, the operating system command interpreter remains active, thus allowing simulation programs to be run as any other program. The command HALT removes the 584 package from the system.

(8)

2.0 ELEMENTS

Basically, a model of a discrete system consists of elements and synchronisations. Elements are the subject of this chapter. Two types of elements are available, called items and processes. Both types have a part in common. First the common types and functions are shown. The second part of this section shows the functions available for items; the last part discusses the functions working on the type proc.

2.1 Element types TYPE elem pElem item pltem proc - ?

.

,

= Ael~~; = elem;

=

pElem; - pElem;

FUNCTION elemTitle(pe: pElem): alfa; FUNCTION isAlive(pe: pElem): boolean; FUNCTION timeln(pe: pElem): real;

The function elemTitle yields the title of an elem. It may be used for tracing purposes.

The function isAlive returns true if the referenced elem represents a process. Otherwise it returns false.

The function tim~In gives the last time an elem has entered some queue. It is very useful for gathering queue statistics, or for the simulation of dead-times.

As mentioned above, elements are present in two kinds: items and processes. Items are liveless elements. They cannot perform any actions of their own. They can only be stored or transported. Processes are living elements. They can perform actions. Machines, conveyors, ships etc. are often modelled as processes. Crates, wagonloads, pallets etc. are often modelled as items. The type pElem is compatible to two different types, it may be a pointer to a process (proc) or a pointer to an item (pItem). This allows some structures (queues for example) to handle both types of element.

All elements are dynamic variables. Their lifetime depends on explicit creation and deletion, and not on a (static) scope.

2.2 Items

As explained in the previous paragraph, items are used liveless elements. The neKt declarations dealing with availaole:

to simulate items are

(9)

FUNCTION newltem(CONST title: PACKED ARRAYlinteger]OF char; size: integer): pItem;

PROCEDURE delItem(pi: pItem);

As items are dynamic variables, they must be created explicitely. For this reason, the function newItem is supplied. It returns a pOinter to a fresh item variable. Since Modular Pascal does not contain a garbage collector, items must be deleted explicitely. This 18 done by the procedure delItem.

In general, items are used to model objects that carry some data. For this reason, the user of 584 should be able to add extra data-fields to an item. This is possible by the next declaration:

TYPE box - RECORD it

END; pBox = "box; l, b, h weight item; integer; real

This declaration defines the type box as an extended item. It is necessary that the item is the first field of the extended item. The language Modular Pascal enables the type-conversion of a pointer of the type pltem to a pointer of the type pBox by using the type-identifier pBox as a cast function. Therefore, all S84-routines that handle items can handle extended items as well.

The function newltem is used to create a new item. The title is converted to the type alfa; it is used to denote an item in the trace listing. The parameter size is used to create an item of the appropriate size; the size of Box should be specified. This size can be obtained by means of the Modular Pascal standard function 'ts!ze'. (See appendix B.l

for some information on tsize)

The routine delltem is used to delete an item. The deleted item is placed in some internal garbage queue.

VAR pBx : pBox; BEGIN pBx := pBox(newltem('box', tSize(pBx"'»)j WITH pBx" DO BEGIN 1 := IOU; b := 120; h :- 60; weight :- 7.62 END; delltem(pltem(pBx); END; • Note: The cast function ( pBx :- pBox(newItem( ••••

»; )

can only

be used, if the two involved pointer types are related to each other. E.g. a pointer to an integer can not be cast to a pointer to a boolean. The type to which one of the pointertypes refers, should be the first field of the record to which the other pointertype refers. (See appendix B.S for

(10)

more information on type casting in Modular Pascal)

2.3 Processes

A process may be seen as a procedure that runs together with other procedures. Not one after another, but in parallel. Procedures and processes are alike, except for one point. The calling environment waits for a procedure to finish. As for processes, this is not the case. After the 'call' of a process, the calling environment proceeds at the same moment the process starts running. They run in parallel.

A process is declared as:

PROCESS <procName>«procFormals»; <procDeclarations> BEGINPROC <procBody> ENDPROC; (Example)

PROCESS cookieMonster(VAR cookieJar: cookieBuffer);

(* the type cookieBuffer is declared elsewhere *)

CONST saturated = false; BEGINPROC

REPEAT

eat(takeCookie(cookieJar» UNTIL saturated

ENDPROC;

The declaration is syntactically identical to the procedure declaration in Pascal, except for the words PROCESS, BEGINPROC and ENDPROC. These words must always be the first word on a line, unlike normal keywords. CONST parameters are not allowed in the formal parameter list of a process. All other parameters that are allowed for procedures and functions are legal in the parameter list of a process.

When a procedure is called, the local variables and the parameters are instantiated. That is: they are created. Space is allocated for them.

~nen the procedure finishes, this space is deallocated. With processes exactly the same thing happens. A process is instantiated too, which implies space allocation for the process. When the body of the process finishes, the process is said to terminate, just like a procedure. Instantiation is done as follows:

(* VAR newProc : proc *) •

newProc:=<procName>«title>, (* PACKED ARRAY[integer]OF char*) <stackSize>, (* integer *)

<fig>, (* pFigure *)

(11)

(Example)

VAR monsterl, monster2 proc

monsterl :- cookieMonster('Monster 1', 0, grafic, Ernie.jar); monster2 :- cookieMonster('Monster 2', 0, NIL, Bert.jar);

The instantiation behaves like a function call. It returns a pointer of type proc, denoting the element which embodies the process. This pointer enables the manipulation of a process as normal data object. The example shows that more than one instantiation may be made, just as a procedure may be called zero or more times. In this case, one cookieMonster releases Ernie of his load of cookies, and another cookieMonster empties Bert's jar.

In front of the parameters that were declared (in the example the cookieJar) three other parameters appear. They are necessary for instantiation purposes only. The first parameter is a string containing the title by which the element is identified. The second one denotes the size of the stack created for the parameters, local variables and procedure return information of the instantiated process. The integer value of STACKSIZE specifies the size of the data stack of the process in words. To get an idea of this size, the number can be interpreted as the number of integers that will fit on the d·atastack. Usually, processes will not require very large stacks. For normal processes, the value 0 can be specified. In that case 884 creates a stack of a default size (see chapter 1.3). This ought to be large enough for an average sized process. For processes that need more stackspace, a value greater than zero is specified. If a process has insufficient stackspace, the runtime exception ' dataStackOverflow' is raised.

The third parameter can be either 'grafic' or 'NIL'. 'Grafic' means that this process is included in the graphic administration. Thus it can be connected to a picture on the graphic screen.

The three 'standard instantiation parameters' are followed by the parameters that were specified in the process declaration.

For every process a lifetime is defined, just as with procedures. It is defined as the time between the creation (i.e. instantiation) of the process, and the termination of the process. During its lifetime a process may perform actions. Those actions can be seen as alterations of the state of the entire system. An action is always performed at a specific moment.

During its lifetime, a process can be in three states:

(12)

A process is called active at a certain moment when it is performing actions at that moment. Because several processes are running parallel, more than one process can be active at one moment.

A process is called busy when it will become active at some moment in the future, without intervention by other processes.

A process is idle when it is neither active nor busy. This implies that it is inserted in some q~eue, or it is waiting for some synchronisation. All processes that are not active (all busy and idle processes) are called passive.

A process terminates when its execution reaches ENDPROC. Any action performed on such a process results in the exception procTerminated (nr.

3 in S84ERR).

The states can be tested by the following functions: FUNCTION isActive(p: proc): boolean;

FUNCTION IsIdle(p: proc): boolean FUNCTION isBusy(p: proc): boolean;

2.3.1 Operations on processes

Now the processes themselves are discussed, together with the operations that can be performed on them. All operations transfer a process from one state to another.

PROCEDURE actlvate(pe: proc; offset: real); PROCEDURE passivate;

PROCEDURE cancel(pe: proc); PROCEDURE hold(t: real);

~

After instantiation a process is in the state idle. It aust be made active explicitely. This is done by means of the procedure activate. The following statements have to be added to the previous example to make the monsters active.

activate(monsterl, 0.0); activate(monster2, 0.0);

(13)

The real parameter is the time offset. The indicated process will be activated after 'offset' time units (simulated time) have passed.

In the previous example, activation and instantiation could have been combined elegantly. In this case, no reference to either one of the processes is needed.

activate(cookieMonster('Monster 1', 0, grafic, Ernie.jar), 0.0);

activate(coo~ieMonster('Monster 2', 0, NIL, Bert.jar), 0.0);

Processes may passivate themselves by a calIon passivate. Be sure that the passivated process is reactivated by another process, because it cannot activate itself. This is illustrated by an example:

(* process 1 *) tOQueue(q, current); passivate;

(* process 2 *)

activate(fromQueue(q), 0.0); This example also illustrates the use of current (see also section 2.4). It always denotes the process itself. Every process may refer to itself by means of current.

Another useful procedure is hold. It makes the current process wait for the specified amount of time. It is often used to model an action. This explains why the state of a process performing a hold is called busy.

PROCESS mailman;

VAR m: mail; (* previously

BEGI~PROC; defined *) LOOP hold(12.3); fetch(m); hold(46.3); E~; ENDPROC;

(* 12.3 time units to walk to the post office *) (* pick up mail *)

(* 46.3 time units to deliver the mail *)

Notice that the actions of walking and delivering are modelled by doing nothing.

Processes that are not idle can be made idle by a calIon the procedure cancel. when a process is performing a hold (busy), this hold can be cancelled. Processes that have been activated, and therefore are active, can be cancelled too. When cancelled, the process becomes idle.

Notice that the following statement: cancel(current);

has the same effect as a calIon 'passivate'. In this

advisabl~ to use the latter, but the effect is identical.

case it •

.

is

Another ex&~ple illustrates the use of cancel in a 'watchdog timeout' situation. A process (say 'pr') must wait for a (global) trig (tr). It may not wait longer than 10 time units. It may be described as follows:

(14)

PROCESS prj

VAR done: boolean; watchd: procj PROCESS watchdog;

BEGINPROC;

IF NOT done THEN signal(tr); ENDPROC;

BEGINPROC

done :- false;

watchd :- watchdog('SubPr', 0, NIL); activate(watchd, 10);

wait(tr); done :- true;

'all other activities' ENDPROC;

(The trig mechanism is described in section 4.6)

2.3.2 Summary of Operations on Processes

The table below gives an overview of the operations that may be used. After each operation, the states are given from and to which processes are brought.

Acts Upon From State To State

instantiate new process none idle

activ8tt:! (t==O) other process idle active

activate (t)O) other process idle busy

passivate current ( self) active idle

cancel other process not idle idle

hold current (self) active busy

The transition from busy to active happens as time proceeds. No operation is needed for that. Synchronisation operations may result in the waiting of processes. In that case the transition from active to idle is always implicit. The reverse transition (from idle to active) is done implicitly too.

2.4 General Information functions

FU~CTION current: proc; FUNCTION time: real;

Processes must refer to themselves from time to time. The function current returns a pointer to the process itself.

A variable is kept in tne simulation system that keeps time. Discrete processes perform actions at a certain moment (never during a period of time) and then tney wait. This means that the simulation time is not real time: time jumps with changing intervals at unpredictable moments. This time can be obtained by a calIon the function time. The unit of

(15)

time (seconds, minutes, etc.) is not prescribed.

2.5 Elem Exceptions

The following exceptions may occur that concern the operatioDs described in this chapter.

- timeError (Exception 1 S84ERR)

This exception occurs when an attempt is made to act in the past. The procedure hold or activate was called with a negative value.

- finish (Exception 2 S84ERR)

This exc~ption is raised when all processes in the idle. Possibly deadlock has occurred. Otherwise programming error has been made: The activation of processes must always be guaranteed.

- procTerminated (Exception 3 S84ERR)

system are a serious passivated

This exception is raised when a procedure tries to act upon a process that has terminated. There is a risk that this exception is not raised: see Appendix B.3

- notldle (Exception 4 S84ERR)

This exception is raised in case of an attempt to activate a process that is not idle. This means that it has been activated already. Only idle processes can be activated.

- idle (Exception 5 S84ERR)

This exception signals an attempt to cancel an idle process. - alive (Exception 6 584ERR)

This exception is raised when an action, intended for an item (a liveless element), is performed on a process (a living element). It occurs for instance when delltem is called on a process. - notAlive (Exception 7 S84ERR)

This exception signals the contrary: An action is an item that is intended for use with processes. may be:isldle, isActive, isBusy, activate, cancel. - inQueue (Exception 9 S84ERR)

performed on Those actions

This exception signals an attempt to activate an element that has been entered in some queue. It is considered illegal for an element to be in two places at a time. For that reason it is impossible to have a process perform actions while it is still

(16)

3.0 QUEUES

Discrete simulation is usually based on working with queues. S84 is no exception. Two kinds of queues are available: The ordinary queue and the priority queue. The ordinary queue is discussed first.

3.1 Ordinary Queues

The following declarations are available: TYPE queue - ?;

PROCEDURE iniQueue(VAR q: queue;

CONST title: PACKED ARRAY[integer]OF char; fig: pFigure);

PROCEDURE toQueue(VAR q: queue; pe: pElem); PROCEDURE pushQueue(VAR q: queue; pe: pElem); FUNCTION fromQueue(VAR q: queue): pEl em; FUNCTION firstQueue(CONST q: queue): pEl em; FUNCTION queueAvail(CONST q: queue): integer;

Queues can be used as a first-in-first-out structure (FIFO), or as a last-in-flrst-out structure (LIFO) in which processes and items can be stored. After declaration, a queue must be initialised. This is done by iniQueue.

The procedure tOQueue is used to put elements (processes or items) in a queue. It implements the FIFO structure; elements are inserted at the rear. The procedure pushQueue is used to implement a LIFO structure; the elements are inserted at the front end of the queue. In both cases the element to be inserted is denoted by a pointer (either proc or pitem). The function fromQueue is used to retrieve elements from the front end of the queue.

The function firstQueue delivers a pointer to the first element of the queue, without removing it from the queue. If the queue is empty, it returns the value NIL. This function may be used to inspect the first element in the queue without retrieving it.

The length of the queue is given by the function queueAvail.

3.2 Priority Queues

The second type of queue is the priority queue. It is used when other mechanisms than FIFO or LIFO are desired. An order criterion in the form of a priority has to be supplied in order to sort the queue in the desired order. The priority is a real value. Two reals are considered equal when their absolute difference is less than 0.0001. Elements with the smallest key come first in the priority queue. The following declarations are supported:

(17)

TYPE prio ""' ?

.

,

PROCEDURE iniPrio(VAR pq: prio;

CONST title: PACKED ARRAY[integer}OF char; fig: pFigure);

PROCEDURE toPrio(VAR pq: prio; pe: pElem; key: real); FUNCTION fromPrio(VAR pq: prio): pElem;

FUNCTION fromThisPrio(VAR pq: prioj key: real): pElem;

FUNCTIO~ firstPrio(CONST pq: prio): pElem;

FUNCTION firstThisPrio(CONST pq: prio; key: real): pElem; FUNCTION prioAvai1( CONST pq: pdo): integer;

The functions and procedures match the procedures and functions of ordinary queues as closely as possible.

The first one is iniPrio, that initialises a prio variable.

The procedure toPrio stores an element in a prio queue, given a certain key. The elements are stored in order of that key.

The function fromPrio gets the first element of the queue out. That is the element being stored with the lowest key. When more than one element was stored with the same key, these elements behave in the FIFO manner: first come first served.

In exceptional cases, one might want to get an element that has been stored with a certain priority. The function fromThisPrio serves this purpose. When no element is found this function returns NIL. When more than one element is present, the FIFO structure is used.

The functions firstPrio and firstThisPrio perform the same function as the function firstQueue: They return a pointer to an element in the prio, witnout removing it.

The function prioAvail tells how many elements are in the queue.

3.3 Queue exceptions

With queues, some exceptions may be raised. The same exceptions can be raised when using priority queues.

- queueEmpty (Exception 8 S84ERR)

This exception is raised when an attempt is made to remove an element from an empty queue.

This exception is not raised in fromThisPrio. Upon an attempt to remove an element that is not present, this function returns NIL instead of raising an exception. ~

- inQueue (Exception 9 S84ERR)

When a process is already in a queue, it may not a queue. No object can be in two places exception signals a violation of this principle.

be inserted in at a time. This

(18)

4.0 SYNCHRONISATION

This chapter discusses the relations between elements. In general, when matter, energy or information are passed between processes, there is a relation between these processes. This passing on means that some kind of synchronisation between the processes must be made. The devices specified in this chapter take care of that. This explains their name: synchronisation, or synchronisation device.

All synchronisation devices have operations that might result in the waiting of a process. This waiting occurs implicitly, as a result of certain unfulfilled conditions. If fulfilment of the condition causes only part of the waiting processes to be reactivated, this is done on a first come first serve basis.

4.1 Sema

The first type of synchronisation that is dealt with is the most fundamental kind. It is the SEMAphore as Dijkstra has defined in 1965 [Dijkstra, 1965]. The following declarations are available:

TYPE sema • ?

.

,

PROCEDURE iniSema(VAR s: sema;

CONST title: PACKED ARRAY[integer]OF char; init: integer; fig: pFigure);

PROCEDURE p(VAR s: sema); PROCEDURE v(VAR s: sema);

FUNCTION semaAvail(CONST s: sema): integer;

Almost all synchronisations in S84 are based on this semaphore. A sema is a variable with some integer value in it. This value can be obtained by the function s~~aAvail. When initialised, this value is assigned to the semaphore. It may never be less than zero. Two actions upon the semaphore are available: p and 'v'. Originally, these names are derived from the dutch words 'Passeren' (to Pass) and 'Vrijgeven' (to Release). These operations are indivisible to the calling process.

The semaphore is much like a black box containing some tokens. The number of tokens in the box is initially zero or more. A process cannot see how many tokens the box contains. A p operation equals obtaining exactly one token. As long as no tokens are available, the process waits. The v operation gives a token to the semaphore. Hence, a v operation cannot cause waiting.

The use of sema can probably be explained best by a short example: the estafette race. The second runner waits for the first runner to finish and so on.

(19)

PROGRAM estafette(output, S84def, S84); VAR estafetteSema : sema;

PROCESS runner; BEGINPROC; p(estafetteSema); hold(3.0); v(estafetteSema); ENDPROC; VAR i: integer; BEGIN 1ni884 ; trace(output. on);

(* take the estafette stick *)

(* models the running *)

(* pass the stick on *)

iniSema(estafetteSema, 'Est. Stick', 0, NIL);

FOR i :- 1 TO 5

DO activate(runner(edit('Runner', i), 0, NIL), 0.0); v(estafetteSema); (* start the first runner *)

hold(20.0); END.

Only one description of a runner process is made. A runner starts to take an estafette stick from the estafetteSema. In fact, an estafette stick has been invented by sportsmen for the sake of synchronisation only! The procedure p guarantees that a stick is taken. This means that the process waits until a stick is available. The main program creates five runners. They all start waiting for the stick. The main program supplies one stick. Exactly one of the waiting processes gets hold of

it, and starts running. Three time units later, when it has finished running, it passes on the stick to another process, which then starts running. The trace output shows what has happened.

************************************************************************

*

Clock time & +0.000

*

*

Tracing Starts

*

*

*

************************************************************************

Time Current Action

+0.000 S84 activates Runner 1 at once activates Runner 2 at once activates Runner 3 at once activates Runner 4 at once activates Runner 5 at once

Runner Runner Runner Runner Runner +3.000 Runner Runner 1 2 3 4 5 1 2

does a V operation on sema: Est. Stick holds +20.000 until +20.000

does a P operation on sema: Est. Stick holds +3.000 until +3.000

waits in a P operation in sema: Est. Stick waits in a P operation in sema: Est. Stick waits in a P operation in sema: Est. Stick waits in a P operation in sema: Est. Stick does a V operation on sema: Est. Stick

terminates

leaves the P operation in sema: Est. Stick holds +3.000 until +6.000

(20)

+6.000 Runner 3 +9.000 Runner 4 +12.000 Runner 5 +15.000

does a V operation on sema: Est. Stick terminates

leaves the P operation in sema: Est. Stick holds +3.000 until +9.000

does a V operation on sema: Est. Stick terminates

leaves the P operation in sema: Est. Stick holds +3.000 until +12.000

does a V operation on sema: Est. Stick terminates

leaves the P operation in sema: Est. Stick holds +3.000 until +15.000

does a V operation on sema: Est. Stick terminates

About the function semaAvail a remark must be made. One might easily be tempted to write the following program:

BEGINPROC

IF semaAvail(s»O THEN p(s);

ENDPROC;

This piece of program was written with the intention to prevent the process from waiting. However, there still is a chance that the process will wait, and therefore this program is not correct. It is possible that after the call of semaAvail, and before the call of p, another process performs a p operation on the semaphore s. In that case, p is called while the value of the semaphore is possibly zero. The reason that this goes wrong is that a test is followed by an action while other processes can interfere. Hence, the result of the test is uncertain when the reSUlting action is performed. The only way to use semaAvail safely. is to use it for reporting purposes only. In that case only observations are made without any consequences for the system. Actually, semaAvail was included in 584 only for that purpose.

4.2 Sync

Tne second type of synchronisation is the sync. It is a simple synchronisation mechanism, that is used when nothing is really transported, but only synchronisation is wanted. A sync is equivalent to a sema that has been initialised on zero.

(21)

TYPE sync - 1;

PROCEDURE iniSync(VAR s: sync;

CONST title: PACKED ARRAY[integer]OF char; fig: pFigure);

PROCEDURE takeSync(VAR s: sync; n: integer); PROCEDURE giveSync(VAR s: sync; n: integer); FUNCTION syncAvail(CONST s: sync): integer;

The warning that was given for the function semaAvail, goes for syncAvail just as well. It is intended only for reporting purposes. To make use of the result of syncAvall in an algorithm is dangerous.

A typical sync application is considered as an example: process control. A small part of a packing department is shown. The production supplies crates when the controller orders them. These crates must be packed on pallets. Eight crates fit on one pallet. The crate packer 'consumes' what production 'produces'. Both production and crate packer are controlled by the controller.

VAR packOrder, crateOrder PROCESS packer;

BEGINPROC LOOP

takeSync(packOrder, 1);

sync;

'consume eight crates and produce a pallet with crates' ENDPROCj

PROCESS producer; BEGINPROC

LOOP

takeSync(crateOrder, 1);

'produce one crate' END ENDPROC; PROCESS controller; BEGINPROC LOOP giveSync(crateOrder, 8); giveSync(packOrder, 1); hold(delayTime); END ENDPROC;

The flow of orders is modelled in this example by means of syncs. The controller 'orders' eight crates from the producer. and one filled pallet from the packer.

Of course, the flow of goods has to be modelled also. This can be done with syncs as well. The quoted parts in the example are exchanged for

(22)

code modelling the flow of goods. VAR packOrder, crateOrder

pallets, crates, storelnp PROCESS packer; BEGINPROC LOOP takeSync(packOrder, 1); sync; sync;

(* Now start gathering one pallet and eight crates *)

takeSync(crates, 8); takeSync(pallets, 1);

(* put the crates on the pallet *)

hold(3.4);

(* And pass the entire thing on *)

giveSync(storelnp, 1); E~ ENDPROC; PROCESS producer; BEGINPROC LOOP takeSync(crateOrder, 1);

hold(O.2B) (* time needed to produce of a crate *)

giveSync(crates, 1);

END ENDPROC;

PROCESS controller;

(* The controller does not have to be altered *)

BEGINPROC LOOP giveSync(crateOrder, 8); giveSync(packOrder, 1); hold(4); E~ ENDPROC;

Because this is only a part of the production, some gaps remain in this example. The question where the pallets come from remains unanswered. They mi6ht come from some pallet store, or maybe a pallet production system. The packer leaves the finished pallets in a sync called storelnp. There must be some process that does something with these finished pallets, or they will pile up. The nice thing about modelling in this way, is that when the entire line is not fast enough, the orders for pallets pile up in packOrder or crateOrder. This is exactly what happens in the real world.

• 4.3 Mutex

A mutex is equivalent to a sema that has been initialised with an integer value greater than zero. Mutex is used when processes are competing for resources. The name comes from 'MUTual EXclusion', which means that the processes must be mutually excluded from the use of the same resource. A good example is a computer system with two line

(23)

printers. All users might want to print something, but only two users at a time can use a printer. Let us look at the declarations:

TYPE mutex .. ?;

PROCEDURE iniMutex(VAR m: mutex;

CONST title: PACKED ARRAY[integer]OF char; initval: integer; fig: pFigure);

PROCEDURE takeMutex(VAR m: mutex; n: integer); PROCEDURE giveMutex(VAR m: mutex; n: integer); FUNCTION mutexAvail(CONST m: mutex): integer;

After declaration the mutex must be initialised. The initial value is two in our example, because the resource consists of two line printers. The model could be made as follows:

VAR printers : mutex;

(* any process wanting to print must do: *)

BEGINPROC takeMutex(printers, 1); print; hold(length/speed); giveMutex(printers, 1); ENDPROC;

(* get hold of one line printer *)

(* model the printing time *) (* release the printer *)

The procedure take~utex takes as many units from the resource as specified. Of course, this number may not exceed the initial value: one cannot claim more line printers than there are available. TakeMutex waits for the specified number of resources. GiveMutex releases the units. The function mutexAvall tells how many units are available. Its use is just as dangerous as syncAvail and semaAvail, so it should be used for reporting pur?oses only.

4.4 Mesg

The word mesg is derived from the word message. This suggests that it can pass messages, and so it does. Mesg is used when an item must be passed to another process. It is a mixture of a queue and a sema. This enables safe item transmission. The following declarations are available:

(24)

TYPE mesg - ?;

PROCEDURE iniMesg(VAR m: mesg;

CONST title: PACKED ARRAY[integer]OF char; fig: pFigure);

FUNCTION takeMesg(VAR m: mesg): pltem; PROCEDURE glveMesg(VAR m: mesg; p: pltem); FUNCTION firstMesg(CONST m: mesg): pltem; FUNCTION mesgAvail(CONST m: mesg): integer;

To illustrate the use of mes6, another example is presented. It deals with a pick and place machine, that picks things (items), handles them, and places them. The items are picked from an input mesg, and placed in an output mesg.

PROCESS manlpulator(VAR inp, outp VAR curlt : pltem;

BEGINPROC LOOP

mesg);

curlt :- takeMesg(inp); (* pick an item *)

hold(2.0) (* handle the item *)

giveMesg(outp, curlt) END

ENDPROC;

Many of these machines can add up to an entire production system, through which a stream of items flow.

Again, the take operation takes care of the waiting. TakeMesg waits until an item is available. A pointer to that item is returned as function result. In case more than one process is waiting on the same mesg, the process that came first, gets the first item.

The function firstMesg returns a pointer to the first item in the message, or NIL, when the message is empty. It can be used to inspect

the first item in the message without removing it.

The function mesgAvail supplies the number of items currently stored in the mesg.

When using the functions firstMesg and mesgAvail, one must be certain that no other processes interfere. The danger described for semaAvail, is present for the functions firstMesg and mesgAvail too. When tests are performed upon the first element in a mesg before the element is removed from it, there is a chance that another process will remove the element. in the meantime.

To transfer user defined items through a message, the cast function as described in section 2.2 should be used.

(25)

4.5 Coop

The word coop comes from 'cooperation of processes'. This type of synchronisation is in many ways similar to a mesg, only now processes are passed on. This can be useful for instance when a process instead of an item must be transported from one place to another. Like mesg. the take and give operations are supplied. What is more, a wait 1s supplied. This is necessary when a process wants to 'give itself'. It was not needed with mesgs. Items cannot perform actions, so they can never give themselves. The actual effect of a wait is that the current process is 'given' to the coop, and is passivated until another process takes it

from the coop and activates it.

The function firstCoop returns a pointer to the first process in the coop, without removing it from the coop.

The function coopAvail tells how many processes are stored in the coop . TYPE coop

..

".

.

,

PROCEDURE iniCoop(VAR c:COOpj

CONST title: PACKED ARRAY[integer}OF char; fig : pFigure);

FUNCTION takeCoop(VAR c: coop): procj PROCEDURE giveCoop(VAR c: coop; pe: proc); PROCEDURE waitCoop(VAR c: coop);

BEGI~ giveCoop(c. current); passivate END; FuNCTION firstCoop(CONST c: coop): proc; FUNCTION coopAvail(CONST c: coop): integer;

The functions firstCoop and coopAvail are dangerous functions, like firstMesg and mesgAvail.

The use of coops is (again) best illustrated by an example. A common

ex~ple has been chosen: the soup kitchen. A person requiring soup calls the procedur~ 'pleaseSoup'. The lady distributing soup cooperates with the person requiring soup for some time.

(26)

VAR bell

soupCounter

sema coop

PROCEDURE pleaseSoup(pl: plate); BEGIN

v(bell); (* wake the soup lady *)

wait(soupCounter); pl.contents :+ obtainSoup; END; PROCESS soupserver; BEGINPROC LOOP p(bell»; activate(takeCoop(soupCounter»; END; ENDPROCj

This might not be the most efficient implementation of the soup kitchen problem, but it gives a good idea of how coops are used.

4.6 Trig

A trig is used when a process wants to trigger an unknown number of other processes. It is the bell that the master rings when lessons start. It wakes up the pupils that must then take the action of going inside to their classrooms. The function wait is called by a process that waits for a signal. It is passivated until the signal comes. The procedure signal activates all waiting processes. When no process is waiting, a calIon signal has no effect. (When the master rings the bell on sunday, no one reacts because no one is present.) The iniTrig operation is done to initialise a trig variable.

TYPE trig

=

?;

PROCEUURE iniTrig(VAR t: trig;

CONST title: PACKED ARRAY[integer]OF CHAR); PROCEDURE wait(VAR t: trig);

PROCEUURE waitCond(VAR t: trig; FUNCTION condition: boolean); PROCEDURE signal(VAR t: trig)j

Again an example can illustrate the use of trig: the skating competition. Skaters may not start before they hear a shot from the umpire's gun.

(27)

PROGRA~ skate(output, S84def, S84); VAR startGun : trig;

PROCESS skater; BEGINPROC

wait(startGun) ;

hold( •.• ); (* skate *)

IF tracing TrlEN write(output, 'finishes'); ENDPROC;

VAR i: integer; BEGIN

ini584 ;

iniTrig(startGun. 'Start Gun'); trace(output. on);

FOR i :=1 TO 4

DO activate(skater(edit('Skater', i), 0, NIL), 0.0); signal(startGun):

hold(50); END.

With the trig declarations, another procedure was declared which has not yet been discussed. It is waitCond. The procedure is used when a process must wait until a certain condition is fulfilled. The condition must be programmed as a boolean function without parameters. The process calls the procedure waitCond on a trig, and passes the boolean function as parameter. Whenever a signal is given, the condition is evaluated. If the condition is true, the trig is left, and the actions resumed. Another example may illustrate its use:

Ships in a harbour want to sail at a certain moment, but they must wait until the weather is quiet enough. How quiet the weather must be depends on the strength of the ship. Strong ships may sail at a wind force beneath 9, and weak ships must wait until the force is beneath 7.

PROGRA~ storm(fileio, output, textio, 584def, 584); TYPE stormForce = 1 .. 12:

VAR weatherReport trig;

storm stormForce:

PROCESS wea ther; BEGI!'iPROC LOOP storm := 3: storm := 5-

,

storm := 11; storm := 10; storm := 9-

storm := 7 •

storm := 2; END signal(weatherReport); signal(weatherReport); signal(weatherReport)j signa1(veatherReport); signal(weatherReport); signal(veatherReport); signal(weatherReport); hold(2.0): hold(8.0); hold(3.S); hold(1.2); hold(O.7); hold(2.0); hold(32.5) •

.

(28)

PROCESS ship(critForce: stormForce); FUNCTION condition: boolean;

BEGIN condition :- storm<critForce END; BEGINPROC

waitCond(weatherReport, condition); IF tracing

THEN write(output, 'Sails at wind force' stora:l); ENDPROC; VAR i : integer; BEGIN 1ni584; iniTrig{weatherReport, 'Weather'); trace(output, on);

activate(weather( 'weather', 0, grafic), 0.0); FOR i := 1 TO 50

DO BEGIN hold(l);

activate(Ship(edit('Str. Ship'. i), 0, NIL, 9), 0.0); activate(Ship(edit{'Weak Ship', 1), 0, NIL, 7), 0.0);

END;

hold(lOO); (* wait for ships *) END.

4.7 Synchronisation Exceptions

The last subject in this chapter are the exceptions that can occur with semaphores.

- illSemaOperatlon (Exception 10 S84ERR)

This exception can occur when a sema is initialised with a negative value. It occurs also when a takeSync, takeMutex, giveSync or giveMutex with an integer value less than one is attempted.

- illIniMutex (Exception 11 S84ERR)

The exception illiniMutex is raised when a mutex is initialised on zero or less.

- illMutOpr (Exception 12 S84ERR)

This exception signals an attempt to take or give more resources than initially available.

(29)

5.0 CONTINUOUS PROCESSES IN S84

This chapter deals with the counterpart of discrete systems, continuous systems. Discrete means that at certain moments in time certain actions happen. With continuous systems certain actions proceed in time continuously.

It depends on that aspect of the behaviour which is of interest, whether reality is modelled as a discrete system or a continuous system. A ferry-boat for example can be seen as a discrete system, and a destillation column as a continuous one. The ferryboat has a finite number of states it can be in (i.e. crossing the river, loading etc), but the destillation column has an infinite number of states (i.e. the outflow of the column can change continuously from 0 to maximum).

Simulation of discrete processes is described in the previous chapters. This chapter deals with the simulation of continuous systems. In S84 both kinds of simulation can be mixed, so hybrid simulation is possible.

5.1 Coprocs in 584

In 584 the following type and procedures are available: TYPE coproc • ?

.

,

FuNCTION install(CONST title: PACKED ARRAY[integer]OF char; FUNCTION dXidT(i: integer; t: real;

CONST x: ARRAY[integer]OF real; ): real;

PROCEDURE watchdog(currCp: coproc;

CONST x: ARRAYlintegerjOF real); VAR state: ARRAY[integer]OF real;

wdFreq. maxStep. minStep, maxError: real; Fig: pFigure): coproc;

PROCEDURE start(cp: coproc); PROCEDURE stop(cp: coproc); PROCEDURE kill(cp: coproc);

FUNCTION isCoprocActive(cp: coproc): boolean; PROCEDURE noWatchdog(cp: coproc;

CONST x: ARRAY[integer]OF real);

8EGI~ (* dummy procedure *) END;

The function install does the instantiation of a continuous process. The parameters have the following meaning: -,

The string title holds the name of the coproc.

The function dXidT specifies the i-th component of the derivative of the state-vector x at time t, where i, t and x are parameters of dXidT. Each coproc is accompanied by a watchdog process. The watchdog gets the same name as the coproc, preceded with 'wd '. The watchdog process will perform the actions specified by the procedure watchdog. The parameter currCp in watchdog is used to denote the corresponding coproc and the

(30)

parameter x to denote the corresponding state. Only the actions needed to control the coproc have to be given in the procedure watchdog. Activating and passivating of the watchdog are taken care of by 584. Therefore procedures like hold and tOQueue should not be used in the procedure watchdog, because this may destroy the administration.

If no watchdog is needed, the parameter wdFreq should be given the value 0.0 and the predefined dummy procedure nOWatchdog can be u.ed.

The variable state represents the state-vector of the process. The lowerbound of this array must always be 1. Make sure that the state vector exists durin6 the entire lifetime of the coproc. Usually, this is achieved by declaring it in the global environment of the coproc.

The parameter wdFreq specifies the frequency of calling watchdog.

By means of maxStep and minStep the minimum and the maximum stepsize for integration are specified.

By means of maxError the maximum derivation from the exact solution is specified. When 0.0 is specified, a default value is used.

Note that only the differential equation of each coproc must be specified. The method of integration is determined by 584. Because a differential equation describes the behaviour of the process fully, the integration method need not be of concern to the user.

The procedure start has the same effect as activate(cp), but it also activates the corresponding watchdog periodically with frequency wdFreq. Before the procedure start is called the global variable state must be initialised.

Stop has the same purpose as cancel(cp). This means the state of the coproc does not change, until a new start(cp) is given. The periodically calling of watchdog is cancelled as well.

A coproc is removed from the system by calling the procedure kill. After killing a coproc it is impossible to restart it. First a new install has to be done. A cop roc should first be stopped before it can be killed. During the lifetime of the coproc (i.e. between its instantiation with

install till its termination with kill) that coproc can be in two states:

- active (started and not stopped)

- idle (not started or already stopped)

The state of the coproc can be obtained by a calIon the function IsCoprocActive.

The types coproc and pElem are not interchangable. As coproc cannot be placed in some queue, nor can cancelled etc. In S84 the basic concept is that once a in some queue it cannot perform any actions (events). has been started, perfor~s actions continuously and SO

placed in some queue.

a consequence a it be activated or process is placed A coproc, once it it can never be

To simulate a continuous process, it must be made discrete by taking a small time interval h and replacing the differential equations for difference equations, where

z(t) • x(tl) for tl-h

<

t

<=

tl

(31)

The stepsize h does not have to be constant. In what way this discrete process resembles its original depends on the size of the interval h, and on the method of integration.

The integration is done according to Runge Kutta Merson [Lapidus, 1971]. The algorithm chooses the optimal integration stepsize, starting with size 'maxStep'. The RKM-method calculates an error-vector. If one of the elements of that vector is greater than some value 'aaxError' the step-size is reduced. When this step-size becomes smaller than some value 'minStep', an exception is raised (Exception 18: stepTooSmall). Some default values for maxError, maxStep and minStep are defined. Schematically the Rl<!-t-method looks like:

given x'

=

F(x,t) and xO at time to, calculate xl at tl

=

to+h by:

kl '" F(xO to )

k2- F(xO + h/3 'If kl to

+

h/3)

k3 - F(xO + h/6 'If (kl + k2) to + h/3)

k4 '" F(xO + h/B 'If (kl + 3 'If k3)

,

to + h/2) k5 '" F(xO + h/2 'If (kl - 3 'If k3 + 4 'If k4), to + h )

xl

..

xO + h/6 'If (kl + 4

*

k4 + kS)

with errorvector: e

=

h/30 'If (2

*

kl - 9

*

k3 - 8

*

k4 - k5)

Integration always takes place 'in advance', meaning at time t integration is done calculating the state at time t

+

stepsize. Of course this can only be done if all other discrete processes have taken their possible actions at time t and no discrete process will take any action somewhere between t and t + stepsize. If this happens, it is possible that a discrete process changes some parameter of a continuous process, while this change in behaviour is not immediately noticed by the involved coproc. Therefore the simulation structure is organized to activate all discrete processes at time t first, and then handle all coprocs. Integration takes place until time tl is reached, where tl is the minimum of the next eventtime of the first discrete process to be reactivated in future and t + stepsize, with stepsize the smallest of all 'maxStep'- values of the current coprocs.

5.2 Watchdog

The user-declared procedure watchdog may contain all kinds of checks on the state of the coproc. Mostly watchdog is used to control the coproc. If one uses a global variable in the function dXidT, this variable can be changed in watchdog and so change the behaviour of that coproc.

Because in real life the whole state of a process 1s normally not observable, it is easy to create some kind of observer y. for example

y = C*x

(32)

PROCEDURE observation(CONST x: ARRAY[integerjOF real; VAR y: ARRAY[integer]OF real);

(* C is some global defined matrix *)

BEGIN muIMatvec(C,x,y) END;

Tbis function can be called (and declared) in watchdog. Observstions are made at intervals of wdFreq time units.

In watchdog it is even possible to stop the corresponding coproc. Therefore the parameter currCp is very usefull. Just add the statement

stop(currCp)

to the other statements in watchdog.

5.3 Examples

The best way to explain the usage of the above procedures and functions is to give an example. This section gives three examples, to present the flavour of continuous simulation in S84.

5.3.1 State Feedback

In systems theory a frequently used system description is the following: (x, y, u are vectors, A, B, C are matrices)

S: x ' · Ax + Bu

where x is the state of the system under consideration and u the control. Usually the following picture is drawn:

The state is invisible to the outside world. The system can be controlled by the input u. Observations yare made. For simplicity the situation y = x is considered (i.e. the whole state is observable) although in most cases some observation y • Cx is used.

The system is controlled (stabilized) using a so called statefeedbacklaw

u

=

Fx

giving a closedloop system of the following form:

x' - (A + BF) x

(33)

u

Under certain conditions on A and B, F can be computed 80 that the

matrix (A + BF) has eigenvalues with real part

<

O. This means the closedloop system is made stable.

In S84 the system can be simulated as follows:

PROG~~ feedback(output, textio, S84def, S84, torrix); CONST n=.. ; m-.. ;

TYPE vector - ARRAY matrix - ARRAY cvec .. ARRAY [1. .n] OF real [1. .n,l. .n] OF

I

L .m] OF real [1. .n,l. .m] OF cmat - ARRAY VAR cp A x B u coproc; matrix; vectorj cmat; cvecj

,

real

,

real

FUNCTION dXidT(i:integerj t: real;

CONST x: ARRAY[integerjOF real ): realj

BEGIN dXidT :- mulVecVec(A[i], x) + mulVecVec(B[i], u) END; PROCEDURE watchdog(cp: coproc;

CONST x: ARRAY[integer]OF real); BEGIN mulMatVec (F,x,u) (* IF abs(x[l])

>

someLimit THEN BEGIN IF tracing u :- F

*

x *) ; THEN write(output.'overflow stop(cp)

occurs, coproc stopped'); END

END; BEGIN

ini584; trace(output, on);

A := .• ; B :- •• ; F :- •• ;

x := ... ;

cp :- install('example', dXidT, watchdog, x, someWdFreq, 0.0, 0.0, 0.0, NIL);

(34)

start(cp); hold(someTime); stop(cp); kill(cp); END.

mulVecVec and mulMatVec are routines that multiply a vector with a vector and a matrix with a vector. 'start(cp)' causes the coproc to start and the watchdog to be activated after periods of 'someWdFreq'. The first calling of watchdog takes place at the same time 'start (cp)' is given, thus before any integration has taken place. This means, that first in watchd06 the vector u is given some value and then integration is done.

This example shows how to simulate exactly one continuous process. Although no discrete processes are declared one such process is added automatically: The watchdog.

The use of this watchdog to calculate the control u periodically is realistic: In real life such a control is calculated periodically too. In most continuous simulation packages and languages such a control cannot be simulated. Only simulation of the system with differential equation:

x' • (A + BF) x

is possible, but this means that u changes continuously and this is certainly not according to the original idea.

In 584 however, the calculation of u is done independent of tne calculation of the differential equation. The equation

x' - Ax + Bu

is integrated, where u is being thought of as a constant. this 'constant' is changed periodically. The time period new control is calculated is completely independent of the in the integration routine.

In watchdog after which a stepsize used Furthermore the watchdog is used as a monitor: When x[l) becomes too large the cop roc is stopped (think of it as some kind of emergency-stop).

5.3.2 Damped Vibratio~

This section describes an example which is quite classical: The damped vibration.

The following process will be used.

(35)

mass m [kg] spring compliancy C [N/mj

F

m

damper resistance R [kgl s]

external force F [N]

velocity v (m/s]

The corresponding differential equation is: M*x" + R*x' + x/C

=

F

This differential equation is made first order: xl" • x2 x2' - F/M - xl/(M*C) - x2*R/M

The continuous process is described by two routines: a function dXidT to compute toe derivative of the i-th component of the statevector x at time t, and a procedure watchdog to monitor the process.

FUNCTION dXidT(i: integer; t:real;

CONST x: ARRAY[integer]OF real): real; OF dXidT := x[2]; BEGI~ CASE i 1 2 : dXidT := (F - xll]/C - x(2]*R)

I

M END END;

PROCEDURE watchdog(cp: coproc

CONST x: ARRAY[integer]OF real);

BEGIN

printrow(output, x, "state"); IF tooBig(x) THEN stop(cp)

END;

5.3.3 Transmission Line

(* tracing *)

(* emergency stop *)

Consider a transmission line as a sequence of capacitors and induction coils. VO is the input, Vr is the output and also the variable which is

of interest. L L In L 1n+1 -+

+

+

+

C

[~--:~O

__________

C_][~_:_1

______

~

C Vn

(36)

I ' .. (V - V ) / L ( i .. 1, • • • t n ) i i i-I V' - (I I ) I C ( i - 1, ••• , n ) i i HI I'

=

V' I R .. (I - I ) I (R*C) n+l n n n+l

The state of the system is given by alII's and V's. They are coded as follows: x[2*i) ,. I i x[2*HIJ ,. V i ( i ". 1, " ' , n+l ) (i=O, ••• ,n )

The following function dXidT is constructed: FUNCTION dXidT(i: integer; t: real;

CONST x: ARRAY[integer]OF real): BEGIN

IF i"l THEN dXidT := "input VO"

IF i=2*n+2 THEN dXidT :- (xL i] - x[ i-2])

IF odd(i) THEN dXidT := (x[i+l] - xli-I]) (* IF even(i) THEN *) dXidT :- (x[i+l] - x[i-I]) END; real; ELSE I (R*C) ELSE I C ELSE / L

Note that quite a complicated system is simulated by just one function consisting of four lines of statements.

5.4 Exceptions

Some exceptions may be raised, while using coprocs. The meaning of the possible exceptions is listed here:

- stepTooSmall (Exception 18 S84ERR)

The integration routine cannot calculate a solution for the differential equation with an error vector with elements smaller then the given 'maxError' and integrationstep not smaller then 'minStep'. Try to run the program again with smaller 'minStep' or greater 'maxError'.

- illStateDim (Exception 19 SB4ERR)

The user declared array. needed as state for the coproc should always have a lowerbound 1. If this is not the case an ~xeption

is raised.

- notStopped (Exception 20 S84ERR)

Try to start or restart a coproc that has not been stopped before.

(37)

Try to start or restart a coproc that has already been started before.

- alreadyStopped (Exception 22 S84ERR)

Try to stop a coproc that has already been stopped. - notlnstalled (Exception 23 S84ERR)

Try to do something with a coproc that has not been installed before.

Referenties

GERELATEERDE DOCUMENTEN

Theorem 3.2.10 allows us to determine the 2-rank of the group of units corresponding to a suitable clique; it is the number of vertices of the clique.. The following lemmas allow us

This model may, for example, explain the first-order ferro- magnetic to paramagnetic transition in UGe 2 , where the quantum fluctuations of the superconducting order parameter

The process evaluation focused on the core activities of the KWS project, namely the communication activities on the nature, objective and results of CSOs and the CT method,

Plan quality Perform quality assurance Perform quality control Develop human resource plan Acquire project team Develop project team Manage project team Identify

For if the emergence of joint action presupposes a closure which brings about collective self- inclusion and other-exclusion, then the constitutive rules of constitutions are the

In some Member States there are considerable gaps in victim protection legislation, for example, because there is no (pre- trial or post-trial) protection in criminal proceedings

Nader onderzoek zou ver - richt kunnen worden naar het alcoholgebruik onder fietsers en bromfietsers en de consequenties van dat gebruik op de verkeersveilig- heid.. Er zijn

Publisher’s PDF, also known as Version of Record (includes final page, issue and volume numbers) Please check the document version of this publication:.. • A submitted manuscript is