Ideal diode: MTK+callbacks to mimic Verilog-A events?

Verilog-A-like circuit components

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!

Ideal diode (with discontinuities)

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

VerilogA events

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 transition() “filter”.

VerilogA events == MTK+callbacks?

I sort of stumbled on a few videos and docs regarding continuous callbacks that appear to do something similar to VerilogA’s @cross events:
Event Handling and Callback Functions · DifferentialEquations.jl

MTK+callbacks only on solve()?

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.

Attempt at creating diode “callback”

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 u and du vectors instead of the more (subjectively) readable sys variables.

Additional/Overall questions

  • Am I possibly interpreting things incorrectly?

Yeah, this is just missing functionality right now. https://github.com/SciML/ModelingToolkit.jl/issues/38 is the issue for it (the oldest open issue! :scream:). You can use the tricks in Frequently Asked Questions · ModelingToolkit.jl to do it in the front end, but that’s nasty. We do need to support events in the front end.

1 Like