I’m trying to create a PWM voltage source using modeling toolkit. I tried used the @discrete_events
macro within the @mtkmodel
block but doing so throws an error: ERROR: KeyError: key pwm₊output₊u(t) not found
when running prob = ODEProblem(sys, Pair[], (0, 1.0e-3))
Here is the full code I’m trying to run:
using ModelingToolkit, OrdinaryDiffEq, Plots
using ModelingToolkitStandardLibrary.Electrical
using ModelingToolkitStandardLibrary.Blocks
using ModelingToolkit: t_nounits as t, D_nounits as D
@mtkmodel PWM begin
# @extend v, i = oneport = OnePort()
@parameters begin
T = 0.2e-3
duty = 0.5
Vcc = 5
end
@components begin
output = RealOutput()
end
@equations begin
output.u ~ Vcc
end
@discrete_events begin
(t == T*duty) => [output.u ~ 0]
(t == T) => [output.u ~ Vcc]
end
end
@mtkmodel PWM_test begin
@parameters begin
R = 1.0
V = 5.0
end
@components begin
resistor = Resistor(R = R)
VDD = Voltage()
pwm = PWM(Vcc = V)
ground = Ground()
end
@equations begin
connect(pwm.output, VDD.V)
connect(VDD.p, resistor.p)
connect(ground.g, VDD.n, resistor.n)
end
end
@mtkbuild sys = PWM_test()
unknowns(sys)
prob = ODEProblem(sys, Pair[], (0, 1.0e-3))
sol = solve(prob)
plot(sol, idxs = [sys.resistor.i],
title = "Circuit Demonstration")
Any ideas on what is going wrong here?
You should replace
@equations begin
output.u ~ Vcc
end
with
@equations begin
D(output.u) ~ 0
end
As the callback should handle the changing output.u
value. Otherwise this equation would immediately pull the voltage back.
And you should use a continous callback. Full example:
using ModelingToolkit, OrdinaryDiffEq, Plots
using ModelingToolkitStandardLibrary.Electrical
using ModelingToolkitStandardLibrary.Blocks
using ModelingToolkit: t_nounits as t, D_nounits as D
@mtkmodel PWM begin
# @extend v, i = oneport = OnePort()
@parameters begin
T = 0.1
duty = 0.5
Vcc = 5
end
@components begin
output = RealOutput(u_start=Vcc)
end
@equations begin
D(output.u) ~ 0
end
@continuous_events begin
(t ~ T*duty) => [output.u ~ 0]
(t ~ T) => [output.u ~ Vcc]
end
end
@mtkmodel PWM_test begin
@parameters begin
R = 1.0
V = 5.0
end
@components begin
resistor = Resistor(R = R)
VDD = Voltage()
pwm = PWM(Vcc = V)
ground = Ground()
end
@equations begin
connect(pwm.output, VDD.V)
connect(VDD.p, resistor.p)
connect(ground.g, VDD.n, resistor.n)
end
end
@mtkbuild sys = PWM_test()
unknowns(sys)
prob = ODEProblem(sys, [sys.pwm.output.u => 0.0], (0, 1.0); dt=0.001)
sol = solve(prob, Tsit5())
plot(sol, idxs = [sys.resistor.i],
title = "Circuit Demonstration")
Thanks for the quick reply!
This does solve my problem, but I quickly run into another; I cannot make these steps periodic. From the docs it seems periodic callbacks are only available using @discrete_events
My end goal is to make a PWM source with all the knobs to turn available in LTSpice.
- V_initial
- V_on
- T_rise
- T_fall
- T_on
- T_period
This supply would oscillate into t = infinity
With that in mind, what is the recommended approach?
You could maybe use a modulo block, where the remainder of the time divided by T_rise is your trigger for turning on the pwm, and the remainder of the time divided by T_fall is the trigger for going down again. Or you can make a trigger by having a variable called trigger
and equation D(trigger) ~ 1
, and when its value reaches T_rise
, you set it back to zero with a continuous callback and trigger the PWM.