;; -*- mode: Lisp; Syntax: Common-Lisp; Package: model; -*-
;;_________________________________________________________
;;
;;
;; E x a m p l e
;;
;; Copyright � 2000 by Kenny Tilton
;;
(in-package :model)
;
; Now let's look at Synapses, which mediate a dependency between two
semaphors.
; The example hear has a #+notyet feature dependency effectively
suppressing
; the form (fSensitivity 0.05). The example simulates a thermometer
perhaps
; malfunctioning which is sending streams of values randomly plus or
minus
; two-hundredths of a degree around the actual temperature. Does not
sound serious, except...
;
; If you run the example as is, when the temperature gets to our on/off
threshhold
; of 100, chances are you will see the boiler toggle itself on and off
several times
; before the temperature moves away from 100.
;
; Building maintenance personel will report this odd behavior, probably
hearing the
; vent open and shut and open again several times in quick succession,
perhaps even
; causing linkage to fail.
;
; The problem is traced to the semaphor rule which reacts too slavishly
to the stream
; of temperature values. A work order is cut to replace the thermometer,
and to reprogram
; the controller not to be so slavish. There are lotys of ways to solve
this, here if
; you remove the #+notyet dependency you can effectively place a synapse
between the
; temperature semaphor of the thermometer and the status semaphor of the
boiler which
; does not even trigger the 'status semaphor unless the received value
differs by the
; specified amount from the last value which was relayed to the
dependent semaphor 'status.
;
; Now the boiler simply cuts off as the temperature surpasses 100, and
stays off even if
; the thermometer temperature goes to 99.98. The trace output [not
included]
; shows that although the temperature
; of the thermometer is changing, only occasionally does the rule to
decide the boiler
; status get kicked off.
;
(defmodel Boiler ()
((status :semaphor t :initarg :status :accessor status :initform
nil);; vanilla semaphor
(vent :semaphor t :initarg :vent :accessor vent :initform nil)
(thermometer :initarg :thermometer :accessor thermometer :initform
nil)
))
(def-sm-echo (status) ((self Boiler)) ;; parameters default to (self
newValue oldValue)
(trc "ECHO> boiler status" self :oldstatus= oldValue :newstatus=
newValue)
;
; also call boiler API to actually turn it on or off
;
)
(def-sm-echo (vent) ((self Boiler))
(trc "ECHO> boiler vent changing from" oldValue :to newValue)
;
; also call boiler API to actually open or close it
;
)
;-------------------------
(defmodel thermometer ()
((temp :semaphor t :initarg :temp :accessor temp :initform nil)
))
;--------------------------
(defun md-example ()
(md-reset) ;; resets debugging/testing specials
(let ((b (to-be (make-instance 'Boiler ;; to-be explained last time
:status (sm? (let ((temp (^temp (Thermometer self)
#+notyet (fSensitivity
0.05))))
(trc "status sm? sees temp" temp) ;;
make apparent relief offered by synapse
(if (< temp 100)
:on :off)))
:vent (sm? (ecase (^status)
(:on :open)
(:off :closed)))
:thermometer (make-instance 'Thermometer
:temp (smv 20)))))
)
;
; let's simulate a thermometer which, when the temperature is
actually
; any given value T will indicate randomly anything in the range
; T plus/minus 0.02. No big deal unless the actual is exactly our
; threshold point of 100...
;
(dotimes (x 4)
(trc "TOP> ----------- set base to" (+ 98 x))
(dotimes (y 10)
(let ((newtemp (+ 98 x (random 0.04) -.02))) ;; force random
variation around (virtual) base
(trc "TOP> ----------- set temp to" newtemp)
(setf (temp (Thermometer b)) newtemp)))))
)