問題3-73〜76

「信号としてのストリーム」というトピックです。電気回路の仕組みについては興味はあるものの、なかなか手をつけられていないのが現状です。そのため、問題を一応は解いてはみましたが、問題に書かれていることをそのままコードとして表現しただけで、その正否については検証することはできませんでした。
問題3-73。RC回路を作成します。まず、回路をモデル化するRC手続きを作り、そこに電流を表すストリームを渡すことで、電圧のストリームが出力されます。

(define (RC r c dt)
  (define (make-output input-stream init-v)
    (add-streams
     (scale-stream input-stream r)
     (integral (scale-stream input-stream (/ 1 c))
               init-v
               dt)))
  make-output)

(define RC1 (RC 5 1 0.5))

(display-stream-iter (RC1 integers 10) 10)

;=>15
;=>20.5
;=>26.5
;=>33.0
;=>40.0
;=>47.5
;=>55.5
;=>64.0
;=>73.0
;=>82.5

問題3-74。ここからは零交差(zero-crossing)に関する問題になります。前の信号と今の信号を比べて、ゼロのラインをまたがっているかどうかを調べる点がキーになります。前後の入力信号を調べて、出力信号を生成する手続きsign-change-detectorは以下のように定義しました。

(define (sign-change-detector current last)
  (cond ((and (< current 0) (> last 0)) -1)
        ((and (> current 0) (< last 0)) 1)
        (else 0)))

Eva Lu Atorのzero-crossingの空欄を補うと、以下のようになります。sense-dataを一個ずらしてmapしてやればよさそうです。

(define zero-crossings
  (stream-map sign-change-detector 
              sense-data 
              (cons-stream 0 sense-data)))

問題3-75。入力信号を平滑化するロジックを組み込みます。Louisの実装の何が悪いのかがわからなかったので、ここのブログのエントリーを参考にしました。平滑化計算には、前後の入力信号をそのまま使いますが、そのあとのsign-change-detectorでは、前後の平滑化された値を渡す必要がありそうです。Louisの実装では、一つ前の平滑化された値が使われていないことになります。以下のようにしてやることで、必要な情報がmake-zero-crossingに渡せることになります。

(define (make-zero-crossings input-stream last-value last-avpt)
  (let ((avpt (/ (+ (stream-car input-stream) last-value) 2)))
    (cons-stream (sign-change-detector avpt last-avpt)
                 (make-zero-crossings (stream-cdr input-stream)
                                      (stream-car input-stream)
                                      avpt))))

問題3-76。smooth手続きを定義して、平滑化ロジックを外部に出します。

(define (smooth input-stream)
  (cons-stream (/ (+ (stream-car input-stream)
                     (stream-car (stream-cdr input-stream)))
                  2)
               (smooth (stream-cdr input-stream))))

これを使って、(cons-stream 0 smooth)というストリームを作れば、入力信号が平滑化されたバージョンのストリームを表現することができます。これをmake-zero-crossingに組み込みます。

(define (make-zero-crossings input-stream last-value smooth last-smooth)
  (cons-stream (sign-change-detector (stream-car smooth) last-smooth)
               (make-zero-crossings (stream-cdr input-stream)
                                    (stream-car input-stream)
                                    (stream-cdr smooth)
                                    (stream-car smooth))))

(define zero-crossings (make-zero-crossings 
                        sense-data 
                        0
                        (cons-stream 0 (smooth sense-data)) 
                        0))

last-smoothを排除してしまいたいところですが、どうも上手くいきませんでした。定義されていない部分のsense-dataがsmoothの中でstream-cdrされてしまうのが原因だと考えられます。