diff --git a/src/Blocks/Blocks.jl b/src/Blocks/Blocks.jl index 36bb597f0..fc25fa172 100644 --- a/src/Blocks/Blocks.jl +++ b/src/Blocks/Blocks.jl @@ -13,6 +13,7 @@ where `u` are inputs, `x` are state variables and `y` are outputs. `x,u,y` are a """ module Blocks using ModelingToolkit, Symbolics, IfElse, OrdinaryDiffEq +using ModelingToolkit: @register @parameters t Dₜ = Differential(t) @@ -26,4 +27,8 @@ include("nonlinear.jl") export Constant, Integrator, Derivative, FirstOrder, SecondOrder, PID, StateSpace include("continuous.jl") +export ConstantFunction, SmoothCosineFunction, SmoothDampedSineFunction, SmoothRampFunction, + SmoothSineFunction, SmoothSquareFunction, SmoothStepFunction, SmoothTriangularFunction +include("wave_functions.jl") + end \ No newline at end of file diff --git a/src/Blocks/wave_functions.jl b/src/Blocks/wave_functions.jl new file mode 100644 index 000000000..3f6f92f75 --- /dev/null +++ b/src/Blocks/wave_functions.jl @@ -0,0 +1,131 @@ +# Define and register smooth functions +using ModelingToolkit, Symbolics +_constant(K) = K +_cos_wave(x, f, A, st, ϕ) = A*cos(2*π*f*(x-st) + ϕ) +_damped_sine_wave(x, f, A, st, ϕ, d) = exp((st-x)*d)*A*sin(2*π*f*(x-st) + ϕ) +_ramp(x, δ, st, et, h) = h/(et-st)*(_xH(x, δ, st) - _xH(x, δ, et)) +_sine(x, f, A, st, ϕ) = A*sin(2*π*f*(x - st) + ϕ) +_square_wave(x, δ, f, A, st) = A*2atan(sin(2π*(x-st)*f)/δ)/π +_step(x, δ, h, a) = h*(atan((x-a)/δ)/π + 1//2) +_triangular_wave(x, δ, f, A, st) = A*(1-2acos((1 - δ)sin(2π*(x-st)*f))/π) +_xH(x, δ, tₒ) = (x-tₒ)*(1+((x-tₒ)/sqrt((x-tₒ)^2+δ^2)))/2 + + +@register _constant(K) +@register _cos_wave(x, f, A, st, ϕ) +@register _damped_sine_wave(x, f, A, st, ϕ, damping) +@register _ramp(x, δ, st, et, h) +@register _sine(x, f, A, st, ϕ) +@register _square_wave(x, δ, f, A, st) +@register _step(x, δ, h, a) +@register _triangular_wave(x, δ, f, A, st) + +function ConstantFunction(;name, K=1.0) + val = K + @info val + @parameters K + @variables y(t) [output=true] + + eqs = [ + y ~ val + ] + + ODESystem(eqs, t, [y], [K], defaults=Dict(K => val), name=name) +end + +function SmoothCosineFunction(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0) + o, A, f, st, ϕ = offset, amplitude, frequency, starttime, phase + δ = 0.00001 + + @parameters offset amplitude frequency starttime phase + @variables y(t) [output=true] + + eqs = [ + y ~ _cos_wave(t, f, A, st, ϕ) * _step(t, δ, 1.0, st) + offset + ] + defaults = Dict(zip((offset, amplitude, frequency, starttime, phase), (o, A, f, st, ϕ))) + ODESystem(eqs, t, [y], [offset, amplitude, frequency, starttime, phase], defaults=defaults, name=name) +end + +function SmoothDampedSineFunction(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0, damping_coef=0.0) + o, A, f, st, ϕ, d = offset, amplitude, frequency, starttime, phase, damping_coef + δ = 0.0001 + + @parameters offset amplitude frequency starttime phase damping_coef + @variables y(t) [output=true] + + eqs = [ + y ~ _step(t, δ, o, 0.0) + _damped_sine_wave(t, f, A, st, ϕ, d) * _step(t, δ, 1.0, st) + ] + defaults = Dict(zip((offset, amplitude, frequency, starttime, phase, damping_coef), (o, A, f, st, ϕ, d))) + ODESystem(eqs, t, [y], [offset, amplitude, frequency, starttime, phase, damping_coef], defaults=defaults, name=name) +end + +function SmoothRampFunction(;name, offset=0.0, starttime=0.0, endtime=1.0, height=1.0) + o, st, et, h = offset, starttime, endtime, height + δ = 0.0001 + + @parameters offset starttime endtime height + @variables y(t) [output=true] + + eqs = [ + y ~ offset + _ramp(t, δ, st, et, h) + ] + defaults = Dict(zip((offset, starttime, endtime, height), (o, st, et, h))) + ODESystem(eqs, t, [y], [offset, starttime, endtime, height], defaults=defaults, name=name) +end + +function SmoothSineFunction(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0) + o, A, f, st, ϕ = offset, amplitude, frequency, starttime, phase + + @parameters offset amplitude frequency starttime phase + @variables y(t) [output=true] + + eqs = [ + y ~ offset + (t > st) * _sine(x, f, A, st, ϕ) + ] + defaults = Dict(zip((offset, amplitude, frequency, starttime, phase), (o, A, f, st, ϕ))) + ODESystem(eqs, t, [y], [offset, amplitude, frequency, starttime, phase], defaults=defaults, name=name) +end + +function SmoothSquareFunction(; name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0) + o, A, f, st = offset, amplitude, frequency, starttime + δ = 0.0001 + + @parameters offset amplitude frequency starttime + @variables y(t) [output=true] + + eqs = [ + y ~ o + _square_wave(t, δ, f, A, st) * (t > st) + ] + defaults = Dict(zip((offset, amplitude, frequency, starttime), (o, A, f, st))) + ODESystem(eqs, t, [y], [offset, amplitude, frequency, starttime], defaults=defaults, name=name) +end + +function SmoothStepFunction(;name, offset=0.0, starttime=0.0, height=1.0) + o, st, h = offset, starttime, height + δ = 0.0001 + + @parameters offset starttime height + @variables y(t) + + eqs = [ + y ~ offset + _step(t, δ, h, st) + ] + defaults = Dict(zip((offset, starttime, height), (o, st, h))) + ODESystem(eqs, t, [y], [offset, starttime, height], defaults=defaults, name=name) +end + +function SmoothTriangularFunction(; name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0) + o, A, f, st = offset, amplitude, frequency, starttime + δ = 0.0001 + + @parameters offset amplitude frequency starttime + @variables y(t) [output=true] + + eqs = [ + y ~ offset + (t>st) * _triangular_wave(t, δ, f, A, st) + ] + defaults = Dict(zip((offset, amplitude, frequency, starttime), (o, A, f, st))) + ODESystem(eqs, t, [y], [offset, amplitude, frequency, starttime], defaults=defaults, name=name) +end diff --git a/src/Electrical/Analog/sources.jl b/src/Electrical/Analog/sources.jl index 4d1abbc16..743fba3f6 100644 --- a/src/Electrical/Analog/sources.jl +++ b/src/Electrical/Analog/sources.jl @@ -1,299 +1,27 @@ -# Define and register smooth functions -_cos_wave(x, f, A, st, ϕ) = A*cos(2*π*f*(x-st) + ϕ) -_damped_sine_wave(x, f, A, st, ϕ, d) = exp((st-x)*d)*A*sin(2*π*f*(x-st) + ϕ) -_ramp(x, δ, st, et, h) = h/(et-st)*(_xH(x, δ, st) - _xH(x, δ, et)) -_square_wave(x, δ, f, A, st) = A*2atan(sin(2π*(x-st)*f)/δ)/π -_step(x, δ, h, a) = h*(atan((x-a)/δ)/π + 0.5) -_triangular_wave(x, δ, f, A, st) = A*(1-2acos((1 - δ)sin(2π*(x-st)*f))/π) -_xH(x, δ, tₒ) = 0.5*(x-tₒ)*(1+((x-tₒ)/sqrt((x-tₒ)^2+δ^2))) - -@register _cos_wave(x, f, A, st, ϕ) -@register _damped_sine_wave(x, f, A, st, ϕ, damping) -@register _ramp(x, δ, st, et, h) -@register _square_wave(x, δ, f, A, st) -@register _step(x, δ, h, a) -@register _triangular_wave(x, δ, f, A, st) - # Voltage sources -function ConstantVoltage(;name, V=1.0) - val = V - - @named p = Pin() - @named n = Pin() - @parameters V - @variables v(t) - - eqs = [ - v ~ p.v - n.v - 0 ~ p.i + n.i - v ~ V - ] - ODESystem(eqs, t, [v], [V], systems=[p, n], defaults=Dict(V => val), name=name) -end - -function CosineVoltage(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0) - o, A, f, st, ϕ = offset, amplitude, frequency, starttime, phase - δ = 0.00001 - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime phase - @variables v(t) - - eqs = [ - v ~ p.v - n.v - v ~ _cos_wave(t, f, A, st, ϕ) * _step(t, δ, 1.0, st) + offset - 0 ~ p.i + n.i - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime, phase), (o, A, f, st, ϕ))) - ODESystem(eqs, t, [v], [offset, amplitude, frequency, starttime, phase], systems=[p, n], defaults=defaults, name=name) -end - -function DampedSineVoltage(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0, damping_coef=0.0) - o, A, f, st, ϕ, d = offset, amplitude, frequency, starttime, phase, damping_coef - δ = 0.0001 - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime phase damping_coef - @variables v(t) - - eqs = [ - v ~ p.v - n.v - v ~ _step(t, δ, o, 0.0) + _damped_sine_wave(t, f, A, st, ϕ, d) * _step(t, δ, 1.0, st) - 0 ~ p.i + n.i - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime, phase, damping_coef), (o, A, f, st, ϕ, d))) - ODESystem(eqs, t, [v], [offset, amplitude, frequency, starttime, phase, damping_coef], systems=[p, n], defaults=defaults, name=name) -end - -function RampVoltage(;name, offset=0.0, starttime=0.0, endtime=1.0, height=1.0) - o, st, et, h = offset, starttime, endtime, height - δ = 0.0001 - - @named p = Pin() - @named n = Pin() - @parameters offset starttime endtime height - @variables v(t) - - eqs = [ - v ~ p.v - n.v - v ~ offset + _ramp(t, δ, st, et, h) - 0 ~ p.i + n.i - ] - defaults = Dict(zip((offset, starttime, endtime, height), (o, st, et, h))) - ODESystem(eqs, t, [v], [offset, starttime, endtime, height], systems=[p, n], defaults=defaults, name=name) -end - -function SineVoltage(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0) - o, A, f, st, ϕ = offset, amplitude, frequency, starttime, phase - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime phase - @variables v(t) - - eqs = [ - v ~ p.v - n.v - v ~ offset + (t > st) * (A*sin(2*π*f*(t - st) + ϕ)) - 0 ~ p.i + n.i - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime, phase), (o, A, f, st, ϕ))) - ODESystem(eqs, t, [v], [offset, amplitude, frequency, starttime, phase], systems=[p, n], defaults=defaults, name=name) -end - -function SquareVoltage(; name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0) - o, A, f, st = offset, amplitude, frequency, starttime - δ = 0.0001 - +function VoltageSource(;name) @named p = Pin() @named n = Pin() - @parameters offset amplitude frequency starttime - @variables v(t) - - eqs = [ - v ~ p.v - n.v - 0 ~ p.i + n.i - v ~ o + _square_wave(t, δ, f, A, st) * (t > st) - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime), (o, A, f, st))) - ODESystem(eqs, t, [v], [offset, amplitude, frequency, starttime], systems=[p, n], defaults=defaults, name=name) -end - -function StepVoltage(;name, offset=0.0, starttime=0.0, height=1.0) - o, st, h = offset, starttime, height - δ = 0.0001 - - @named p = Pin() - @named n = Pin() - @parameters offset starttime height @variables v(t) eqs = [ v ~ p.v - n.v - v ~ offset + _step(t, δ, h, st) 0 ~ p.i + n.i ] - defaults = Dict(zip((offset, starttime, height), (o, st, h))) - ODESystem(eqs, t, [v], [offset, starttime, height], systems=[p, n], defaults=defaults, name=name) -end - -function TriangularVoltage(; name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0) - o, A, f, st = offset, amplitude, frequency, starttime - δ = 0.0001 - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime - @variables v(t) - - eqs = [ - v ~ p.v - n.v - 0 ~ p.i + n.i - v ~ offset + (t>st) * _triangular_wave(t, δ, f, A, st) - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime), (o, A, f, st))) - ODESystem(eqs, t, [v], [offset, amplitude, frequency, starttime], systems=[p, n], defaults=defaults, name=name) + ODESystem(eqs, t, [v], [], systems=[p, n], name=name) end # Current Sources -function ConstantCurrent(;name, I=1.0) - val = I - - @named p = Pin() - @named n = Pin() - @parameters I - @variables i(t) - - eqs = [ - 0 ~ p.i + n.i - i ~ p.i - i ~ I - ] - ODESystem(eqs, t, [i], [I], systems=[p, n], defaults=Dict(I => val), name=name) -end - -function CosineCurrent(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0) - o, A, f, st, ϕ = offset, amplitude, frequency, starttime, phase - δ = 0.00001 - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime phase - @variables i(t) - - eqs = [ - i ~ _cos_wave(t, f, A, st, ϕ) * _step(t, δ, 1.0, st) + offset - 0 ~ p.i + n.i - i ~ p.i - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime, phase), (o, A, f, st, ϕ))) - ODESystem(eqs, t, [i], [offset, amplitude, frequency, starttime, phase], systems=[p, n], defaults=defaults, name=name) -end - -function DampedSineCurrent(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0, damping_coef=1.0) - o, A, f, st, ϕ, d = offset, amplitude, frequency, starttime, phase, damping_coef - δ = 0.0001 - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime phase damping_coef - @variables i(t) - - eqs = [ - i ~ _step(t, δ, o, 0.0) + _damped_sine_wave(t, f, A, st, ϕ, d) * _step(t, δ, 1.0, st) - 0 ~ p.i + n.i - i ~ p.i - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime, phase, damping_coef), (o, A, f, st, ϕ, d))) - ODESystem(eqs, t, [i], [offset, amplitude, frequency, starttime, phase, damping_coef], systems=[p, n], defaults=defaults, name=name) -end - -function RampCurrent(;name, offset=0.0, starttime=0.0, endtime=1.0, height=1.0) - o, st, et, h = offset, starttime, endtime, height - δ = 0.0001 +function CurrentSource(;name) @named p = Pin() @named n = Pin() - @parameters offset starttime endtime height - @variables i(t) + @variables i(t) v(t) eqs = [ - i ~ _step(t, δ, o, 0.0) + _ramp(t, δ, st, et, h) - 0 ~ p.i + n.i - i ~ p.i - ] - defaults = Dict(zip((offset, starttime, endtime, height), (o, st, et, h))) - ODESystem(eqs, t, [i], [offset, starttime, endtime, height], systems=[p, n], defaults=defaults, name=name) -end - -function SineCurrent(;name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0, phase=0.0) - o, A, f, st, ϕ = offset, amplitude, frequency, starttime, phase - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime phase - @variables i(t) - - eqs = [ - i ~ offset + (t > st) * (A*sin(2*π*f*(t - st) + ϕ)) - 0 ~ p.i + n.i - i ~ p.i - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime, phase), (o, A, f, st, ϕ))) - ODESystem(eqs, t, [i], [offset, amplitude, frequency, starttime, phase], systems=[p, n], defaults=defaults, name=name) -end - -function SquareCurrent(; name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0) - o, A, f, st = offset, amplitude, frequency, starttime - δ = 0.0001 - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime - @variables i(t) - - eqs = [ - 0 ~ p.i + n.i - i ~ o + _square_wave(t, δ, f, A, st) * (t > st) - i ~ p.i - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime), (o, A, f, st))) - ODESystem(eqs, t, [i], [offset, amplitude, frequency, starttime], systems=[p, n], defaults=defaults, name=name) -end - -function StepCurrent(;name, offset=0.0, starttime=0.0, height=1.0) - o, st, h = offset, starttime, height - δ = 0.0001 - - @named p = Pin() - @named n = Pin() - @parameters offset starttime height - @variables i(t) - - eqs = [ - i ~ offset + _step(t, δ, h, st) + v ~ p.v - n.v 0 ~ p.i + n.i i ~ p.i ] - defaults = Dict(zip((offset, starttime, height), (o, st, h))) - ODESystem(eqs, t, [i], [offset, starttime, height], systems=[p, n], defaults=defaults, name=name) -end - -function TriangularCurrent(; name, offset=0.0, amplitude=1.0, frequency=1.0, starttime=0.0) - o, A, f, st = offset, amplitude, frequency, starttime - δ = 0.0001 - - @named p = Pin() - @named n = Pin() - @parameters offset amplitude frequency starttime - @variables i(t) - - eqs = [ - 0 ~ p.i + n.i - i ~ offset + _step(t, δ, 1, st) * _triangular_wave(t, δ, f, A, st) - i ~ p.i - ] - defaults = Dict(zip((offset, amplitude, frequency, starttime), (o, A, f, st))) - ODESystem(eqs, t, [i], [offset, amplitude, frequency, starttime], systems=[p, n], defaults=defaults, name=name) -end + ODESystem(eqs, t, [i, v], [], systems=[p, n], name=name) +end \ No newline at end of file diff --git a/src/Electrical/Electrical.jl b/src/Electrical/Electrical.jl index 64a5d22e5..70d808417 100644 --- a/src/Electrical/Electrical.jl +++ b/src/Electrical/Electrical.jl @@ -22,12 +22,7 @@ export # Analog Components CurrentSensor, PotentialSensor, VoltageSensor, PowerSensor, MultiSensor, #Analog Sources - ConstantVoltage, SineVoltage, StepVoltage, RampVoltage, - SquareVoltage, TriangularVoltage, - CosineVoltage, DampedSineVoltage, - ConstantCurrent, SineCurrent, StepCurrent, RampCurrent, - SquareCurrent, TriangularCurrent, - CosineCurrent, DampedSineCurrent, + CurrentSource, VoltageSource, connect, Pin # Digital Gates diff --git a/test/analog.jl b/test/analog.jl index b6f2a0b7a..32a543945 100644 --- a/test/analog.jl +++ b/test/analog.jl @@ -1,5 +1,5 @@ using ModelingToolkitStandardLibrary.Electrical, ModelingToolkit, OrdinaryDiffEq, Test -using ModelingToolkitStandardLibrary.Electrical: _step, _square_wave, _triangular_wave, +using ModelingToolkitStandardLibrary.Blocks: _step, _square_wave, _triangular_wave, _cos_wave, _damped_sine_wave, _ramp # using Plots @@ -8,40 +8,6 @@ using ModelingToolkitStandardLibrary.Electrical: _step, _square_wave, _triangula R = 5 @named resistor = Resistor(R=R) -@info "Testing the voltage sources..." -@testset "voltage sources" begin - @named resistor = Resistor(R=R) - @named voltage_sensor = VoltageSensor() - offset = 1 - freq = 50 - @named sinesource = SineVoltage(offset=offset, amplitude=1.0, frequency=freq, starttime=.5, phase=0.0) - @named constsource = ConstantVoltage(V=1.0) - @named stepsource = StepVoltage(height=10, offset=1.0, starttime=1.0) - sources = [constsource, sinesource, stepsource] - for source in sources - rc_eqs = [ - connect(voltage_sensor.p, source.p, resistor.p) - connect(voltage_sensor.n, source.n, resistor.n, ground.g) - ] - @named rc_model = ODESystem(rc_eqs, t, systems = [resistor, source, voltage_sensor, ground]) - sys = structural_simplify(rc_model) - u0 = [ - resistor.p.i => 10.0 - constsource.v => 1.0 - ] - prob = ODEProblem(sys, u0, (0, 2.0)) - sol = solve(prob, Rosenbrock23()) - - if source == constsource - @test sol[voltage_sensor.v][1:20000:end] ≈ ones(length(sol.t[1:20000:end])) atol=1e-3 - elseif source == stepsource - @test sol[voltage_sensor.v][1:20000:end] ≈ [(t < 1) ? offset : offset + height for t in sol.t[1:20000:end]] atol=1e-3 - else - @test sol[voltage_sensor.v][1:20000:end] ≈ [(t < 0.5) ? offset : offset + sin(2π*freq*(t .- 0.5)) for t in sol.t[1:20000:end]] atol=1e-6 - end - end -end - @info "Testing the sensors..." @testset "sensors" begin offset = 1 @@ -196,55 +162,7 @@ end # savefig(plt, "integrator") end -@info "Testing voltage function generators..." -@testset "Voltage function generators" begin - st, o, h, f, A, et, ϕ, d, δ = 0.7, 1.25, 3, 2, 2.5, 2.5, π/4, 0.1, 0.0001 - - @named ground = Ground() - @named res = Resistor() - @named voltage_sensor = VoltageSensor() - @named vstep = StepVoltage(starttime=st, offset=o, height=h) - @named vsquare = SquareVoltage(offset=o, starttime=st, amplitude=A, frequency=f) - @named vtri = TriangularVoltage(offset=o, starttime=st, amplitude=A, frequency=f) - # @named vsawtooth = SawToothVoltage(amplitude=A, starttime=st, frequency=f, offset=o) - @named vcosine = CosineVoltage(offset=o, amplitude=A, frequency=f, starttime=st, phase=ϕ) - @named vdamped_sine = DampedSineVoltage(offset=o, amplitude=A, frequency=f, starttime=st, phase=ϕ, damping_coef=d) - @named vramp = RampVoltage(offset=o, starttime=st, endtime=et, height=h) - - vsources = [vtri, vsquare, vstep, vcosine, vdamped_sine, vramp] - waveforms(i, x) = getindex([o .+ (x .> st) .* _triangular_wave.(x, δ, f, A, st), - o .+ (x .> st) .* _square_wave.(x, δ, f, A, st), - o .+ _step.(x, δ, h, st), - # o .+ (x .> st). * _sawtooth_wave.(x, δ, f, A, st), - o .+ (x .> st) .* _cos_wave.(x, f, A, st, ϕ), - o .+ (x .> st) .* _damped_sine_wave.(x, f, A, st, ϕ, d), - o .+ _ramp.(x, δ, st, et, h)], i) - for i in 1:length(vsources) - vsource = vsources[i] - @info Symbolics.getname(vsource) - eqs = [ - connect(vsource.p, voltage_sensor.p, res.p) - connect(ground.g, voltage_sensor.n, vsource.n, res.n) - ] - @named vmodel = ODESystem(eqs, t, systems = [voltage_sensor, res, vsource, ground]) - vsys = structural_simplify(vmodel) - - u0 = [ - vsource.v => 1 - res.v => 1 - ] - - prob = ODEProblem(vsys, u0, (0, 10.0)) - vsol = solve(prob, dt=0.1, Rosenbrock23()) - - @test vsol[vsource.v][1150:end] ≈ waveforms(i, vsol.t)[1150:end] atol=1e-1 - # For visual inspection - # plt = plot(sol) - # savefig(plt, "test_current_$(Symbolics.getname(source))") - end -end - -@info "Testing the Current generators..." +#=@info "Testing the Current generators..." @testset "Current function generators" begin st, o, h, f, A, et, ϕ, d, δ = 0.7, 1.25, 3, 2, 2.5, 2.5, π/4, 0.1, 0.0001 @@ -290,4 +208,4 @@ end # plt = plot(sol) # savefig(plt, "test_current_$(Symbolics.getname(source))") end -end \ No newline at end of file +end=# \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl index c55d5571d..6f8f98552 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,9 +1,10 @@ using SafeTestsets @safetestset "Blocks: math" begin include("test_math.jl") end +@safetestset "Blocks: function generators" begin include("wave_functions.jl") end @safetestset "Blocks: nonlinear" begin include("test_nonlinear.jl") end @safetestset "Blocks: continuous" begin include("test_continuous.jl") end @safetestset "Analog Circuits" begin include("analog.jl") end -#@safetestset "Digital Circuits" begin include("digital.jl") end +# @safetestset "Digital Circuits" begin include("digital.jl") end @safetestset "RC Circuit Demo" begin include("demo.jl") end @safetestset "Thermal Circuits" begin include("thermal.jl") end diff --git a/test/wave_functions.jl b/test/wave_functions.jl new file mode 100644 index 000000000..c975c9f54 --- /dev/null +++ b/test/wave_functions.jl @@ -0,0 +1,99 @@ +using ModelingToolkitStandardLibrary.Electrical, ModelingToolkit, OrdinaryDiffEq, Test +using ModelingToolkitStandardLibrary.Blocks +using ModelingToolkitStandardLibrary.Blocks: _step, _square_wave, _triangular_wave, + _cos_wave, _damped_sine_wave, _ramp + +@parameters t +@named ground = Ground() +@named resistor = Resistor() + +st, o, h, f, A, et, ϕ, d, δ = 0.7, 1.25, 3, 2, 2.5, 2.5, π/4, 0.1, 0.0001 +waveforms(i, x) = getindex([o .+ (x .> st) .* _triangular_wave.(x, δ, f, A, st), + o .+ (x .> st) .* _square_wave.(x, δ, f, A, st), + o .+ _step.(x, δ, h, st), + # o .+ (x .> st). * _sawtooth_wave.(x, δ, f, A, st), + o .+ (x .> st) .* _cos_wave.(x, f, A, st, ϕ), + o .+ (x .> st) .* _damped_sine_wave.(x, f, A, st, ϕ, d), + o .+ _ramp.(x, δ, st, et, h)], i) + +@info "Testing voltage function generators..." +@testset "Voltage function generators" begin + + @named voltage_sensor = VoltageSensor() + @named source = VoltageSource() + + @named step = StepFunction(starttime=st, offset=o, height=h) + @named square = SquareFunction(offset=o, starttime=st, amplitude=A, frequency=f) + @named tri = TriangularFunction(offset=o, starttime=st, amplitude=A, frequency=f) + @named cosine = CosineFunction(offset=o, amplitude=A, frequency=f, starttime=st, phase=ϕ) + @named ramp = RampFunction(offset=o, starttime=st, endtime=et, height=h) + @named damped_sine = DampedSineFunction(offset=o, amplitude=A, frequency=f, starttime=st, phase=ϕ, damping_coef=d) + # @named vsawtooth = SawToothVoltage(amplitude=A, starttime=st, frequency=f, offset=o) + + wavefunctions = [tri, square, step, cosine, damped_sine, ramp] + source_name = Symbolics.getname(source) + @info "Testing for $source_name sources with following shapes of waves" + for w in 1:length(wavefunctions) + wave = wavefunctions[w] + @info Symbolics.getname(wave) + rc_eqs = [ + wave.y ~ source.v + connect(voltage_sensor.p, source.p, resistor.p) + connect(voltage_sensor.n, source.n, ground.g, resistor.n) + ] + @named model = ODESystem(rc_eqs, t, systems = [wave, source, resistor, voltage_sensor, ground]) + sys = structural_simplify(model) + + u0 = [ + source.v => 1 + resistor.v => 1 + ] + + prob = ODEProblem(sys, u0, (0, 10.0)) + sol = solve(prob, dt=0.1, Rosenbrock23()) + + @test sol[source.v][1150:end] ≈ waveforms(w, sol.t)[1150:end] atol=1e-1 + # source_name == "current_source" && @test sol[source.i][1150:end] ≈ waveforms(w, sol.t)[1150:end] atol=1e-1 + # For visual inspection + # plt = plot(sol) + # savefig(plt, "test_current_$(Symbolics.getname(source))") + end +end + +@info "Testing current function generators..." +@testset "Current function generators" begin + @named current_sensor = CurrentSensor() + @named source = CurrentSource() + + @named step = SmoothStepFunction(starttime=st, offset=o, height=h) + @named square = SmoothSquareFunction(offset=o, starttime=st, amplitude=A, frequency=f) + @named tri = SmoothTriangularFunction(offset=o, starttime=st, amplitude=A, frequency=f) + @named cosine = SmoothCosineFunction(offset=o, amplitude=A, frequency=f, starttime=st, phase=ϕ) + @named ramp = SmoothRampFunction(offset=o, starttime=st, endtime=et, height=h) + @named damped_sine = SmoothDampedSineFunction(offset=o, amplitude=A, frequency=f, starttime=st, phase=ϕ, damping_coef=d) + # @named vsawtooth = SawToothVoltage(amplitude=A, starttime=st, frequency=f, offset=o) + + wavefunctions = [tri, square, step, cosine, damped_sine, ramp] + for w in 1:length(wavefunctions) + wave = wavefunctions[w] + @info "Testing $(Symbolics.getname(wave))" + eqs = [ + wave.y ~ source.i + connect(source.p, resistor.p) + connect(source.n, resistor.n) + ] + @named model = ODESystem(eqs, t, systems = [wave, source, resistor]) + sys = alias_elimination(model) + + u0 = [ + source.i => 1 + resistor.v => 1 + source.v => 1 + ] + + prob = ODEProblem(sys, u0, (0, 10.0)) + sol = solve(prob, dt=0.1, Rosenbrock23()) + # plot(sol) + @test sol[source.i][1150:end] ≈ waveforms(w, sol.t)[1150:end] atol=1e-1 + end +end \ No newline at end of file