#lang racket
(require rackunit
plot)
(provide (except-out (all-defined-out)
twopi i))
(define sample-rate/fr (make-parameter 44100))
(define i (sqrt -1))
(define twopi (* 2 pi))
(define (response/raw poly)
(define sr-inv (/ 1 (sample-rate/fr)))
(lambda (omega)
(let ([z (exp (* i sr-inv twopi omega))])
(poly z))))
(define (response/mag poly)
(compose
(lambda (x)
(max -100 (* 10 (/ (log (expt (magnitude x) 2)) (log 10))))
(* 10 (/ (log (max 1e-6 (magnitude x))) (/ (log 10) 2))))
(response/raw poly)))
(define (response-plot poly dbrel min-freq max-freq)
(plot (line (lambda (x)
(- ((response/mag poly) x) dbrel)))
#:x-min min-freq
#:x-max max-freq
#:y-max 0
#:y-min -100
#:width 600))
(define (roots->poly iir-poles)
(coefficients->poly (roots->coefficients iir-poles)))
(define (roots->coefficients iir-poles)
(let ([neg-poles (map - iir-poles)])
(reverse
(for/list ([exponent (in-range (add1 (length neg-poles)))])
(sum-of (map product-of (all-but-n exponent neg-poles)))))))
(define (sum-of l) (foldl + 0 l))
(define (product-of l) (foldl * 1 l))
(define (all-but-n n l)
(cond [(= n 0) (list l)]
[(= n (length l)) (list empty)]
[else (append (all-but-n (- n 1) (rest l))
(map (lambda (x)
(cons (first l) x))
(all-but-n n (rest l))))]))
(define ((coefficients->poly coefficients) x)
(for/fold ([so-far 0])
([coefficient (in-list coefficients)])
(+ coefficient (* so-far x))))
(define (poles&zeros->fun poles zeros)
(coefficient-sets->fun (roots->coefficients poles)
(roots->coefficients zeros)))
(define (coefficient-sets->fun fb-coefficients ff-coefficients)
(let ([feedback-poly (coefficients->poly fb-coefficients)]
[feedforward-poly (coefficients->poly ff-coefficients)])
(lambda (x)
(/ (feedforward-poly x)
(feedback-poly x)))))