12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485(* Claude Code
*
* Copyright (C) 2026 Yoann Padioleau
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public License
* (LGPL) as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*)(* See Diode_ladder.mli *)typet={v:floatarray;(* v1..v4 *)mutablelast_x:float(* the input before, the trapezoid's *)}letcreate():t={v=Array.make40.;last_x=0.}letreset(t:t):unit=Array.fillt.v040.;t.last_x<-0.letrate=float_of_intSignal.rate(* the equations as v' = w (A v + b u): A's rows, b = (2, 0, 0, 0) *)leta=[|[|-4.;2.;0.;0.|];[|1.;-2.;1.;0.|];[|0.;1.;-2.;1.|];[|0.;0.;1.;-1.|]|](* the feedback enters through u = x - k v4: A's first row gains
* -2 k in its last column *)letwith_feedback(k:float):floatarrayarray=Array.mapi(funirow->Array.mapi(funjaij->ifi=0&&j=3thenaij-.(2.*.k)elseaij)row)a(* [solve m y]: m x = y, 4 x 4, Gaussian elimination with partial
* pivoting; m and y are overwritten *)letsolve(m:floatarrayarray)(y:floatarray):floatarray=letn=4inforc=0ton-1doletp=refcinforr=c+1ton-1doifFloat.absm.(r).(c)>Float.absm.(!p).(c)thenp:=rdone;lettmp=m.(c)inm.(c)<-m.(!p);m.(!p)<-tmp;letty=y.(c)iny.(c)<-y.(!p);y.(!p)<-ty;forr=c+1ton-1doletf=m.(r).(c)/.m.(c).(c)inforj=cton-1dom.(r).(j)<-m.(r).(j)-.(f*.m.(c).(j))done;y.(r)<-y.(r)-.(f*.y.(c))donedone;letx=Array.maken0.inforr=n-1downto0dolets=refy.(r)inforj=r+1ton-1dos:=!s-.(m.(r).(j)*.x.(j))done;x.(r)<-!s/.m.(r).(r)done;xletprocess(t:t)~(cutoff:Signal.t)~(resonance:float)(s:Signal.t):unit=letak=with_feedbackresonanceinArray.iteri(funix->letx=tanhxinletfc=Float.max10.(Float.min20000.cutoff.(i))in(* prewarped: the trapezoid's h w / 2 = tan (pi fc / rate) *)letg=tan(Float.pi*.Float.minfc(0.45*.rate)/.rate)in(* (I - g A) v' = (I + g A) v + g b (x + x_last) *)letm=Array.init4(funr->Array.init4(func->(ifr=cthen1.else0.)-.(g*.ak.(r).(c))))inlety=Array.init4(funr->letsum=reft.v.(r)inforc=0to3dosum:=!sum+.(g*.ak.(r).(c)*.t.v.(c))done;ifr=0then!sum+.(g*.2.*.(x+.t.last_x))else!sum)inletv=solvemyinArray.blitv0t.v04;t.last_x<-x;s.(i)<-v.(3))s