From: Kenny Tilton
Subject: Semaphors & Synapses
Date: 
Message-ID: <39F4DE69.21B47C83@nyc.rr.com>
;; -*- 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)))))

    )