I recently found examples how to use ModelingToolkit.jl to model electrical circuit components in a Verilog-A-esque fashion. Pretty neat!:
→ ModelingToolkit.jl/electrical_components.jl at master · SciML/ModelingToolkit.jl · GitHub
Using a similar methodology, I got a Shockley (exponential) diode model working. I’m having a bit of trouble converging on more complex circuits, but I got it to work - which is good!
I then tried creating an “ideal” diode model using this same methodology, but it won’t simulate very well. I am aware that there are convergence issues when models have discontinuities like this, but Verilog-A seems to be able to manage quite well despite these issues.
Here is my model:
function Diode(::Ideal; name) @named(p = Pin()); @named(n = Pin()) @variables v(t) i(t) eqs = [ v ~ p.v - n.v #Convenience 0 ~ p.i + n.i #in = -out i ~ p.i #Positive current flows *into* p terminal 0 ~ IfElse.ifelse(v<0, i, v) ] ODESystem(eqs, t, [v, i], , systems=[p, n], defaults=Dict(), name=name) end
I suspect one thing helping out in VerilogA is the fact that you can use events to trigger a timepoint at the discontinuity (If I remember correctly).
Here is an example of using events from the VerilogAMS Reference manual (v2.4):
module comparator(cout, inp, inm); output cout; input inp, inm; electrical cout, inp, inm; parameter real td = 1n, tr = 1n, tf = 1n; real vcout; analog begin @(cross(V(inp) - V(inm), 0)) vcout = ((V(inp) > V(inm)) ? 1 : 0); V(cout) <+ transition(vcout, td, tr, tf); end endmodule
Apparently, the VerilogA
@cross event is critical to help the simulator produce accurately-timed results with this device. In my experience, this sort of code deals fairly well with discontinuities - as long as the output transitions with finite rise/fall times
(tr, tf) - which it does thanks to the
I sort of stumbled on a few videos and docs regarding continuous callbacks that appear to do something similar to VerilogA’s
→ Event Handling and Callback Functions · DifferentialEquations.jl
One thing I noticed, though is that it only seems to be possible to add callbacks “globally” when you call
solve(). I find the way you add VerilogA’s
@cross events to be much more elegant/practical - given that it is specified/registered within the “device” model itself.
Adding callbacks to the
solve() command feels sort of inelegant/error-prone, etc when compared to the VerilogA events solution.
I tried to build my own callback to trigger a timepoint in my simulation using the docs I found:
(Event Handling and Callback Functions · DifferentialEquations.jl)
function condition(sys,t,integrator) # Event @ v = 0 sys.v ~ 0 end function affect!(integrator) nothing end cb = ContinuousCallback(condition,affect!)
But I don’t think this is correct. My model is using what I believe is called the “domain-specific language” layer from ModelingToolkit: “
@variables v(t) i(t)”, etc.
All examples I found in the DifferentialEquations.jl documentation expect you to use the
du vectors instead of the more (subjectively) readable
- Am I possibly interpreting things incorrectly?