Convergence Issues with Controllable Switch and Square Wave using MTK

Hi everyone,

I am new to the Julia community and I’m interested in the applications of the ModelingToolkit package.

In particular, I’m trying to simulate a switching circuit using an External Control Signal and a Controllable Switch. The Switch is designed as a non-ideal resistor where the resistance value varies from high to low in response to the Control Signal. I tried a simple test circuit as below with two approaches :


       +V  
        |  
       ┌┴┐     Control (Square Wave)
       │S│<─────●  
       └┬┘            
        |            
       [R]  ← Load resistor R  
        |            
       GND           

  1. Using a sinusoidal wave as Control Signal. In this case the model works. Here’s the plot of the Voltage on the load and the resistance of the Cotrollable “Switch”:

  1. Using a square wave as Control Signal. In this case the model has convergence problems. It don’t show any “error” but two warnings:
┌ Warning: Rosenbrock methods on equations without differential states do not bound the error on interpolations.

and

┌ Warning: At t=0.0, dt was forced below floating point epsilon 5.0e-324, and step error estimate = NaN. Aborting. There is either an error in your model specification or the true solution is unstable (or the true solution can not be represented in the precision of Float64).

and the resulting plot is empty :

So I’m having some questions as I’m stuck in the implementation

  • Which solver and settings (tolerances, max step size) work best for fast switching circuits in ModelingToolkit.jl?
  • Are there any references or examples of switching models using MTK?
  • Can ModelingToolkit.jl reliably handle non-linear, hybrid systems like this?

Here’s the code of the Circuit model:

@mtkmodel R_Test begin
    @parameters begin
        RLoad_param = 10, [description = "Output Load (Ohm)"]
        Vin_param = 200, [description = "Vin Souce (Vdc)"]
        f = 100, [description = "Switch input Frequency (Hz)"]
    end

    @components begin
        switch_input = squareWave(frequency = f, amplitude = 1, offset = 0, dutyCycle = 0.3)
        #switch_input = Sine(frequency = f, amplitude = 0.99, offset = 1.0)
        voltage_input = Constant(k = Vin_param)
        switch = IdealSwitch(Ron = 1e-3, Roff = 1)
        source = Voltage()
        RLoad = Resistor(R = RLoad_param)
        ground = Ground()
    end

    @equations begin 
      connect(voltage_input.output, source.V)
      connect(switch_input.output, switch.conduction)
      connect(source.p, switch.p)
      connect(switch.n,RLoad.p)
      connect(source.n, RLoad.n, ground.g) 
    end
end

The Switch is defined as

@mtkmodel IdealSwitch begin
  @extend v, i = oneport = OnePort()  
  
  @parameters begin 
    Ron = 1e-3, [description = "On resistance magnitud"]
    Roff = 1e6, [description = "Off resistance magnitud"]
  end

  @components begin
    conduction = RealInput() 
  end

  @variables begin
    q(t), [description = "Control Signal "]
    R(t), [description = "Resistance "]
  end
  
  @equations begin
    q ~ conduction.u
    R ~  Ron + q * Roff
    v ~ i * R
  end
end 

The square wave is defined as

@component function squareWave(;name, frequency,  amplitude = 1, offset = 0, dutyCycle = 0.5)
    @named output = RealOutput()
    pars = @parameters  amplitude=amplitude frequency=frequency dutyCycle=dutyCycle
    equation =  amplitude * mod1(t, 1/frequency) < dutyCycle/frequency
    eqs = output.u ~ equation
    compose(System(eqs, t, [], pars; name = name), [output])
end 

and the solver configuration is

@mtkcompile sys = R_Test()
prob = ODEProblem(sys, Pair[], (0.0, 100e-3); guesses = [sys.switch.i => 5.0])
sol = solve(prob, Rodas5();
            reltol=1e-8,
            abstol=1e-10,
            dt=1e-7,        
            dtmax=1e-5,     
            saveat=1e-5)

Any pointers or references to prior work are greatly appreciated!
Thanks!

It’s still a bit experimental but you can try the iflifting to see if the event handling fixes it. Right now it’s opt-in.

Thanks for your help @ChrisRackauckas. I’ve integrated the iflifting call into my code but now I’m seeing this error for both control signals:

ERROR: BoundsError: attempt to access 0-element Vector{Int64} at index [1]

I suspect the problem is how I added iflifting, rather than the feature itself… Here’s the change I made:

#@mtkcompile sys = R_Test()
@named sys_dec = R_Test()
sys = structural_simplify(sys_dec,additional_passes = [IfLifting])

Any ideas on how I can debug this? Thanks

Open an issue, easier to track it there.