From fd8898366d22df92df448717e8d36b246f9f8806 Mon Sep 17 00:00:00 2001 From: Claude Code Date: Sun, 4 Jan 2026 07:24:52 -0500 Subject: [PATCH] Switch from JuliaFormatter to Runic.jl for code formatting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Update CI workflow to use fredrikekre/runic-action@v1 - Remove .JuliaFormatter.toml configuration - Format all source files with Runic.jl 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- .JuliaFormatter.toml | 2 - .github/workflows/FormatCheck.yml | 14 +- docs/make.jl | 24 +- docs/pages.jl | 8 +- src/Blocks/Blocks.jl | 6 +- src/Blocks/continuous.jl | 106 ++-- src/Blocks/math.jl | 34 +- src/Blocks/nonlinear.jl | 15 +- src/Blocks/sources.jl | 265 ++++++---- src/Blocks/utils.jl | 46 +- src/Electrical/Analog/ideal_components.jl | 30 +- src/Electrical/Analog/mosfets.jl | 54 +- src/Electrical/Analog/sensors.jl | 10 +- src/Electrical/Analog/sources.jl | 4 +- src/Electrical/Analog/transistors.jl | 168 +++--- src/Electrical/Digital/components.jl | 20 +- src/Electrical/Digital/gates.jl | 56 +- src/Electrical/Digital/logic.jl | 6 +- src/Electrical/Digital/logic_vectors.jl | 14 +- src/Electrical/Digital/sources.jl | 20 +- src/Electrical/Digital/tables.jl | 99 ++-- src/Electrical/Electrical.jl | 10 +- src/Electrical/utils.jl | 16 +- .../IsothermalCompressible.jl | 2 +- .../IsothermalCompressible/components.jl | 281 ++++++----- .../IsothermalCompressible/sources.jl | 6 +- src/Hydraulic/IsothermalCompressible/utils.jl | 34 +- src/Magnetic/FluxTubes/FluxTubes.jl | 2 +- src/Magnetic/FluxTubes/basic.jl | 16 +- src/Magnetic/FluxTubes/sources.jl | 4 +- src/Magnetic/FluxTubes/utils.jl | 2 +- src/Mechanical/MultiBody2D/components.jl | 32 +- src/Mechanical/Rotational/components.jl | 16 +- src/Mechanical/Rotational/sensors.jl | 8 +- src/Mechanical/Rotational/sources.jl | 38 +- src/Mechanical/Rotational/utils.jl | 24 +- src/Mechanical/Translational/components.jl | 56 +- src/Mechanical/Translational/sensors.jl | 6 +- src/Mechanical/Translational/sources.jl | 18 +- .../TranslationalModelica/components.jl | 10 +- .../TranslationalModelica/sources.jl | 8 +- src/Mechanical/TranslationalModelica/utils.jl | 18 +- .../TranslationalPosition/components.jl | 46 +- .../TranslationalPosition/sensors.jl | 6 +- .../TranslationalPosition/sources.jl | 2 +- src/Mechanical/TranslationalPosition/utils.jl | 16 +- src/ModelingToolkitStandardLibrary.jl | 2 +- src/Thermal/HeatTransfer/ideal_components.jl | 14 +- src/Thermal/HeatTransfer/sensors.jl | 6 +- src/Thermal/HeatTransfer/sources.jl | 12 +- src/Thermal/Thermal.jl | 4 +- src/Thermal/utils.jl | 4 +- test/Blocks/continuous.jl | 232 +++++---- test/Blocks/math.jl | 137 ++--- test/Blocks/nonlinear.jl | 48 +- test/Blocks/sources.jl | 477 +++++++++++------- test/Blocks/test_analysis_points.jl | 167 +++--- test/Blocks/utils.jl | 16 +- test/Electrical/analog.jl | 329 +++++++----- test/Electrical/digital.jl | 14 +- test/Hydraulic/isothermal_compressible.jl | 187 ++++--- test/Magnetic/magnetic.jl | 32 +- test/Mechanical/multibody.jl | 10 +- test/Mechanical/rotational.jl | 91 ++-- test/Mechanical/translational.jl | 82 +-- test/Mechanical/translational_modelica.jl | 14 +- test/Thermal/demo.jl | 8 +- test/Thermal/motor.jl | 8 +- test/Thermal/piston.jl | 8 +- test/Thermal/thermal.jl | 94 ++-- test/chua_circuit.jl | 44 +- test/multi_domain.jl | 46 +- 72 files changed, 2225 insertions(+), 1539 deletions(-) delete mode 100644 .JuliaFormatter.toml diff --git a/.JuliaFormatter.toml b/.JuliaFormatter.toml deleted file mode 100644 index 9c7935911..000000000 --- a/.JuliaFormatter.toml +++ /dev/null @@ -1,2 +0,0 @@ -style = "sciml" -format_markdown = true \ No newline at end of file diff --git a/.github/workflows/FormatCheck.yml b/.github/workflows/FormatCheck.yml index 7e46c8db9..6762c6f3e 100644 --- a/.github/workflows/FormatCheck.yml +++ b/.github/workflows/FormatCheck.yml @@ -1,13 +1,19 @@ -name: "Format Check" +name: format-check on: push: branches: + - 'master' - 'main' + - 'release-' tags: '*' pull_request: jobs: - format-check: - name: "Format Check" - uses: "SciML/.github/.github/workflows/format-check.yml@v1" + runic: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: fredrikekre/runic-action@v1 + with: + version: '1' diff --git a/docs/make.jl b/docs/make.jl index a0cac1b6d..a2fb0ddfe 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -17,9 +17,11 @@ ENV["GKSwstype"] = "100" include("pages.jl") -makedocs(sitename = "ModelingToolkitStandardLibrary.jl", +makedocs( + sitename = "ModelingToolkitStandardLibrary.jl", authors = "Julia Computing", - modules = [ModelingToolkit, + modules = [ + ModelingToolkit, ModelingToolkitStandardLibrary, ModelingToolkitStandardLibrary.Blocks, ModelingToolkitStandardLibrary.Mechanical, @@ -29,13 +31,19 @@ makedocs(sitename = "ModelingToolkitStandardLibrary.jl", ModelingToolkitStandardLibrary.Electrical, ModelingToolkitStandardLibrary.Thermal, ModelingToolkitStandardLibrary.Hydraulic, - ModelingToolkitStandardLibrary.Hydraulic.IsothermalCompressible], + ModelingToolkitStandardLibrary.Hydraulic.IsothermalCompressible, + ], clean = true, doctest = false, linkcheck = true, linkcheck_ignore = ["https://www.mathworks.com/help/simscape/ug/basic-principles-of-modeling-physical-networks.html#bq89sba-6"], warnonly = [:docs_block, :missing_docs, :cross_references], - format = Documenter.HTML(assets = ["assets/favicon.ico"], - canonical = "https://docs.sciml.ai/ModelingToolkitStandardLibrary/stable/"), - pages = pages) + format = Documenter.HTML( + assets = ["assets/favicon.ico"], + canonical = "https://docs.sciml.ai/ModelingToolkitStandardLibrary/stable/" + ), + pages = pages +) -deploydocs(repo = "github.com/SciML/ModelingToolkitStandardLibrary.jl"; - push_preview = true) +deploydocs( + repo = "github.com/SciML/ModelingToolkitStandardLibrary.jl"; + push_preview = true +) diff --git a/docs/pages.jl b/docs/pages.jl index d2331982b..00bcb942a 100644 --- a/docs/pages.jl +++ b/docs/pages.jl @@ -5,11 +5,11 @@ pages = [ "Custom Components" => "tutorials/custom_component.md", "Thermal Conduction Model" => "tutorials/thermal_model.md", "DC Motor with Speed Controller" => "tutorials/dc_motor_pi.md", - "SampledData Component" => "tutorials/input_component.md" + "SampledData Component" => "tutorials/input_component.md", ], "About Acausal Connections" => [ "Theory" => "connectors/connections.md", - "Sign Convention" => "connectors/sign_convention.md" + "Sign Convention" => "connectors/sign_convention.md", ], "API" => [ "Basic Blocks" => "API/blocks.md", @@ -18,6 +18,6 @@ pages = [ "Mechanical Components" => "API/mechanical.md", "Thermal Components" => "API/thermal.md", "Hydraulic Components" => "API/hydraulic.md", - "Linear Analysis" => "API/linear_analysis.md" - ] + "Linear Analysis" => "API/linear_analysis.md", + ], ] diff --git a/src/Blocks/Blocks.jl b/src/Blocks/Blocks.jl index 9adc16129..6361c9fae 100644 --- a/src/Blocks/Blocks.jl +++ b/src/Blocks/Blocks.jl @@ -11,14 +11,14 @@ export RealInput, RealInputArray, RealOutput, RealOutputArray, SISO include("utils.jl") export Gain, Sum, MatrixGain, Feedback, Add, Add3, Product, Division, Power, Modulo, - UnaryMinus, Floor, Ceil + UnaryMinus, Floor, Ceil export Abs, Sign, Sqrt, Sin, Cos, Tan, Asin, Acos, Atan, Atan2, Sinh, Cosh, Tanh, Exp export Log, Log10 include("math.jl") export Constant, TimeVaryingFunction, Sine, Cosine, ContinuousClock, Ramp, Step, ExpSine, - Square, Triangular, Parameter, SampledData, - Interpolation, ParametrizedInterpolation + Square, Triangular, Parameter, SampledData, + Interpolation, ParametrizedInterpolation include("sources.jl") export Limiter, DeadZone, SlewRateLimiter diff --git a/src/Blocks/continuous.jl b/src/Blocks/continuous.jl index 18ff14ce2..50806ca80 100644 --- a/src/Blocks/continuous.jl +++ b/src/Blocks/continuous.jl @@ -34,7 +34,7 @@ Initial value of integrator state ``x`` can be set with `x` equations = Equation[ D(x) ~ k * u, - y ~ x + y ~ x, ] sys = System(equations, t, vars, pars; name, systems) @@ -74,7 +74,7 @@ Initial value of the state ``x`` can be set with `x`. """ @component function Derivative(; name, k = 1, T = nothing, x = 0.0) @symcheck T > 0 || - throw(ArgumentError("Time constant `T` has to be strictly positive")) + throw(ArgumentError("Time constant `T` has to be strictly positive")) @named siso = SISO() @unpack u, y = siso @@ -93,7 +93,7 @@ Initial value of the state ``x`` can be set with `x`. equations = Equation[ D(x) ~ (u - x) / T, - y ~ (k / T) * (u - x) + y ~ (k / T) * (u - x), ] sys = System(equations, t, vars, pars; name, systems) @@ -137,7 +137,7 @@ See also [`SecondOrder`](@ref) """ @component function FirstOrder(; name, lowpass = true, T = nothing, k = 1.0, x = 0.0) @symcheck T > 0 || - throw(ArgumentError("Time constant `T` has to be strictly positive")) + throw(ArgumentError("Time constant `T` has to be strictly positive")) @named siso = SISO() @unpack u, y = siso @@ -156,7 +156,7 @@ See also [`SecondOrder`](@ref) equations = Equation[ D(x) ~ (k * u - x) / T, - lowpass ? (y ~ x) : (y ~ k * u - x) + lowpass ? (y ~ x) : (y ~ k * u - x), ] sys = System(equations, t, vars, pars; name, systems) @@ -211,7 +211,7 @@ Initial value of the state `x` can be set with `x`, and of derivative state `xd` equations = Equation[ D(x) ~ xd, D(xd) ~ w * (w * (k * u - x) - 2 * d * xd), - y ~ x + y ~ x, ] sys = System(equations, t, vars, pars; name, systems) @@ -243,7 +243,7 @@ See also [`LimPI`](@ref) """ @component function PI(; name, k = 1.0, T = 1.0, gainPI__k = nothing) @symcheck T > 0 || - throw(ArgumentError("Time constant `T` has to be strictly positive")) + throw(ArgumentError("Time constant `T` has to be strictly positive")) pars = @parameters begin k = k, [description = "Proportional gain"] @@ -266,7 +266,7 @@ See also [`LimPI`](@ref) connect(addPI.output, gainPI.input), connect(gainPI.output, ctr_output), connect(err_input, int.input), - connect(int.output, addPI.input2) + connect(int.output, addPI.input2), ] return System(equations, t, vars, pars; name, systems) @@ -293,18 +293,20 @@ Text-book version of a PID-controller without actuator saturation and anti-windu See also [`LimPID`](@ref) """ -@component function PID(; name, k = 1, Ti = false, Td = false, Nd = 10, int__x = 0, - der__x = 0) +@component function PID(; + name, k = 1, Ti = false, Td = false, Nd = 10, int__x = 0, + der__x = 0 + ) with_I = !isequal(Ti, false) with_D = !isequal(Td, false) @named err_input = RealInput() # control error @named ctr_output = RealOutput() # control signal @symcheck Ti ≥ 0 || - throw(ArgumentError("Ti out of bounds, got $(Ti) but expected Ti ≥ 0")) + throw(ArgumentError("Ti out of bounds, got $(Ti) but expected Ti ≥ 0")) @symcheck Td ≥ 0 || - throw(ArgumentError("Td out of bounds, got $(Td) but expected Td ≥ 0")) + throw(ArgumentError("Td out of bounds, got $(Td) but expected Td ≥ 0")) @symcheck Nd > 0 || - throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0")) + throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0")) pars = @parameters begin k = k, [description = "Proportional gain"] @@ -339,7 +341,7 @@ See also [`LimPID`](@ref) eqs = [ connect(err_input, addPID.input1), connect(addPID.output, gainPID.input), - connect(gainPID.output, ctr_output) + connect(gainPID.output, ctr_output), ] if with_I push!(eqs, connect(err_input, int.input)) @@ -380,7 +382,7 @@ The simplified expression above is given without the anti-windup protection. """ @component function LimPI(; name, k = 1, T = nothing, u_max = nothing, u_min = -u_max, Ta = nothing, int__x = 0.0) @symcheck Ta > 0 || - throw(ArgumentError("Time constant `Ta` has to be strictly positive")) + throw(ArgumentError("Time constant `Ta` has to be strictly positive")) @symcheck T > 0 || throw(ArgumentError("Time constant `T` has to be strictly positive")) @symcheck u_max ≥ u_min || throw(ArgumentError("u_min must be smaller than u_max")) pars = @parameters begin @@ -411,7 +413,7 @@ The simplified expression above is given without the anti-windup protection. connect(err_input, addTrack.input1), connect(gainTrack.output, addTrack.input2), connect(addTrack.output, int.input), - connect(int.output, addPI.input2) + connect(int.output, addPI.input2), ] System(eqs, t, [], pars; name = name, systems = sys) end @@ -449,14 +451,16 @@ where the transfer function for the derivative includes additional filtering, se - `measurement` - `ctr_output` """ -@component function LimPID(; name, k = 1, Ti = false, Td = false, wp = 1, wd = 1, - Ni = Ti == 0 ? Inf : √(max(Td / Ti, 1e-6)), +@component function LimPID(; + name, k = 1, Ti = false, Td = false, wp = 1, wd = 1, + Ni = Ti == 0 ? Inf : √(max(Td / Ti, 1.0e-6)), Nd = 10, u_max = Inf, u_min = u_max > 0 ? -u_max : -Inf, gains = false, int__x = 0.0, - der__x = 0.0) + der__x = 0.0 + ) with_I = !isequal(Ti, false) with_D = !isequal(Td, false) with_AWM = Ni != Inf @@ -465,12 +469,12 @@ where the transfer function for the derivative includes additional filtering, se Td = Td / k end @symcheck Ti ≥ 0 || - throw(ArgumentError("Ti out of bounds, got $(Ti) but expected Ti ≥ 0")) + throw(ArgumentError("Ti out of bounds, got $(Ti) but expected Ti ≥ 0")) @symcheck Td ≥ 0 || - throw(ArgumentError("Td out of bounds, got $(Td) but expected Td ≥ 0")) + throw(ArgumentError("Td out of bounds, got $(Td) but expected Td ≥ 0")) @symcheck u_max ≥ u_min || throw(ArgumentError("u_min must be smaller than u_max")) @symcheck Nd > 0 || - throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0")) + throw(ArgumentError("Nd out of bounds, got $(Nd) but expected Nd > 0")) pars = @parameters begin k = k, [description = "Proportional gain"] @@ -530,7 +534,7 @@ where the transfer function for the derivative includes additional filtering, se connect(addP.output, addPID.input1), connect(addPID.output, gainPID.input), connect(gainPID.output, limiter.input), - connect(limiter.output, ctr_output) + connect(limiter.output, ctr_output), ] if with_I push!(eqs, connect(reference, addI.input1)) @@ -592,8 +596,10 @@ y &= h(x, u) linearized around the operating point `x₀, u₀`, we have `y0, u0 = h(x₀, u₀), u₀`. """ -@component function StateSpace(; A, B, C, D = nothing, x = zeros(size(A, 1)), name, - u0 = zeros(size(B, 2)), y0 = zeros(size(C, 1))) +@component function StateSpace(; + A, B, C, D = nothing, x = zeros(size(A, 1)), name, + u0 = zeros(size(B, 2)), y0 = zeros(size(C, 1)) + ) nx, nu, ny = size(A, 1), size(B, 2), size(C, 1) size(A, 2) == nx || error("`A` has to be a square matrix.") size(B, 1) == nx || error("`B` has to be of dimension ($nx x $nu).") @@ -608,19 +614,23 @@ linearized around the operating point `x₀, u₀`, we have `y0, u0 = h(x₀, u end @named input = RealInput(nin = nu) @named output = RealOutput(nout = ny) - @variables x(t)[1:nx]=x [ - description = "State variables of StateSpace system $name" + @variables x(t)[1:nx] = x [ + description = "State variables of StateSpace system $name", ] # pars = @parameters A=A B=B C=C D=D # This is buggy eqs = [ # FIXME: if array equations work - [Differential(t)(x[i]) ~ - sum(A[i, k] * x[k] for k in 1:nx) + - sum(B[i, j] * (input.u[j] - u0[j]) for j in 1:nu) - for i in 1:nx]..., # cannot use D here - [output.u[j] ~ - sum(C[j, i] * x[i] for i in 1:nx) + - sum(D[j, k] * (input.u[k] - u0[k]) for k in 1:nu) + y0[j] - for j in 1:ny]... + [ + Differential(t)(x[i]) ~ + sum(A[i, k] * x[k] for k in 1:nx) + + sum(B[i, j] * (input.u[j] - u0[j]) for j in 1:nu) + for i in 1:nx + ]..., # cannot use D here + [ + output.u[j] ~ + sum(C[j, i] * x[i] for i in 1:nx) + + sum(D[j, k] * (input.u[k] - u0[k]) for k in 1:nu) + y0[j] + for j in 1:ny + ]..., ] compose(System(eqs, t, vcat(x...), [], name = name), [input, output]) end @@ -668,16 +678,16 @@ See also [`StateSpace`](@ref) which handles MIMO systems, as well as [ControlSys @parameters begin b[1:nb] = b, - [ - description = "Numerator coefficients of transfer function (e.g., 2s + 3 is specified as [2,3])" - ] + [ + description = "Numerator coefficients of transfer function (e.g., 2s + 3 is specified as [2,3])", + ] a[1:na] = a, - [ - description = "Denominator coefficients of transfer function (e.g., `s² + 2ωs + ω^2` is specified as [1, 2ω, ω^2])" - ] + [ + description = "Denominator coefficients of transfer function (e.g., `s² + 2ωs + ω^2` is specified as [1, 2ω, ω^2])", + ] bb[1:(nbb + nb)] = [zeros(nbb); b] end - d = bb[1] / a[1]# , [description = "Direct feedthrough gain"] + d = bb[1] / a[1] # , [description = "Direct feedthrough gain"] a = collect(a) a_end = ifelse(a[end] > 100 * symbolic_eps(sqrt(a' * a)), a[end], 1.0) @@ -685,7 +695,7 @@ See also [`StateSpace`](@ref) which handles MIMO systems, as well as [ControlSys pars = [collect(b); a; collect(bb)] @variables begin x(t)[1:nx] = zeros(nx), - [description = "State of transfer function on controller canonical form"] + [description = "State of transfer function on controller canonical form"] x_scaled(t)[1:nx] = collect(x) * a_end, [description = "Scaled vector x"] u(t), [description = "Input of transfer function"] y(t), [description = "Output of transfer function"] @@ -700,10 +710,12 @@ See also [`StateSpace`](@ref) which handles MIMO systems, as well as [ControlSys if nx == 0 eqs = [y ~ d * u] else - eqs = Equation[D(x_scaled[1]) ~ (-a[2:na]'x_scaled + a_end * u) / a[1] - D.(x_scaled[2:nx]) .~ x_scaled[1:(nx - 1)] - y ~ ((bb[2:na] - d * a[2:na])'x_scaled) / a_end + d * u - x .~ x_scaled ./ a_end] + eqs = Equation[ + D(x_scaled[1]) ~ (-a[2:na]'x_scaled + a_end * u) / a[1] + D.(x_scaled[2:nx]) .~ x_scaled[1:(nx - 1)] + y ~ ((bb[2:na] - d * a[2:na])'x_scaled) / a_end + d * u + x .~ x_scaled ./ a_end + ] end push!(eqs, input.u ~ u) push!(eqs, output.u ~ y) diff --git a/src/Blocks/math.jl b/src/Blocks/math.jl index db4b94f12..b06168568 100644 --- a/src/Blocks/math.jl +++ b/src/Blocks/math.jl @@ -27,7 +27,7 @@ Output the product of a gain value with the input signal. end equations = Equation[ - y ~ k * u + y ~ k * u, ] sys = System(equations, t, vars, pars; name, systems) @@ -65,8 +65,10 @@ Output the product of a gain matrix with the input signal vector. end equations = Equation[ - [output.u[i] ~ sum(K[i, j] * input.u[j] for j in 1:nin) - for i in 1:nout]... + [ + output.u[i] ~ sum(K[i, j] * input.u[j] for j in 1:nin) + for i in 1:nout + ]..., ] return System(equations, t, vars, pars; name, systems) @@ -96,7 +98,7 @@ Input port dimension can be set with `input__nin` end equations = Equation[ - output.u ~ sum(input.u) + output.u ~ sum(input.u), ] return System(equations, t, vars, pars; name, systems) @@ -127,7 +129,7 @@ Output difference between reference input (input1) and feedback input (input2). end equations = Equation[ - output.u ~ input1.u - input2.u + output.u ~ input1.u - input2.u, ] return System(equations, t, vars, pars; name, systems) @@ -165,7 +167,7 @@ Output the sum of the two scalar inputs. end equations = Equation[ - output.u ~ k1 * input1.u + k2 * input2.u + output.u ~ k1 * input1.u + k2 * input2.u, ] return System(equations, t, vars, pars; name, systems) @@ -207,7 +209,7 @@ Output the sum of the three scalar inputs. end equations = Equation[ - output.u ~ k1 * input1.u + k2 * input2.u + k3 * input3.u + output.u ~ k1 * input1.u + k2 * input2.u + k3 * input3.u, ] return System(equations, t, vars, pars; name, systems) @@ -238,7 +240,7 @@ Output product of the two inputs. end equations = Equation[ - output.u ~ input1.u * input2.u + output.u ~ input1.u * input2.u, ] return System(equations, t, vars, pars; name, systems) @@ -269,7 +271,7 @@ Output first input divided by second input. end equations = Equation[ - output.u ~ input1.u / input2.u + output.u ~ input1.u / input2.u, ] return System(equations, t, vars, pars; name, systems) @@ -300,7 +302,7 @@ Output the exponential with base as the first input and exponent as second input end equations = Equation[ - output.u ~ base.u^exponent.u + output.u ~ base.u^exponent.u, ] return System(equations, t, vars, pars; name, systems) @@ -331,7 +333,7 @@ Output the remainder when the first input is divided by second input. end equations = Equation[ - remainder.u ~ mod(dividend.u, divisor.u) + remainder.u ~ mod(dividend.u, divisor.u), ] return System(equations, t, vars, pars; name, systems) @@ -360,7 +362,7 @@ Output the product of -1 and the input. end equations = Equation[ - output.u ~ -(input.u) + output.u ~ -(input.u), ] return System(equations, t, vars, pars; name, systems) @@ -389,7 +391,7 @@ Output the floor rounding of the input. end equations = Equation[ - output.u ~ floor(input.u) + output.u ~ floor(input.u), ] return System(equations, t, vars, pars; name, systems) @@ -418,7 +420,7 @@ Output the ceiling rounding of the input. end equations = Equation[ - output.u ~ ceil(input.u) + output.u ~ ceil(input.u), ] return System(equations, t, vars, pars; name, systems) @@ -450,7 +452,7 @@ If the given function is not composed of simple core methods (e.g. sin, abs, ... end equations = Equation[ - y ~ func(u) + y ~ func(u), ] sys = System(equations, t, vars, pars; name, systems) @@ -582,7 +584,7 @@ Output the arc tangent of the input. end equations = Equation[ - output.u ~ atan(input1.u, input2.u) + output.u ~ atan(input1.u, input2.u), ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Blocks/nonlinear.jl b/src/Blocks/nonlinear.jl index 4fc0d4f2f..5aaf7087b 100644 --- a/src/Blocks/nonlinear.jl +++ b/src/Blocks/nonlinear.jl @@ -20,11 +20,11 @@ Limit the range of a signal. m = (y_max + y_min) / 2 siso = SISO(u_start = m, y_start = m, name = :siso) # Default signals to center of saturation to minimize risk of saturation while linearizing etc. @unpack u, y = siso - pars = @parameters y_max=y_max [description="Maximum allowed output of Limiter $name"] y_min=y_min [ - description="Minimum allowed output of Limiter $name" + pars = @parameters y_max = y_max [description = "Maximum allowed output of Limiter $name"] y_min = y_min [ + description = "Minimum allowed output of Limiter $name", ] eqs = [ - y ~ clamp(u, y_min, y_max) + y ~ clamp(u, y_min, y_max), ] extend(System(eqs, t, [], pars; name = name), siso) end @@ -80,7 +80,7 @@ If the input is within `u_min` ... `u_max`, the output is zero. Outside of this end equations = Equation[ - y ~ _dead_zone(u, u_min, u_max) + y ~ _dead_zone(u, u_min, u_max), ] sys = System(equations, t, vars, pars; name, systems) @@ -106,7 +106,8 @@ Initial value of state `Y` can be set with `int.y` - `output` """ @component function SlewRateLimiter(; - name, y_start = 0.0, rising = 1.0, falling = -rising, Td = 0.001) + name, y_start = 0.0, rising = 1.0, falling = -rising, Td = 0.001 + ) pars = @parameters begin rising = rising, [description = "Maximum rising slew rate of SlewRateLimiter"] falling = falling, [description = "Derivative time constant of SlewRateLimiter"] @@ -123,11 +124,11 @@ Initial value of state `Y` can be set with `int.y` @unpack y, u = siso eqs = [ - D(y) ~ clamp((u - y) / Td, falling, rising) + D(y) ~ clamp((u - y) / Td, falling, rising), ] initialization_eqs = [ - y ~ y_start + y ~ y_start, ] return extend(System(eqs, t, [], pars; name, initialization_eqs), siso) diff --git a/src/Blocks/sources.jl b/src/Blocks/sources.jl index 8baa1feb8..3aa381e4a 100644 --- a/src/Blocks/sources.jl +++ b/src/Blocks/sources.jl @@ -6,60 +6,62 @@ using PreallocationTools # These are "smooth" aka differentiable and avoid Gibbs effect # These follow: `offset` + `smooth_wave` * `smooth_step` with zero output for `t < start_time` function smooth_cos(x, δ, f, amplitude, ϕ, offset, start_time) - offset + - amplitude * cos(2 * π * f * (x - start_time) + ϕ) * - smooth_step(x, δ, one(x), zero(x), start_time) + return offset + + amplitude * cos(2 * π * f * (x - start_time) + ϕ) * + smooth_step(x, δ, one(x), zero(x), start_time) end function smooth_damped_sin(x, δ, f, amplitude, damping, ϕ, offset, start_time) - offset + - exp((start_time - x) * damping) * amplitude * sin(2 * π * f * (x - start_time) + ϕ) * - smooth_step(x, δ, one(x), zero(x), start_time) + return offset + + exp((start_time - x) * damping) * amplitude * sin(2 * π * f * (x - start_time) + ϕ) * + smooth_step(x, δ, one(x), zero(x), start_time) end function smooth_ramp(x, δ, height, duration, offset, start_time) - offset + - height / (duration) * - (smooth_xH(x, δ, start_time) - smooth_xH(x, δ, start_time + duration)) + return offset + + height / (duration) * + (smooth_xH(x, δ, start_time) - smooth_xH(x, δ, start_time + duration)) end function smooth_sin(x, δ, f, amplitude, ϕ, offset, start_time) - offset + - amplitude * sin(2 * pi * f * (x - start_time) + ϕ) * - smooth_step(x, δ, one(x), zero(x), start_time) + return offset + + amplitude * sin(2 * pi * f * (x - start_time) + ϕ) * + smooth_step(x, δ, one(x), zero(x), start_time) end function smooth_square(x, δ, f, amplitude, offset, start_time) - offset + - amplitude * 2atan(sin(2π * (x - start_time) * f) / δ) / π * - smooth_step(x, δ, one(x), zero(x), start_time) + return offset + + amplitude * 2atan(sin(2π * (x - start_time) * f) / δ) / π * + smooth_step(x, δ, one(x), zero(x), start_time) end function smooth_step(x, δ, height, offset, start_time) - offset + height * (atan((x - start_time) / δ) / π + 0.5) + return offset + height * (atan((x - start_time) / δ) / π + 0.5) end function smooth_triangular(x, δ, f, amplitude, offset, start_time) - offset + - amplitude * (1 - 2acos((1 - δ)sin(2π * (x - start_time) * f)) / π) * - smooth_step(x, δ, one(x), zero(x), start_time) + return offset + + amplitude * (1 - 2acos((1 - δ)sin(2π * (x - start_time) * f)) / π) * + smooth_step(x, δ, one(x), zero(x), start_time) end function smooth_xH(x, δ, tₒ) - 0.5 * (x - tₒ) * (1 + ((x - tₒ) / sqrt((x - tₒ)^2 + δ^2))) + return 0.5 * (x - tₒ) * (1 + ((x - tₒ) / sqrt((x - tₒ)^2 + δ^2))) end function square(x, f, amplitude, offset, start_time) - offset + - (x > start_time) * (amplitude * - (4 * floor(f * (x - start_time)) - 2 * floor(2 * (x - start_time) * f) + 1)) + return offset + + (x > start_time) * ( + amplitude * + (4 * floor(f * (x - start_time)) - 2 * floor(2 * (x - start_time) * f) + 1) + ) end function triangular(x, f, amplitude, offset, start_time) p = 1 / f # period - offset + - (x > start_time) * - (4 * amplitude * f * abs(abs((x - p / 4 - start_time) % p) - p / 2) - amplitude) + return offset + + (x > start_time) * + (4 * amplitude * f * abs(abs((x - p / 4 - start_time) % p) - p / 2) - amplitude) end """ @@ -88,7 +90,7 @@ Generate constant signal. end equations = Equation[ - output.u ~ k + output.u ~ k, ] return System(equations, t, vars, pars; name, systems) @@ -116,7 +118,7 @@ The input variable `t` can be changed by passing a different variable as the key end equations = Equation[ - output.u ~ f(t) + output.u ~ f(t), ] return System(equations, t, vars, pars; name, systems) @@ -143,25 +145,29 @@ Generate sine signal. - `output` """ -@component function Sine(; name, +@component function Sine(; + name, frequency = nothing, amplitude = 1, phase = 0, offset = 0, start_time = 0, - smooth = false) + smooth = false + ) @named output = RealOutput() - pars = @parameters offset=offset start_time=start_time amplitude=amplitude frequency=frequency phase=phase + pars = @parameters offset = offset start_time = start_time amplitude = amplitude frequency = frequency phase = phase equation = if smooth == false - offset + ifelse(t < start_time, 0, - amplitude * sin(2 * pi * frequency * (t - start_time) + phase)) + offset + ifelse( + t < start_time, 0, + amplitude * sin(2 * pi * frequency * (t - start_time) + phase) + ) else - smooth === true && (smooth = 1e-5) + smooth === true && (smooth = 1.0e-5) smooth_sin(t, smooth, frequency, amplitude, phase, offset, start_time) end eqs = [ - output.u ~ equation + output.u ~ equation, ] compose(System(eqs, t, [], pars; name = name), [output]) @@ -185,24 +191,28 @@ Generate cosine signal. # Connectors: - `output` """ -@component function Cosine(; name, +@component function Cosine(; + name, frequency = nothing, amplitude = 1, phase = 0, offset = 0, start_time = 0, - smooth = false) + smooth = false + ) @named output = RealOutput() - pars = @parameters offset=offset start_time=start_time amplitude=amplitude frequency=frequency phase=phase + pars = @parameters offset = offset start_time = start_time amplitude = amplitude frequency = frequency phase = phase equation = if smooth == false - offset + ifelse(t < start_time, zero(t), - amplitude * cos(2 * pi * frequency * (t - start_time) + phase)) + offset + ifelse( + t < start_time, zero(t), + amplitude * cos(2 * pi * frequency * (t - start_time) + phase) + ) else - smooth === true && (smooth = 1e-5) + smooth === true && (smooth = 1.0e-5) smooth_cos(t, smooth, frequency, amplitude, phase, offset, start_time) end eqs = [ - output.u ~ equation + output.u ~ equation, ] compose(System(eqs, t, [], pars; name = name), [output]) @@ -224,9 +234,9 @@ Generate current time signal. """ @component function ContinuousClock(; name, offset = 0, start_time = 0) @named output = RealOutput() - pars = @parameters offset=offset start_time=start_time + pars = @parameters offset = offset start_time = start_time eqs = [ - output.u ~ offset + ifelse(t < start_time, zero(t), t - start_time) + output.u ~ offset + ifelse(t < start_time, zero(t), t - start_time), ] compose(System(eqs, t, [], pars; name = name), [output]) @@ -250,25 +260,31 @@ Generate ramp signal. - `output` """ -@component function Ramp(; name, +@component function Ramp(; + name, height = 1.0, duration = 1.0, offset = 0.0, start_time = 0.0, - smooth = false) + smooth = false + ) @named output = RealOutput() - pars = @parameters offset=offset start_time=start_time height=height duration=duration + pars = @parameters offset = offset start_time = start_time height = height duration = duration equation = if smooth == false - offset + ifelse(t < start_time, zero(height), - ifelse(t < (start_time + duration), (t - start_time) * height / duration, - height)) + offset + ifelse( + t < start_time, zero(height), + ifelse( + t < (start_time + duration), (t - start_time) * height / duration, + height + ) + ) else - smooth === true && (smooth = 1e-5) + smooth === true && (smooth = 1.0e-5) smooth_ramp(t, smooth, height, duration, offset, start_time) end eqs = [ - output.u ~ equation + output.u ~ equation, ] compose(System(eqs, t, [], pars; name = name), [output]) @@ -292,8 +308,10 @@ Generate smooth square signal. - `output` """ -@component function Square(; name, frequency = 1.0, amplitude = 1.0, - offset = 0.0, start_time = 0.0, smooth = false) +@component function Square(; + name, frequency = 1.0, amplitude = 1.0, + offset = 0.0, start_time = 0.0, smooth = false + ) @named output = RealOutput() pars = @parameters begin frequency = frequency @@ -305,12 +323,12 @@ Generate smooth square signal. equation = if smooth == false square(t, frequency, amplitude, offset, start_time) else - smooth === true && (smooth = 1e-5) + smooth === true && (smooth = 1.0e-5) smooth_square(t, smooth, frequency, amplitude, offset, start_time) end eqs = [ - output.u ~ equation + output.u ~ equation, ] compose(System(eqs, t, [], pars; name = name), [output]) @@ -336,25 +354,26 @@ Generate step signal. """ @component function Step(; name, height = 1.0, offset = 0.0, start_time = 0.0, duration = Inf, - smooth = 1e-5) + smooth = 1.0e-5 + ) @named output = RealOutput() duration_numeric = duration - pars = @parameters offset=offset start_time=start_time height=height duration=duration + pars = @parameters offset = offset start_time = start_time height = height duration = duration equation = if smooth == false # use comparison in case smooth is a float offset + - ifelse((start_time <= t) & (t < start_time + duration), height, zero(height)) + ifelse((start_time <= t) & (t < start_time + duration), height, zero(height)) else - smooth === true && (smooth = 1e-5) + smooth === true && (smooth = 1.0e-5) if duration_numeric == Inf smooth_step(t, smooth, height, offset, start_time) else smooth_step(t, smooth, height, offset, start_time) - - smooth_step(t, smooth, height, zero(start_time), start_time + duration) + smooth_step(t, smooth, height, zero(start_time), start_time + duration) end end eqs = [ - output.u ~ equation + output.u ~ equation, ] compose(System(eqs, t, [], pars; name = name), [output]) @@ -380,29 +399,35 @@ Exponentially damped sine signal. - `output` """ -@component function ExpSine(; name, +@component function ExpSine(; + name, frequency = nothing, amplitude = 1.0, damping = 0.1, phase = 0.0, offset = 0.0, start_time = 0.0, - smooth = false) + smooth = false + ) @named output = RealOutput() - pars = @parameters offset=offset start_time=start_time amplitude=amplitude frequency=frequency phase=phase damping=damping + pars = @parameters offset = offset start_time = start_time amplitude = amplitude frequency = frequency phase = phase damping = damping equation = if smooth == false - offset + ifelse(t < start_time, zero(amplitude), + offset + ifelse( + t < start_time, zero(amplitude), amplitude * exp(-damping * (t - start_time)) * - sin(2 * pi * frequency * (t - start_time) + phase)) + sin(2 * pi * frequency * (t - start_time) + phase) + ) else - smooth === true && (smooth = 1e-5) - smooth_damped_sin(t, smooth, frequency, amplitude, damping, phase, offset, - start_time) + smooth === true && (smooth = 1.0e-5) + smooth_damped_sin( + t, smooth, frequency, amplitude, damping, phase, offset, + start_time + ) end eqs = [ - output.u ~ equation + output.u ~ equation, ] compose(System(eqs, t, [], pars; name = name), [output]) @@ -427,8 +452,10 @@ Generate smooth triangular signal for frequencies less than or equal to 25 Hz - `output` """ -@component function Triangular(; name, amplitude = 1.0, frequency = 1.0, - offset = 0.0, start_time = 0.0, smooth = false) +@component function Triangular(; + name, amplitude = 1.0, frequency = 1.0, + offset = 0.0, start_time = 0.0, smooth = false + ) @named output = RealOutput() pars = @parameters begin amplitude = amplitude @@ -440,12 +467,12 @@ Generate smooth triangular signal for frequencies less than or equal to 25 Hz equation = if smooth == false triangular(t, frequency, amplitude, offset, start_time) else - smooth === true && (smooth = 1e-5) + smooth === true && (smooth = 1.0e-5) smooth_triangular(t, smooth, frequency, amplitude, offset, start_time) end eqs = [ - output.u ~ equation + output.u ~ equation, ] compose(System(eqs, t, [], pars; name = name), [output]) @@ -528,7 +555,7 @@ Base.min(x::Parameter, y::Number) = min(x.ref, y) Base.min(x::Parameter, y::Parameter) = min(x.ref, y.ref) function Base.show(io::IO, m::MIME"text/plain", p::Parameter) - if !isempty(p.data) + return if !isempty(p.data) print(io, p.data) else print(io, p.ref) @@ -540,7 +567,7 @@ Symbolics.@register_symbolic get_sample_time(memory::Parameter) Base.convert(::Type{T}, x::Parameter{T}) where {T <: Real} = x.ref function Base.convert(::Type{<:Parameter{T}}, x::Number) where {T <: Real} - Parameter{T}(T[], x, true) + return Parameter{T}(T[], x, true) end # SampledData utilities ---------------- @@ -552,7 +579,7 @@ function linear_interpolation(x1::Real, x2::Real, t1::Real, t2::Real, t) return slope * t + intercept else - @assert x1==x2 "x1 ($x1) and x2 ($x2) should be equal if t1 == t2" + @assert x1 == x2 "x1 ($x1) and x2 ($x2) should be equal if t1 == t2" return x2 end @@ -573,10 +600,12 @@ function first_order_backwards_difference(t, buffer, Δt, circular_buffer) return (x1 - x0) / Δt end -function get_sampled_data(t, +function get_sampled_data( + t, buffer::Vector{T}, dt::T, - circular_buffer = true) where {T <: Real} + circular_buffer = true + ) where {T <: Real} if t < 0 t = zero(t) end @@ -616,31 +645,33 @@ function get_sampled_data(t, end end function get_sampled_data(t, buffer) - get_sampled_data(t, buffer.data, buffer.ref, buffer.circular_buffer) + return get_sampled_data(t, buffer.data, buffer.ref, buffer.circular_buffer) end Symbolics.@register_symbolic Parameter(data::Vector, ref, circular_buffer::Bool) Symbolics.@register_symbolic get_sampled_data(t, buffer::Parameter) Symbolics.@register_symbolic get_sampled_data(t, buffer::Vector, dt, circular_buffer) false Symbolics.@register_derivative get_sampled_data(t, buffer) 1 first_order_backwards_difference(t, buffer) function ChainRulesCore.frule((_, ẋ, _), ::typeof(get_sampled_data), t, buffer) - first_order_backwards_difference(t, buffer) * ẋ + return first_order_backwards_difference(t, buffer) * ẋ end Symbolics.@register_derivative get_sampled_data(t, buffer, dt, circular_buffer) 1 begin first_order_backwards_difference(t, buffer, dt, circular_buffer) end -function ChainRulesCore.frule((_, ẋ, _), +function ChainRulesCore.frule( + (_, ẋ, _), ::typeof(get_sampled_data), t, buffer, sample_time, - circular_buffer) - first_order_backwards_difference(t, buffer, sample_time, circular_buffer) * ẋ + circular_buffer + ) + return first_order_backwards_difference(t, buffer, sample_time, circular_buffer) * ẋ end # SampledData component ---------------- module SampledDataType -@enum Option vector_based struct_based + @enum Option vector_based struct_based end """ @@ -656,11 +687,13 @@ data input component. # Connectors: - `output` """ -@component function SampledData(::Val{SampledDataType.vector_based}; +@component function SampledData( + ::Val{SampledDataType.vector_based}; name, buffer = nothing, sample_time = nothing, - circular_buffer = true) + circular_buffer = true + ) T = eltype(buffer) pars = @parameters begin buffer::Vector{T} = buffer #::Vector{Real} @@ -673,7 +706,7 @@ data input component. output = RealOutput() end eqs = [ - output.u ~ get_sampled_data(t, p) + output.u ~ get_sampled_data(t, p), ] return System(eqs, t, vars, [pars; p]; name, systems) end @@ -690,7 +723,8 @@ data input component. - `output` """ @component function SampledData( - ::Val{SampledDataType.struct_based}; name, buffer::Parameter) + ::Val{SampledDataType.struct_based}; name, buffer::Parameter + ) pars = @parameters begin buffer::typeof(buffer) = buffer #::Parameter end @@ -699,7 +733,7 @@ data input component. output = RealOutput() end eqs = [ - output.u ~ get_sampled_data(t, buffer) + output.u ~ get_sampled_data(t, buffer), ] return System(eqs, t, vars, pars; name, systems) end @@ -708,27 +742,33 @@ SampledData(x::SampledDataType.Option; kwargs...) = SampledData(Val(x); kwargs.. # struct_based function SampledData(T::Type, circular_buffer = true; name) - SampledData(SampledDataType.struct_based; + return SampledData( + SampledDataType.struct_based; name, - buffer = Parameter(T[], zero(T), circular_buffer)) + buffer = Parameter(T[], zero(T), circular_buffer) + ) end # vector_based function SampledData(sample_time::T, circular_buffer = true; name) where {T <: Real} - SampledData(SampledDataType.vector_based; + return SampledData( + SampledDataType.vector_based; name, buffer = T[], sample_time, - circular_buffer) + circular_buffer + ) end -function SampledData(buffer::Vector{<:Real}, +function SampledData( + buffer::Vector{<:Real}, sample_time::Real, circular_buffer = true; - name) - SampledData(SampledDataType.vector_based; name, buffer, sample_time, circular_buffer) + name + ) + return SampledData(SampledDataType.vector_based; name, buffer, sample_time, circular_buffer) end function SampledData(; name, buffer, sample_time, circular_buffer) - SampledData(SampledDataType.vector_based; name, buffer, sample_time, circular_buffer) + return SampledData(SampledDataType.vector_based; name, buffer, sample_time, circular_buffer) end """ @@ -758,7 +798,7 @@ such as `LinearInterpolation`, `ConstantInterpolation` or `CubicSpline`. """ function Interpolation(interp_type, u, x, args...; name) itp = interp_type(u, x, args...) - Interpolation(; itp, name) + return Interpolation(; itp, name) end @deprecate Interpolation(itp; name) Interpolation(; itp, name) @@ -770,8 +810,9 @@ function Interpolation(; itp, name) eqs = [output.u ~ interpolator(input.u)] - System( - eqs, t, [], [interpolator]; name, systems = [input, output]) + return System( + eqs, t, [], [interpolator]; name, systems = [input, output] + ) end """ @@ -801,7 +842,7 @@ struct CachedInterpolation{T, I, U, X, C} X = typeof(prev_x) C = typeof(cache) - new{T, I, U, X, C}(interpolation_type, prev_u, prev_x, cache) + return new{T, I, U, X, C}(interpolation_type, prev_u, prev_x, cache) end end @@ -812,7 +853,8 @@ function (f::CachedInterpolation{T})(u, x, args) where {T} get_tmp(prev_u, u) .= u get_tmp(prev_x, x) .= x cache.bufs[(u, x)] = interpolation_type( - get_tmp(prev_u, u), get_tmp(prev_x, x), args...) + get_tmp(prev_u, u), get_tmp(prev_x, x), args... + ) else cache[(u, x)] end @@ -852,12 +894,13 @@ such as `LinearInterpolation`, `ConstantInterpolation` or `CubicSpline`. """ function ParametrizedInterpolation( interp_type::T, u::AbstractVector, x::AbstractVector, args...; - name) where {T} + name + ) where {T} build_interpolation = CachedInterpolation(interp_type, u, x, args) @parameters data[1:length(x)] = u @parameters ts[1:length(x)] = x - @parameters interpolation_type::T=interp_type [tunable = false] + @parameters interpolation_type::T = interp_type [tunable = false] @parameters (interpolator::interp_type)(..)::eltype(u) @named input = RealInput() @@ -865,15 +908,17 @@ function ParametrizedInterpolation( eqs = [output.u ~ interpolator(input.u)] - System(eqs, ModelingToolkitBase.t_nounits, [], + return System( + eqs, ModelingToolkitBase.t_nounits, [], [data, ts, interpolation_type, interpolator]; bindings = [ - interpolator => build_interpolation(data, ts, args) + interpolator => build_interpolation(data, ts, args), ], systems = [input, output], - name) + name + ) end function ParametrizedInterpolation(; interp_type, u::AbstractVector, x::AbstractVector, name) - ParametrizedInterpolation(interp_type, u, x; name) + return ParametrizedInterpolation(interp_type, u, x; name) end diff --git a/src/Blocks/utils.jl b/src/Blocks/utils.jl index 07e643690..872e685b6 100644 --- a/src/Blocks/utils.jl +++ b/src/Blocks/utils.jl @@ -1,19 +1,21 @@ @connector function RealInput(; - name, nin = 1, u_start = nothing, guess = nin > 1 ? zeros(nin) : 0.0) + name, nin = 1, u_start = nothing, guess = nin > 1 ? zeros(nin) : 0.0 + ) if u_start !== nothing Base.depwarn( - "The keyword argument `u_start` is deprecated. Use `guess` instead.", :u_start) + "The keyword argument `u_start` is deprecated. Use `guess` instead.", :u_start + ) guess = u_start end if nin == 1 @variables u(t) [ input = true, - description = "Inner variable in RealInput $name" + description = "Inner variable in RealInput $name", ] else @variables u(t)[1:nin] [ input = true, - description = "Inner variable in RealInput $name" + description = "Inner variable in RealInput $name", ] end System(Equation[], t, [u;], []; name = name, guesses = [u => guess]) @@ -33,12 +35,13 @@ Connector with one input signal of type Real. @connector function RealInputArray(; name, nin, u_start = nothing, guess = zeros(nin)) if u_start !== nothing Base.depwarn( - "The keyword argument `u_start` is deprecated. Use `guess` instead.", :u_start) + "The keyword argument `u_start` is deprecated. Use `guess` instead.", :u_start + ) guess = u_start end @variables u(t)[1:nin] [ input = true, - description = "Inner variable in RealInputArray $name" + description = "Inner variable in RealInputArray $name", ] System(Equation[], t, [u], []; name = name, guesses = [u => guess]) end @@ -56,21 +59,23 @@ Connector with an array of input signals of type Real. """ RealInputArray @connector function RealOutput(; - name, nout = 1, u_start = nothing, guess = nout > 1 ? zeros(nout) : 0.0) + name, nout = 1, u_start = nothing, guess = nout > 1 ? zeros(nout) : 0.0 + ) if u_start !== nothing Base.depwarn( - "The keyword argument `u_start` is deprecated. Use `guess` instead.", :u_start) + "The keyword argument `u_start` is deprecated. Use `guess` instead.", :u_start + ) guess = u_start end if nout == 1 @variables u(t) [ output = true, - description = "Inner variable in RealOutput $name" + description = "Inner variable in RealOutput $name", ] else @variables u(t)[1:nout] [ output = true, - description = "Inner variable in RealOutput $name" + description = "Inner variable in RealOutput $name", ] end System(Equation[], t, [u;], []; name = name, guesses = [u => guess]) @@ -90,12 +95,13 @@ Connector with one output signal of type Real. @connector function RealOutputArray(; name, nout, u_start = nothing, guess = zeros(nout)) if u_start !== nothing Base.depwarn( - "The keyword argument `u_start` is deprecated. Use `guess` instead.", :u_start) + "The keyword argument `u_start` is deprecated. Use `guess` instead.", :u_start + ) guess = u_start end @variables u(t)[1:nout] [ output = true, - description = "Inner variable in RealOutputArray $name" + description = "Inner variable in RealOutputArray $name", ] System(Equation[], t, [u], []; name = name, guesses = [u => guess]) end @@ -140,7 +146,7 @@ Single input single output (SISO) continuous system block. equations = Equation[ u ~ input.u, - y ~ output.u + y ~ output.u, ] return System(equations, t, vars, pars; name, systems) @@ -158,15 +164,19 @@ Base class for a multiple input multiple output (MIMO) continuous system block. - `u_start`: Initial value for the input - `y_start`: Initial value for the output """ -@component function MIMO(; name, nin = 1, nout = 1, u_start = zeros(nin), - y_start = zeros(nout)) +@component function MIMO(; + name, nin = 1, nout = 1, u_start = zeros(nin), + y_start = zeros(nout) + ) @named input = RealInput(nin = nin, guess = u_start) @named output = RealOutput(nout = nout, guess = y_start) - @variables(u(t)[1:nin]=u_start, [description="Input of MIMO system $name"], - y(t)[1:nout]=y_start, [description="Output of MIMO system $name"],) + @variables( + u(t)[1:nin] = u_start, [description = "Input of MIMO system $name"], + y(t)[1:nout] = y_start, [description = "Output of MIMO system $name"], + ) eqs = [ [u[i] ~ input.u[i] for i in 1:nin]..., - [y[i] ~ output.u[i] for i in 1:nout]... + [y[i] ~ output.u[i] for i in 1:nout]..., ] return System(eqs, t, vcat(u..., y...), []; name = name, systems = [input, output]) end diff --git a/src/Electrical/Analog/ideal_components.jl b/src/Electrical/Analog/ideal_components.jl index 89a47712e..fed4501a9 100644 --- a/src/Electrical/Analog/ideal_components.jl +++ b/src/Electrical/Analog/ideal_components.jl @@ -20,7 +20,7 @@ node. end equations = Equation[ - g.v ~ 0 + g.v ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -81,11 +81,11 @@ Generic resistor with optional temperature dependency. Equation[ R_T ~ R * (1 + alpha * (heat_port.T - T_ref)), heat_port.Q_flow ~ -v * i, - v ~ i * R_T + v ~ i * R_T, ] else Equation[ - v ~ i * R + v ~ i * R, ] end @@ -126,7 +126,7 @@ See [OnePort](@ref) end equations = Equation[ - i ~ v * G + i ~ v * G, ] sys = System(equations, t, vars, pars; name, systems) @@ -167,7 +167,7 @@ See [OnePort](@ref) end equations = Equation[ - D(v) ~ i / C + D(v) ~ i / C, ] sys = System(equations, t, vars, pars; name, systems) @@ -208,7 +208,7 @@ See [OnePort](@ref) end equations = Equation[ - D(i) ~ 1 / L * v + D(i) ~ 1 / L * v, ] sys = System(equations, t, vars, pars; name, systems) @@ -248,7 +248,7 @@ See [TwoPort](@ref) equations = Equation[ v1 ~ 0, - i1 ~ 0 + i1 ~ 0, ] sys = System(equations, t, vars, pars; name, systems) @@ -283,7 +283,7 @@ See [OnePort](@ref) end equations = Equation[ - v ~ 0 + v ~ 0, ] sys = System(equations, t, vars, pars; name, systems) @@ -336,7 +336,7 @@ Electromotoric force (electric/mechanic transformer) D(phi) ~ w, k * w ~ v, flange.tau ~ -k * i, - support.tau ~ -flange.tau + support.tau ~ -flange.tau, ] sys = System(equations, t, vars, pars; name, systems) @@ -365,7 +365,7 @@ Generic diode with optional temperature dependency. - `T`: [K] Constant ambient temperature - only used if T_dep=false - `T_dep`: [bool] Temperature dependency """ -@component function Diode(; T_dep = false, Is = 1e-6, n = 1, T = 300.15, v = 0.0, name) +@component function Diode(; T_dep = false, Is = 1.0e-6, n = 1, T = 300.15, v = 0.0, name) consts = @constants begin k = 1.380649e-23 # Boltzmann constant (J/K) q = 1.602176634e-19 # Elementary charge (C) @@ -403,11 +403,11 @@ Generic diode with optional temperature dependency. Equation[ Vt ~ k * port.T / q, # Thermal voltage equation i ~ Is * (exp(v / (n * Vt)) - 1), # Shockley diode equation with temperature dependence - port.Q_flow ~ -v * i # -LossPower + port.Q_flow ~ -v * i, # -LossPower ] else Equation[ - i ~ Is * (exp(v * q / (n * k * T)) - 1) # Shockley diode equation + i ~ Is * (exp(v * q / (n * k * T)) - 1), # Shockley diode equation ] end @@ -453,7 +453,7 @@ R = R_const + pos * R_ref * (1 + alpha * (port.T - T_ref)) - `alpha`: [K⁻¹] Temperature coefficient of resistance - `enforce_bounds`: Enforce bounds for the position of the wiper (0-1) """ -@component function VariableResistor(; T_dep = false, enforce_bounds = true, R_ref = 1.0, T_ref = 300.15, R_const = 1e-3, alpha = 1e-3, name) +@component function VariableResistor(; T_dep = false, enforce_bounds = true, R_ref = 1.0, T_ref = 300.15, R_const = 1.0e-3, alpha = 1.0e-3, name) @named oneport = OnePort() @unpack v, i = oneport @@ -491,11 +491,11 @@ R = R_const + pos * R_ref * (1 + alpha * (port.T - T_ref)) conditional_eqs = if T_dep Equation[ port.Q_flow ~ -v * i, # -LossPower - R ~ R_const + pos * R_ref * (1 + alpha * (port.T - T_ref)) + R ~ R_const + pos * R_ref * (1 + alpha * (port.T - T_ref)), ] else Equation[ - R ~ R_const + pos * R_ref + R ~ R_const + pos * R_ref, ] end diff --git a/src/Electrical/Analog/mosfets.jl b/src/Electrical/Analog/mosfets.jl index 2310a8008..0059c9b59 100644 --- a/src/Electrical/Analog/mosfets.jl +++ b/src/Electrical/Analog/mosfets.jl @@ -24,12 +24,14 @@ Creates an N-type MOSFET transistor Based on the MOSFET models in (Sedra, A. S., Smith, K. C., Carusone, T. C., & Gaudet, V. C. (2021). Microelectronic circuits (8th ed.). Oxford University Press.) """ -@component function NMOS(; name, - use_transconductance = true, - V_GS = nothing, V_DS = nothing, V_OV = nothing, - V_tn = 0.8, R_DS = 1e7, lambda = 0.04, - mu_n = nothing, C_ox = nothing, W = nothing, L = nothing, - k_n = 20e-3) +@component function NMOS(; + name, + use_transconductance = true, + V_GS = nothing, V_DS = nothing, V_OV = nothing, + V_tn = 0.8, R_DS = 1.0e7, lambda = 0.04, + mu_n = nothing, C_ox = nothing, W = nothing, L = nothing, + k_n = 20.0e-3 + ) pars = @parameters begin V_tn = V_tn, [description = "Threshold voltage (V)"] R_DS = R_DS, [description = "Drain to source resistance (Ω)"] @@ -66,13 +68,17 @@ Based on the MOSFET models in (Sedra, A. S., Smith, K. C., Carusone, T. C., & Ga V_GS ~ g.v - ifelse(d.v < s.v, d.v, s.v), V_OV ~ V_GS - V_tn, d.i ~ - ifelse(d.v < s.v, -1, 1) * ifelse(V_GS < V_tn, + ifelse(d.v < s.v, -1, 1) * ifelse( + V_GS < V_tn, V_DS / R_DS, - ifelse(V_DS < V_OV, + ifelse( + V_DS < V_OV, k_n * (1 + lambda * V_DS) * (V_OV - V_DS / 2) * V_DS + V_DS / R_DS, - ((k_n * V_OV^2) / 2) * (1 + lambda * V_DS) + V_DS / R_DS)), + ((k_n * V_OV^2) / 2) * (1 + lambda * V_DS) + V_DS / R_DS + ) + ), g.i ~ 0, - s.i ~ -d.i + s.i ~ -d.i, ] return System(equations, t, vars, pars; name, systems) @@ -104,12 +110,14 @@ Creates an N-type MOSFET transistor Based on the MOSFET models in (Sedra, A. S., Smith, K. C., Carusone, T. C., & Gaudet, V. C. (2021). Microelectronic circuits (8th ed.). Oxford University Press.) """ -@component function PMOS(; name, - use_transconductance = true, - V_GS = nothing, V_DS = nothing, - V_tp = -1.5, R_DS = 1e7, lambda = 1 / 25, - mu_p = nothing, C_ox = nothing, W = nothing, L = nothing, - k_p = 20e-3) +@component function PMOS(; + name, + use_transconductance = true, + V_GS = nothing, V_DS = nothing, + V_tp = -1.5, R_DS = 1.0e7, lambda = 1 / 25, + mu_p = nothing, C_ox = nothing, W = nothing, L = nothing, + k_p = 20.0e-3 + ) pars = @parameters begin V_tp = V_tp, [description = "Threshold voltage (V)"] R_DS = R_DS, [description = "Drain-source resistance (Ω)"] @@ -144,14 +152,18 @@ Based on the MOSFET models in (Sedra, A. S., Smith, K. C., Carusone, T. C., & Ga V_DS ~ ifelse(d.v > s.v, s.v - d.v, d.v - s.v), V_GS ~ g.v - ifelse(d.v > s.v, d.v, s.v), d.i ~ - -ifelse(d.v > s.v, -1.0, 1.0) * ifelse(V_GS > V_tp, + -ifelse(d.v > s.v, -1.0, 1.0) * ifelse( + V_GS > V_tp, V_DS / R_DS, - ifelse(V_DS > (V_GS - V_tp), + ifelse( + V_DS > (V_GS - V_tp), k_p * (1 + lambda * V_DS) * ((V_GS - V_tp) - V_DS / 2) * V_DS + - V_DS / R_DS, - ((k_p * (V_GS - V_tp)^2) / 2) * (1 + lambda * V_DS) + V_DS / R_DS)), + V_DS / R_DS, + ((k_p * (V_GS - V_tp)^2) / 2) * (1 + lambda * V_DS) + V_DS / R_DS + ) + ), g.i ~ 0, - s.i ~ -d.i + s.i ~ -d.i, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Electrical/Analog/sensors.jl b/src/Electrical/Analog/sensors.jl index 4d1d34a22..837bb4905 100644 --- a/src/Electrical/Analog/sensors.jl +++ b/src/Electrical/Analog/sensors.jl @@ -29,7 +29,7 @@ an ideal ammeter. equations = Equation[ p.v ~ n.v, i ~ p.i, - i ~ -n.i + i ~ -n.i, ] return System(equations, t, vars, pars; name, systems) @@ -62,7 +62,7 @@ Creates a circuit component which measures the potential at a pin. equations = Equation[ p.i ~ 0, - phi ~ p.v + phi ~ p.v, ] return System(equations, t, vars, pars; name, systems) @@ -98,7 +98,7 @@ Creates a circuit component that measures the voltage across it. Analogous to an equations = Equation[ p.i ~ 0, n.i ~ 0, - v ~ p.v - n.v + v ~ p.v - n.v, ] return System(equations, t, vars, pars; name, systems) @@ -145,7 +145,7 @@ consumed by a circuit. connect(voltage_sensor.n, nv), connect(current_sensor.p, pc), connect(current_sensor.n, nc), - power ~ current_sensor.i * voltage_sensor.v + power ~ current_sensor.i * voltage_sensor.v, ] return System(equations, t, vars, pars; name, systems) @@ -192,7 +192,7 @@ Combines a [`VoltageSensor`](@ref) and a [`CurrentSensor`](@ref). connect(current_sensor.p, pc), connect(current_sensor.n, nc), i ~ current_sensor.i, - v ~ voltage_sensor.v + v ~ voltage_sensor.v, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Electrical/Analog/sources.jl b/src/Electrical/Analog/sources.jl index a742e0c76..9ad12be25 100644 --- a/src/Electrical/Analog/sources.jl +++ b/src/Electrical/Analog/sources.jl @@ -28,7 +28,7 @@ See [OnePort](@ref) end equations = Equation[ - v ~ V.u + v ~ V.u, ] sys = System(equations, t, vars, pars; name, systems) @@ -65,7 +65,7 @@ See [OnePort](@ref) end equations = Equation[ - i ~ I.u + i ~ I.u, ] sys = System(equations, t, vars, pars; name, systems) diff --git a/src/Electrical/Analog/transistors.jl b/src/Electrical/Analog/transistors.jl index 60e214a8e..db1d4fd22 100644 --- a/src/Electrical/Analog/transistors.jl +++ b/src/Electrical/Analog/transistors.jl @@ -42,21 +42,23 @@ Early voltage effect. - `NF`: Forward emission coefficient - `NR`: Reverse emission coefficient """ -@component function NPN(; name, - use_substrate = false, - use_Early = true, - use_advanced_continuation = false, - V_BE = nothing, V_BC = nothing, ICC = nothing, IEC = nothing, - C_jC = nothing, C_jE = nothing, C_DC = nothing, C_DE = nothing, - I_sub = nothing, V_sub = nothing, V_CS = nothing, - B_F = 50.0, B_R = 0.1, Is = 1e-16, V_T = 0.026, - V_A = 0.02, phi_C = 0.8, phi_E = 0.6, - Z_C = 0.1, Z_E = 0.1, - Tau_f = 0.12e-9, Tau_r = 5e-9, - C_jC0 = 0.5e-12, C_jE0 = 0.4e-12, - C_CS = 1e-12, - gamma_C = 0.5, gamma_E = 1.0/3.0, - NF = 1.0, NR = 1.0) +@component function NPN(; + name, + use_substrate = false, + use_Early = true, + use_advanced_continuation = false, + V_BE = nothing, V_BC = nothing, ICC = nothing, IEC = nothing, + C_jC = nothing, C_jE = nothing, C_DC = nothing, C_DE = nothing, + I_sub = nothing, V_sub = nothing, V_CS = nothing, + B_F = 50.0, B_R = 0.1, Is = 1.0e-16, V_T = 0.026, + V_A = 0.02, phi_C = 0.8, phi_E = 0.6, + Z_C = 0.1, Z_E = 0.1, + Tau_f = 0.12e-9, Tau_r = 5.0e-9, + C_jC0 = 0.5e-12, C_jE0 = 0.4e-12, + C_CS = 1.0e-12, + gamma_C = 0.5, gamma_E = 1.0 / 3.0, + NF = 1.0, NR = 1.0 + ) pars = @parameters begin B_F = B_F, [description = "Forward beta"] @@ -113,30 +115,46 @@ Early voltage effect. V_BE ~ b.v - e.v, V_BC ~ b.v - c.v, ICC ~ Is * (exp(V_BE / V_T) - 1), - IEC ~ Is * (exp(V_BC / V_T) - 1) + IEC ~ Is * (exp(V_BC / V_T) - 1), ] if !use_advanced_continuation - push!(equations, C_jC ~ ifelse(V_BC / phi_C > 0.0, 1 + gamma_C * V_BC / phi_C, - (C_jC0) / (1 - V_BC / phi_C)^gamma_C)) - push!(equations, C_jE ~ ifelse(V_BE / phi_E > 0.0, 1 + gamma_E * V_BE / phi_E, - (C_jE0) / (1 - V_BE / phi_E)^gamma_E)) + push!( + equations, C_jC ~ ifelse( + V_BC / phi_C > 0.0, 1 + gamma_C * V_BC / phi_C, + (C_jC0) / (1 - V_BC / phi_C)^gamma_C + ) + ) + push!( + equations, C_jE ~ ifelse( + V_BE / phi_E > 0.0, 1 + gamma_E * V_BE / phi_E, + (C_jE0) / (1 - V_BE / phi_E)^gamma_E + ) + ) end if use_advanced_continuation - push!(equations, C_jC ~ ifelse(V_BC > phi_C - Z_C, - ((C_jC0 * gamma_C * (1 - ((phi_C - Z_C) / phi_C))^(-gamma_C - 1)) / phi_C) * - V_BC - - ((C_jC0 * gamma_C * (1 - ((phi_C - Z_C) / phi_C))^(-gamma_C - 1)) / phi_C) * - (phi_C - Z_C) + (C_jC0) / (1 - (phi_C - Z_C) / phi_C)^gamma_C, - (C_jC0) / (1 - V_BC / phi_C)^gamma_C)) - - push!(equations, C_jE ~ ifelse(V_BE > phi_E - Z_E, - ((C_jE0 * gamma_E * (1 - ((phi_E - Z_E) / phi_E))^(-gamma_E - 1)) / phi_E) * - V_BE - - ((C_jE0 * gamma_E * (1 - ((phi_E - Z_E) / phi_E))^(-gamma_E - 1)) / phi_E) * - (phi_E - Z_E) + (C_jE0) / (1 - (phi_E - Z_E) / phi_E)^gamma_E, - (C_jE0) / (1 - V_BE / phi_E)^gamma_E)) + push!( + equations, C_jC ~ ifelse( + V_BC > phi_C - Z_C, + ((C_jC0 * gamma_C * (1 - ((phi_C - Z_C) / phi_C))^(-gamma_C - 1)) / phi_C) * + V_BC - + ((C_jC0 * gamma_C * (1 - ((phi_C - Z_C) / phi_C))^(-gamma_C - 1)) / phi_C) * + (phi_C - Z_C) + (C_jC0) / (1 - (phi_C - Z_C) / phi_C)^gamma_C, + (C_jC0) / (1 - V_BC / phi_C)^gamma_C + ) + ) + + push!( + equations, C_jE ~ ifelse( + V_BE > phi_E - Z_E, + ((C_jE0 * gamma_E * (1 - ((phi_E - Z_E) / phi_E))^(-gamma_E - 1)) / phi_E) * + V_BE - + ((C_jE0 * gamma_E * (1 - ((phi_E - Z_E) / phi_E))^(-gamma_E - 1)) / phi_E) * + (phi_E - Z_E) + (C_jE0) / (1 - (phi_E - Z_E) / phi_E)^gamma_E, + (C_jE0) / (1 - V_BE / phi_E)^gamma_E + ) + ) end push!(equations, C_DE ~ Tau_f * (Is / (NF * V_T)) * exp(V_BE / (NF * V_T))) @@ -205,21 +223,23 @@ Early voltage effect. - `NF`: Forward emission coefficient - `NR`: Reverse emission coefficient """ -@component function PNP(; name, - use_substrate = false, - use_Early = true, - use_advanced_continuation = false, - V_EB = nothing, V_CB = nothing, ICC = nothing, IEC = nothing, - C_jC = nothing, C_jE = nothing, C_DC = nothing, C_DE = nothing, - I_sub = nothing, V_sub = nothing, V_CS = nothing, - B_F = 50.0, B_R = 0.1, Is = 1e-16, V_T = 0.026, - V_A = 0.02, phi_C = 0.8, phi_E = 0.6, - Z_C = 0.1, Z_E = 0.1, - Tau_f = 0.12e-9, Tau_r = 5e-9, - C_jC0 = 0.5e-12, C_jE0 = 0.4e-12, - C_CS = 1e-12, - gamma_C = 0.5, gamma_E = 1.0/3.0, - NF = 1.0, NR = 1.0) +@component function PNP(; + name, + use_substrate = false, + use_Early = true, + use_advanced_continuation = false, + V_EB = nothing, V_CB = nothing, ICC = nothing, IEC = nothing, + C_jC = nothing, C_jE = nothing, C_DC = nothing, C_DE = nothing, + I_sub = nothing, V_sub = nothing, V_CS = nothing, + B_F = 50.0, B_R = 0.1, Is = 1.0e-16, V_T = 0.026, + V_A = 0.02, phi_C = 0.8, phi_E = 0.6, + Z_C = 0.1, Z_E = 0.1, + Tau_f = 0.12e-9, Tau_r = 5.0e-9, + C_jC0 = 0.5e-12, C_jE0 = 0.4e-12, + C_CS = 1.0e-12, + gamma_C = 0.5, gamma_E = 1.0 / 3.0, + NF = 1.0, NR = 1.0 + ) pars = @parameters begin B_F = B_F, [description = "Forward beta"] @@ -276,30 +296,46 @@ Early voltage effect. V_EB ~ e.v - b.v, V_CB ~ c.v - b.v, ICC ~ Is * (exp(V_EB / V_T) - 1), - IEC ~ Is * (exp(V_CB / V_T) - 1) + IEC ~ Is * (exp(V_CB / V_T) - 1), ] if !use_advanced_continuation - push!(equations, C_jC ~ ifelse(V_CB / phi_C > 0.0, 1 + gamma_C * V_CB / phi_C, - (C_jC0) / (1 - V_CB / phi_C)^gamma_C)) - push!(equations, C_jE ~ ifelse(V_EB / phi_E > 0.0, 1 + gamma_E * V_EB / phi_E, - (C_jE0) / (1 - V_EB / phi_E)^gamma_E)) + push!( + equations, C_jC ~ ifelse( + V_CB / phi_C > 0.0, 1 + gamma_C * V_CB / phi_C, + (C_jC0) / (1 - V_CB / phi_C)^gamma_C + ) + ) + push!( + equations, C_jE ~ ifelse( + V_EB / phi_E > 0.0, 1 + gamma_E * V_EB / phi_E, + (C_jE0) / (1 - V_EB / phi_E)^gamma_E + ) + ) end if use_advanced_continuation - push!(equations, C_jC ~ ifelse(V_CB > phi_C - Z_C, - ((C_jC0 * gamma_C * (1 - ((phi_C - Z_C) / phi_C))^(-gamma_C - 1)) / phi_C) * - V_CB - - ((C_jC0 * gamma_C * (1 - ((phi_C - Z_C) / phi_C))^(-gamma_C - 1)) / phi_C) * - (phi_C - Z_C) + (C_jC0) / (1 - (phi_C - Z_C) / phi_C)^gamma_C, - (C_jC0) / (1 - V_CB / phi_C)^gamma_C)) - - push!(equations, C_jE ~ ifelse(V_EB > phi_E - Z_E, - ((C_jE0 * gamma_E * (1 - ((phi_E - Z_E) / phi_E))^(-gamma_E - 1)) / phi_E) * - V_EB - - ((C_jE0 * gamma_E * (1 - ((phi_E - Z_E) / phi_E))^(-gamma_E - 1)) / phi_E) * - (phi_E - Z_E) + (C_jE0) / (1 - (phi_E - Z_E) / phi_E)^gamma_E, - (C_jE0) / (1 - V_EB / phi_E)^gamma_E)) + push!( + equations, C_jC ~ ifelse( + V_CB > phi_C - Z_C, + ((C_jC0 * gamma_C * (1 - ((phi_C - Z_C) / phi_C))^(-gamma_C - 1)) / phi_C) * + V_CB - + ((C_jC0 * gamma_C * (1 - ((phi_C - Z_C) / phi_C))^(-gamma_C - 1)) / phi_C) * + (phi_C - Z_C) + (C_jC0) / (1 - (phi_C - Z_C) / phi_C)^gamma_C, + (C_jC0) / (1 - V_CB / phi_C)^gamma_C + ) + ) + + push!( + equations, C_jE ~ ifelse( + V_EB > phi_E - Z_E, + ((C_jE0 * gamma_E * (1 - ((phi_E - Z_E) / phi_E))^(-gamma_E - 1)) / phi_E) * + V_EB - + ((C_jE0 * gamma_E * (1 - ((phi_E - Z_E) / phi_E))^(-gamma_E - 1)) / phi_E) * + (phi_E - Z_E) + (C_jE0) / (1 - (phi_E - Z_E) / phi_E)^gamma_E, + (C_jE0) / (1 - V_EB / phi_E)^gamma_E + ) + ) end push!(equations, C_DE ~ Tau_f * (Is / (NF * V_T)) * exp(V_EB / (NF * V_T))) diff --git a/src/Electrical/Digital/components.jl b/src/Electrical/Digital/components.jl index 023a0d0c9..80f0c4e09 100644 --- a/src/Electrical/Digital/components.jl +++ b/src/Electrical/Digital/components.jl @@ -29,10 +29,12 @@ Takes two bits as input, and outputs the sum and the carry @named y2 = DigitalPin() @variables sum(t), carry(t) - eqs = [y1.val ~ _xor(x1.val, x2.val) - y2.val ~ _and(x1.val, x2.val) - sum ~ y1.val - carry ~ y2.val] + eqs = [ + y1.val ~ _xor(x1.val, x2.val) + y2.val ~ _and(x1.val, x2.val) + sum ~ y1.val + carry ~ y2.val + ] System(eqs, t, [sum, carry], [], systems = [x1, x2, y1, y2], name = name) end @@ -67,10 +69,12 @@ Takes three bits as input, and outputs the sum and the carry @named y2 = DigitalPin() @variables sum(t), carry(t) - eqs = [y1.val ~ _xor(x1.val, x2.val, x3.val) - y2.val ~ _or(_and(x3.val, _xor(x1.val, x2.val)), _and(x1.val, x2.val)) - sum ~ y1.val - carry ~ y2.val] + eqs = [ + y1.val ~ _xor(x1.val, x2.val, x3.val) + y2.val ~ _or(_and(x3.val, _xor(x1.val, x2.val)), _and(x1.val, x2.val)) + sum ~ y1.val + carry ~ y2.val + ] System(eqs, t, [sum, carry], [], systems = [x1, x2, x3, y1, y2], name = name) end diff --git a/src/Electrical/Digital/gates.jl b/src/Electrical/Digital/gates.jl index 9f5e9e6e3..396aaa34d 100644 --- a/src/Electrical/Digital/gates.jl +++ b/src/Electrical/Digital/gates.jl @@ -16,9 +16,11 @@ function Not(; name) @named x = DigitalPin() @named y = DigitalPin() - eqs = [x.i ~ y.i - y.val ~ _not(x.val)] - System(eqs, t, [], [], systems = [x, y], name = name) + eqs = [ + x.i ~ y.i + y.val ~ _not(x.val) + ] + return System(eqs, t, [], [], systems = [x, y], name = name) end """ @@ -42,9 +44,11 @@ function And(; name, N = 2) @named y = DigitalPin() vals = [k.val for k in x] - eqs = [y.val ~ _and(vals...) - y.i ~ sum(k -> k.i, x)] - System(eqs, t, [], [], systems = [x..., y], name = name) + eqs = [ + y.val ~ _and(vals...) + y.i ~ sum(k -> k.i, x) + ] + return System(eqs, t, [], [], systems = [x..., y], name = name) end """ @@ -68,9 +72,11 @@ function Nand(; name, N = 2) @named y = DigitalPin() vlist = [k.val for k in x] - eqs = [y.val ~ _not(_and(vlist...)) - y.i ~ sum(k -> k.i, x)] - System(eqs, t, [], [], systems = [x..., y], name = name) + eqs = [ + y.val ~ _not(_and(vlist...)) + y.i ~ sum(k -> k.i, x) + ] + return System(eqs, t, [], [], systems = [x..., y], name = name) end """ @@ -94,9 +100,11 @@ function Or(; name, N = 2) @named y = DigitalPin() vals = [k.val for k in x] - eqs = [y.val ~ _or(vals...) - y.i ~ sum(k -> k.i, x)] - System(eqs, t, [], [], systems = [x..., y], name = name) + eqs = [ + y.val ~ _or(vals...) + y.i ~ sum(k -> k.i, x) + ] + return System(eqs, t, [], [], systems = [x..., y], name = name) end """ @@ -120,9 +128,11 @@ function Nor(; name, N = 2) @named y = DigitalPin() vlist = [k.val for k in x] - eqs = [y.val ~ _not(_or(vlist...)) - y.i ~ sum(k -> k.i, x)] - System(eqs, t, [], [], systems = [x..., y], name = name) + eqs = [ + y.val ~ _not(_or(vlist...)) + y.i ~ sum(k -> k.i, x) + ] + return System(eqs, t, [], [], systems = [x..., y], name = name) end """ @@ -146,9 +156,11 @@ function Xor(; name, N = 2) @named y = DigitalPin() vals = [k.val for k in x] - eqs = [y.val ~ _xor(vals...) - y.i ~ sum(k -> k.i, x)] - System(eqs, t, [], [], systems = [x..., y], name = name) + eqs = [ + y.val ~ _xor(vals...) + y.i ~ sum(k -> k.i, x) + ] + return System(eqs, t, [], [], systems = [x..., y], name = name) end """ @@ -172,7 +184,9 @@ function Xnor(; name, N = 2) @named y = DigitalPin() vlist = [k.val for k in x] - eqs = [y.val ~ _not(_xor(vlist...)) - y.i ~ sum(k -> k.i, x)] - System(eqs, t, [], [], systems = [x..., y], name = name) + eqs = [ + y.val ~ _not(_xor(vlist...)) + y.i ~ sum(k -> k.i, x) + ] + return System(eqs, t, [], [], systems = [x..., y], name = name) end diff --git a/src/Electrical/Digital/logic.jl b/src/Electrical/Digital/logic.jl index ed6f52ffa..9d22ce1e8 100644 --- a/src/Electrical/Digital/logic.jl +++ b/src/Electrical/Digital/logic.jl @@ -1,4 +1,4 @@ -@enum Logic Uninitialized=1 ForcingUnknown ForcingZero ForcingOne HighImpedance WeakUnknown WeakZero WeakOne DontCare +@enum Logic Uninitialized = 1 ForcingUnknown ForcingZero ForcingOne HighImpedance WeakUnknown WeakZero WeakOne DontCare const U = Uninitialized const X = ForcingUnknown @@ -11,7 +11,7 @@ const H = WeakOne const DC = DontCare function Base.show(io::IO, ::MIME"text/plain", l::Logic) - if Int(l) == 1 + return if Int(l) == 1 print(io, "U") elseif Int(l) == 2 print(io, "X") @@ -41,7 +41,7 @@ Base.one(::Type{Logic}) = F1 # Helpers to convert 1 and 0 to their `Logic` counterparts function Base.convert(l::Type{Logic}, i::Number) - if i == zero(i) + return if i == zero(i) zero(l) elseif i == one(i) one(l) diff --git a/src/Electrical/Digital/logic_vectors.jl b/src/Electrical/Digital/logic_vectors.jl index 590621cd1..138a71833 100644 --- a/src/Electrical/Digital/logic_vectors.jl +++ b/src/Electrical/Digital/logic_vectors.jl @@ -5,14 +5,14 @@ const LogicOrNumber = Union{Logic, Number} struct StdULogicVector{N} <: AbstractArray{Logic, N} logic::Array{Logic, N} function StdULogicVector(l::Array) - new{ndims(l)}(Array{Logic}(convert.(Logic, l))) + return new{ndims(l)}(Array{Logic}(convert.(Logic, l))) end end struct StdLogicVector{N} <: AbstractArray{Logic, N} logic::Array{Logic, N} function StdLogicVector(l::Array) - new{ndims(l)}(Array{Logic}(convert.(Logic, l))) + return new{ndims(l)}(Array{Logic}(convert.(Logic, l))) end end @@ -23,14 +23,16 @@ size(l::LogicVector) = size(l.logic) axes(l::LogicVector) = axes(l.logic) getindex(s::LogicVector, i::Int) = getindex(s.logic, i) -function Base.getindex(s::LogicVector, i1::Int, i2::Int, - I::Int...) - getindex(s.logic, i1, i2, I...) +function Base.getindex( + s::LogicVector, i1::Int, i2::Int, + I::Int... + ) + return getindex(s.logic, i1, i2, I...) end setindex!(A::LogicVector, x::Logic, i1::Int) = setindex!(A.logic, x, i1) function Base.setindex!(A::LogicVector, x::Logic, i1::Int, i2::Int, I::Int...) - setindex!(A.logic, x, i1, i2, I...) + return setindex!(A.logic, x, i1, i2, I...) end get_logic_level(s::LogicVector) = Int.(s.logic) diff --git a/src/Electrical/Digital/sources.jl b/src/Electrical/Digital/sources.jl index c7be94b3a..8d83a752d 100644 --- a/src/Electrical/Digital/sources.jl +++ b/src/Electrical/Digital/sources.jl @@ -18,10 +18,12 @@ function PulseDiff(; name, Val = 1, dt = 0.1) @variables val(t) D = ModelingToolkitBase.Difference(t; dt = dt) - eqs = [D(val) ~ Val - val ~ d.val] + eqs = [ + D(val) ~ Val + val ~ d.val + ] - System(eqs, t, [val], [], systems = [d], initial_conditions = Dict(Val => 0), name = name) + return System(eqs, t, [val], [], systems = [d], initial_conditions = Dict(Val => 0), name = name) end """ @@ -40,9 +42,9 @@ function Set(; name) @named d = DigitalPin() eqs = [ - d.val ~ 1 + d.val ~ 1, ] - System(eqs, t, [], [], systems = [d], name = name) + return System(eqs, t, [], [], systems = [d], name = name) end """ @@ -61,9 +63,9 @@ function Reset(; name) @named d = DigitalPin() eqs = [ - d.val ~ 0 + d.val ~ 0, ] - System(eqs, t, [], [], systems = [d], name = name) + return System(eqs, t, [], [], systems = [d], name = name) end """ @@ -82,7 +84,7 @@ function Pulse(; name, duty_cycle = 0.5, T = 1.0) @named d = DigitalPin() eqs = [ - d.val ~ IfElse.ifelse(t % T > duty_cycle * T, 1, 0) + d.val ~ IfElse.ifelse(t % T > duty_cycle * T, 1, 0), ] - System(eqs, t, [], [], systems = [d], name = name) + return System(eqs, t, [], [], systems = [d], name = name) end diff --git a/src/Electrical/Digital/tables.jl b/src/Electrical/Digital/tables.jl index beb171730..ba7c79306 100644 --- a/src/Electrical/Digital/tables.jl +++ b/src/Electrical/Digital/tables.jl @@ -4,7 +4,7 @@ struct LogicTable{N} <: AbstractArray{Logic, N} any(i -> i != 9, size(l)) && throw(ArgumentError("Incorrect number of logic values are passed. A variable of type `LogicTable` must have nine entries corresponding to 9 logic levels")) - new{ndims(l)}(l) + return new{ndims(l)}(l) end end @@ -14,42 +14,47 @@ Base.axes(l::LogicTable) = axes(l.logic) getindex(s::LogicTable, l::Logic) = getindex(s.logic, get_logic_level(l)) function Base.getindex(s::LogicTable, i1::Logic, i2::Logic) - getindex(s.logic, get_logic_level(i1), get_logic_level(i2)) + return getindex(s.logic, get_logic_level(i1), get_logic_level(i2)) end -function Base.getindex(s::LogicTable, i1::Logic, i2::Logic, - I::Logic...) - getindex(s.logic, get_logic_level(i1), get_logic_level(i2), get_logic_level(I...)...) +function Base.getindex( + s::LogicTable, i1::Logic, i2::Logic, + I::Logic... + ) + return getindex(s.logic, get_logic_level(i1), get_logic_level(i2), get_logic_level(I...)...) end getindex(s::LogicTable, l::Int) = getindex(s.logic, l) function getindex(s::LogicTable, i1::Int, i2::Int, I::Int...) - getindex(s.logic, i1, i2, I...) + return getindex(s.logic, i1, i2, I...) end function Base.setindex!(A::LogicTable, x::Logic, i1::Int) - setindex!(A.logic, x, i1) + return setindex!(A.logic, x, i1) end function Base.setindex!(A::LogicTable, x::Logic, i1::Int, i2::Int, I::Int...) - setindex!(A.logic, x, i1, i2, I...) + return setindex!(A.logic, x, i1, i2, I...) end get_logic_level(l::LogicTable) = Int.(l.logic) # AND gate -const AndTable = LogicTable([ - # U X F0 F1 Z W L H DC - U U F0 U U U F0 U U # U - U X F0 X X X F0 X X # X - F0 F0 F0 F0 F0 F0 F0 F0 F0 # F0 - U X F0 F1 X X F0 F1 X # F1 - U X F0 X X X F0 X X # Z - U X F0 X X X F0 X X # W - F0 F0 F0 F0 F0 F0 F0 F0 F0 # L - U X F0 F1 X X F0 F1 X # H - U X F0 X X X F0 X X]) # DC +const AndTable = LogicTable( + [ + # U X F0 F1 Z W L H DC + U U F0 U U U F0 U U # U + U X F0 X X X F0 X X # X + F0 F0 F0 F0 F0 F0 F0 F0 F0 # F0 + U X F0 F1 X X F0 F1 X # F1 + U X F0 X X X F0 X X # Z + U X F0 X X X F0 X X # W + F0 F0 F0 F0 F0 F0 F0 F0 F0 # L + U X F0 F1 X X F0 F1 X # H + U X F0 X X X F0 X X + ] +) # DC function _and2(a::Logic, b::Logic) - AndTable[a, b] + return AndTable[a, b] end _and2(a::Number, b::Logic) = _and2(convert(Logic, a), b) _and2(a::Logic, b::Number) = _and2(a, convert(Logic, b)) @@ -74,20 +79,23 @@ _not(x::Number) = _not(convert(Logic, x)) @register_symbolic _not(x) # OR gate -const OrTable = LogicTable([ - # U X F0 F1 Z W L H DC - U U U F1 U U U F1 U # U - U X X F1 X X X F1 X # X - U X F0 F1 X X F0 F1 X # F0 - F1 F1 F1 F1 F1 F1 F1 F1 F1 # F1 - U X X F1 X X X F1 X # Z - U X X F1 X X X F1 X # W - U X F0 F1 X X F0 F1 X # L - F1 F1 F1 F1 F1 F1 F1 F1 F1 # H - U X X F1 X X X F1 X]) # DC +const OrTable = LogicTable( + [ + # U X F0 F1 Z W L H DC + U U U F1 U U U F1 U # U + U X X F1 X X X F1 X # X + U X F0 F1 X X F0 F1 X # F0 + F1 F1 F1 F1 F1 F1 F1 F1 F1 # F1 + U X X F1 X X X F1 X # Z + U X X F1 X X X F1 X # W + U X F0 F1 X X F0 F1 X # L + F1 F1 F1 F1 F1 F1 F1 F1 F1 # H + U X X F1 X X X F1 X + ] +) # DC function _or2(a::Logic, b::Logic) - OrTable[a, b] + return OrTable[a, b] end _or2(a::Number, b::Logic) = _or2(convert(Logic, a), b) _or2(a::Logic, b::Number) = _or2(a, convert(Logic, b)) @@ -104,20 +112,23 @@ end @register_symbolic _or(a, b) # XOR gate -const XorTable = LogicTable([ - # U X F0 F1 Z W L H DC - U U U U U U U U U # U - U X X X X X X X X # X - U X F0 F1 X X F0 F1 X # F0 - U X F1 F0 X X F1 F0 X # F1 - U X X X X X X X X # Z - U X X X X X X X X # W - U X F0 F1 X X F0 F1 X # L - U X F1 F0 X X F1 F0 X # H - U X X X X X X X X]) # DC +const XorTable = LogicTable( + [ + # U X F0 F1 Z W L H DC + U U U U U U U U U # U + U X X X X X X X X # X + U X F0 F1 X X F0 F1 X # F0 + U X F1 F0 X X F1 F0 X # F1 + U X X X X X X X X # Z + U X X X X X X X X # W + U X F0 F1 X X F0 F1 X # L + U X F1 F0 X X F1 F0 X # H + U X X X X X X X X + ] +) # DC function _xor2(a::Logic, b::Logic) - XorTable[a, b] + return XorTable[a, b] end _xor2(a::Number, b::Logic) = _xor2(convert(Logic, a), b) _xor2(a::Logic, b::Number) = _xor2(a, convert(Logic, b)) diff --git a/src/Electrical/Electrical.jl b/src/Electrical/Electrical.jl index 9330653f7..5f0b4d332 100644 --- a/src/Electrical/Electrical.jl +++ b/src/Electrical/Electrical.jl @@ -14,8 +14,8 @@ export Pin, OnePort include("utils.jl") export Capacitor, - Ground, Inductor, Resistor, Conductor, Short, IdealOpAmp, EMF, - Diode, VariableResistor + Ground, Inductor, Resistor, Conductor, Short, IdealOpAmp, EMF, + Diode, VariableResistor include("Analog/ideal_components.jl") export CurrentSensor, PotentialSensor, VoltageSensor, PowerSensor, MultiSensor @@ -42,12 +42,12 @@ export Logic include("Digital/logic.jl") export StdLogicVector, StdULogicVector, - std_ulogic, UX01, UX01Z, X01, X01Z, - get_logic_level + std_ulogic, UX01, UX01Z, X01, X01Z, + get_logic_level include("Digital/logic_vectors.jl") export LogicTable, - AndTable, OrTable, NotTable, XorTable + AndTable, OrTable, NotTable, XorTable include("Digital/tables.jl") end diff --git a/src/Electrical/utils.jl b/src/Electrical/utils.jl index a24f35ac8..df6d434fe 100644 --- a/src/Electrical/utils.jl +++ b/src/Electrical/utils.jl @@ -47,7 +47,7 @@ Component with two electrical pins `p` and `n` and current `i` flows from `p` to equations = Equation[ v ~ p.v - n.v, 0 ~ p.i + n.i, - i ~ p.i + i ~ p.i, ] return System(equations, t, vars, pars; name, systems) @@ -96,7 +96,7 @@ Current `i1` flows from `p1` to `n1` and `i2` from `p2` to `n2`. i1 ~ p1.i, v2 ~ p2.v - n2.v, 0 ~ p2.i + n2.i, - i2 ~ p2.i + i2 ~ p2.i, ] return System(equations, t, vars, pars; name, systems) @@ -105,11 +105,15 @@ end @connector function DigitalPin(; name) @variables val(t) v(t) i(t) eqs = [ - val ~ IfElse.ifelse((0.0 <= v) & (v <= 0.8) | (2.0 <= v) & (v <= 5.0), - IfElse.ifelse(v > 2.0, 1, 0), X) + val ~ IfElse.ifelse( + (0.0 <= v) & (v <= 0.8) | (2.0 <= v) & (v <= 5.0), + IfElse.ifelse(v > 2.0, 1, 0), X + ), ] - System(Equation[], t, [val, v, i], [], guesses = Dict(val => 0, i => 0), - name = name) + System( + Equation[], t, [val, v, i], [], guesses = Dict(val => 0, i => 0), + name = name + ) end @doc """ DigitalPin(; name) diff --git a/src/Hydraulic/IsothermalCompressible/IsothermalCompressible.jl b/src/Hydraulic/IsothermalCompressible/IsothermalCompressible.jl index fc114b7b8..5865fac1a 100644 --- a/src/Hydraulic/IsothermalCompressible/IsothermalCompressible.jl +++ b/src/Hydraulic/IsothermalCompressible/IsothermalCompressible.jl @@ -15,7 +15,7 @@ export HydraulicPort, HydraulicFluid include("utils.jl") export Cap, Tube, FixedVolume, DynamicVolume, Open, FlowDivider, Valve, Volume, SpoolValve, - SpoolValve2Way, Actuator + SpoolValve2Way, Actuator include("components.jl") export MassFlow, Pressure, FixedPressure diff --git a/src/Hydraulic/IsothermalCompressible/components.jl b/src/Hydraulic/IsothermalCompressible/components.jl index 4964afbf3..51092447c 100644 --- a/src/Hydraulic/IsothermalCompressible/components.jl +++ b/src/Hydraulic/IsothermalCompressible/components.jl @@ -1,4 +1,3 @@ - """ Cap(; name) @@ -20,7 +19,7 @@ Caps a hydraulic port to prevent mass flow in or out. equations = Equation[ port.p ~ p, - port.dm ~ 0 + port.dm ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -48,7 +47,7 @@ Provides an "open" boundary condition for a hydraulic port such that mass flow ` equations = Equation[ port.p ~ p, - port.dm ~ dm + port.dm ~ dm, ] return System(equations, t, vars, pars; name, systems) @@ -74,13 +73,15 @@ Variable length internal flow model of the fully developed incompressible flow f - `port_a`: hydraulic port - `port_b`: hydraulic port """ -@component function TubeBase(add_inertia = true, variable_length = true; +@component function TubeBase( + add_inertia = true, variable_length = true; area = nothing, length_int = nothing, head_factor = 1, perimeter = 2 * sqrt(area * pi), shape_factor = 64, - name) + name + ) pars = @parameters begin area = area length_int = length_int @@ -128,8 +129,10 @@ Variable length internal flow model of the fully developed incompressible flow f 0 end - eqs = [0 ~ port_a.dm + port_b.dm - domain_connect(port_a, port_b)] + eqs = [ + 0 ~ port_a.dm + port_b.dm + domain_connect(port_a, port_b) + ] if variable_length push!(eqs, Δp ~ ifelse(c > 0, shear + inertia, zero(c))) @@ -161,11 +164,15 @@ Constant length internal flow model discretized by `N` (`FixedVolume`: `N`, `Tub - `port_a`: hydraulic port - `port_b`: hydraulic port """ -@component function Tube(N, add_inertia = true; area = nothing, length = nothing, head_factor = 1, +@component function Tube( + N, add_inertia = true; area = nothing, length = nothing, head_factor = 1, perimeter = 2 * sqrt(area * pi), - shape_factor = 64, p_int = nothing, name) - @assert(N>0, - "the Tube component must be defined with at least 1 segment (i.e. N>0), found N=$N") + shape_factor = 64, p_int = nothing, name + ) + @assert( + N > 0, + "the Tube component must be defined with at least 1 segment (i.e. N>0), found N=$N" + ) #TODO: How to set an assert effective_length >= length ?? pars = @parameters begin @@ -186,26 +193,34 @@ Constant length internal flow model discretized by `N` (`FixedVolume`: `N`, `Tub pipe_bases = [] for i in 1:N - x = TubeBase(add_inertia, false; name = Symbol("p$i"), + x = TubeBase( + add_inertia, false; name = Symbol("p$i"), shape_factor = ParentScope(shape_factor), area = ParentScope(area), length_int = N > 1 ? ParentScope(length) / (N - 1) : ParentScope(length), head_factor = ParentScope(head_factor), - perimeter = ParentScope(perimeter)) + perimeter = ParentScope(perimeter) + ) push!(pipe_bases, x) end - eqs = [connect(pipe_bases[1].port_a, port_a) - connect(pipe_bases[end].port_b, port_b)] + eqs = [ + connect(pipe_bases[1].port_a, port_a) + connect(pipe_bases[end].port_b, port_b) + ] volumes = [] for i in 1:(N - 1) - x = FixedVolume(; name = Symbol("v$i"), + x = FixedVolume(; + name = Symbol("v$i"), vol = ParentScope(area) * ParentScope(length) / (N - 1), - p_int = ParentScope(p_int)) + p_int = ParentScope(p_int) + ) push!(volumes, x) - push!(eqs, - connect(x.port, pipe_bases[i].port_b, pipe_bases[i + 1].port_a)) + push!( + eqs, + connect(x.port, pipe_bases[i].port_b, pipe_bases[i + 1].port_a) + ) end return System(eqs, t, vars, pars; name, systems = [ports; pipe_bases; volumes]) @@ -245,7 +260,7 @@ Reduces the flow from `port_a` to `port_b` by `n`. Useful for modeling parallel connect(port_a, port_b, open.port), dm_a ~ port_a.dm, dm_b ~ dm_a / n, - open.dm ~ dm_a - dm_b # extra flow dumps into an open port + open.dm ~ dm_a - dm_b, # extra flow dumps into an open port # port_b.dm ~ dm_b # divided flow goes to port_b ] @@ -253,7 +268,8 @@ Reduces the flow from `port_a` to `port_b` by `n`. Useful for modeling parallel end @component function ValveBase( - reversible = false; minimum_area = 0, Cd = nothing, Cd_reverse = Cd, name) + reversible = false; minimum_area = 0, Cd = nothing, Cd_reverse = Cd, name + ) pars = @parameters begin Cd = Cd Cd_reverse = Cd_reverse @@ -289,10 +305,12 @@ end ifelse(Δp > 0, Cd, Cd_reverse) end - eqs = [0 ~ port_a.dm + port_b.dm - domain_connect(port_a, port_b) - dm ~ regRoot(2 * Δp * ρ / c) * x # I think this should be reformulated as: regRoot(2 DP rho) c x - y ~ x] + eqs = [ + 0 ~ port_a.dm + port_b.dm + domain_connect(port_a, port_b) + dm ~ regRoot(2 * Δp * ρ / c) * x # I think this should be reformulated as: regRoot(2 DP rho) c x + y ~ x + ] System(eqs, t, vars, pars; name, systems) end @@ -315,10 +333,12 @@ Valve with `area` input and discharge coefficient `Cd` defined by https://en.wik - `port_b`: hydraulic port - `area`: real input setting the valve `area`. When `reversible = true`, negative input reverses flow direction, otherwise a floor of `minimum_area` is enforced. """ -@component function Valve(reversible = false; +@component function Valve( + reversible = false; Cd = nothing, Cd_reverse = Cd, minimum_area = 0, - name) + name + ) pars = @parameters begin Cd = Cd Cd_reverse = Cd_reverse @@ -329,21 +349,27 @@ Valve with `area` input and discharge coefficient `Cd` defined by https://en.wik port_a = HydraulicPort() port_b = HydraulicPort() area = RealInput() - base = ValveBase(reversible; Cd, Cd_reverse, - minimum_area) + base = ValveBase( + reversible; Cd, Cd_reverse, + minimum_area + ) end vars = [] - eqs = [connect(base.port_a, port_a) - connect(base.port_b, port_b) - base.area ~ area.u] + eqs = [ + connect(base.port_a, port_a) + connect(base.port_b, port_b) + base.area ~ area.u + ] System(eqs, t, vars, pars; name, systems) end -@component function VolumeBase(; area = nothing, dead_volume = 0, p_int = nothing, x_int = nothing, - name) +@component function VolumeBase(; + area = nothing, dead_volume = 0, p_int = nothing, x_int = nothing, + name + ) pars = @parameters begin area = area dead_volume = dead_volume @@ -366,12 +392,14 @@ end dm = port.dm p = port.p - eqs = [vol ~ dead_volume + area * x - D(x) ~ dx - D(m) ~ dm - #rho ~ full_density(port, p) - p ~ full_pressure(port, rho) # see https://github.com/SciML/OrdinaryDiffEq.jl/issues/2561 - m ~ rho * vol] + eqs = [ + vol ~ dead_volume + area * x + D(x) ~ dx + D(m) ~ dm + #rho ~ full_density(port, p) + p ~ full_pressure(port, rho) # see https://github.com/SciML/OrdinaryDiffEq.jl/issues/2561 + m ~ rho * vol + ] initialization_eqs = [p ~ p_int] @@ -397,7 +425,7 @@ Fixed fluid volume. end systems = @named begin - port = HydraulicPort(;) + port = HydraulicPort() end vars = @variables begin @@ -409,11 +437,13 @@ Fixed fluid volume. # let dm = port.dm - eqs = [D(m) ~ dm - # rho ~ full_density(port, p) - p ~ full_pressure(port, rho) # see https://github.com/SciML/OrdinaryDiffEq.jl/issues/2561 - p ~ port.p - m ~ rho * vol] + eqs = [ + D(m) ~ dm + # rho ~ full_density(port, p) + p ~ full_pressure(port, rho) # see https://github.com/SciML/OrdinaryDiffEq.jl/issues/2561 + p ~ port.p + m ~ rho * vol + ] System(eqs, t, vars, pars; name, systems) end @@ -461,7 +491,8 @@ See also [`FixedVolume`](@ref), [`DynamicVolume`](@ref) area = nothing, direction = +1, x_int = nothing, - name) + name + ) pars = @parameters begin area = area x_int = x_int @@ -480,36 +511,41 @@ See also [`FixedVolume`](@ref), [`DynamicVolume`](@ref) systems = @named begin port = HydraulicPort() flange = MechanicalPort() - damper = ValveBase(reversible; + damper = ValveBase( + reversible; Cd, Cd_reverse, - minimum_area) + minimum_area + ) end systems = @named begin port = HydraulicPort() flange = MechanicalPort() - damper = ValveBase(reversible; + damper = ValveBase( + reversible; Cd, Cd_reverse, - minimum_area) + minimum_area + ) end eqs = [ - # connectors - port.p ~ p - port.dm ~ dm - flange.v * direction ~ dx - flange.f * direction ~ -f - # differentials - D(x) ~ dx - D(m) ~ dm - - # physics - # rho ~ full_density(port, p) - p ~ full_pressure(port, rho) # see https://github.com/SciML/OrdinaryDiffEq.jl/issues/2561 - f ~ p * area - m ~ rho * x * area] + # connectors + port.p ~ p + port.dm ~ dm + flange.v * direction ~ dx + flange.f * direction ~ -f + # differentials + D(x) ~ dx + D(m) ~ dm + + # physics + # rho ~ full_density(port, p) + p ~ full_pressure(port, rho) # see https://github.com/SciML/OrdinaryDiffEq.jl/issues/2561 + f ~ p * area + m ~ rho * x * area + ] System(eqs, t, vars, pars; name, systems) end @@ -558,7 +594,8 @@ dm ────► │ │ area - `port`: hydraulic port - `flange`: mechanical translational port """ -@component function DynamicVolume(reversible = false; +@component function DynamicVolume( + reversible = false; area = nothing, x_int = 0, x_max = nothing, @@ -573,12 +610,13 @@ dm ────► │ │ area p_int = nothing, # Valve - Cd = 1e2, + Cd = 1.0e2, Cd_reverse = Cd, minimum_area = 0, # Damping - d = 0, name) + d = 0, name + ) @assert (direction == +1)||(direction == -1) "direction argument must be +/-1, found $direction" #TODO: How to set an assert effective_length >= length ?? @@ -608,17 +646,20 @@ dm ────► │ │ area end systems = @named begin - port = HydraulicPort(;) - flange = MechanicalPort(;) - damper = ValveBase(reversible; + port = HydraulicPort() + flange = MechanicalPort() + damper = ValveBase( + reversible; Cd, Cd_reverse, - minimum_area) + minimum_area + ) moving_volume = VolumeBase(; area, dead_volume = area * x_int, p_int, - x_int = 0) + x_int = 0 + ) end ratio = (x - x_min) / (x_damp - x_min) @@ -632,13 +673,15 @@ dm ────► │ │ area dx = moving_volume.dx p = moving_volume.port.p - eqs = [vol ~ x * area - D(x) ~ flange.v * direction - damper.area ~ damper_area - connect(port, damper.port_b) - connect(moving_volume.port, damper.port_a) - dx ~ flange.v * direction - p * area - dx * d ~ -flange.f * direction] + eqs = [ + vol ~ x * area + D(x) ~ flange.v * direction + damper.area ~ damper_area + connect(port, damper.port_b) + connect(moving_volume.port, damper.port_a) + dx ~ flange.v * direction + p * area - dx * d ~ -flange.f * direction + ] return System(eqs, t, vars, pars; name, systems) end @@ -668,8 +711,8 @@ See [`Valve`](@ref) for more information. end systems = @named begin - port_a = HydraulicPort(;) - port_b = HydraulicPort(;) + port_a = HydraulicPort() + port_b = HydraulicPort() flange = MechanicalPort() valve = ValveBase(reversible; Cd) end @@ -679,12 +722,14 @@ See [`Valve`](@ref) for more information. dx(t), [guess = 0] end - eqs = [D(x) ~ dx - flange.v ~ dx - flange.f ~ 0 #TODO: model flow force - connect(valve.port_a, port_a) - connect(valve.port_b, port_b) - valve.area ~ x * 2π * d] + eqs = [ + D(x) ~ dx + flange.v ~ dx + flange.f ~ 0 #TODO: model flow force + connect(valve.port_a, port_a) + connect(valve.port_b, port_b) + valve.area ~ x * 2π * d + ] System(eqs, t, vars, pars; name, systems) end @@ -729,25 +774,27 @@ See [`SpoolValve`](@ref) for more information. vSA = SpoolValve(reversible; Cd, d, x_int) vBR = SpoolValve(reversible; Cd, d, x_int) - port_s = HydraulicPort(;) - port_a = HydraulicPort(;) - port_b = HydraulicPort(;) - port_r = HydraulicPort(;) + port_s = HydraulicPort() + port_a = HydraulicPort() + port_b = HydraulicPort() + port_r = HydraulicPort() mass = Mass(; m = m, g = g) flange = MechanicalPort() end - eqs = [connect(vSA.port_a, port_s) - connect(vSA.port_b, port_a) - connect(vBR.port_a, port_b) - connect(vBR.port_b, port_r) - connect(vSA.flange, vBR.flange, mass.flange, flange)] + eqs = [ + connect(vSA.port_a, port_s) + connect(vSA.port_b, port_a) + connect(vBR.port_a, port_b) + connect(vBR.port_b, port_r) + connect(vSA.flange, vBR.flange, mass.flange, flange) + ] initialization_eqs = [ - mass.s ~ x_int - # mass.v ~ dx_int + mass.s ~ x_int, + # mass.v ~ dx_int ] System(eqs, t, vars, pars; name, systems, initialization_eqs) @@ -822,7 +869,8 @@ Actuator made of two DynamicVolumes connected in opposite direction with body ma - `port_b`: hydraulic port - `flange`: mechanical translational port """ -@component function Actuator(reversible = false; +@component function Actuator( + reversible = false; area_a = nothing, area_b = nothing, perimeter_a = 2 * sqrt(area_a * pi), @@ -841,12 +889,13 @@ Actuator made of two DynamicVolumes connected in opposite direction with body ma minimum_volume_b = 0, damping_volume_a = minimum_volume_a, damping_volume_b = minimum_volume_b, - Cd = 1e4, + Cd = 1.0e4, Cd_reverse = Cd, d = 0, p_a_int = nothing, p_b_int = nothing, - name) + name + ) pars = @parameters begin area_a = area_a area_b = area_b @@ -882,7 +931,8 @@ Actuator made of two DynamicVolumes connected in opposite direction with body ma #TODO: include effective_length systems = @named begin - vol_a = DynamicVolume(reversible; direction = +1, + vol_a = DynamicVolume( + reversible; direction = +1, area = area_a, x_int = length_a_int, x_max = total_length, @@ -894,9 +944,11 @@ Actuator made of two DynamicVolumes connected in opposite direction with body ma Cd, Cd_reverse, d, - p_int = p_a_int) + p_int = p_a_int + ) - vol_b = DynamicVolume(reversible; direction = -1, + vol_b = DynamicVolume( + reversible; direction = -1, area = area_b, x_int = length_b_int, x_max = total_length, @@ -908,21 +960,24 @@ Actuator made of two DynamicVolumes connected in opposite direction with body ma Cd, Cd_reverse, d, - p_int = p_b_int) + p_int = p_b_int + ) mass = Mass(; m, g) port_a = HydraulicPort() port_b = HydraulicPort() flange = MechanicalPort() end - eqs = [connect(vol_a.port, port_a) - connect(vol_b.port, port_b) - connect(vol_a.flange, vol_b.flange, mass.flange, flange) - D(x) ~ dx - dx ~ vol_a.flange.v] + eqs = [ + connect(vol_a.port, port_a) + connect(vol_b.port, port_b) + connect(vol_a.flange, vol_b.flange, mass.flange, flange) + D(x) ~ dx + dx ~ vol_a.flange.v + ] initialization_eqs = [ - mass.s ~ x_int + mass.s ~ x_int, ] System(eqs, t, vars, pars; name, systems, initialization_eqs) @@ -976,7 +1031,7 @@ dm ────► effective area equations = Equation[ connect(valve.area, area.output), connect(valve.port_a, port_a), - connect(valve.port_b, port_b) + connect(valve.port_b, port_b), ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Hydraulic/IsothermalCompressible/sources.jl b/src/Hydraulic/IsothermalCompressible/sources.jl index 34234193f..3bfbf0db1 100644 --- a/src/Hydraulic/IsothermalCompressible/sources.jl +++ b/src/Hydraulic/IsothermalCompressible/sources.jl @@ -20,7 +20,7 @@ Hydraulic mass flow input source end equations = Equation[ - port.dm ~ -dm.u + port.dm ~ -dm.u, ] return System(equations, t, vars, pars; name, systems) @@ -49,7 +49,7 @@ Fixed pressure source end equations = Equation[ - port.p ~ p + port.p ~ p, ] return System(equations, t, vars, pars; name, systems) @@ -77,7 +77,7 @@ input pressure source end equations = Equation[ - port.p ~ p.u + port.p ~ p.u, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Hydraulic/IsothermalCompressible/utils.jl b/src/Hydraulic/IsothermalCompressible/utils.jl index dfa87554b..539470552 100644 --- a/src/Hydraulic/IsothermalCompressible/utils.jl +++ b/src/Hydraulic/IsothermalCompressible/utils.jl @@ -1,6 +1,6 @@ # regPow(x, a, delta = 0.01) = x * (x * x + delta * delta)^((a - 1) / 2); function regPow(x, a, delta = 0.01) - ifelse(abs(x / delta) >= 1, sign(x) * abs(x / delta)^a * delta^a, (delta^a * x) / delta) + return ifelse(abs(x / delta) >= 1, sign(x) * abs(x / delta)^a * delta^a, (delta^a * x) / delta) end regRoot(x, delta = 0.01) = regPow(x, 0.5, delta) @@ -47,9 +47,11 @@ Fluid parameter setter for isothermal compressible fluid domain. Defaults given - `ρ_gas`: [kg/m^3] density of fluid in gas state at reference gage pressure `p_gas` (set by `gas_density` argument) - `p_gas`: [Pa] reference pressure (set by `gas_pressure` argument) """ -@connector function HydraulicFluid(; density = 997, bulk_modulus = 2.09e9, +@connector function HydraulicFluid(; + density = 997, bulk_modulus = 2.09e9, viscosity = 0.0010016, gas_density = 0.0073955, - gas_pressure = -1000, n = 1, let_gas = 1, name) + gas_pressure = -1000, n = 1, let_gas = 1, name + ) pars = @parameters begin ρ = density β = bulk_modulus @@ -65,7 +67,7 @@ Fluid parameter setter for isothermal compressible fluid domain. Defaults given end eqs = [ - dm ~ 0 + dm ~ 0, ] System(eqs, t, vars, pars; name) @@ -112,8 +114,10 @@ function friction_factor(dm, area, d_h, viscosity, shape_factor) if Re <= 2000 return f_laminar(shape_factor, Re) elseif 2000 < Re < 3000 - return transition(2000, 3000, f_laminar(shape_factor, Re), - f_turbulent(shape_factor, Re), Re) + return transition( + 2000, 3000, f_laminar(shape_factor, Re), + f_turbulent(shape_factor, Re), Re + ) else return f_turbulent(shape_factor, Re) end @@ -130,8 +134,8 @@ bulk_modulus(port) = port.β viscosity(port) = port.μ function liquid_density(port, p) - density_ref(port) * - regPow(1 + density_exp(port) * p / bulk_modulus(port), 1 / density_exp(port)) + return density_ref(port) * + regPow(1 + density_exp(port) * p / bulk_modulus(port), 1 / density_exp(port)) end #Tait-Murnaghan equation of state liquid_density(port) = liquid_density(port, port.p) @@ -139,7 +143,7 @@ liquid_density(port) = liquid_density(port, port.p) # (p/beta + 1)*rho_0 = rho function liquid_pressure(port, rho) - (rho / density_ref(port) - 1) * bulk_modulus(port) + return (rho / density_ref(port) - 1) * bulk_modulus(port) end function gas_density(port, p) @@ -157,16 +161,20 @@ function gas_pressure(port, rho) end function full_density(port, p) - ifelse(port.let_gas == 1, + return ifelse( + port.let_gas == 1, ifelse(p >= 0, liquid_density(port, p), gas_density(port, p)), - liquid_density(port, p)) + liquid_density(port, p) + ) end full_density(port) = full_density(port, port.p) function full_pressure(port, rho) - ifelse(port.let_gas == 1, + return ifelse( + port.let_gas == 1, ifelse( - rho >= density_ref(port), liquid_pressure(port, rho), gas_pressure(port, rho)), + rho >= density_ref(port), liquid_pressure(port, rho), gas_pressure(port, rho) + ), liquid_pressure(port, rho) ) end diff --git a/src/Magnetic/FluxTubes/FluxTubes.jl b/src/Magnetic/FluxTubes/FluxTubes.jl index e91676558..f5db15420 100644 --- a/src/Magnetic/FluxTubes/FluxTubes.jl +++ b/src/Magnetic/FluxTubes/FluxTubes.jl @@ -7,7 +7,7 @@ export PositiveMagneticPort, NegativeMagneticPort, TwoPort include("utils.jl") export Ground, Idle, Short, Crossing, ConstantPermeance, ConstantReluctance, EddyCurrent, - ElectroMagneticConverter + ElectroMagneticConverter include("basic.jl") export ConstantMagneticPotentialDifference, ConstantMagneticFlux diff --git a/src/Magnetic/FluxTubes/basic.jl b/src/Magnetic/FluxTubes/basic.jl index 8c65b46b2..3e19eed9c 100644 --- a/src/Magnetic/FluxTubes/basic.jl +++ b/src/Magnetic/FluxTubes/basic.jl @@ -15,7 +15,7 @@ Zero magnetic potential. end equations = Equation[ - port.V_m ~ 0 + port.V_m ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -40,7 +40,7 @@ Idle running branch. end equations = Equation[ - Phi ~ 0 + Phi ~ 0, ] sys = System(equations, t, vars, pars; name, systems) @@ -66,7 +66,7 @@ Short cut branch. end equations = Equation[ - V_m ~ 0 + V_m ~ 0, ] sys = System(equations, t, vars, pars; name, systems) @@ -96,7 +96,7 @@ This is a simple crossing of two branches. The ports port_p1 and port_p2 are con equations = Equation[ connect(port_p1, port_p2), - connect(port_n1, port_n2) + connect(port_n1, port_n2), ] return System(equations, t, vars, pars; name, systems) @@ -126,7 +126,7 @@ Constant permeance. end equations = Equation[ - Phi ~ G_m * V_m + Phi ~ G_m * V_m, ] sys = System(equations, t, vars, pars; name, systems) @@ -157,7 +157,7 @@ Constant reluctance. end equations = Equation[ - V_m ~ Phi * R_m + V_m ~ Phi * R_m, ] sys = System(equations, t, vars, pars; name, systems) @@ -203,7 +203,7 @@ Initial magnetic flux flowing into the port_p can be set with `Phi` ([Wb]) i ~ p.i, #converter equations: V_m ~ i * N, # Ampere's law - D(Phi) ~ -v / N + D(Phi) ~ -v / N, ] sys = System(equations, t, vars, pars; name, systems) @@ -242,7 +242,7 @@ Initial magnetic flux flowing into the port_p can be set with `Phi` ([`Wb`]) end equations = Equation[ - D(Phi) ~ V_m * R + D(Phi) ~ V_m * R, ] sys = System(equations, t, vars, pars; name, systems) diff --git a/src/Magnetic/FluxTubes/sources.jl b/src/Magnetic/FluxTubes/sources.jl index 6ca7f8b9b..d9fd57e83 100644 --- a/src/Magnetic/FluxTubes/sources.jl +++ b/src/Magnetic/FluxTubes/sources.jl @@ -24,7 +24,7 @@ Parameters: equations = Equation[ V_m ~ port_p.V_m - port_n.V_m, Phi ~ port_p.Phi, - 0 ~ port_p.Phi + port_n.Phi + 0 ~ port_p.Phi + port_n.Phi, ] return System(equations, t, vars, pars; name, systems) @@ -56,7 +56,7 @@ Parameters: equations = Equation[ V_m ~ port_p.V_m - port_n.V_m, Phi ~ port_p.Phi, - 0 ~ port_p.Phi + port_n.Phi + 0 ~ port_p.Phi + port_n.Phi, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Magnetic/FluxTubes/utils.jl b/src/Magnetic/FluxTubes/utils.jl index d1aaf22c8..920305b25 100644 --- a/src/Magnetic/FluxTubes/utils.jl +++ b/src/Magnetic/FluxTubes/utils.jl @@ -44,7 +44,7 @@ Partial component with magnetic potential difference between two magnetic ports equations = Equation[ V_m ~ port_p.V_m - port_n.V_m, Phi ~ port_p.Phi, - 0 ~ port_p.Phi + port_n.Phi + 0 ~ port_p.Phi + port_n.Phi, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/MultiBody2D/components.jl b/src/Mechanical/MultiBody2D/components.jl index 30d06b0e6..319b584c0 100644 --- a/src/Mechanical/MultiBody2D/components.jl +++ b/src/Mechanical/MultiBody2D/components.jl @@ -1,15 +1,17 @@ -@component function Link(; name, - m = nothing, l = nothing, I = nothing, g = nothing, - x1_0 = 0.0, y1_0 = 0.0, - A = nothing, dA = nothing, ddA = nothing, - fx1 = nothing, fy1 = nothing, - fx2 = nothing, fy2 = nothing, - x1 = nothing, dx1 = nothing, - y1 = nothing, dy1 = nothing, - x2 = nothing, dx2 = nothing, - y2 = nothing, dy2 = nothing, - x_cm = nothing, dx_cm = nothing, ddx_cm = nothing, - y_cm = nothing, dy_cm = nothing, ddy_cm = nothing) +@component function Link(; + name, + m = nothing, l = nothing, I = nothing, g = nothing, + x1_0 = 0.0, y1_0 = 0.0, + A = nothing, dA = nothing, ddA = nothing, + fx1 = nothing, fy1 = nothing, + fx2 = nothing, fy2 = nothing, + x1 = nothing, dx1 = nothing, + y1 = nothing, dy1 = nothing, + x2 = nothing, dx2 = nothing, + y2 = nothing, dy2 = nothing, + x_cm = nothing, dx_cm = nothing, ddx_cm = nothing, + y_cm = nothing, dy_cm = nothing, ddy_cm = nothing + ) pars = @parameters begin m = m l = l @@ -83,8 +85,8 @@ # torques I * ddA ~ - -fy1 * (x2 - x1) / 2 + fy2 * (x2 - x1) / 2 + fx1 * (y2 - y1) / 2 - - fx2 * (y2 - y1) / 2, + -fy1 * (x2 - x1) / 2 + fy2 * (x2 - x1) / 2 + fx1 * (y2 - y1) / 2 - + fx2 * (y2 - y1) / 2, # geometry x2 ~ l * cos(A) + x1, @@ -98,7 +100,7 @@ TX2.f ~ fx2, TX2.s ~ x2, TY2.f ~ fy2, - TY2.s ~ y2 + TY2.s ~ y2, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/Rotational/components.jl b/src/Mechanical/Rotational/components.jl index ab254880d..d1deacec2 100644 --- a/src/Mechanical/Rotational/components.jl +++ b/src/Mechanical/Rotational/components.jl @@ -24,7 +24,7 @@ Flange fixed in housing at a given angle. end equations = Equation[ - flange.phi ~ phi0 + flange.phi ~ phi0, ] return System(equations, t, vars, pars; name, systems) @@ -73,7 +73,7 @@ end phi ~ flange_b.phi, D(phi) ~ w, D(w) ~ a, - J * a ~ flange_a.tau + flange_b.tau + J * a ~ flange_a.tau + flange_b.tau, ] return System(equations, t, vars, pars; name, systems) @@ -117,7 +117,7 @@ Linear 1D rotational spring end equations = Equation[ - tau ~ c * (phi_rel - phi_rel0) + tau ~ c * (phi_rel - phi_rel0), ] sys = System(equations, t, vars, pars; name, systems) @@ -162,7 +162,7 @@ Linear 1D rotational damper end equations = Equation[ - tau ~ d * w_rel + tau ~ d * w_rel, ] sys = System(equations, t, vars, pars; name, systems) @@ -212,7 +212,7 @@ Linear 1D rotational spring and damper equations = Equation[ tau_c ~ c * (phi_rel - phi_rel0), tau_d ~ d * w_rel, - tau ~ tau_c + tau_d + tau ~ tau_c + tau_d, ] sys = System(equations, t, vars, pars; name, systems) @@ -262,7 +262,7 @@ This element characterizes any type of gear box which is fixed in the ground and phi_a ~ flange_a.phi - phi_support, phi_b ~ flange_b.phi - phi_support, phi_a ~ ratio * phi_b, - 0 ~ ratio * flange_a.tau + flange_b.tau + 0 ~ ratio * flange_a.tau + flange_b.tau, ] sys = System(equations, t, vars, pars; name, systems) @@ -319,8 +319,8 @@ Friction model: "Armstrong, B. and C.C. de Wit, Friction Modeling and Compensati equations = Equation[ tau ~ - str_scale * (exp(-(w_rel / w_st)^2) * w_rel / w_st) + - tau_c * tanh(w_rel / w_coul) + f * w_rel # Stribeck friction + Coulomb friction + Viscous friction + str_scale * (exp(-(w_rel / w_st)^2) * w_rel / w_st) + + tau_c * tanh(w_rel / w_coul) + f * w_rel, # Stribeck friction + Coulomb friction + Viscous friction ] sys = System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/Rotational/sensors.jl b/src/Mechanical/Rotational/sensors.jl index 3e6147a61..618f66dda 100644 --- a/src/Mechanical/Rotational/sensors.jl +++ b/src/Mechanical/Rotational/sensors.jl @@ -22,7 +22,7 @@ Ideal sensor to measure the absolute flange angle equations = Equation[ phi.u ~ flange.phi, - flange.tau ~ 0 + flange.tau ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -52,7 +52,7 @@ Ideal sensor to measure the absolute flange angular velocity equations = Equation[ D(flange.phi) ~ w.u, - flange.tau ~ 0 + flange.tau ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -84,7 +84,7 @@ Ideal sensor to measure the torque between two flanges (`= flange_a.tau`) equations = Equation[ flange_a.phi ~ flange_b.phi, - tau.u ~ flange_a.tau + tau.u ~ flange_a.tau, ] return System(equations, t, vars, pars; name, systems) @@ -119,7 +119,7 @@ Ideal sensor to measure the relative angular velocity 0 ~ flange_a.tau + flange_b.tau, phi_rel ~ flange_b.phi - flange_a.phi, D(phi_rel) ~ w_rel.u, - 0 ~ flange_a.tau + 0 ~ flange_a.tau, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/Rotational/sources.jl b/src/Mechanical/Rotational/sources.jl index 0f756a6b9..94023983b 100644 --- a/src/Mechanical/Rotational/sources.jl +++ b/src/Mechanical/Rotational/sources.jl @@ -13,7 +13,7 @@ end equations = Equation[ - phi ~ flange.phi - phi_support + phi ~ flange.phi - phi_support, ] sys = System(equations, t, vars, pars; name, systems) @@ -53,7 +53,7 @@ Input signal acting as external torque on a flange end equations = Equation[ - flange.tau ~ -tau.u + flange.tau ~ -tau.u, ] sys = System(equations, t, vars, pars; name, systems) @@ -97,7 +97,7 @@ Constant torque source equations = Equation[ w ~ D(phi), tau ~ -flange.tau, - tau ~ tau_constant + tau ~ tau_constant, ] sys = System(equations, t, vars, pars; name, systems) @@ -152,14 +152,14 @@ Forced movement of a flange according to a reference angular velocity signal phi ~ flange.phi - phi_support, D(phi) ~ w, w ~ w_ref.u, - a ~ 0 + a ~ 0, ] else Equation[ phi ~ flange.phi - phi_support, D(phi) ~ w, D(w) ~ a, - a ~ (w_ref.u - w) * tau_filt + a ~ (w_ref.u - w) * tau_filt, ] end @@ -203,26 +203,32 @@ The input signal `phi_ref` defines the reference angle in [rad]. Flange is force w_crit = 2 * π * f_crit af = 1.3617 # s coefficient of Bessel filter - bf = 0.6180 # s*s coefficient of Bessel filter + bf = 0.618 # s*s coefficient of Bessel filter vars = @variables begin phi(t), - [guess = 0.0, description = "Rotation angle of flange with respect to support"] + [guess = 0.0, description = "Rotation angle of flange with respect to support"] w(t), - [guess = 0.0, description = "Angular velocity of flange with respect to support"] + [guess = 0.0, description = "Angular velocity of flange with respect to support"] a(t), - [guess = 0.0, - description = "Angular acceleration of flange with respect to support"] + [ + guess = 0.0, + description = "Angular acceleration of flange with respect to support", + ] end equations = if exact - [phi ~ flange.phi - phi_support - phi ~ phi_ref.u] + [ + phi ~ flange.phi - phi_support + phi ~ phi_ref.u + ] else - [phi ~ flange.phi - phi_support - D(phi) ~ w - D(w) ~ a - a ~ ((phi_ref.u - phi) * w_crit - af * w) * (w_crit / bf)] + [ + phi ~ flange.phi - phi_support + D(phi) ~ w + D(w) ~ a + a ~ ((phi_ref.u - phi) * w_crit - af * w) * (w_crit / bf) + ] end extend(System(equations, t; name, systems = [phi_ref]), partial_element) end diff --git a/src/Mechanical/Rotational/utils.jl b/src/Mechanical/Rotational/utils.jl index f9a89886c..9f2d1fdb4 100644 --- a/src/Mechanical/Rotational/utils.jl +++ b/src/Mechanical/Rotational/utils.jl @@ -88,7 +88,7 @@ Partial model for the compliant connection of two rotational 1-dim. shaft flange equations = Equation[ phi_rel ~ flange_b.phi - flange_a.phi, flange_b.tau ~ tau, - flange_a.tau ~ -tau + flange_a.tau ~ -tau, ] return System(equations, t, vars, pars; name, systems) @@ -124,7 +124,7 @@ Partial model for the compliant connection of two rotational 1-dim. shaft flange phi_rel(t) = phi_rel, [description = "Relative rotation angle between flanges", guess = 0.0] w_rel(t) = w_rel, [description = "Relative angular velocity between flanges", guess = 0.0] a_rel(t) = a_rel, - [description = "Relative angular acceleration between flanges", guess = 0.0] + [description = "Relative angular acceleration between flanges", guess = 0.0] tau(t) = tau, [description = "Torque between flanges", guess = 0.0] end @@ -133,7 +133,7 @@ Partial model for the compliant connection of two rotational 1-dim. shaft flange D(phi_rel) ~ w_rel, D(w_rel) ~ a_rel, flange_b.tau ~ tau, - flange_a.tau ~ -tau + flange_a.tau ~ -tau, ] return System(equations, t, vars, pars; name, systems) @@ -160,11 +160,14 @@ Partial model for a component with one rotational 1-dim. shaft flange and a supp @named flange = Flange() sys = [flange] @variables phi_support(t) [ - description = "Absolute angle of support flange", guess = 0.0] + description = "Absolute angle of support flange", guess = 0.0, + ] if use_support @named support = Support() - eqs = [support.phi ~ phi_support - support.tau ~ -flange.tau] + eqs = [ + support.phi ~ phi_support + support.tau ~ -flange.tau + ] push!(sys, support) else eqs = [phi_support ~ 0] @@ -196,11 +199,14 @@ Partial model for a component with two rotational 1-dim. shaft flanges and a sup @named flange_b = Flange() sys = [flange_a, flange_b] @variables phi_support(t) [ - description = "Absolute angle of support flange", guess = 0.0] + description = "Absolute angle of support flange", guess = 0.0, + ] if use_support @named support = Support() - eqs = [support.phi ~ phi_support - support.tau ~ -flange_a.tau - flange_b.tau] + eqs = [ + support.phi ~ phi_support + support.tau ~ -flange_a.tau - flange_b.tau + ] push!(sys, support) else eqs = [phi_support ~ 0] diff --git a/src/Mechanical/Translational/components.jl b/src/Mechanical/Translational/components.jl index 2f4b62f11..b7d75d780 100644 --- a/src/Mechanical/Translational/components.jl +++ b/src/Mechanical/Translational/components.jl @@ -20,7 +20,7 @@ Use to close a system that has un-connected `MechanicalPort`'s where the force s end equations = Equation[ - flange.f ~ f + flange.f ~ f, ] return System(equations, t, vars, pars; name, systems) @@ -47,7 +47,7 @@ Fixes a flange position (velocity = 0) end equations = Equation[ - flange.v ~ 0 + flange.v ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -86,13 +86,17 @@ Sliding mass with inertia f(t), [guess = 0] end - eqs = [flange.v ~ v - flange.f ~ f - D(s) ~ v - D(v) ~ f / m + g] + eqs = [ + flange.v ~ v + flange.f ~ f + D(s) ~ v + D(v) ~ f / m + g + ] - return compose(System(eqs, t, vars, pars; name = name), - flange) + return compose( + System(eqs, t, vars, pars; name = name), + flange + ) end const REL = Val(:relative) @@ -130,13 +134,17 @@ end # default @named flange_a = MechanicalPort() @named flange_b = MechanicalPort() - eqs = [D(delta_s) ~ flange_a.v - flange_b.v - f ~ k * delta_s - flange_a.f ~ +f - flange_b.f ~ -f] - return compose(System(eqs, t, vars, pars; name = name), + eqs = [ + D(delta_s) ~ flange_a.v - flange_b.v + f ~ k * delta_s + flange_a.f ~ +f + flange_b.f ~ -f + ] + return compose( + System(eqs, t, vars, pars; name = name), flange_a, - flange_b) #flange_a.f => +k*delta_s, flange_b.f => -k*delta_s + flange_b + ) #flange_a.f => +k*delta_s, flange_b.f => -k*delta_s end const ABS = Val(:absolute) @@ -154,14 +162,18 @@ const ABS = Val(:absolute) @named flange_a = MechanicalPort() @named flange_b = MechanicalPort() - eqs = [D(sa) ~ flange_a.v - D(sb) ~ flange_b.v - f ~ k * (sa - sb - l) #delta_s - flange_a.f ~ +f - flange_b.f ~ -f] - return compose(System(eqs, t, vars, pars; name = name), + eqs = [ + D(sa) ~ flange_a.v + D(sb) ~ flange_b.v + f ~ k * (sa - sb - l) #delta_s + flange_a.f ~ +f + flange_b.f ~ -f + ] + return compose( + System(eqs, t, vars, pars; name = name), flange_a, - flange_b) #, flange_a.f => k * (flange_a__s - flange_b__s - l) + flange_b + ) #, flange_a.f => k * (flange_a__s - flange_b__s - l) end """ @@ -197,7 +209,7 @@ Linear 1D translational damper v ~ flange_a.v - flange_b.v, f ~ v * d, flange_a.f ~ +f, - flange_b.f ~ -f + flange_b.f ~ -f, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/Translational/sensors.jl b/src/Mechanical/Translational/sensors.jl index fceb8efd5..6e7020a03 100644 --- a/src/Mechanical/Translational/sensors.jl +++ b/src/Mechanical/Translational/sensors.jl @@ -24,7 +24,7 @@ Linear 1D force sensor, measures the force between two flanges. equations = Equation[ flange_a.v ~ flange_b.v, flange_a.f + flange_b.f ~ 0.0, - output.u ~ flange_a.f + output.u ~ flange_a.f, ] return System(equations, t, vars, pars; name, systems) @@ -60,7 +60,7 @@ Linear 1D position sensor. equations = Equation[ D(s) ~ flange.v, output.u ~ s, - flange.f ~ 0.0 + flange.f ~ 0.0, ] return System(equations, t, vars, pars; name, systems) @@ -96,7 +96,7 @@ Linear 1D acceleration sensor. equations = Equation[ a ~ D(flange.v), output.u ~ a, - flange.f ~ 0.0 + flange.f ~ 0.0, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/Translational/sources.jl b/src/Mechanical/Translational/sources.jl index 00719c410..5260d51c3 100644 --- a/src/Mechanical/Translational/sources.jl +++ b/src/Mechanical/Translational/sources.jl @@ -21,7 +21,7 @@ Linear 1D force input source end equations = Equation[ - flange.f ~ -f.u + flange.f ~ -f.u, ] return System(equations, t, vars, pars; name, systems) @@ -46,13 +46,15 @@ Linear 1D position input source. Set `solves_force=false` to force input force end eqs = [ - D(s.u) ~ flange.v + D(s.u) ~ flange.v, ] !solves_force && push!(eqs, 0 ~ flange.f) - System(eqs, t, vars, []; - name, systems) + System( + eqs, t, vars, []; + name, systems + ) end """ @@ -72,7 +74,7 @@ Linear 1D position input source. Set `solves_force=false` to force input force end eqs = [ - v.u ~ flange.v + v.u ~ flange.v, ] !solves_force && push!(eqs, 0 ~ flange.f) @@ -98,8 +100,10 @@ Linear 1D position input source. Set `solves_force=false` to force input force vars = @variables v(t) - eqs = [v ~ flange.v - D(v) ~ a.u] + eqs = [ + v ~ flange.v + D(v) ~ a.u + ] !solves_force && push!(eqs, 0 ~ flange.f) diff --git a/src/Mechanical/TranslationalModelica/components.jl b/src/Mechanical/TranslationalModelica/components.jl index cefb0bfca..b74dbffcf 100644 --- a/src/Mechanical/TranslationalModelica/components.jl +++ b/src/Mechanical/TranslationalModelica/components.jl @@ -24,7 +24,7 @@ Flange fixed in housing at a given position. end equations = Equation[ - flange.s ~ s0 + flange.s ~ s0, ] return System(equations, t, vars, pars; name, systems) @@ -67,7 +67,7 @@ Sliding mass with inertia equations = Equation[ v ~ D(s), a ~ D(v), - m * a ~ flange_a.f + flange_b.f + m * a ~ flange_a.f + flange_b.f, ] sys = System(equations, t, vars, pars; name, systems) @@ -105,7 +105,7 @@ Linear 1D translational spring end equations = Equation[ - f ~ c * (s_rel - s_rel0) + f ~ c * (s_rel - s_rel0), ] sys = System(equations, t, vars, pars; name, systems) @@ -143,7 +143,7 @@ Linear 1D translational damper equations = Equation[ f ~ d * v_rel, - lossPower ~ f * v_rel + lossPower ~ f * v_rel, ] sys = System(equations, t, vars, pars; name, systems) @@ -187,7 +187,7 @@ Linear 1D translational spring and damper in parallel equations = Equation[ f ~ c * (s_rel - s_rel0) + d * v_rel, - lossPower ~ d * v_rel^2 + lossPower ~ d * v_rel^2, ] sys = System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/TranslationalModelica/sources.jl b/src/Mechanical/TranslationalModelica/sources.jl index 7223f2728..9e5c33c2d 100644 --- a/src/Mechanical/TranslationalModelica/sources.jl +++ b/src/Mechanical/TranslationalModelica/sources.jl @@ -18,7 +18,7 @@ Input signal acting as external force on a flange end equations = Equation[ - flange.f ~ -f.u + flange.f ~ -f.u, ] sys = System(equations, t, vars, pars; name, systems) @@ -47,7 +47,7 @@ The input signal can be provided from one of the signal generator blocks of the w_crit = 2π * f_crit af = 1.3617 - bf = 0.6180 + bf = 0.618 systems = @named begin s_ref = RealInput() @@ -62,13 +62,13 @@ The input signal can be provided from one of the signal generator blocks of the Equation[ s ~ s_ref.u, v ~ D(s), - a ~ D(v) + a ~ D(v), ] else Equation[ a ~ ((s_ref.u - s) * w_crit - af * v) * (w_crit / bf), v ~ D(s), - a ~ D(v) + a ~ D(v), ] end diff --git a/src/Mechanical/TranslationalModelica/utils.jl b/src/Mechanical/TranslationalModelica/utils.jl index a649fd65d..0faaf1379 100644 --- a/src/Mechanical/TranslationalModelica/utils.jl +++ b/src/Mechanical/TranslationalModelica/utils.jl @@ -77,7 +77,7 @@ Partial model for the compliant connection of two translational 1-dim. flanges. equations = Equation[ s_rel ~ flange_b.s - flange_a.s, flange_b.f ~ +f, - flange_a.f ~ -f + flange_a.f ~ -f, ] sys = System(equations, t, vars, pars; name, systems) @@ -115,7 +115,7 @@ Partial model for the compliant connection of two translational 1-dim. flanges. s_rel ~ flange_b.s - flange_a.s, v_rel ~ D(s_rel), flange_b.f ~ f, - flange_a.f ~ -f + flange_a.f ~ -f, ] sys = System(equations, t, vars, pars; name, systems) @@ -139,10 +139,10 @@ function PartialElementaryOneFlangeAndSupport2(; name, use_support = false) @named flange = Flange() @variables s_support(t) [description = "Absolute position of support flange"] @variables s(t) [ - description = "Distance between flange and support (= flange.s - support.s)" + description = "Distance between flange and support (= flange.s - support.s)", ] eqs = [s ~ flange.s - s_support] - if use_support + return if use_support @named support = Support() push!(eqs, support.f ~ -flange.f) compose(System(eqs, t; name = name), flange, support) @@ -172,9 +172,11 @@ function PartialElementaryTwoFlangesAndSupport2(; name, use_support = false) @variables s_b(t) [description = "Distance between right flange and support"] @variables s_support(t) [description = "Absolute position of support flange"] - eqs = [s_a ~ flange_a.s - s_support - s_b ~ flange_b.s - s_support] - if use_support + eqs = [ + s_a ~ flange_a.s - s_support + s_b ~ flange_b.s - s_support + ] + return if use_support @named support = Support() push!(eqs, support.f ~ -flange_a.f - flange_b.f) compose(System(eqs, t; name = name), flange, support) @@ -201,7 +203,7 @@ end equations = Equation[ flange_a.s ~ s - L / 2, - flange_b.s ~ s + L / 2 + flange_b.s ~ s + L / 2, ] sys = System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/TranslationalPosition/components.jl b/src/Mechanical/TranslationalPosition/components.jl index 00767d9d0..1953dd490 100644 --- a/src/Mechanical/TranslationalPosition/components.jl +++ b/src/Mechanical/TranslationalPosition/components.jl @@ -24,7 +24,7 @@ Flange fixed in housing at a given position. end equations = Equation[ - flange.s ~ s_0 + flange.s ~ s_0, ] return System(equations, t, vars, pars; name, systems) @@ -69,15 +69,17 @@ Sliding mass with inertia flange.s ~ s, flange.f ~ f, D(s) ~ v, - D(v) ~ f / m + D(v) ~ f / m, ] return System(equations, t, vars, pars; name, systems) end const REL = Val(:relative) -@component function Spring(::Val{:relative}; name, k = nothing, va = 0.0, vb = 0.0, - delta_s = 0) +@component function Spring( + ::Val{:relative}; name, k = nothing, va = 0.0, vb = 0.0, + delta_s = 0 + ) pars = @parameters begin k = k end @@ -91,17 +93,20 @@ const REL = Val(:relative) @named flange_a = Flange() @named flange_b = Flange() - eqs = [D(flange_a.s) ~ va - D(flange_b.s) ~ vb - D(delta_s) ~ va - vb - f ~ k * delta_s - flange_a.f ~ +f - flange_b.f ~ -f] + eqs = [ + D(flange_a.s) ~ va + D(flange_b.s) ~ vb + D(delta_s) ~ va - vb + f ~ k * delta_s + flange_a.f ~ +f + flange_b.f ~ -f + ] return compose( System(eqs, t, vars, pars; name = name), flange_a, - flange_b) + flange_b + ) end const ABS = Val(:absolute) @@ -122,11 +127,13 @@ Linear 1D translational spring - `flange_b: 1-dim. translational flange on opposite side of spring` #default function """ function Spring(; name, k = nothing, l = 0) - Spring(ABS; name, k, l) + return Spring(ABS; name, k, l) end #default function -@component function Spring(::Val{:absolute}; - name, k = nothing, l = 0) +@component function Spring( + ::Val{:absolute}; + name, k = nothing, l = 0 + ) pars = @parameters begin k = k l = l @@ -139,10 +146,11 @@ end #default function @named flange_b = Flange() eqs = [ - # delta_s ~ flange_a.s - flange_b.s - f ~ k * (flange_a.s - flange_b.s - l) #delta_s - flange_a.f ~ +f - flange_b.f ~ -f] + # delta_s ~ flange_a.s - flange_b.s + f ~ k * (flange_a.s - flange_b.s - l) #delta_s + flange_a.f ~ +f + flange_b.f ~ -f + ] return compose(System(eqs, t, vars, pars; name = name), flange_a, flange_b) end @@ -183,7 +191,7 @@ Linear 1D translational damper D(flange_b.s) ~ vb, f ~ (va - vb) * d, flange_a.f ~ +f, - flange_b.f ~ -f + flange_b.f ~ -f, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/TranslationalPosition/sensors.jl b/src/Mechanical/TranslationalPosition/sensors.jl index 801340f02..ec7f5367f 100644 --- a/src/Mechanical/TranslationalPosition/sensors.jl +++ b/src/Mechanical/TranslationalPosition/sensors.jl @@ -25,7 +25,7 @@ Linear 1D force sensor, measures the force between two flanges. equations = Equation[ flange_a.s ~ flange_b.s, flange_a.f + flange_b.f ~ 0.0, - output.u ~ flange_a.f + output.u ~ flange_a.f, ] return System(equations, t, vars, pars; name, systems) @@ -59,7 +59,7 @@ Linear 1D position sensor. equations = Equation[ output.u ~ flange.s, - flange.f ~ 0.0 + flange.f ~ 0.0, ] return System(equations, t, vars, pars; name, systems) @@ -95,7 +95,7 @@ Linear 1D acceleration sensor. equations = Equation[ a ~ D(D(flange.s)), output.u ~ a, - flange.f ~ 0.0 + flange.f ~ 0.0, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/TranslationalPosition/sources.jl b/src/Mechanical/TranslationalPosition/sources.jl index f77f873ff..ea4a854c5 100644 --- a/src/Mechanical/TranslationalPosition/sources.jl +++ b/src/Mechanical/TranslationalPosition/sources.jl @@ -19,7 +19,7 @@ Input signal acting as external force on a flange end equations = Equation[ - flange.f ~ -f.u + flange.f ~ -f.u, ] sys = System(equations, t, vars, pars; name, systems) diff --git a/src/Mechanical/TranslationalPosition/utils.jl b/src/Mechanical/TranslationalPosition/utils.jl index 7736928a6..37fb92edd 100644 --- a/src/Mechanical/TranslationalPosition/utils.jl +++ b/src/Mechanical/TranslationalPosition/utils.jl @@ -63,7 +63,7 @@ Partial model for the compliant connection of two translational 1-dim. flanges. D(flange_b.s) ~ v_b, D(s_rel) ~ v_b - v_a, flange_b.f ~ +f, - flange_a.f ~ -f + flange_a.f ~ -f, ] return System(equations, t, vars, pars; name, systems) @@ -105,7 +105,7 @@ Partial model for the compliant connection of two translational 1-dim. flanges. equations = Equation[ delta_s ~ flange_a.s - flange_b.s, flange_a.f ~ +f, - flange_b.f ~ -f + flange_b.f ~ -f, ] return System(equations, t, vars, pars; name, systems) @@ -130,8 +130,10 @@ Partial model for a component with one translational 1-dim. shaft flange and a s @variables s_support(t) if use_support @named support = Support() - eqs = [support.s ~ s_support - support.f ~ -flange.f] + eqs = [ + support.s ~ s_support + support.f ~ -flange.f + ] push!(sys, support) else eqs = [s_support ~ 0] @@ -159,8 +161,10 @@ Partial model for a component with two translational 1-dim. flanges and a suppor @variables s_support(t) if use_support @named support = Support() - eqs = [support.s ~ s_support - support.f ~ -flange_a.f - flange_b.f] + eqs = [ + support.s ~ s_support + support.f ~ -flange_a.f - flange_b.f + ] push!(sys, support) else eqs = [s_support ~ 0] diff --git a/src/ModelingToolkitStandardLibrary.jl b/src/ModelingToolkitStandardLibrary.jl index 07885fee4..650129c47 100644 --- a/src/ModelingToolkitStandardLibrary.jl +++ b/src/ModelingToolkitStandardLibrary.jl @@ -10,7 +10,7 @@ macro symcheck(ex) ex.args[1].head === :call || error("Expected an expression on the form sym > val || error()") sym = ex.args[1].args[2] - quote + return quote _issymbolic(x) = !(unwrap(x) isa Real) _issymbolic($(esc(sym))) || ($(esc(ex))) end diff --git a/src/Thermal/HeatTransfer/ideal_components.jl b/src/Thermal/HeatTransfer/ideal_components.jl index 7d42e8a1c..bacb548b9 100644 --- a/src/Thermal/HeatTransfer/ideal_components.jl +++ b/src/Thermal/HeatTransfer/ideal_components.jl @@ -33,7 +33,7 @@ Lumped thermal element storing heat equations = Equation[ T ~ port.T, der_T ~ port.Q_flow / C, - D(T) ~ der_T + D(T) ~ der_T, ] return System(equations, t, vars, pars; name, systems) @@ -72,7 +72,7 @@ see [`Element1D`](@ref) end equations = Equation[ - Q_flow ~ G * dT + Q_flow ~ G * dT, ] sys = System(equations, t, vars, pars; name, systems) @@ -113,7 +113,7 @@ Lumped thermal element transporting heat without storing it. end equations = Equation[ - dT ~ R * Q_flow + dT ~ R * Q_flow, ] sys = System(equations, t, vars, pars; name, systems) @@ -154,7 +154,7 @@ Lumped thermal element for heat convection. end equations = Equation[ - Q_flow ~ G * dT + Q_flow ~ G * dT, ] sys = System(equations, t, vars, pars; name, systems) @@ -195,7 +195,7 @@ Lumped thermal element for heat convection. end equations = Equation[ - dT ~ R * Q_flow + dT ~ R * Q_flow, ] sys = System(equations, t, vars, pars; name, systems) @@ -238,7 +238,7 @@ Lumped thermal element for radiation heat transfer. end equations = Equation[ - Q_flow ~ G * sigma * (port_a.T^4 - port_b.T^4) + Q_flow ~ G * sigma * (port_a.T^4 - port_b.T^4), ] sys = System(equations, t, vars, pars; name, systems) @@ -282,7 +282,7 @@ This is a model to collect the heat flows from `m` heatports to one single heatp equations = Equation[ port_b.Q_flow + sum(k -> k.Q_flow, port_a) ~ 0, port_b.T ~ port_a[1].T, - [port_a[i].T ~ port_a[i + 1].T for i in 1:(m - 1)]... + [port_a[i].T ~ port_a[i + 1].T for i in 1:(m - 1)]..., ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Thermal/HeatTransfer/sensors.jl b/src/Thermal/HeatTransfer/sensors.jl index 7d1067d1a..8a450daf0 100644 --- a/src/Thermal/HeatTransfer/sensors.jl +++ b/src/Thermal/HeatTransfer/sensors.jl @@ -26,7 +26,7 @@ lags are associated with this sensor model. equations = Equation[ T.u ~ port.T, - port.Q_flow ~ 0 + port.Q_flow ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -62,7 +62,7 @@ output signal in kelvin. equations = Equation[ T.u ~ port_a.T - port_b.T, port_a.Q_flow ~ 0, - port_b.Q_flow ~ 0 + port_b.Q_flow ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -100,7 +100,7 @@ The output signal is positive, if the heat flows from `port_a` to `port_b`. equations = Equation[ port_a.T ~ port_b.T, port_a.Q_flow + port_b.Q_flow ~ 0, - Q_flow.u ~ port_a.Q_flow + Q_flow.u ~ port_a.Q_flow, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Thermal/HeatTransfer/sources.jl b/src/Thermal/HeatTransfer/sources.jl index 9e5a800f2..d06abf83b 100644 --- a/src/Thermal/HeatTransfer/sources.jl +++ b/src/Thermal/HeatTransfer/sources.jl @@ -32,9 +32,11 @@ the component FixedHeatFlow is connected, if parameter `Q_flow` is positive. end equations = Equation[ - port.Q_flow ~ ifelse(alpha == 0.0, + port.Q_flow ~ ifelse( + alpha == 0.0, -Q_flow, # Simplified equation when alpha is 0 - -Q_flow * (1 + alpha * (port.T - T_ref))) + -Q_flow * (1 + alpha * (port.T - T_ref)) + ), ] return System(equations, t, vars, pars; name, systems) @@ -68,7 +70,7 @@ This model defines a fixed temperature `T` at its port in kelvin, i.e., it defin end equations = Equation[ - port.T ~ T + port.T ~ T, ] return System(equations, t, vars, pars; name, systems) @@ -110,7 +112,7 @@ dependent losses (which are given a reference temperature T_ref). end equations = Equation[ - port.Q_flow ~ -Q_flow.u * (1 + alpha * (port.T - T_ref)) + port.Q_flow ~ -Q_flow.u * (1 + alpha * (port.T - T_ref)), ] return System(equations, t, vars, pars; name, systems) @@ -143,7 +145,7 @@ the temperature at the specified value. end equations = Equation[ - port.T ~ T.u + port.T ~ T.u, ] return System(equations, t, vars, pars; name, systems) diff --git a/src/Thermal/Thermal.jl b/src/Thermal/Thermal.jl index 8139e5efe..5df7b306f 100644 --- a/src/Thermal/Thermal.jl +++ b/src/Thermal/Thermal.jl @@ -10,8 +10,8 @@ export HeatPort, Element1D include("utils.jl") export BodyRadiation, ConvectiveConductor, ConvectiveResistor, HeatCapacitor, - ThermalConductor, - ThermalResistor, ThermalCollector + ThermalConductor, + ThermalResistor, ThermalCollector include("HeatTransfer/ideal_components.jl") export RelativeTemperatureSensor, HeatFlowSensor, TemperatureSensor diff --git a/src/Thermal/utils.jl b/src/Thermal/utils.jl index 8ba3bb6a2..6489775a5 100644 --- a/src/Thermal/utils.jl +++ b/src/Thermal/utils.jl @@ -57,7 +57,7 @@ flow rate through the element from `port_a` to `port_b`, `Q_flow`. equations = Equation[ dT ~ port_a.T - port_b.T, port_a.Q_flow ~ Q_flow, - port_a.Q_flow + port_b.Q_flow ~ 0 + port_a.Q_flow + port_b.Q_flow ~ 0, ] return System(equations, t, vars, pars; name, systems) @@ -98,7 +98,7 @@ flow rate through the element from `solid` to `fluid`, `Q_flow`. equations = Equation[ dT ~ solid.T - fluid.T, solid.Q_flow ~ Q_flow, - solid.Q_flow + fluid.Q_flow ~ 0 + solid.Q_flow + fluid.Q_flow ~ 0, ] return System(equations, t, vars, pars; name, systems) diff --git a/test/Blocks/continuous.jl b/test/Blocks/continuous.jl index 5227e60c1..2ebb304fa 100644 --- a/test/Blocks/continuous.jl +++ b/test/Blocks/continuous.jl @@ -31,15 +31,16 @@ end @named iosys = System( [ connect(source.output, der.input), - connect(der.output, int.input) + connect(der.output, int.input), ], t, - systems = [int, source, der]) + systems = [int, source, der] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test all(isapprox.(sol[source.output.u], sol[int.output.u], atol = 1e-1)) + @test all(isapprox.(sol[source.output.u], sol[int.output.u], atol = 1.0e-1)) end @testset "PT1" begin @@ -53,7 +54,7 @@ end prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[pt1.output.u]≈pt1_func.(sol.t, k, T) atol=1e-3 + @test sol[pt1.output.u] ≈ pt1_func.(sol.t, k, T) atol = 1.0e-3 # Test highpass feature @named pt1 = FirstOrder(; k = k, T = T, lowpass = false) @@ -62,7 +63,7 @@ end prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[pt1.output.u]≈k .- pt1_func.(sol.t, k, T) atol=1e-3 + @test sol[pt1.output.u] ≈ k .- pt1_func.(sol.t, k, T) atol = 1.0e-3 end @testset "PT2" begin @@ -72,9 +73,15 @@ end -k * (-1 + cos(t * w)) else d = complex(d) - real(k * (1 + - (-cosh(sqrt(-1 + d^2) * t * w) - - (d * sinh(sqrt(-1 + d^2) * t * w)) / sqrt(-1 + d^2)) / exp(d * t * w))) + real( + k * ( + 1 + + ( + -cosh(sqrt(-1 + d^2) * t * w) - + (d * sinh(sqrt(-1 + d^2) * t * w)) / sqrt(-1 + d^2) + ) / exp(d * t * w) + ) + ) end end @@ -86,7 +93,7 @@ end prob = ODEProblem(sys, [unknowns(sys) .=> 0.0...; pt2.xd => 0.0], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[pt2.output.u]≈pt2_func.(sol.t, k, w, d) atol=1e-3 + @test sol[pt2.output.u] ≈ pt2_func.(sol.t, k, w, d) atol = 1.0e-3 end @testset "StateSpace" begin @@ -96,40 +103,44 @@ end D = [0;;] @named ss = StateSpace(; A, B, C, D, x = zeros(2)) @named c = Constant(; k = 1) - @named model = System([ - connect(c.output, ss.input) + @named model = System( + [ + connect(c.output, ss.input), ], t, - systems = [ss, c]) + systems = [ss, c] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success # initial condition - @test sol[ss.x[1]][1]≈0 atol=1e-3 - @test sol[ss.x[2]][1]≈0 atol=1e-3 + @test sol[ss.x[1]][1] ≈ 0 atol = 1.0e-3 + @test sol[ss.x[2]][1] ≈ 0 atol = 1.0e-3 # equilibrium point is at [1, 0] - @test sol[ss.x[1]][end]≈1 atol=1e-3 - @test sol[ss.x[2]][end]≈0 atol=1e-3 + @test sol[ss.x[1]][end] ≈ 1 atol = 1.0e-3 + @test sol[ss.x[2]][end] ≈ 0 atol = 1.0e-3 # non-zero operating point u0 = [1] # This causes no effective input to the system since c.k = 1 y0 = [2] @named ss = StateSpace(; A, B, C, D, x = zeros(2), u0, y0) - @named model = System([ - connect(c.output, ss.input) + @named model = System( + [ + connect(c.output, ss.input), ], t, - systems = [ss, c]) + systems = [ss, c] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[ss.x[1]][end ÷ 2]≈0 atol=1e-3 # Test that x did not move - @test sol[ss.x[1]][end]≈0 atol=1e-3 # Test that x did not move - @test sol[ss.x[2]][end]≈0 atol=1e-3 - @test sol[ss.output.u[1]][end]≈y0[] atol=1e-3 # Test that the output equals the operating point + @test sol[ss.x[1]][end ÷ 2] ≈ 0 atol = 1.0e-3 # Test that x did not move + @test sol[ss.x[1]][end] ≈ 0 atol = 1.0e-3 # Test that x did not move + @test sol[ss.x[2]][end] ≈ 0 atol = 1.0e-3 + @test sol[ss.output.u[1]][end] ≈ y0[] atol = 1.0e-3 # Test that the output equals the operating point end """ @@ -139,10 +150,12 @@ Second order demo plant @named input = RealInput() @named output = RealOutput() D = Differential(t) - sts = @variables x1(t)=x[1] x2(t)=x[2] - eqs = [D(x1) ~ x2 - D(x2) ~ -x1 - 0.5 * x2 + input.u - output.u ~ 0.9 * x1 + x2] + sts = @variables x1(t) = x[1] x2(t) = x[2] + eqs = [ + D(x1) ~ x2 + D(x2) ~ -x1 - 0.5 * x2 + input.u + output.u ~ 0.9 * x1 + x2 + ] compose(System(eqs, t, sts, []; name), [input, output]) end @@ -157,17 +170,18 @@ end connect(ref.output, fb.input1), connect(plant.output, fb.input2), connect(fb.output, pi_controller.err_input), - connect(pi_controller.ctr_output, plant.input) + connect(pi_controller.ctr_output, plant.input), ], t, - systems = [pi_controller, plant, ref, fb]) + systems = [pi_controller, plant, ref, fb] + ) sys = mtkcompile(model) initial_conditions(sys)[sys.pi_controller.gainPI.k] = 1.0 prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s end @testset "PID" begin @@ -181,16 +195,17 @@ end connect(ref.output, fb.input1), connect(plant.output, fb.input2), connect(fb.output, pid_controller.err_input), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref, fb]) + systems = [pid_controller, plant, ref, fb] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s @testset "PI" begin @named pid_controller = PID(k = 3, Ti = 0.5, Td = false) @@ -199,16 +214,17 @@ end connect(ref.output, fb.input1), connect(plant.output, fb.input2), connect(fb.output, pid_controller.err_input), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref, fb]) + systems = [pid_controller, plant, ref, fb] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s end @testset "PD" begin @@ -218,15 +234,16 @@ end connect(ref.output, fb.input1), connect(plant.output, fb.input2), connect(fb.output, pid_controller.err_input), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref, fb]) + systems = [pid_controller, plant, ref, fb] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference @test sol[plant.output.u][end] > 1 # without I there will be a steady-state error end end @@ -234,11 +251,13 @@ end @testset "LimPI" begin re_val = 1 @named ref = Constant(; k = re_val) - @named pi_controller_lim = LimPI(k = 3, + @named pi_controller_lim = LimPI( + k = 3, T = 0.5, u_max = 1.5, u_min = -1.5, - Ta = 0.1) + Ta = 0.1 + ) @named pi_controller = PI(T = 0.5) @named sat = Limiter(y_max = 1.5, y_min = -1.5) @named plant = Plant() @@ -252,10 +271,11 @@ end connect(plant.output, fb.input2), connect(fb.output, pi_controller.err_input), connect(pi_controller.ctr_output, sat.input), - connect(sat.output, plant.input) + connect(sat.output, plant.input), ], t, - systems = [pi_controller, plant, ref, fb, sat]) + systems = [pi_controller, plant, ref, fb, sat] + ) sys = mtkcompile(model) initial_conditions(sys)[sys.pi_controller.gainPI.k] = 1.0 prob = ODEProblem(sys, Pair[], (0.0, 20.0)) @@ -270,10 +290,11 @@ end connect(plant.output, fb.input2), connect(fb.output, pi_controller_lim.err_input), connect(pi_controller_lim.ctr_output, sat.input), - connect(sat.output, plant.input) + connect(sat.output, plant.input), ], t, - systems = [pi_controller_lim, plant, ref, fb, sat]) + systems = [pi_controller_lim, plant, ref, fb, sat] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 20.0)) sol = solve(prob, Rodas4()) @@ -281,10 +302,10 @@ end @test sol.retcode == Success @test sol_lim.retcode == ReturnCode.Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference - @test all(isapprox.(sol_lim[ref.output.u], re_val, atol = 1e-3)) # check reference - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s - @test sol_lim[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test all(isapprox.(sol_lim[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s + @test sol_lim[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s @test all(-1.5 .<= sol_lim[pi_controller_lim.ctr_output.u] .<= 1.5) # test limit # Plots.plot(sol; vars=[plant.output.u]) # without anti-windup measure @@ -296,133 +317,150 @@ end @named ref = Constant(; k = re_val) @named pid_controller = LimPID( k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5, u_min = -1.5, - Ni = 0.1 / 0.5) + Ni = 0.1 / 0.5 + ) @named plant = Plant() @named model = System( [ connect(ref.output, pid_controller.reference), connect(plant.output, pid_controller.measurement), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref]) + systems = [pid_controller, plant, ref] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) # Plots.plot(sol, vars=[plant.output.u, plant.input.u]) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s @test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit @testset "PI" begin - @named pid_controller = LimPID(k = 3, Ti = 0.5, Td = false, u_max = 1.5, - u_min = -1.5, Ni = 0.1 / 0.5) + @named pid_controller = LimPID( + k = 3, Ti = 0.5, Td = false, u_max = 1.5, + u_min = -1.5, Ni = 0.1 / 0.5 + ) @named model = System( [ connect(ref.output, pid_controller.reference), connect(plant.output, pid_controller.measurement), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref]) + systems = [pid_controller, plant, ref] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) # Plots.plot(sol, vars=[plant.output.u, plant.input.u]) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s @test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit end @testset "PD" begin - @named pid_controller = LimPID(k = 10, Ti = false, Td = 1, u_max = 1.5, - u_min = -1.5) + @named pid_controller = LimPID( + k = 10, Ti = false, Td = 1, u_max = 1.5, + u_min = -1.5 + ) @named model = System( [ connect(ref.output, pid_controller.reference), connect(plant.output, pid_controller.measurement), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref]) + systems = [pid_controller, plant, ref] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) # Plots.plot(sol, vars=[plant.output.u, plant.input.u]) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference @test sol[plant.output.u][end] > 0.5 # without I there will be a steady-state error @test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit end @testset "set-point weights" begin @testset "wp" begin - @named pid_controller = LimPID(k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5, - u_min = -1.5, Ni = 0.1 / 0.5, wp = 0, wd = 1) + @named pid_controller = LimPID( + k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5, + u_min = -1.5, Ni = 0.1 / 0.5, wp = 0, wd = 1 + ) @named model = System( [ connect(ref.output, pid_controller.reference), connect(plant.output, pid_controller.measurement), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref]) + systems = [pid_controller, plant, ref] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) # Plots.plot(sol, vars=[plant.output.u, plant.input.u]) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference sol[pid_controller.addP.output.u] == -sol[pid_controller.measurement.u] - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s @test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit end @testset "wd" begin - @named pid_controller = LimPID(k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5, - u_min = -1.5, Ni = 0.1 / 0.5, wp = 1, wd = 0) + @named pid_controller = LimPID( + k = 3, Ti = 0.5, Td = 1 / 100, u_max = 1.5, + u_min = -1.5, Ni = 0.1 / 0.5, wp = 1, wd = 0 + ) @named model = System( [ connect(ref.output, pid_controller.reference), connect(plant.output, pid_controller.measurement), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref]) + systems = [pid_controller, plant, ref] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) # Plots.plot(sol, vars=[plant.output.u, plant.input.u]) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s sol[pid_controller.addD.output.u] == -sol[pid_controller.measurement.u] @test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit end end @testset "PI without AWM" begin - @named pid_controller = LimPID(k = 3, Ti = 0.5, Td = false, u_max = 1.5, - u_min = -1.5, Ni = Inf) + @named pid_controller = LimPID( + k = 3, Ti = 0.5, Td = false, u_max = 1.5, + u_min = -1.5, Ni = Inf + ) @named model = System( [ connect(ref.output, pid_controller.reference), connect(plant.output, pid_controller.measurement), - connect(pid_controller.ctr_output, plant.input) + connect(pid_controller.ctr_output, plant.input), ], t, - systems = [pid_controller, plant, ref]) + systems = [pid_controller, plant, ref] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) # Plots.plot(sol, vars=[plant.output.u, plant.input.u]) @test sol.retcode == Success - @test all(isapprox.(sol[ref.output.u], re_val, atol = 1e-3)) # check reference - @test sol[plant.output.u][end]≈re_val atol=1e-3 # zero control error after 100s + @test all(isapprox.(sol[ref.output.u], re_val, atol = 1.0e-3)) # check reference + @test sol[plant.output.u][end] ≈ re_val atol = 1.0e-3 # zero control error after 100s @test all(-1.5 .<= sol[pid_controller.ctr_output.u] .<= 1.5) # test limit end @@ -436,7 +474,7 @@ end prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[pt1.output.u]≈pt1_func.(sol.t, 1.2, 3.14) atol=1e-3 + @test sol[pt1.output.u] ≈ pt1_func.(sol.t, 1.2, 3.14) atol = 1.0e-3 # Test logic for a_end by constructing an integrator @named c = Constant(; k = 1) @@ -456,10 +494,16 @@ end -k * (-1 + cos(t * w)) else d = complex(d) - real(k * (1 + - (-cosh(sqrt(-1 + d^2) * t * w) - - (d * sinh(sqrt(-1 + d^2) * t * w)) / sqrt(-1 + d^2)) / - exp(d * t * w))) + real( + k * ( + 1 + + ( + -cosh(sqrt(-1 + d^2) * t * w) - + (d * sinh(sqrt(-1 + d^2) * t * w)) / sqrt(-1 + d^2) + ) / + exp(d * t * w) + ) + ) end end @@ -470,7 +514,7 @@ end prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[pt1.output.u]≈pt2_func.(sol.t, k, w, d) atol=1e-3 + @test sol[pt1.output.u] ≈ pt2_func.(sol.t, k, w, d) atol = 1.0e-3 # test zeros (high-pass version of first test) @named c = Constant(; k = 1) @@ -480,8 +524,8 @@ end prob = ODEProblem(sys, Pair[], (0.0, 100.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[pt1.output.u]≈1 .- pt1_func.(sol.t, 1, 1) atol=1e-3 - @test sol[pt1.x[1]]≈pt1_func.(sol.t, 1, 1) atol=1e-3 # Test that scaling of state works properly + @test sol[pt1.output.u] ≈ 1 .- pt1_func.(sol.t, 1, 1) atol = 1.0e-3 + @test sol[pt1.x[1]] ≈ pt1_func.(sol.t, 1, 1) atol = 1.0e-3 # Test that scaling of state works properly # Test with no state @named pt1 = TransferFunction(b = [2.7], a = [pi]) diff --git a/test/Blocks/math.jl b/test/Blocks/math.jl index 608d6f5b8..e8e032248 100644 --- a/test/Blocks/math.jl +++ b/test/Blocks/math.jl @@ -12,9 +12,10 @@ using OrdinaryDiffEq: ReturnCode.Success @named model = System( [ connect(c.output, gain.input), - connect(gain.output, int.input) + connect(gain.output, int.input), ], - t, systems = [int, gain, c]) + t, systems = [int, gain, c] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 1.0], (0.0, 1.0)) @@ -30,16 +31,17 @@ end @named c = Constant(; k = 2) @named gain = Gain(; k = 1) @named int = Integrator(; k = 1) - @named fb = Feedback(;) + @named fb = Feedback() @named model = System( [ connect(c.output, fb.input1), connect(fb.input2, int.output), connect(fb.output, gain.input), - connect(gain.output, int.input) + connect(gain.output, int.input), ], t, - systems = [int, gain, c, fb]) + systems = [int, gain, c, fb] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 100.0)) @@ -53,16 +55,17 @@ end @testset "Add" begin @named c1 = Constant(; k = 1) @named c2 = Sine(; frequency = 1) - @named add = Add(;) + @named add = Add() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, add.input1), connect(c2.output, add.input2), - connect(add.output, int.input) + connect(add.output, int.input), ], t, - systems = [int, add, c1, c2]) + systems = [int, add, c1, c2] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -78,10 +81,11 @@ end [ connect(c1.output, add.input1), connect(c2.output, add.input2), - connect(add.output, int.input) + connect(add.output, int.input), ], t, - systems = [int, add, c1, c2]) + systems = [int, add, c1, c2] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -95,17 +99,18 @@ end @named c1 = Constant(; k = 1) @named c2 = Sine(; frequency = 1) @named c3 = Sine(; frequency = 2) - @named add = Add3(;) + @named add = Add3() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, add.input1), connect(c2.output, add.input2), connect(c3.output, add.input3), - connect(add.output, int.input) + connect(add.output, int.input), ], t, - systems = [int, add, c1, c2, c3]) + systems = [int, add, c1, c2, c3] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -123,33 +128,35 @@ end connect(c1.output, add.input1), connect(c2.output, add.input2), connect(c3.output, add.input3), - connect(add.output, int.input) + connect(add.output, int.input), ], t, - systems = [int, add, c1, c2, c3]) + systems = [int, add, c1, c2, c3] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @test isequal(unbound_inputs(sys), []) @test sol.retcode == Success @test sol[add.output.u] ≈ - k1 .* 1 .+ k2 .* sin.(2 * pi * sol.t) .+ k3 .* sin.(2 * pi * 2 * sol.t) + k1 .* 1 .+ k2 .* sin.(2 * pi * sol.t) .+ k3 .* sin.(2 * pi * 2 * sol.t) end end @testset "Product" begin @named c1 = Constant(; k = 2) @named c2 = Sine(; frequency = 1) - @named prod = Product(;) + @named prod = Product() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, prod.input1), connect(c2.output, prod.input2), - connect(prod.output, int.input) + connect(prod.output, int.input), ], t, - systems = [int, prod, c1, c2]) + systems = [int, prod, c1, c2] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -161,16 +168,17 @@ end @testset "Power" begin @named c1 = Sine(; frequency = 1) @named c2 = Constant(; k = 2) - @named pow = Power(;) + @named pow = Power() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, pow.base), connect(c2.output, pow.exponent), - connect(pow.output, int.input) + connect(pow.output, int.input), ], t, - systems = [int, pow, c1, c2]) + systems = [int, pow, c1, c2] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -182,14 +190,15 @@ end @testset "Modulo" begin @named c1 = Ramp(height = 2, duration = 1, offset = 1, start_time = 0, smooth = false) @named c2 = Constant(; k = 1) - @named modl = Modulo(;) + @named modl = Modulo() @named model = System( [ connect(c1.output, modl.dividend), - connect(c2.output, modl.divisor) + connect(c2.output, modl.divisor), ], t, - systems = [modl, c1, c2]) + systems = [modl, c1, c2] + ) sys = mtkcompile(model) prob = ODEProblem(sys, [], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -200,15 +209,16 @@ end @testset "UnaryMinus" begin @named c1 = Sine(; frequency = 1) - @named minu = UnaryMinus(;) + @named minu = UnaryMinus() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, minu.input), - connect(minu.output, int.input) + connect(minu.output, int.input), ], t, - systems = [int, minu, c1]) + systems = [int, minu, c1] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -219,15 +229,16 @@ end @testset "Floor" begin @named c1 = Sine(; frequency = 1) - @named flr = Floor(;) + @named flr = Floor() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, flr.input), - connect(flr.output, int.input) + connect(flr.output, int.input), ], t, - systems = [int, flr, c1]) + systems = [int, flr, c1] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -238,15 +249,16 @@ end @testset "Ceil" begin @named c1 = Sine(; frequency = 1) - @named cel = Ceil(;) + @named cel = Ceil() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, cel.input), - connect(cel.output, int.input) + connect(cel.output, int.input), ], t, - systems = [int, cel, c1]) + systems = [int, cel, c1] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -258,16 +270,17 @@ end @testset "Division" begin @named c1 = Sine(; frequency = 1) @named c2 = Constant(; k = 2) - @named div = Division(;) + @named div = Division() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, div.input1), connect(c2.output, div.input2), - connect(div.output, int.input) + connect(div.output, int.input), ], t, - systems = [int, div, c1, c2]) + systems = [int, div, c1, c2] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -278,15 +291,16 @@ end @testset "Abs" begin @named c = Sine(; frequency = 1) - @named absb = Abs(;) + @named absb = Abs() @named int = Integrator(; k = 1) @named model = System( [ connect(c.output, absb.input), - connect(absb.output, int.input) + connect(absb.output, int.input), ], t, - systems = [int, absb, c]) + systems = [int, absb, c] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -310,19 +324,19 @@ end @testset "Math" begin for (block, func) in [ - (Abs, abs), - (Sign, sign), - (Sin, sin), - (Cos, cos), - (Tan, tan), - (Asin, asin), - (Acos, acos), - (Atan, atan), - (Sinh, sinh), - (Cosh, cosh), - (Tanh, tanh), - (Exp, exp) - ] + (Abs, abs), + (Sign, sign), + (Sin, sin), + (Cos, cos), + (Tan, tan), + (Asin, asin), + (Acos, acos), + (Atan, atan), + (Sinh, sinh), + (Cosh, cosh), + (Tanh, tanh), + (Exp, exp), + ] @info "testing $block" @named source = Sine(frequency = 1, amplitude = 0.5) @named b = block() @@ -330,9 +344,10 @@ end @named model = System( [ connect(source.output, b.input), - connect(b.output, int.input) + connect(b.output, int.input), ], - t, systems = [int, b, source]) + t, systems = [int, b, source] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -350,9 +365,10 @@ end @named model = System( [ connect(source.output, b.input), - connect(b.output, int.input) + connect(b.output, int.input), ], - t, systems = [int, b, source]) + t, systems = [int, b, source] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0, b.input.u => 2.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -365,16 +381,17 @@ end @testset "Atan2" begin @named c1 = Sine(; frequency = 1, offset = 2) @named c2 = Sine(; frequency = 1, offset = 1) - @named b = Atan2(;) + @named b = Atan2() @named int = Integrator(; k = 1) @named model = System( [ connect(c1.output, b.input1), connect(c2.output, b.input2), - connect(b.output, int.input) + connect(b.output, int.input), ], t, - systems = [int, b, c1, c2]) + systems = [int, b, c1, c2] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[int.x => 0.0, b.input1.u => 2, b.input2.u => 1], (0.0, 1.0)) diff --git a/test/Blocks/nonlinear.jl b/test/Blocks/nonlinear.jl index b164f25da..2a65d4728 100644 --- a/test/Blocks/nonlinear.jl +++ b/test/Blocks/nonlinear.jl @@ -13,10 +13,11 @@ using OrdinaryDiffEq: ReturnCode.Success @named model = System( [ connect(c.output, int.input), - connect(int.output, sat.input) + connect(int.output, sat.input), ], t, - systems = [int, c, sat]) + systems = [int, c, sat] + ) sys = mtkcompile(model) prob = ODEProblem(sys, [int.x => 1.0], (0.0, 1.0)) @@ -34,10 +35,11 @@ using OrdinaryDiffEq: ReturnCode.Success @named iosys = System( [ connect(source.output, lim.input), - connect(lim.output, int.input) + connect(lim.output, int.input), ], t, - systems = [source, lim, int]) + systems = [source, lim, int] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, unknowns(sys) .=> 0.0, (0.0, 10.0)) @@ -45,8 +47,12 @@ using OrdinaryDiffEq: ReturnCode.Success sol = solve(prob, Rodas4()) @test SciMLBase.successful_retcode(sol) @test all(abs.(sol[lim.output.u]) .<= 0.5) - @test all(isapprox.(sol[lim.output.u], clamp.(sol[source.output.u], y_min, y_max), - atol = 1e-2)) + @test all( + isapprox.( + sol[lim.output.u], clamp.(sol[source.output.u], y_min, y_max), + atol = 1.0e-2 + ) + ) # Plots.plot(sol; vars=[source.output.u, lim.output.u]) # Plots.scatter(sol[source.output.u], sol[lim.output.u]) @@ -62,10 +68,11 @@ end @named model = System( [ connect(c.output, int.input), - connect(int.output, dz.input) + connect(int.output, dz.input), ], t, - systems = [int, c, dz]) + systems = [int, c, dz] + ) sys = mtkcompile(model) prob = ODEProblem(sys, [int.x => 1.0], (0.0, 1.0)) sol = solve(prob, Rodas4()) @@ -82,10 +89,11 @@ end @named model = System( [ connect(source.output, dz.input), - connect(dz.output, int.input) + connect(dz.output, int.input), ], t, - systems = [int, source, dz]) + systems = [int, source, dz] + ) sys = mtkcompile(model) prob = ODEProblem(sys, [int.x => 1.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @@ -93,8 +101,12 @@ end @test SciMLBase.successful_retcode(sol) @test all(sol[dz.output.u] .<= 2) @test all(sol[dz.output.u] .>= -1) - @test all(isapprox.(sol[dz.output.u], - _dead_zone.(sol[source.output.u], u_min, u_max), atol = 1e-2)) + @test all( + isapprox.( + sol[dz.output.u], + _dead_zone.(sol[source.output.u], u_min, u_max), atol = 1.0e-2 + ) + ) # Plots.plot(sol; vars=[source.output.u, dz.output.u]) # Plots.scatter(sol[source.output.u], sol[dz.output.u]) @@ -105,18 +117,20 @@ end @testset "SlewRateLimiter" begin @named source = Sine(; frequency = 1 / 2) @named rl = SlewRateLimiter(; rising = 1, falling = -1, Td = 0.001, y_start = -1 / 3) - @named iosys = System([ - connect(source.output, rl.input) + @named iosys = System( + [ + connect(source.output, rl.input), ], t, - systems = [source, rl]) + systems = [source, rl] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[], (0.0, 10.0)) tS = 0.01 - sol = solve(prob, Rodas4(), saveat = tS, abstol = 1e-10, reltol = 1e-10) + sol = solve(prob, Rodas4(), saveat = tS, abstol = 1.0e-10, reltol = 1.0e-10) @test SciMLBase.successful_retcode(sol) @test all(abs.(sol[rl.output.u]) .<= 0.51) - @test all(-1 - 1e-5 .<= diff(sol[rl.output.u]) ./ tS .<= 1 + 1e-5) # just an approximation + @test all(-1 - 1.0e-5 .<= diff(sol[rl.output.u]) ./ tS .<= 1 + 1.0e-5) # just an approximation end diff --git a/test/Blocks/sources.jl b/test/Blocks/sources.jl index 1742dde89..f2120b752 100644 --- a/test/Blocks/sources.jl +++ b/test/Blocks/sources.jl @@ -3,8 +3,8 @@ using SciCompDSL using ModelingToolkitStandardLibrary.Blocks using ModelingToolkit: t_nounits as t, D_nounits as D using ModelingToolkitStandardLibrary.Blocks: smooth_sin, smooth_cos, smooth_damped_sin, - smooth_square, smooth_step, smooth_ramp, - smooth_triangular, triangular, square + smooth_square, smooth_step, smooth_ramp, + smooth_triangular, triangular, square using OrdinaryDiffEq: ReturnCode.Success using DataInterpolations using DataFrames @@ -16,18 +16,20 @@ using ADTypes @testset "Constant" begin @named src = Constant(k = 2) @named int = Integrator() - @named iosys = System([ - connect(src.output, int.input) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u][end]≈2 atol=1e-3 + @test sol[src.output.u][end] ≈ 2 atol = 1.0e-3 end @testset "TimeVaryingFunction" begin @@ -36,26 +38,31 @@ end @named src = TimeVaryingFunction(f) @named int = Integrator() @named iosys = System( - [y ~ src.output.u - D(y) ~ dy - D(dy) ~ ddy - connect(src.output, int.input)], + [ + y ~ src.output.u + D(y) ~ dy + D(dy) ~ ddy + connect(src.output, int.input) + ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, unknowns(sys) .=> 0.0, (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u]≈f.(sol.t) atol=1e-3 - @test sol[int.output.u][end]≈1 / 3 * 10^3 + 10 atol=1e-3 # closed-form solution to integral + @test sol[src.output.u] ≈ f.(sol.t) atol = 1.0e-3 + @test sol[int.output.u][end] ≈ 1 / 3 * 10^3 + 10 atol = 1.0e-3 # closed-form solution to integral end @testset "Sine" begin function sine(t, frequency, amplitude, phase, offset, start_time) - offset + ifelse(t < start_time, 0, - amplitude * sin(2 * pi * frequency * (t - start_time) + phase)) + offset + ifelse( + t < start_time, 0, + amplitude * sin(2 * pi * frequency * (t - start_time) + phase) + ) end frequency = 1 @@ -63,50 +70,61 @@ end phase = 0 offset = 1 start_time = 2 - δ = 1e-5 + δ = 1.0e-5 @named int = Integrator() - @named src = Sine(frequency = frequency, amplitude = amplitude, phase = phase, - offset = offset, start_time = start_time) - @named iosys = System([ - connect(src.output, int.input) + @named src = Sine( + frequency = frequency, amplitude = amplitude, phase = phase, + offset = offset, start_time = start_time + ) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u]≈sine.(sol.t, frequency, amplitude, phase, offset, start_time) atol=1e-3 + @test sol[src.output.u] ≈ sine.(sol.t, frequency, amplitude, phase, offset, start_time) atol = 1.0e-3 - @named smooth_src = Sine(frequency = frequency, + @named smooth_src = Sine( + frequency = frequency, amplitude = amplitude, phase = phase, offset = offset, start_time = start_time, - smooth = true) - @named smooth_iosys = System([ - connect(smooth_src.output, int.input) + smooth = true + ) + @named smooth_iosys = System( + [ + connect(smooth_src.output, int.input), ], t, - systems = [int, smooth_src]) + systems = [int, smooth_src] + ) smooth_sys = mtkcompile(smooth_iosys) smooth_prob = ODEProblem(smooth_sys, Pair[int.x => 0.0], (0.0, 10.0)) smooth_sol = solve(smooth_prob, Rodas4()) @test sol.retcode == Success - @test smooth_sol[smooth_src.output.u]≈smooth_sin.( + @test smooth_sol[smooth_src.output.u] ≈ smooth_sin.( smooth_sol.t, δ, frequency, amplitude, - phase, offset, start_time) atol=1e-3 + phase, offset, start_time + ) atol = 1.0e-3 end @testset "Cosine" begin function cosine(t, frequency, amplitude, phase, offset, start_time) - offset + ifelse(t < start_time, 0, - amplitude * cos(2 * pi * frequency * (t - start_time) + phase)) + offset + ifelse( + t < start_time, 0, + amplitude * cos(2 * pi * frequency * (t - start_time) + phase) + ) end frequency = 1 @@ -114,47 +132,56 @@ end phase = 0 offset = 1 start_time = 2 - δ = 1e-5 + δ = 1.0e-5 @named int = Integrator() - @named src = Cosine(frequency = frequency, + @named src = Cosine( + frequency = frequency, amplitude = amplitude, phase = phase, offset = offset, start_time = start_time, - smooth = false) - @named iosys = System([ - connect(src.output, int.input) + smooth = false + ) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u]≈cosine.(sol.t, frequency, amplitude, phase, offset, start_time) atol=1e-3 + @test sol[src.output.u] ≈ cosine.(sol.t, frequency, amplitude, phase, offset, start_time) atol = 1.0e-3 - @named smooth_src = Cosine(frequency = frequency, + @named smooth_src = Cosine( + frequency = frequency, amplitude = amplitude, phase = phase, offset = offset, start_time = start_time, - smooth = true) - @named smooth_iosys = System([ - connect(smooth_src.output, int.input) + smooth = true + ) + @named smooth_iosys = System( + [ + connect(smooth_src.output, int.input), ], t, - systems = [int, smooth_src]) + systems = [int, smooth_src] + ) smooth_sys = mtkcompile(smooth_iosys) smooth_prob = ODEProblem(smooth_sys, Pair[int.x => 0.0], (0.0, 10.0)) smooth_sol = solve(smooth_prob, Rodas4()) @test smooth_sol.retcode == Success - @test smooth_sol[smooth_src.output.u]≈smooth_cos.( + @test smooth_sol[smooth_src.output.u] ≈ smooth_cos.( smooth_sol.t, δ, frequency, amplitude, - phase, offset, start_time) atol=1e-3 + phase, offset, start_time + ) atol = 1.0e-3 end @testset "ContinuousClock" begin @@ -164,109 +191,137 @@ end @named src = ContinuousClock(offset = offset, start_time = start_time) @named int = Integrator() - @named iosys = System([ - connect(src.output, int.input) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u]≈cont_clock.(sol.t, offset, start_time) atol=1e-3 + @test sol[src.output.u] ≈ cont_clock.(sol.t, offset, start_time) atol = 1.0e-3 end @testset "Ramp" begin function ramp(t, offset, height, duration, start_time) - offset + ifelse(t < start_time, 0, - ifelse(t < (start_time + duration), (t - start_time) * height / duration, - height)) + offset + ifelse( + t < start_time, 0, + ifelse( + t < (start_time + duration), (t - start_time) * height / duration, + height + ) + ) end - offset, height, duration, start_time, δ = 1, 2, 2, 0, 1e-5 + offset, height, duration, start_time, δ = 1, 2, 2, 0, 1.0e-5 @named int = Integrator() - @named src = Ramp(offset = offset, height = height, duration = duration, - start_time = start_time) - @named iosys = System([ - connect(src.output, int.input) + @named src = Ramp( + offset = offset, height = height, duration = duration, + start_time = start_time + ) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u]≈ramp.(sol.t, offset, height, duration, start_time) atol=1e-3 + @test sol[src.output.u] ≈ ramp.(sol.t, offset, height, duration, start_time) atol = 1.0e-3 start_time = 2 - @named smooth_src = Ramp(offset = offset, height = height, duration = duration, - start_time = start_time, smooth = true) - @named smooth_iosys = System([ - connect(smooth_src.output, int.input) + @named smooth_src = Ramp( + offset = offset, height = height, duration = duration, + start_time = start_time, smooth = true + ) + @named smooth_iosys = System( + [ + connect(smooth_src.output, int.input), ], t, - systems = [int, smooth_src]) + systems = [int, smooth_src] + ) smooth_sys = mtkcompile(smooth_iosys) smooth_prob = ODEProblem(smooth_sys, Pair[int.x => 0.0], (0.0, 10.0)) smooth_sol = solve(smooth_prob, Rodas4()) @test smooth_sol.retcode == Success - @test smooth_sol[smooth_src.output.u]≈smooth_ramp.(smooth_sol.t, δ, height, duration, - offset, start_time) atol=1e-3 + @test smooth_sol[smooth_src.output.u] ≈ smooth_ramp.( + smooth_sol.t, δ, height, duration, + offset, start_time + ) atol = 1.0e-3 end @testset "Step" begin step(t, offset, height, start_time) = offset + ifelse(t < start_time, 0, height) - offset, height, start_time, δ = 1, 2, 5, 1e-5 + offset, height, start_time, δ = 1, 2, 5, 1.0e-5 @named int = Integrator() - @named src = Step(offset = offset, height = height, start_time = start_time, - smooth = false) - @named iosys = System([ - connect(src.output, int.input) + @named src = Step( + offset = offset, height = height, start_time = start_time, + smooth = false + ) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u]≈step.(sol.t, offset, height, start_time) atol=1e-2 + @test sol[src.output.u] ≈ step.(sol.t, offset, height, start_time) atol = 1.0e-2 @test sol(start_time, idxs = src.output.u) == height + offset # Test that the step is applied at the start time # test with duration duration = 1.2 - @named src = Step(offset = offset, height = height, start_time = start_time, - duration = duration, smooth = false) - @named iosys = System([ - connect(src.output, int.input) + @named src = Step( + offset = offset, height = height, start_time = start_time, + duration = duration, smooth = false + ) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4(), dtmax = 0.1) # set dtmax to prevent the solver from overstepping the entire step disturbance @test sol.retcode == Success - @test sol[src.output.u]≈step.(sol.t, offset, height, start_time) - - step.(sol.t, 0, height, start_time + duration) atol=1e-2 - - @named smooth_src = Step(offset = offset, height = height, start_time = start_time, - smooth = true) - @named smooth_iosys = System([ - connect(smooth_src.output, int.input) + @test sol[src.output.u] ≈ step.(sol.t, offset, height, start_time) - + step.(sol.t, 0, height, start_time + duration) atol = 1.0e-2 + + @named smooth_src = Step( + offset = offset, height = height, start_time = start_time, + smooth = true + ) + @named smooth_iosys = System( + [ + connect(smooth_src.output, int.input), ], t, - systems = [int, smooth_src]) + systems = [int, smooth_src] + ) smooth_sys = mtkcompile(smooth_iosys) smooth_prob = ODEProblem(smooth_sys, Pair[int.x => 0.0], (0.0, 10.0)) @@ -274,16 +329,20 @@ end @test smooth_sol.retcode == Success @test smooth_sol[smooth_src.output.u] ≈ - smooth_step.(smooth_sol.t, δ, height, offset, start_time) + smooth_step.(smooth_sol.t, δ, height, offset, start_time) # with duration - @named smooth_src = Step(offset = offset, height = height, start_time = start_time, - smooth = true, duration = duration) - @named smooth_iosys = System([ - connect(smooth_src.output, int.input) + @named smooth_src = Step( + offset = offset, height = height, start_time = start_time, + smooth = true, duration = duration + ) + @named smooth_iosys = System( + [ + connect(smooth_src.output, int.input), ], t, - systems = [int, smooth_src]) + systems = [int, smooth_src] + ) smooth_sys = mtkcompile(smooth_iosys) smooth_prob = ODEProblem(smooth_sys, Pair[int.x => 0.0], (0.0, 10.0)) @@ -291,8 +350,8 @@ end @test smooth_sol.retcode == Success @test smooth_sol[smooth_src.output.u] ≈ - smooth_step.(smooth_sol.t, δ, height, offset, start_time) - - smooth_step.(smooth_sol.t, δ, height, 0, start_time + duration) + smooth_step.(smooth_sol.t, δ, height, offset, start_time) - + smooth_step.(smooth_sol.t, δ, height, 0, start_time + duration) end @testset "Square" begin @@ -300,39 +359,49 @@ end amplitude = 2 offset = 1 start_time = 2.5 - δ = 1e-5 + δ = 1.0e-5 @named int = Integrator() - @named src = Square(frequency = frequency, amplitude = amplitude, - offset = offset, start_time = start_time) - @named iosys = System([ - connect(src.output, int.input) + @named src = Square( + frequency = frequency, amplitude = amplitude, + offset = offset, start_time = start_time + ) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u]≈square.(sol.t, frequency, amplitude, offset, start_time) atol=1e-3 - - @named smooth_src = Square(frequency = frequency, amplitude = amplitude, - offset = offset, start_time = start_time, smooth = true) - @named smooth_iosys = System([ - connect(smooth_src.output, int.input) + @test sol[src.output.u] ≈ square.(sol.t, frequency, amplitude, offset, start_time) atol = 1.0e-3 + + @named smooth_src = Square( + frequency = frequency, amplitude = amplitude, + offset = offset, start_time = start_time, smooth = true + ) + @named smooth_iosys = System( + [ + connect(smooth_src.output, int.input), ], t, - systems = [int, smooth_src]) + systems = [int, smooth_src] + ) smooth_sys = mtkcompile(smooth_iosys) smooth_prob = ODEProblem(smooth_sys, Pair[int.x => 0.0], (0.0, 10.0)) smooth_sol = solve(smooth_prob, Rodas4()) @test smooth_sol.retcode == Success - @test smooth_sol[smooth_src.output.u]≈smooth_square.(smooth_sol.t, δ, frequency, - amplitude, offset, start_time) atol=1e-3 + @test smooth_sol[smooth_src.output.u] ≈ smooth_square.( + smooth_sol.t, δ, frequency, + amplitude, offset, start_time + ) atol = 1.0e-3 end @testset "Triangular" begin @@ -340,86 +409,110 @@ end amplitude = 1 offset = 2 start_time = 1 - δ = 1e-5 + δ = 1.0e-5 @named int = Integrator() - @named src = Triangular(frequency = frequency, amplitude = amplitude, - offset = offset, start_time = start_time) - @named iosys = System([ - connect(src.output, int.input) + @named src = Triangular( + frequency = frequency, amplitude = amplitude, + offset = offset, start_time = start_time + ) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 4.0)) sol = solve(prob, Rodas4(), saveat = 0.01) @test sol.retcode == Success - @test sol[src.output.u]≈triangular.(sol.t, frequency, amplitude, offset, start_time) atol=1e-3 - - @named smooth_src = Triangular(frequency = frequency, amplitude = amplitude, - offset = offset, start_time = start_time, smooth = true) - @named smooth_iosys = System([ - connect(smooth_src.output, int.input) + @test sol[src.output.u] ≈ triangular.(sol.t, frequency, amplitude, offset, start_time) atol = 1.0e-3 + + @named smooth_src = Triangular( + frequency = frequency, amplitude = amplitude, + offset = offset, start_time = start_time, smooth = true + ) + @named smooth_iosys = System( + [ + connect(smooth_src.output, int.input), ], t, - systems = [int, smooth_src]) + systems = [int, smooth_src] + ) smooth_sys = mtkcompile(smooth_iosys) smooth_prob = ODEProblem(smooth_sys, Pair[int.x => 0.0], (0.0, 4.0)) smooth_sol = solve(smooth_prob, Rodas4(), saveat = 0.01) @test smooth_sol.retcode == Success - @test smooth_sol[smooth_src.output.u]≈smooth_triangular.(smooth_sol.t, δ, frequency, - amplitude, offset, start_time) atol=1e-3 + @test smooth_sol[smooth_src.output.u] ≈ smooth_triangular.( + smooth_sol.t, δ, frequency, + amplitude, offset, start_time + ) atol = 1.0e-3 end @testset "ExpSine" begin function exp_sine(t, amplitude, frequency, damping, phase, start_time) - offset + ifelse(t < start_time, 0, + offset + ifelse( + t < start_time, 0, amplitude * exp(-damping * (t - start_time)) * - sin(2 * pi * frequency * (t - start_time) + phase)) + sin(2 * pi * frequency * (t - start_time) + phase) + ) end - frequency, amplitude, damping = 3, 2, 0.10 - phase, offset, start_time, δ = 0, 0, 0, 1e-5 - @named src = ExpSine(frequency = frequency, amplitude = amplitude, damping = damping, - phase = phase, offset = offset, start_time = start_time) + frequency, amplitude, damping = 3, 2, 0.1 + phase, offset, start_time, δ = 0, 0, 0, 1.0e-5 + @named src = ExpSine( + frequency = frequency, amplitude = amplitude, damping = damping, + phase = phase, offset = offset, start_time = start_time + ) @named int = Integrator() - @named iosys = System([ - connect(src.output, int.input) + @named iosys = System( + [ + connect(src.output, int.input), ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) prob = ODEProblem(sys, Pair[int.x => 0.0], (0.0, 10.0)) sol = solve(prob, Rodas4()) @test sol.retcode == Success - @test sol[src.output.u]≈exp_sine.(sol.t, amplitude, frequency, damping, phase, - start_time) atol=1e-3 + @test sol[src.output.u] ≈ exp_sine.( + sol.t, amplitude, frequency, damping, phase, + start_time + ) atol = 1.0e-3 offset, start_time = 1, 2 - @named smooth_src = ExpSine(frequency = frequency, amplitude = amplitude, + @named smooth_src = ExpSine( + frequency = frequency, amplitude = amplitude, damping = damping, phase = phase, offset = offset, - start_time = start_time, smooth = true) - @named smooth_iosys = System([ - connect(smooth_src.output, int.input) + start_time = start_time, smooth = true + ) + @named smooth_iosys = System( + [ + connect(smooth_src.output, int.input), ], t, - systems = [int, smooth_src]) + systems = [int, smooth_src] + ) smooth_sys = mtkcompile(smooth_iosys) smooth_prob = ODEProblem(smooth_sys, Pair[int.x => 0.0], (0.0, 10.0)) smooth_sol = solve(smooth_prob, Rodas4()) @test smooth_sol.retcode == Success - @test smooth_sol[smooth_src.output.u]≈smooth_damped_sin.(smooth_sol.t, δ, frequency, + @test smooth_sol[smooth_src.output.u] ≈ smooth_damped_sin.( + smooth_sol.t, δ, frequency, amplitude, damping, phase, - offset, start_time) atol=1e-3 + offset, start_time + ) atol = 1.0e-3 end @testset "SampledData" begin - dt = 4e-4 + dt = 4.0e-4 t_end = 10.0 time = 0:dt:t_end x = @. time^2 + 1.0 @@ -429,28 +522,33 @@ end @named src = SampledData(Float64) @named int = Integrator() @named iosys = System( - [y ~ src.output.u - D(y) ~ dy - D(dy) ~ ddy - connect(src.output, int.input)], + [ + y ~ src.output.u + D(y) ~ dy + D(dy) ~ ddy + connect(src.output, int.input) + ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) s = complete(iosys) - prob = ODEProblem(sys, + prob = ODEProblem( + sys, [s.src.buffer => Parameter(x, dt)], (0.0, t_end); - tofloat = false) + tofloat = false + ) # prob = remake(prob; p = Parameter.(prob.p)) #<-- no longer needed with ModelingToolkit.jl PR #2231 sol = solve(prob, Rodas4()) @test sol.retcode == Success @test sol[src.output.u][1] == 1.0 #check correct initial condition - @test sol(time)[src.output.u]≈x atol=1e-3 - @test sol[int.output.u][end]≈1 / 3 * 10^3 + 10.0 atol=1e-3 # closed-form solution to integral - @test sol[dy][end]≈2 * time[end] atol=1e-3 - @test sol[ddy][end]≈2 atol=1e-3 + @test sol(time)[src.output.u] ≈ x atol = 1.0e-3 + @test sol[int.output.u][end] ≈ 1 / 3 * 10^3 + 10.0 atol = 1.0e-3 # closed-form solution to integral + @test sol[dy][end] ≈ 2 * time[end] atol = 1.0e-3 + @test sol[ddy][end] ≈ 2 atol = 1.0e-3 end @testset "using Vector Based" begin @@ -458,27 +556,32 @@ end @named src = SampledData(dt) @named int = Integrator() @named iosys = System( - [y ~ src.output.u - D(y) ~ dy - D(dy) ~ ddy - connect(src.output, int.input)], + [ + y ~ src.output.u + D(y) ~ dy + D(dy) ~ ddy + connect(src.output, int.input) + ], t, - systems = [int, src]) + systems = [int, src] + ) sys = mtkcompile(iosys) s = complete(iosys) - prob = ODEProblem(sys, + prob = ODEProblem( + sys, [s.src.buffer => x, s.src.sample_time => dt], (0.0, t_end); - tofloat = false) + tofloat = false + ) sol = solve(prob, Rodas4()) @test sol.retcode == Success @test sol[src.output.u][1] == 1.0 #check correct initial condition - @test sol(time)[src.output.u]≈x atol=1e-3 - @test sol[int.output.u][end]≈1 / 3 * 10^3 + 10.0 atol=1e-3 # closed-form solution to integral - @test sol[dy][end]≈2 * time[end] atol=1e-3 - @test sol[ddy][end]≈2 atol=1e-3 + @test sol(time)[src.output.u] ≈ x atol = 1.0e-3 + @test sol[int.output.u][end] ≈ 1 / 3 * 10^3 + 10.0 atol = 1.0e-3 # closed-form solution to integral + @test sol[dy][end] ≈ 2 * time[end] atol = 1.0e-3 + @test sol[ddy][end] ≈ 2 atol = 1.0e-3 end end @@ -502,13 +605,15 @@ end @testset "Interpolation in model macro" begin function MassSpringDamper(; name) @named input = RealInput() - @variables f(t) x(t)=0 dx(t)=0 ddx(t) - @parameters m=10 k=1000 d=1 + @variables f(t) x(t) = 0 dx(t) = 0 ddx(t) + @parameters m = 10 k = 1000 d = 1 - eqs = [f ~ input.u - ddx * 10 ~ k * x + d * dx + f - D(x) ~ dx - D(dx) ~ ddx] + eqs = [ + f ~ input.u + ddx * 10 ~ k * x + d * dx + f + D(x) ~ dx + D(dx) ~ ddx + ] System(eqs, t; name, systems = [input]) end @@ -527,7 +632,7 @@ end connect(src.input, clk.output) connect(src.output, model.input) end - end; + end @mtkcompile sys = model_with_lut() prob = ODEProblem(sys, [], (0.0, 1)) @@ -581,7 +686,8 @@ end set_data! = setp(prob, i.data) of = OptimizationFunction(loss, AutoForwardDiff()) op = OptimizationProblem( - of, u, (prob, set_data!), lb = zeros(15), ub = fill(2.0, 15)) + of, u, (prob, set_data!), lb = zeros(15), ub = fill(2.0, 15) + ) # check that type changing works @test length(ForwardDiff.gradient(x -> of(x, (prob, set_data!)), u)) == 15 @@ -594,7 +700,8 @@ end @testset "BSplineInterpolation" begin @named i = ParametrizedInterpolation( - BSplineInterpolation, u, x, 3, :Uniform, :Uniform) + BSplineInterpolation, u, x, 3, :Uniform, :Uniform + ) eqs = [i.input.u ~ t, D(y) ~ i.output.u] @named model = System(eqs, t, systems = [i]) @@ -609,13 +716,15 @@ end @testset "Initialization" begin function MassSpringDamper(; name) @named input = RealInput() - vars = @variables f(t) x(t)=0 dx(t) [guess = 0] ddx(t) - pars = @parameters m=10 k=1000 d=1 + vars = @variables f(t) x(t) = 0 dx(t) [guess = 0] ddx(t) + pars = @parameters m = 10 k = 1000 d = 1 - eqs = [f ~ input.u - ddx * 10 ~ k * x + d * dx + f - D(x) ~ dx - D(dx) ~ ddx] + eqs = [ + f ~ input.u + ddx * 10 ~ k * x + d * dx + f + D(x) ~ dx + D(dx) ~ ddx + ] System(eqs, t, vars, pars; name, systems = [input]) end @@ -625,14 +734,16 @@ end @named clk = ContinuousClock() @named model = MassSpringDamper() - eqs = [connect(model.input, src.output) - connect(src.input, clk.output)] + eqs = [ + connect(model.input, src.output) + connect(src.input, clk.output) + ] System(eqs, t; name, systems = [src, clk, model]) end function generate_data() - dt = 4e-4 + dt = 4.0e-4 time = 0:dt:0.1 data = sin.(2 * pi * time * 100) diff --git a/test/Blocks/test_analysis_points.jl b/test/Blocks/test_analysis_points.jl index b2fa43fa4..83dd7b539 100644 --- a/test/Blocks/test_analysis_points.jl +++ b/test/Blocks/test_analysis_points.jl @@ -13,15 +13,17 @@ using ControlSystemsBase # Test with explicitly created AnalysisPoint ap = AnalysisPoint(:plant_input) -eqs = [connect(P.output, C.input) - connect(C.output, ap, P.input)] +eqs = [ + connect(P.output, C.input) + connect(C.output, ap, P.input) +] sys = System(eqs, t, systems = [P, C], name = :hej) ssys = mtkcompile(sys) prob = ODEProblem(ssys, [P.x => 1], (0, 10)) sol = solve(prob, Rodas5()) @test norm(sol.u[1]) >= 1 -@test norm(sol.u[end]) < 1e-6 # This fails without the feedback through C +@test norm(sol.u[end]) < 1.0e-6 # This fails without the feedback through C # plot(sol) matrices, _ = get_sensitivity(sys, ap) @@ -44,8 +46,10 @@ T = comp_sensitivity(P, C) # or feedback(P*C) =# # Test with automatically created analysis point -eqs = [connect(P.output, C.input) - connect(C.output, :plant_input, P.input)] +eqs = [ + connect(P.output, C.input) + connect(C.output, :plant_input, P.input) +] sys = System(eqs, t, systems = [P, C], name = :hej) matrices, _ = get_sensitivity(sys, :plant_input) @@ -82,8 +86,10 @@ matrices, _ = linearize(open_sys, [u], [y]) @test matrices.D[] == 0 # Test with more than one AnalysisPoint -eqs = [connect(P.output, :plant_output, C.input) - connect(C.output, :plant_input, P.input)] +eqs = [ + connect(P.output, :plant_output, C.input) + connect(C.output, :plant_input, P.input) +] sys = System(eqs, t, systems = [P, C], name = :hej) matrices, _ = get_sensitivity(sys, :plant_input) @@ -108,9 +114,11 @@ matrices2, _ = linearize(sys, :plant_input, [P.output.u]) @named C = Gain(; k = 1) @named add = Blocks.Add(k2 = -1) -eqs = [connect(P.output, :plant_output, add.input2) - connect(add.output, C.input) - connect(C.output, :plant_input, P.input)] +eqs = [ + connect(P.output, :plant_output, add.input2) + connect(add.output, C.input) + connect(C.output, :plant_input, P.input) +] # eqs = [connect(P.output, add.input2) # connect(add.output, C.input) @@ -121,8 +129,10 @@ sys_inner = System(eqs, t, systems = [P, C, add], name = :inner) @named r = Constant(k = 1) @named F = FirstOrder(k = 1, T = 3) -eqs = [connect(r.output, F.input) - connect(F.output, sys_inner.add.input1)] +eqs = [ + connect(r.output, F.input) + connect(F.output, sys_inner.add.input1) +] sys_outer = System(eqs, t, systems = [F, sys_inner, r], name = :outer) # test first that the mtkcompile works correctly @@ -161,23 +171,27 @@ c = 10 # Damping coefficient @named torque = Torque() function SystemModel(u = nothing; name = :model) - eqs = [connect(torque.flange, inertia1.flange_a) - connect(inertia1.flange_b, spring.flange_a, damper.flange_a) - connect(inertia2.flange_a, spring.flange_b, damper.flange_b)] + eqs = [ + connect(torque.flange, inertia1.flange_a) + connect(inertia1.flange_b, spring.flange_a, damper.flange_a) + connect(inertia2.flange_a, spring.flange_b, damper.flange_b) + ] if u !== nothing push!(eqs, connect(torque.tau, u.output)) - return System(eqs, t; + return System( + eqs, t; systems = [ torque, inertia1, inertia2, spring, damper, - u + u, ], - name) + name + ) end - System(eqs, t; systems = [torque, inertia1, inertia2, spring, damper], name) + return System(eqs, t; systems = [torque, inertia1, inertia2, spring, damper], name) end @named r = Step(start_time = 0) @@ -187,26 +201,30 @@ model = SystemModel() @named sensor = AngleSensor() @named er = Add(k2 = -1) -connections = [connect(r.output, :r, filt.input) - connect(filt.output, er.input1) - connect(pid.ctr_output, :u, model.torque.tau) - connect(model.inertia2.flange_b, sensor.flange) - connect(sensor.phi, :y, er.input2) - connect(er.output, :e, pid.err_input)] - -closed_loop = System(connections, t, systems = [model, pid, filt, sensor, r, er], +connections = [ + connect(r.output, :r, filt.input) + connect(filt.output, er.input1) + connect(pid.ctr_output, :u, model.torque.tau) + connect(model.inertia2.flange_b, sensor.flange) + connect(sensor.phi, :y, er.input2) + connect(er.output, :e, pid.err_input) +] + +closed_loop = System( + connections, t, systems = [model, pid, filt, sensor, r, er], name = :closed_loop, initial_conditions = [ model.inertia1.phi => 0.0, model.inertia2.phi => 0.0, model.inertia1.w => 0.0, model.inertia2.w => 0.0, filt.x => 0.0, - filt.xd => 0.0 - ]) + filt.xd => 0.0, + ] +) sys = mtkcompile(closed_loop) prob = ODEProblem(sys, unknowns(sys) .=> 0.0, (0.0, 4.0)) -sol = solve(prob, Rodas5P(), reltol = 1e-6, abstol = 1e-9) +sol = solve(prob, Rodas5P(), reltol = 1.0e-6, abstol = 1.0e-9) # plot( # plot(sol, vars = [filt.y, model.inertia1.phi, model.inertia2.phi]), # plot(sol, vars = [pid.ctr_output.u], title = "Control signal"), @@ -218,7 +236,7 @@ lsys = ss(matrices...) |> sminreal @test lsys.nx == 8 stepres = ControlSystemsBase.step(c2d(lsys, 0.001), 4) -@test Array(stepres.y[:])≈Array(sol(0:0.001:4, idxs = model.inertia2.phi)) rtol=1e-4 +@test Array(stepres.y[:]) ≈ Array(sol(0:0.001:4, idxs = model.inertia2.phi)) rtol = 1.0e-4 # plot(stepres, plotx=true, ploty=true, size=(800, 1200), leftmargin=5Plots.mm) # plot!(sol, vars = [model.inertia2.phi], sp=1, l=:dash) @@ -236,11 +254,14 @@ Si = ss(matrices...) @named feedback = Feedback() @named ref = Step() @named sys_inner = System( - [connect(P_inner.output, :y, feedback.input2) - connect(feedback.output, :u, P_inner.input) - connect(ref.output, :r, feedback.input1)], + [ + connect(P_inner.output, :y, feedback.input2) + connect(feedback.output, :u, P_inner.input) + connect(ref.output, :r, feedback.input1) + ], t, - systems = [P_inner, feedback, ref]) + systems = [P_inner, feedback, ref] +) P_not_broken, _ = linearize(sys_inner, :u, :y) @test P_not_broken.A[] == -2 @@ -252,23 +273,34 @@ P_broken, _ = linearize(sys_inner, :u, :y, loop_openings = [:y]) Sinner = sminreal(ss(get_sensitivity(sys_inner, :u)[1]...)) @named sys_inner = System( - [connect(P_inner.output, :y, feedback.input2) - connect(feedback.output, :u, P_inner.input)], + [ + connect(P_inner.output, :y, feedback.input2) + connect(feedback.output, :u, P_inner.input) + ], t, - systems = [P_inner, feedback]) + systems = [P_inner, feedback] +) @named P_outer = FirstOrder(k = rand(), T = rand()) @named sys_outer = System( - [connect(sys_inner.P_inner.output, :y2, P_outer.input) - connect(P_outer.output, :u2, sys_inner.feedback.input1)], + [ + connect(sys_inner.P_inner.output, :y2, P_outer.input) + connect(P_outer.output, :u2, sys_inner.feedback.input1) + ], t, - systems = [P_outer, sys_inner]) + systems = [P_outer, sys_inner] +) Souter = sminreal(ss(get_sensitivity(sys_outer, sys_outer.sys_inner.u)[1]...)) -Sinner2 = sminreal(ss(get_sensitivity( - sys_outer, sys_outer.sys_inner.u, loop_openings = [:y2])[1]...)) +Sinner2 = sminreal( + ss( + get_sensitivity( + sys_outer, sys_outer.sys_inner.u, loop_openings = [:y2] + )[1]... + ) +) @test Sinner.nx == 1 @test Sinner == Sinner2 @@ -291,8 +323,10 @@ D = [0.0 0.0; 0.0 0.0] @named K = Blocks.StateSpace(A, B, C, D) Kss = CS.ss(A, B, C, D) -eqs = [connect(P.output, :plant_output, K.input) - connect(K.output, :plant_input, P.input)] +eqs = [ + connect(P.output, :plant_output, K.input) + connect(K.output, :plant_input, P.input) +] sys = System(eqs, t, systems = [P, K], name = :hej) matrices, _ = ModelingToolkit.get_sensitivity(sys, :plant_input) @@ -308,7 +342,8 @@ T = -CS.feedback(Kss * Pss, I(2), pos_feedback = true) @test CS.tf(CS.ss(matrices...)) ≈ CS.tf(T) matrices, _ = ModelingToolkit.get_looptransfer( - sys, :plant_input) + sys, :plant_input +) L = Kss * Pss @test CS.tf(CS.ss(matrices...)) ≈ CS.tf(L) @@ -321,22 +356,27 @@ G = CS.feedback(Pss, Kss, pos_feedback = true) @named C = Gain(; k = 1) @named add = Blocks.Add(k2 = -1) -eqs = [connect(P.output, :plant_output, add.input2) - connect(add.output, C.input) - connect(C.output, :plant_input, P.input)] +eqs = [ + connect(P.output, :plant_output, add.input2) + connect(add.output, C.input) + connect(C.output, :plant_input, P.input) +] sys_inner = System(eqs, t, systems = [P, C, add], name = :inner) @named r = Constant(k = 1) @named F = FirstOrder(k = 1, T = 3) -eqs = [connect(r.output, F.input) - connect(F.output, sys_inner.add.input1)] +eqs = [ + connect(r.output, F.input) + connect(F.output, sys_inner.add.input1) +] sys_outer = System(eqs, t, systems = [F, sys_inner, r], name = :outer) matrices, -_ = get_sensitivity( - sys_outer, [sys_outer.inner.plant_input, sys_outer.inner.plant_output]) + _ = get_sensitivity( + sys_outer, [sys_outer.inner.plant_input, sys_outer.inner.plant_output] +) Ps = tf(1, [1, 1]) |> ss Cs = tf(1) |> ss @@ -351,8 +391,9 @@ So = CS.feedback(1, Ps * Cs) @test tf(G[2, 1]) ≈ tf(CS.feedback(Ps, Cs)) matrices, -_ = get_comp_sensitivity( - sys_outer, [sys_outer.inner.plant_input, sys_outer.inner.plant_output]) + _ = get_comp_sensitivity( + sys_outer, [sys_outer.inner.plant_input, sys_outer.inner.plant_output] +) G = CS.ss(matrices...) |> sminreal Ti = CS.feedback(Cs * Ps) @@ -365,19 +406,22 @@ To = CS.feedback(Ps * Cs) # matrices, _ = get_looptransfer(sys_outer, [:inner_plant_input, :inner_plant_output]) matrices, _ = get_looptransfer( - sys_outer, sys_outer.inner.plant_input) + sys_outer, sys_outer.inner.plant_input +) L = CS.ss(matrices...) |> sminreal @test tf(L) ≈ -tf(Cs * Ps) matrices, _ = get_looptransfer( - sys_outer, sys_outer.inner.plant_output) + sys_outer, sys_outer.inner.plant_output +) L = CS.ss(matrices...) |> sminreal @test tf(L[1, 1]) ≈ -tf(Ps * Cs) # Calling looptransfer like below is not the intended way, but we can work out what it should return if we did so it remains a valid test matrices, -_ = get_looptransfer( - sys_outer, [sys_outer.inner.plant_input, sys_outer.inner.plant_output]) + _ = get_looptransfer( + sys_outer, [sys_outer.inner.plant_input, sys_outer.inner.plant_output] +) L = CS.ss(matrices...) |> sminreal @test tf(L[1, 1]) ≈ tf(0) @test tf(L[2, 2]) ≈ tf(0) @@ -385,7 +429,8 @@ L = CS.ss(matrices...) |> sminreal @test tf(L[2, 1]) ≈ tf(Ps) matrices, -_ = linearize( - sys_outer, [sys_outer.inner.plant_input], [sys_outer.inner.plant_output]) + _ = linearize( + sys_outer, [sys_outer.inner.plant_input], [sys_outer.inner.plant_output] +) G = CS.ss(matrices...) |> sminreal @test tf(G) ≈ tf(CS.feedback(Ps, Cs)) diff --git a/test/Blocks/utils.jl b/test/Blocks/utils.jl index 19b6ccfb4..4248177d5 100644 --- a/test/Blocks/utils.jl +++ b/test/Blocks/utils.jl @@ -7,9 +7,9 @@ using Symbolics @testset "Array Guesses" begin for (block, guess) in [ - (RealInputArray(; nin = 3, name = :a), zeros(3)), - (RealOutputArray(; nout = 3, name = :a), zeros(3)) - ] + (RealInputArray(; nin = 3, name = :a), zeros(3)), + (RealOutputArray(; nout = 3, name = :a), zeros(3)), + ] guesses = ModelingToolkit.guesses(block) @test Symbolics.value(guesses[@nonamespace block.u]) == guess end @@ -17,11 +17,11 @@ end @testset "Scalarized Guesses" begin for (block, guess) in [ - (RealInput(; name = :a), 0.0), - (RealInput(; nin = 3, name = :a), zeros(3)), - (RealOutput(; name = :a), 0.0), - (RealOutput(; nout = 3, name = :a), zeros(3)) - ] + (RealInput(; name = :a), 0.0), + (RealInput(; nin = 3, name = :a), zeros(3)), + (RealOutput(; name = :a), 0.0), + (RealOutput(; nout = 3, name = :a), zeros(3)), + ] guesses = ModelingToolkit.guesses(block) @test Symbolics.value(guesses[@nonamespace block.u][1]) == guess[1] end diff --git a/test/Electrical/analog.jl b/test/Electrical/analog.jl index db51640a4..4e9a4cf34 100644 --- a/test/Electrical/analog.jl +++ b/test/Electrical/analog.jl @@ -2,8 +2,8 @@ using ModelingToolkitStandardLibrary.Electrical, ModelingToolkit, OrdinaryDiffEq using SciCompDSL using ModelingToolkit: t_nounits as t, D_nounits as D using ModelingToolkitStandardLibrary.Blocks: Step, - Constant, Sine, Cosine, ExpSine, Ramp, - Square, Triangular + Constant, Sine, Cosine, ExpSine, Ramp, + Square, Triangular using ModelingToolkitStandardLibrary.Blocks: square, triangular using ModelingToolkitStandardLibrary.Thermal: FixedTemperature using OrdinaryDiffEq: ReturnCode.Success @@ -21,18 +21,21 @@ using OrdinaryDiffEq: ReturnCode.Success @named current_sensor = CurrentSensor() @named power_sensor = PowerSensor() - connections = [connect(source.output, voltage.V) - connect(voltage.p, resistor.p) - connect(resistor.n, current_sensor.p) - connect(current_sensor.n, power_sensor.pc) - connect(power_sensor.nc, capacitor.p) - connect(capacitor.n, voltage.n, ground.g) - connect(capacitor.p, voltage_sensor.p) - connect(capacitor.n, voltage_sensor.n) - connect(capacitor.p, power_sensor.pv) - connect(capacitor.n, power_sensor.nv)] - - @named model = System(connections, t; + connections = [ + connect(source.output, voltage.V) + connect(voltage.p, resistor.p) + connect(resistor.n, current_sensor.p) + connect(current_sensor.n, power_sensor.pc) + connect(power_sensor.nc, capacitor.p) + connect(capacitor.n, voltage.n, ground.g) + connect(capacitor.p, voltage_sensor.p) + connect(capacitor.n, voltage_sensor.n) + connect(capacitor.p, power_sensor.pv) + connect(capacitor.n, power_sensor.nv) + ] + + @named model = System( + connections, t; systems = [ resistor, capacitor, @@ -41,8 +44,9 @@ using OrdinaryDiffEq: ReturnCode.Success ground, voltage_sensor, current_sensor, - power_sensor - ]) + power_sensor, + ] + ) sys = mtkcompile(model) prob = ODEProblem(sys, [], (0.0, 10.0)) sol = solve(prob, Tsit5()) @@ -51,39 +55,44 @@ using OrdinaryDiffEq: ReturnCode.Success # Plots.plot(sol; vars=[power_sensor.power, capacitor.i * capacitor.v]) # Plots.plot(sol; vars=[resistor.i, current_sensor.i]) @test SciMLBase.successful_retcode(sol) - @test sol[capacitor.v]≈sol[voltage_sensor.v] atol=1e-3 - @test sol[power_sensor.power]≈sol[capacitor.i * capacitor.v] atol=1e-3 - @test sol[resistor.i]≈sol[current_sensor.i] atol=1e-3 + @test sol[capacitor.v] ≈ sol[voltage_sensor.v] atol = 1.0e-3 + @test sol[power_sensor.power] ≈ sol[capacitor.i * capacitor.v] atol = 1.0e-3 + @test sol[resistor.i] ≈ sol[current_sensor.i] atol = 1.0e-3 end # simple voltage divider @testset "voltage divider with a short branch" begin @named source = Constant(k = 10) @named voltage = Voltage() - @named R0 = Resistor(R = 1e3) - @named R1 = Resistor(R = 1e3) - @named R2 = Resistor(R = 1e3) + @named R0 = Resistor(R = 1.0e3) + @named R1 = Resistor(R = 1.0e3) + @named R2 = Resistor(R = 1.0e3) @named ground = Ground() @named short = Short() - connections = [connect(source.output, voltage.V) - connect(voltage.p, R1.p) - connect(R1.n, short.p, R0.p) - connect(short.n, R0.n, R2.p) - connect(R2.n, voltage.n, ground.g)] + connections = [ + connect(source.output, voltage.V) + connect(voltage.p, R1.p) + connect(R1.n, short.p, R0.p) + connect(short.n, R0.n, R2.p) + connect(R2.n, voltage.n, ground.g) + ] - @named model = System(connections, t, + @named model = System( + connections, t, systems = [R0, R1, R2, source, short, voltage, ground]; guesses = [ - R2.v => 0.0, R1.v => 0.0]) + R2.v => 0.0, R1.v => 0.0, + ] + ) sys = mtkcompile(model) prob = ODEProblem(sys, [], (0, 2.0)) sol = solve(prob, Rodas4()) # has no state; does not work with Tsit5 @test SciMLBase.successful_retcode(sol) @test sol[short.v] == sol[R0.v] == zeros(length(sol.t)) @test sol[R0.i] == zeros(length(sol.t)) - @test sol[R1.p.v][end]≈10 atol=1e-3 - @test sol[R1.n.v][end]≈5 atol=1e-3 - @test sol[R2.n.v][end]≈0 atol=1e-3 + @test sol[R1.p.v][end] ≈ 10 atol = 1.0e-3 + @test sol[R1.n.v][end] ≈ 5 atol = 1.0e-3 + @test sol[R2.n.v][end] ≈ 0 atol = 1.0e-3 end # simple RC @@ -94,20 +103,24 @@ end @named capacitor = Capacitor(C = 1, v = 0.0) @named ground = Ground() - connections = [connect(source.output, voltage.V) - connect(voltage.p, resistor.p) - connect(resistor.n, capacitor.p) - connect(capacitor.n, voltage.n, ground.g)] - - @named model = System(connections, t; - systems = [resistor, capacitor, source, voltage, ground]) + connections = [ + connect(source.output, voltage.V) + connect(voltage.p, resistor.p) + connect(resistor.n, capacitor.p) + connect(capacitor.n, voltage.n, ground.g) + ] + + @named model = System( + connections, t; + systems = [resistor, capacitor, source, voltage, ground] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 10.0)) sol = solve(prob, Tsit5()) # Plots.plot(sol; vars=[source.v, capacitor.v]) @test SciMLBase.successful_retcode(sol) - @test sol[capacitor.v][end]≈10 atol=1e-3 + @test sol[capacitor.v][end] ≈ 10 atol = 1.0e-3 end # simple RL @@ -118,33 +131,43 @@ end @named inductor = Inductor(L = 1.0, i = 0.0) @named ground = Ground() - connections = [connect(source.output, voltage.V) - connect(voltage.p, resistor.p) - connect(resistor.n, inductor.p) - connect(inductor.n, voltage.n, ground.g)] - - @named model = System(connections, t; - systems = [resistor, inductor, source, voltage, ground]) + connections = [ + connect(source.output, voltage.V) + connect(voltage.p, resistor.p) + connect(resistor.n, inductor.p) + connect(inductor.n, voltage.n, ground.g) + ] + + @named model = System( + connections, t; + systems = [resistor, inductor, source, voltage, ground] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 10.0)) sol = solve(prob, Tsit5()) # Plots.plot(sol; vars=[inductor.i, inductor.i]) @test SciMLBase.successful_retcode(sol) - @test sol[inductor.i][end]≈10 atol=1e-3 + @test sol[inductor.i][end] ≈ 10 atol = 1.0e-3 end @testset "RC with voltage sources" begin R, C = 1, 1 @named voltage = Voltage() @named source_const = Constant(k = 10) - @named source_sin = Sine(offset = 1, amplitude = 10, frequency = 2, start_time = 0.5, - phase = 0) + @named source_sin = Sine( + offset = 1, amplitude = 10, frequency = 2, start_time = 0.5, + phase = 0 + ) @named source_step = Step(offset = 1, height = 10, start_time = 0.5) - @named source_tri = Triangular(offset = 1, start_time = 0.5, amplitude = 10, - frequency = 2) - @named source_dsin = ExpSine(offset = 1, amplitude = 10, frequency = 2, - start_time = 0.5, phase = 0, damping = 0.5) + @named source_tri = Triangular( + offset = 1, start_time = 0.5, amplitude = 10, + frequency = 2 + ) + @named source_dsin = ExpSine( + offset = 1, amplitude = 10, frequency = 2, + start_time = 0.5, phase = 0, damping = 0.5 + ) @named source_ramp = Ramp(offset = 1, height = 10, start_time = 0.5, duration = 1) sources = [source_const, source_sin, source_step, source_tri, source_dsin, source_ramp] @@ -153,13 +176,17 @@ end @named ground = Ground() for source in sources - connections = [connect(source.output, voltage.V) - connect(voltage.p, resistor.p) - connect(resistor.n, capacitor.p) - connect(capacitor.n, voltage.n, ground.g)] + connections = [ + connect(source.output, voltage.V) + connect(voltage.p, resistor.p) + connect(resistor.n, capacitor.p) + connect(capacitor.n, voltage.n, ground.g) + ] - @named model = System(connections, t; - systems = [resistor, capacitor, source, ground, voltage]) + @named model = System( + connections, t; + systems = [resistor, capacitor, source, ground, voltage] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 10.0)) sol = solve(prob, Tsit5()) @@ -180,23 +207,27 @@ end @named capacitor = Capacitor(C = 1, v = 0.0) @named ground = Ground() - connections = [connect(source.output, current.I) - connect(current.p, resistor.n) - connect(capacitor.n, resistor.p) - connect(capacitor.p, current.n, ground.g)] - - @named model = System(connections, t; - systems = [ground, resistor, current, capacitor, source]) + connections = [ + connect(source.output, current.I) + connect(current.p, resistor.n) + connect(capacitor.n, resistor.p) + connect(capacitor.p, current.n, ground.g) + ] + + @named model = System( + connections, t; + systems = [ground, resistor, current, capacitor, source] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0.0, 10.0)) sol = solve(prob, Tsit5()) y(x, st) = (x .> st) .* abs.(collect(x) .- st) @test SciMLBase.successful_retcode(sol) - @test sum(reduce(vcat, sol[capacitor.v]) .- y(sol.t, start_time))≈0 atol=1e-2 + @test sum(reduce(vcat, sol[capacitor.v]) .- y(sol.t, start_time)) ≈ 0 atol = 1.0e-2 end @testset "Integrator" begin - R = 1e3 + R = 1.0e3 f = 1 Vin = 5 @named ground = Ground() @@ -208,14 +239,17 @@ end @named voltage = Voltage() @named sensor = VoltageSensor() - connections = [connect(square_source.output, voltage.V) - connect(voltage.p, R1.p) - connect(R1.n, C1.n, R2.p, opamp.n1) - connect(opamp.p2, C1.p, R2.n) - connect(opamp.p1, ground.g, opamp.n2, voltage.n) - connect(opamp.p2, sensor.p) - connect(sensor.n, ground.g)] - @named model = System(connections, t, + connections = [ + connect(square_source.output, voltage.V) + connect(voltage.p, R1.p) + connect(R1.n, C1.n, R2.p, opamp.n1) + connect(opamp.p2, C1.p, R2.n) + connect(opamp.p1, ground.g, opamp.n2, voltage.n) + connect(opamp.p2, sensor.p) + connect(sensor.n, ground.g) + ] + @named model = System( + connections, t, systems = [ R1, R2, @@ -224,11 +258,14 @@ end voltage, C1, ground, - sensor - ]) + sensor, + ] + ) sys = mtkcompile(model) - u0 = [C1.v => 0.0 - R1.v => 0.0] + u0 = [ + C1.v => 0.0 + R1.v => 0.0 + ] prob = ODEProblem(sys, u0, (0, 100.0)) sol = solve(prob, Rodas4()) @test SciMLBase.successful_retcode(sol) @@ -240,8 +277,10 @@ end _step(x, h, st) = ifelse(x < st, 0, h) _cos_wave(x, f, A, st, ϕ) = A * cos(2 * π * f * (x - st) + ϕ) -_ramp(x, st, d, h) = ifelse(x < st, 0, - ifelse(x < (st + d), (x - st) * h / d, h)) +_ramp(x, st, d, h) = ifelse( + x < st, 0, + ifelse(x < (st + d), (x - st) * h / d, h) +) _sine_wave(x, f, A, st, ϕ) = A * sin(2 * π * f * (x - st) + ϕ) _damped_sine_wave(x, f, A, st, ϕ, d) = exp((st - x) * d) * A * sin(2 * π * f * (x - st) + ϕ) @@ -254,11 +293,15 @@ _damped_sine_wave(x, f, A, st, ϕ, d) = exp((st - x) * d) * A * sin(2 * π * f * @named voltage = Voltage() @named voltage_sensor = VoltageSensor() @named step = Step(start_time = st, offset = o, height = h) - @named cosine = Cosine(offset = o, amplitude = A, frequency = f, start_time = st, - phase = ϕ) + @named cosine = Cosine( + offset = o, amplitude = A, frequency = f, start_time = st, + phase = ϕ + ) @named sine = Sine(offset = o, amplitude = A, frequency = f, start_time = st, phase = ϕ) - @named damped_sine = ExpSine(offset = o, amplitude = A, frequency = f, start_time = st, - phase = ϕ, damping = d) + @named damped_sine = ExpSine( + offset = o, amplitude = A, frequency = f, start_time = st, + phase = ϕ, damping = d + ) @named ramp = Ramp(offset = o, start_time = st, duration = et - st, height = h) @named vsquare = Square(offset = o, start_time = st, amplitude = A, frequency = f) @named tri = Triangular(offset = o, start_time = st, amplitude = A, frequency = f) @@ -267,33 +310,40 @@ _damped_sine_wave(x, f, A, st, ϕ, d) = exp((st - x) * d) * A * sin(2 * π * f * sources = [step, cosine, sine, damped_sine, ramp, tri, vsquare] #, vsawtooth] function waveforms(i, x) getindex( - [o .+ _step.(x, h, st), + [ + o .+ _step.(x, h, st), o .+ (x .> st) .* _cos_wave.(x, f, A, st, ϕ), o .+ (x .> st) .* _sine_wave.(x, f, A, st, ϕ), o .+ (x .> st) .* _damped_sine_wave.(x, f, A, st, ϕ, d), o .+ _ramp.(x, st, (et - st), h), triangular.(x, f, A, o, st), - square.(x, f, A, o, st)], - i) + square.(x, f, A, o, st), + ], + i + ) end # o .+ (x .> st). * _sawtooth_wave.(x, δ, f, A, st), for i in 1:lastindex(sources) source = sources[i] @info "Testing Voltage with $(nameof(source)) source" - eqs = [connect(source.output, voltage.V) - connect(voltage.p, voltage_sensor.p, res.p) - connect(res.n, cap.p) - connect(ground.g, voltage_sensor.n, voltage.n, cap.n)] - @named vmodel = System(eqs, t, + eqs = [ + connect(source.output, voltage.V) + connect(voltage.p, voltage_sensor.p, res.p) + connect(res.n, cap.p) + connect(ground.g, voltage_sensor.n, voltage.n, cap.n) + ] + @named vmodel = System( + eqs, t, systems = [ voltage_sensor, res, cap, source, voltage, - ground - ]) + ground, + ] + ) vsys = mtkcompile(vmodel) u0 = [cap.v => 0.0] @@ -302,7 +352,7 @@ _damped_sine_wave(x, f, A, st, ϕ, d) = exp((st - x) * d) * A * sin(2 * π * f * sol = solve(prob, dt = 0.1, Tsit5()) @test SciMLBase.successful_retcode(sol) - @test sol[voltage.V.u]≈waveforms(i, sol.t) atol=1e-1 + @test sol[voltage.V.u] ≈ waveforms(i, sol.t) atol = 1.0e-1 @test sol[voltage.p.v] ≈ sol[voltage.V.u] # For visual inspection # plt = plot(sol; vars=[voltage.v]) @@ -319,11 +369,15 @@ end @named current_sensor = CurrentSensor() @named current = Current() @named step = Step(start_time = st, offset = o, height = h) - @named cosine = Cosine(offset = o, amplitude = A, frequency = f, start_time = st, - phase = ϕ) + @named cosine = Cosine( + offset = o, amplitude = A, frequency = f, start_time = st, + phase = ϕ + ) @named sine = Sine(offset = o, amplitude = A, frequency = f, start_time = st, phase = ϕ) - @named damped_sine = ExpSine(offset = o, amplitude = A, frequency = f, start_time = st, - phase = ϕ, damping = d) + @named damped_sine = ExpSine( + offset = o, amplitude = A, frequency = f, start_time = st, + phase = ϕ, damping = d + ) @named ramp = Ramp(offset = o, start_time = st, duration = et - st, height = h) @named vsquare = Square(offset = o, start_time = st, amplitude = A, frequency = f) @named tri = Triangular(offset = o, start_time = st, amplitude = A, frequency = f) @@ -332,34 +386,41 @@ end sources = [step, cosine, sine, damped_sine, ramp, tri, vsquare] #, idamped_sine] function waveforms(i, x) getindex( - [o .+ _step.(x, h, st), + [ + o .+ _step.(x, h, st), o .+ (x .> st) .* _cos_wave.(x, f, A, st, ϕ), o .+ (x .> st) .* _sine_wave.(x, f, A, st, ϕ), o .+ (x .> st) .* _damped_sine_wave.(x, f, A, st, ϕ, d), o .+ _ramp.(x, st, (et - st), h), triangular.(x, f, A, o, st), - square.(x, f, A, o, st)], - i) + square.(x, f, A, o, st), + ], + i + ) end # # o .+ (x .> st). * _sawtooth_wave.(x, δ, f, A, st) for i in 1:lastindex(sources) source = sources[i] @info "Testing Current with $(nameof(source)) source" - eqs = [connect(source.output, current.I) - connect(current.p, current_sensor.n) - connect(current_sensor.p, res.p) - connect(res.n, cap.p) - connect(current.n, ground.g, cap.n)] - @named model = System(eqs, t, + eqs = [ + connect(source.output, current.I) + connect(current.p, current_sensor.n) + connect(current_sensor.p, res.p) + connect(res.n, cap.p) + connect(current.n, ground.g, cap.n) + ] + @named model = System( + eqs, t, systems = [ current_sensor, source, current, res, cap, - ground - ]) + ground, + ] + ) isys = mtkcompile(model) u0 = [cap.v => 0.0] @@ -368,8 +429,8 @@ end sol = solve(prob, dt = 0.1, Tsit5()) @test SciMLBase.successful_retcode(sol) - @test sol[current.I.u]≈waveforms(i, sol.t) atol=1e-1 - @test sol[current.I.u]≈sol[current.p.i] atol=1e-1 + @test sol[current.I.u] ≈ waveforms(i, sol.t) atol = 1.0e-1 + @test sol[current.I.u] ≈ sol[current.p.i] atol = 1.0e-1 # For visual inspection # plt = plot(sol) # savefig(plt, "test_current_$(source.name)") @@ -383,7 +444,7 @@ end C = 1.0 V = 10.0 n = 1.0 - Is = 1e-3 + Is = 1.0e-3 f = 1.0 end @components begin @@ -414,8 +475,8 @@ end capacitor_voltage = sol[sys.capacitor.v] # Tests - @test all(diode_current .>= -1e-3) - @test capacitor_voltage[end] .≈ 8.26 rtol=3e-1 + @test all(diode_current .>= -1.0e-3) + @test capacitor_voltage[end] .≈ 8.26 rtol = 3.0e-1 # For visual inspection # plt = plot(sol; idxs = [diode.i, resistor.i, capacitor.v], @@ -433,7 +494,7 @@ end V = 10.0 T = 300.0 # Ambient temperature in Kelvin n = 2.0 - Is = 1e-6 + Is = 1.0e-6 f = 1.0 end @components begin @@ -471,8 +532,8 @@ end q = 1.602176634e-19 # Elementary charge (C) # Tests - @test all(diode_current .>= -1e-6) # Diode current should not exceed reverse saturation - @test capacitor_voltage[end]≈7.75 rtol=3e-1 # Final capacitor voltage close to input voltage + @test all(diode_current .>= -1.0e-6) # Diode current should not exceed reverse saturation + @test capacitor_voltage[end] ≈ 7.75 rtol = 3.0e-1 # Final capacitor voltage close to input voltage # For visual inspection # plt = plot(sol; vars = [heating_diode.i, resistor.i, capacitor.v], @@ -738,7 +799,7 @@ end end end - @mtkcompile sys = SimpleNPNCircuit(V_cc = 3.0, V_b = 0.70) + @mtkcompile sys = SimpleNPNCircuit(V_cc = 3.0, V_b = 0.7) prob = ODEProblem(sys, Pair[], (0.0, 10.0); guesses = [sys.Q1.I_sub => 1.0]) sol = solve(prob) @@ -778,17 +839,18 @@ end end end - @mtkcompile sys = SimpleNPNCircuitSubstrate(V_b = 0.70) + @mtkcompile sys = SimpleNPNCircuitSubstrate(V_b = 0.7) prob = ODEProblem(sys, [sys.Q1.c.i => 0.0], (0.0, 10.0); guesses = [sys.Q1.I_sub => 1.0, sys.Vcc_sine.output.u => 1.0]) sol = solve(prob) @test isapprox( sol[sys.Q1.b.i][15] + - sol[sys.Q1.e.i][15] + - sol[sys.Q1.c.i][15] + - sol[sys.Q1.s.i][15], - 0.0, atol = 1e-16) + sol[sys.Q1.e.i][15] + + sol[sys.Q1.c.i][15] + + sol[sys.Q1.s.i][15], + 0.0, atol = 1.0e-16 + ) end @testset "PNP Tests" begin @@ -821,7 +883,7 @@ end end end - @mtkcompile sys = SimplePNPCircuit(V_cc = 3.0, V_b = 0.70) + @mtkcompile sys = SimplePNPCircuit(V_cc = 3.0, V_b = 0.7) prob = ODEProblem(sys, Pair[], (0.0, 10.0)) sol = solve(prob) @@ -861,16 +923,17 @@ end end end - @mtkcompile sys = SimplePNPCircuitSubstrate(V_b = 0.70) + @mtkcompile sys = SimplePNPCircuitSubstrate(V_b = 0.7) prob = ODEProblem(sys, [sys.Q1.c.i => 0.0], (0.0, 10.0); guesses = [sys.Q1.I_sub => 1.0]) sol = solve(prob) @test isapprox( sol[sys.Q1.b.i][15] + - sol[sys.Q1.e.i][15] + - sol[sys.Q1.c.i][15] + - sol[sys.Q1.s.i][15], + sol[sys.Q1.e.i][15] + + sol[sys.Q1.c.i][15] + + sol[sys.Q1.s.i][15], 0.0, - atol = 1e-16) + atol = 1.0e-16 + ) end diff --git a/test/Electrical/digital.jl b/test/Electrical/digital.jl index 0d8c88049..96fed72b9 100644 --- a/test/Electrical/digital.jl +++ b/test/Electrical/digital.jl @@ -21,8 +21,10 @@ using OrdinaryDiffEq: ReturnCode.Success # Logic zeros and ones @test zero(Logic) == zero(U) == F0 @test one(Logic) == one(U) == F1 - @test ones(Logic, 2, 2) == [F1 F1 - F1 F1] + @test ones(Logic, 2, 2) == [ + F1 F1 + F1 F1 + ] # Logic vectors u_logic = StdULogicVector([U, W, X, 1]) @@ -41,8 +43,12 @@ using OrdinaryDiffEq: ReturnCode.Success @test X01Z.logic == [X, F0, F1, Z] # Logic vector helpers - test_logic_matrix = StdULogicVector([U F0 - F1 X]) + test_logic_matrix = StdULogicVector( + [ + U F0 + F1 X + ] + ) test_logic_vector = StdLogicVector([U, F0, F1, X]) size(test_logic_matrix) == (2, 2) diff --git a/test/Hydraulic/isothermal_compressible.jl b/test/Hydraulic/isothermal_compressible.jl index 6611eaa86..57a23edab 100644 --- a/test/Hydraulic/isothermal_compressible.jl +++ b/test/Hydraulic/isothermal_compressible.jl @@ -8,7 +8,8 @@ import ModelingToolkitStandardLibrary.Mechanical.Translational as T using ModelingToolkitStandardLibrary.Blocks: Parameter NEWTON = NLNewton( - check_div = false, always_new = true, max_iter = 100, relax = 9 // 10, κ = 1e-6) + check_div = false, always_new = true, max_iter = 100, relax = 9 // 10, κ = 1.0e-6 +) @testset "Fluid Domain and Tube" begin function FluidSystem(N; bulk_modulus, name) @@ -19,24 +20,28 @@ NEWTON = NLNewton( systems = @named begin fluid = IC.HydraulicFluid(; bulk_modulus) - stp = B.Step(; height = 10e5, offset = 0, start_time = 0.005, - duration = Inf, smooth = true) + stp = B.Step(; + height = 10.0e5, offset = 0, start_time = 0.005, + duration = Inf, smooth = true + ) src = IC.Pressure() vol = IC.FixedVolume(; vol = 10.0, p_int) res = IC.Tube(N; area = 0.01, length = 50.0, p_int) end - eqs = [connect(stp.output, src.p) - connect(fluid, src.port) - connect(src.port, res.port_a) - connect(res.port_b, vol.port)] + eqs = [ + connect(stp.output, src.p) + connect(fluid, src.port) + connect(src.port, res.port_a) + connect(res.port_b, vol.port) + ] System(eqs, t, [], pars; name, systems) end - @mtkcompile s1_1 = FluidSystem(1; bulk_modulus = 1e9) - @mtkcompile s1_2 = FluidSystem(1; bulk_modulus = 2e9) - @mtkcompile s5_1 = FluidSystem(5; bulk_modulus = 1e9) + @mtkcompile s1_1 = FluidSystem(1; bulk_modulus = 1.0e9) + @mtkcompile s1_2 = FluidSystem(1; bulk_modulus = 2.0e9) + @mtkcompile s5_1 = FluidSystem(5; bulk_modulus = 1.0e9) p1_1 = ODEProblem(s1_1, [], (0, 0.05)) p1_2 = ODEProblem(s1_2, [], (0, 0.05)) @@ -67,17 +72,20 @@ end systems = @named begin fluid = IC.HydraulicFluid() - sink = IC.FixedPressure(; p = 10e5) - vol = IC.FixedVolume(; vol = 5, p_int = 1e5) - valve = IC.Valve(; Cd = 1e5, minimum_area = 0) + sink = IC.FixedPressure(; p = 10.0e5) + vol = IC.FixedVolume(; vol = 5, p_int = 1.0e5) + valve = IC.Valve(; Cd = 1.0e5, minimum_area = 0) ramp = B.Ramp(; - height = 0.1, duration = 0.1, offset = 0, start_time = 0.1, smooth = true) + height = 0.1, duration = 0.1, offset = 0, start_time = 0.1, smooth = true + ) end - eqs = [connect(fluid, sink.port) - connect(sink.port, valve.port_a) - connect(valve.port_b, vol.port) - connect(valve.area, ramp.output)] + eqs = [ + connect(fluid, sink.port) + connect(sink.port, valve.port_a) + connect(valve.port_b, vol.port) + connect(valve.area, ramp.output) + ] System(eqs, t, [], pars; name, systems) end @@ -85,67 +93,77 @@ end @named valve_system = ValveSystem() sys = mtkcompile(valve_system) prob = ODEProblem(sys, [], (0, 1)) - sol = solve(prob, Rodas5P(); abstol = 1e-6, reltol = 1e-9) + sol = solve(prob, Rodas5P(); abstol = 1.0e-6, reltol = 1.0e-9) s = complete(valve_system) # the volume should discharge to 10bar - @test sol[s.vol.port.p][end]≈10e5 atol=1e5 + @test sol[s.vol.port.p][end] ≈ 10.0e5 atol = 1.0e5 # fig = Figure() # tm = 0:0.01:1 |> collect # ax = Axis(fig[1,1]) - # lines!(ax, tm, sol.(tm; idxs=sys.vol.port.p)); + # lines!(ax, tm, sol.(tm; idxs=sys.vol.port.p)); # fig end @testset "DynamicVolume and minimum_volume feature" begin # Need help here - function TestSystem(; name, area = 0.01, length = 0.1, damping_volume = length * area * - 0.1) + function TestSystem(; + name, area = 0.01, length = 0.1, damping_volume = length * area * + 0.1 + ) pars = [] # DynamicVolume values systems = @named begin - fluid = IC.HydraulicFluid(; bulk_modulus = 1e9) + fluid = IC.HydraulicFluid(; bulk_modulus = 1.0e9) - src1 = IC.Pressure(;) - src2 = IC.Pressure(;) + src1 = IC.Pressure() + src2 = IC.Pressure() - vol1 = IC.DynamicVolume(; direction = +1, + vol1 = IC.DynamicVolume(; + direction = +1, area, x_int = length, x_max = length * 2, x_min = length * 0.1, x_damp = damping_volume / area + length * 0.1, - d = 1e3, - p_int = 10e5) + d = 1.0e3, + p_int = 10.0e5 + ) # vol1 = IC.Volume(;area, direction = +1, x_int=length) - vol2 = IC.DynamicVolume(; direction = -1, + vol2 = IC.DynamicVolume(; + direction = -1, area, x_int = length, x_max = length * 2, x_min = length * 0.1, x_damp = damping_volume / area + length * 0.1, - d = 1e3, - p_int = 10e5) + d = 1.0e3, + p_int = 10.0e5 + ) # vol2 = IC.Volume(;area, direction = -1, x_int=length) mass = T.Mass(; m = 10) - sin1 = B.Sine(; frequency = 0.5, amplitude = +1e5, offset = 10e5) - sin2 = B.Sine(; frequency = 0.5, amplitude = -1e5, offset = 10e5) + sin1 = B.Sine(; frequency = 0.5, amplitude = +1.0e5, offset = 10.0e5) + sin2 = B.Sine(; frequency = 0.5, amplitude = -1.0e5, offset = 10.0e5) end - eqs = [connect(fluid, src1.port) - connect(fluid, src2.port) - connect(src1.port, vol1.port) - connect(src2.port, vol2.port) - connect(vol1.flange, mass.flange, vol2.flange) - connect(src1.p, sin1.output) - connect(src2.p, sin2.output)] + eqs = [ + connect(fluid, src1.port) + connect(fluid, src2.port) + connect(src1.port, vol1.port) + connect(src2.port, vol2.port) + connect(vol1.flange, mass.flange, vol2.flange) + connect(src1.p, sin1.output) + connect(src2.p, sin2.output) + ] - initialization_eqs = [mass.s ~ 0.0 - mass.v ~ 0.0] + initialization_eqs = [ + mass.s ~ 0.0 + mass.v ~ 0.0 + ] System(eqs, t, [], pars; name, systems, initialization_eqs) end @@ -153,7 +171,7 @@ end @named sys = TestSystem() sys = mtkcompile(sys; allow_symbolic = true) prob = ODEProblem(sys, [], (0, 5)) - sol = solve(prob, Rodas5P(); abstol = 1e-6, reltol = 1e-9) + sol = solve(prob, Rodas5P(); abstol = 1.0e-6, reltol = 1.0e-9) # begin # fig = Figure() @@ -194,21 +212,21 @@ end @testset "Actuator System" begin function ActuatorSystem(use_input; name) pars = @parameters begin - p_s = 200e5 - p_r = 5e5 + p_s = 200.0e5 + p_r = 5.0e5 - A_1 = 360e-4 - A_2 = 360e-4 + A_1 = 360.0e-4 + A_2 = 360.0e-4 - p_1 = 45e5 - p_2 = 45e5 + p_1 = 45.0e5 + p_2 = 45.0e5 l_1 = 1.5 l_2 = 1.5 m_f = 250 g = 0 - d = 100e-3 + d = 100.0e-3 Cd = 0.01 @@ -229,12 +247,13 @@ end area_b = A_2, m = m_piston, g = 0, - minimum_volume_a = A_1 * 1e-3, - minimum_volume_b = A_2 * 1e-3, - damping_volume_a = A_1 * 5e-3, - damping_volume_b = A_2 * 5e-3, + minimum_volume_a = A_1 * 1.0e-3, + minimum_volume_b = A_2 * 1.0e-3, + damping_volume_a = A_1 * 5.0e-3, + damping_volume_b = A_2 * 5.0e-3, p_a_int = p_1, - p_b_int = p_2) + p_b_int = p_2 + ) # body = T.Mass(; m = 1500) # pipe = IC.Tube(1; area = A_2, length = 2.0, p_int = p_2) snk = IC.FixedPressure(; p = p_r) @@ -255,28 +274,30 @@ end push!(systems, input) - eqs = [connect(input.output, pos.s) - connect(valve.flange, pos.flange) - connect(valve.port_a, piston.port_a) - # connect(piston.flange, body.flange) + eqs = [ + connect(input.output, pos.s) + connect(valve.flange, pos.flange) + connect(valve.port_a, piston.port_a) + # connect(piston.flange, body.flange) - connect(piston.port_b, valve.port_b) + connect(piston.port_b, valve.port_b) - # connect(piston.port_b, pipe.port_b) - # # connect(piston.port_b, m1.port_a) - # # connect(m1.port_b, pipe.port_b) + # connect(piston.port_b, pipe.port_b) + # # connect(piston.port_b, m1.port_a) + # # connect(m1.port_b, pipe.port_b) - # connect(pipe.port_a, valve.port_b) - # # connect(pipe.port_a, m2.port_b) - # # connect(m2.port_a, valve.port_b) + # connect(pipe.port_a, valve.port_b) + # # connect(pipe.port_a, m2.port_b) + # # connect(m2.port_a, valve.port_b) - connect(src.port, valve.port_s) - connect(snk.port, valve.port_r) - connect(fluid, src.port, snk.port) - D(piston.mass.v) ~ ddx] + connect(src.port, valve.port_s) + connect(snk.port, valve.port_r) + connect(fluid, src.port, snk.port) + D(piston.mass.v) ~ ddx + ] initialization_eqs = [ - # body.s ~ 0 + # body.s ~ 0 ] System(eqs, t, vars, pars; name, systems, initialization_eqs) @@ -289,7 +310,7 @@ end @mtkcompile sys = ActuatorSystem(true) - dt = 1e-4 + dt = 1.0e-4 time = 0:dt:0.1 x = @. (time - 0.015)^2 - 10 * (time - 0.02)^3 @@ -325,17 +346,23 @@ end systems = @named begin fluid = IC.HydraulicFluid(; let_gas) - vol = IC.DynamicVolume(; area = 0.001, x_int = 0.05, - x_max = 0.1, x_damp = 0.02, x_min = 0.01, direction = +1, p_int = 100e5) + vol = IC.DynamicVolume(; + area = 0.001, x_int = 0.05, + x_max = 0.1, x_damp = 0.02, x_min = 0.01, direction = +1, p_int = 100.0e5 + ) mass = T.Mass(; m = 100, g = -9.807) # s = 0.05 cap = IC.Cap() end - eqs = [connect(fluid, cap.port, vol.port) - connect(vol.flange, mass.flange)] + eqs = [ + connect(fluid, cap.port, vol.port) + connect(vol.flange, mass.flange) + ] - initialization_eqs = [mass.s ~ 0.05 - mass.v ~ 0] + initialization_eqs = [ + mass.s ~ 0.05 + mass.v ~ 0 + ] return System(eqs, t, [], pars; name, systems, initialization_eqs) end @@ -347,7 +374,7 @@ end prob2 = ODEProblem(sys, [sys.let_gas => 0], (0, 0.05)) # @time sol1 = solve(prob1, Rodas5P(); abstol=1e-9, reltol=1e-9) #BUG: Using BigFloat gives... ERROR: MethodError: no method matching getindex(::Missing, ::Int64) - @time sol1 = solve(prob1, Rodas5P(); adaptive = false, dt = 1e-6) #TODO: fix BigFloat to implement abstol=1e-9, reltol=1e-9 + @time sol1 = solve(prob1, Rodas5P(); adaptive = false, dt = 1.0e-6) #TODO: fix BigFloat to implement abstol=1e-9, reltol=1e-9 @time sol2 = solve(prob2, Rodas5P()) # case 1: no negative pressure will only have gravity pulling mass back down diff --git a/test/Magnetic/magnetic.jl b/test/Magnetic/magnetic.jl index e6e8da787..334e1b69d 100644 --- a/test/Magnetic/magnetic.jl +++ b/test/Magnetic/magnetic.jl @@ -25,18 +25,21 @@ using OrdinaryDiffEq: ReturnCode.Success @named r_mAirPar = Magnetic.FluxTubes.ConstantReluctance(R_m = a * b * l_air * mu_air) @named r_mFe = Magnetic.FluxTubes.ConstantReluctance(R_m = a * b * l_Fe * mu_Fe) @named r_mLeak = Magnetic.FluxTubes.ConstantReluctance(R_m = 1.2e6) - connections = [connect(source.output, voltage.V) - connect(voltage.p, r.p) - connect(r.n, coil.p) - connect(voltage.n, coil.n) - connect(coil.port_p, r_mLeak.port_p) - connect(r_mLeak.port_p, r_mAirPar.port_p) - connect(r_mAirPar.port_n, r_mFe.port_p) - connect(r_mFe.port_n, r_mLeak.port_n) - connect(r_mFe.port_n, coil.port_n) - connect(ground.g, voltage.n) - connect(ground_m.port, r_mFe.port_n)] - @named model = System(connections, t, + connections = [ + connect(source.output, voltage.V) + connect(voltage.p, r.p) + connect(r.n, coil.p) + connect(voltage.n, coil.n) + connect(coil.port_p, r_mLeak.port_p) + connect(r_mLeak.port_p, r_mAirPar.port_p) + connect(r_mAirPar.port_n, r_mFe.port_p) + connect(r_mFe.port_n, r_mLeak.port_n) + connect(r_mFe.port_n, coil.port_n) + connect(ground.g, voltage.n) + connect(ground_m.port, r_mFe.port_n) + ] + @named model = System( + connections, t, systems = [ source, r, @@ -46,8 +49,9 @@ using OrdinaryDiffEq: ReturnCode.Success r_mAirPar, r_mFe, r_mLeak, - voltage - ]) + voltage, + ] + ) sys = mtkcompile(model) prob = ODEProblem(sys, Pair[], (0, 0.1)) sol = solve(prob, Rodas4()) diff --git a/test/Mechanical/multibody.jl b/test/Mechanical/multibody.jl index 991e42a8f..8cb13cca1 100644 --- a/test/Mechanical/multibody.jl +++ b/test/Mechanical/multibody.jl @@ -15,10 +15,12 @@ using Test # @named m1 = Mass(;m=0.5) # @named m2 = Mass(;m=0.5) -eqs = [connect(link1.TX1, cart.flange) #, force.flange) - connect(link1.TY1, fixed.flange) - connect(link1.TX2, link2.TX1) - connect(link1.TY2, link2.TY1)] +eqs = [ + connect(link1.TX1, cart.flange) #, force.flange) + connect(link1.TY1, fixed.flange) + connect(link1.TX2, link2.TX1) + connect(link1.TY2, link2.TY1) +] @named model = System(eqs, t, [], []; systems = [link1, link2, cart, fixed]) diff --git a/test/Mechanical/rotational.jl b/test/Mechanical/rotational.jl index dece4bec8..8b0205950 100644 --- a/test/Mechanical/rotational.jl +++ b/test/Mechanical/rotational.jl @@ -1,6 +1,6 @@ using ModelingToolkitStandardLibrary.Mechanical.Rotational, - ModelingToolkit, OrdinaryDiffEq, - Test + ModelingToolkit, OrdinaryDiffEq, + Test using SciCompDSL using ModelingToolkit: t_nounits as t, D_nounits as D import ModelingToolkitStandardLibrary.Blocks @@ -13,7 +13,7 @@ using OrdinaryDiffEq: ReturnCode.Success @components begin fixed = Fixed() inertia1 = Inertia(J = 2) # this one is fixed - spring = Spring(c = 1e4) + spring = Spring(c = 1.0e4) damper = Damper(d = 10) inertia2 = Inertia(J = 2, phi = pi / 2) end @@ -31,17 +31,18 @@ using OrdinaryDiffEq: ReturnCode.Success @test SciMLBase.successful_retcode(sol1) prob = DAEProblem( - sys, D.(unknowns(sys)) .=> prob.f(sol1.u[1], prob.p, 0.0), (0, 10.0)) + sys, D.(unknowns(sys)) .=> prob.f(sol1.u[1], prob.p, 0.0), (0, 10.0) + ) dae_sol = solve(prob, DFBDF()) @test SciMLBase.successful_retcode(dae_sol) @test all(dae_sol[sys.inertia1.w] .== 0) - @test dae_sol[sys.inertia2.w][end]≈0 atol=1e-3 # all energy has dissipated + @test dae_sol[sys.inertia2.w][end] ≈ 0 atol = 1.0e-3 # all energy has dissipated @mtkmodel WithSpringDamper begin @components begin fixed = Fixed() inertia1 = Inertia(J = 2) # this one is fixed - springdamper = SpringDamper(; c = 1e4, d = 10) + springdamper = SpringDamper(; c = 1.0e4, d = 10) inertia2 = Inertia(J = 2, phi = pi / 2) end @equations begin @@ -56,7 +57,7 @@ using OrdinaryDiffEq: ReturnCode.Success prob = ODEProblem(sys, [D(D(sys.inertia2.phi)) => 0], (0, 10.0)) sol2 = solve(prob, Rodas4()) @test SciMLBase.successful_retcode(sol2) - @test sol2(0:1:10, idxs = sys.inertia2.w).u≈sol1(0:1:10, idxs = sys.inertia2.w).u atol=1e-3 + @test sol2(0:1:10, idxs = sys.inertia2.w).u ≈ sol1(0:1:10, idxs = sys.inertia2.w).u atol = 1.0e-3 # Plots.plot(sol; vars=[inertia1.w, inertia2.w]) end @@ -73,7 +74,7 @@ end fixed = Fixed() torque = Torque(; use_support = true) inertia1 = Inertia(J = 2, phi = pi / 2) - spring = Rotational.Spring(c = 1e4) + spring = Rotational.Spring(c = 1.0e4) damper = Damper(d = 10) inertia2 = Inertia(J = 4) sine = Blocks.Sine(amplitude = amplitude, frequency = frequency) @@ -91,19 +92,26 @@ end @mtkcompile sys = TwoInertiasWithDrivingTorque() deqs = [eq.lhs => eq.rhs for eq in equations(sys)] prob = DAEProblem( - sys, [deqs; - D(D(sys.inertia2.phi)) => 1.0; sys.spring.flange_b.phi => 0.0], (0, 10.0)) + sys, [ + deqs; + D(D(sys.inertia2.phi)) => 1.0; sys.spring.flange_b.phi => 0.0 + ], (0, 10.0) + ) sol = solve(prob, DFBDF()) @test SciMLBase.successful_retcode(sol) prob = ODEProblem( - sys, [D(D(sys.inertia2.phi)) => 0.0, sys.spring.flange_b.phi => 0.0], (0, 1.0)) + sys, [D(D(sys.inertia2.phi)) => 0.0, sys.spring.flange_b.phi => 0.0], (0, 1.0) + ) sol = solve(prob, Rodas4()) @test SciMLBase.successful_retcode(sol) # exact opposite oscillation with smaller amplitude J2 = 2*J1 and with an offset. - @test all(isapprox.( - sol[sys.inertia1.w], -sol[sys.inertia2.w] * 2 .+ sol[sys.inertia1.w][1], atol = 1)) + @test all( + isapprox.( + sol[sys.inertia1.w], -sol[sys.inertia2.w] * 2 .+ sol[sys.inertia1.w][1], atol = 1 + ) + ) @test all(sol[sys.torque.flange.tau] .== -sol[sys.sine.output.u]) # torque source is equal to negative sine ## Test with constant torque source @@ -112,7 +120,7 @@ end fixed = Fixed() torque = ConstantTorque(use_support = true, tau_constant = 1) inertia1 = Inertia(J = 2, phi = pi / 2) - spring = Rotational.Spring(c = 1e4) + spring = Rotational.Spring(c = 1.0e4) damper = Damper(d = 10) inertia2 = Inertia(J = 4) end @@ -127,10 +135,11 @@ end @mtkcompile sys = TwoInertiasWitConstantTorque() prob = ODEProblem( - sys, [D(D(sys.inertia2.phi)) => 1.0, sys.spring.flange_b.phi => 0.0], (0, 10.0)) + sys, [D(D(sys.inertia2.phi)) => 1.0, sys.spring.flange_b.phi => 0.0], (0, 10.0) + ) sol = solve(prob, Rodas4()) @test SciMLBase.successful_retcode(sol) - @test sol(sol.t[end], idxs = sys.inertia1.w)≈sol(sol.t[end], idxs = sys.inertia2.w) rtol=0.1 # both inertias have same angular velocity after initial transient + @test sol(sol.t[end], idxs = sys.inertia1.w) ≈ sol(sol.t[end], idxs = sys.inertia2.w) rtol = 0.1 # both inertias have same angular velocity after initial transient end # see: https://doc.modelica.org/Modelica%204.0.0/Resources/helpWSM/Modelica/Modelica.Mechanics.Rotational.Examples.First.html @@ -151,7 +160,7 @@ end inertia1 = Inertia(J = J_motor) idealGear = IdealGear(ratio = ratio, use_support = true) inertia2 = Inertia(J = 2) - spring = Spring(c = 1e4) + spring = Spring(c = 1.0e4) inertia3 = Inertia(J = J_load) damper = Damper(d = damping) sine = Blocks.Sine(amplitude = amplitude, frequency = frequency) @@ -173,7 +182,8 @@ end @mtkcompile sys = FirstExample() prob = ODEProblem( - sys, [sys.inertia3.w => 0.0, sys.spring.flange_a.phi => 0.0], (0, 1.0)) + sys, [sys.inertia3.w => 0.0, sys.spring.flange_a.phi => 0.0], (0, 1.0) + ) sol = solve(prob, Rodas4()) @test SciMLBase.successful_retcode(sol) # Plots.plot(sol; vars=[inertia2.w, inertia3.w]) @@ -200,8 +210,10 @@ end spring = Spring(c = 6.5) damper = Damper(d = 0.01) inertia = Inertia(J = 0.0001) - friction = RotationalFriction(f = 0.001, tau_c = 20, w_brk = 0.06035, - tau_brk = 25) + friction = RotationalFriction( + f = 0.001, tau_c = 20, w_brk = 0.06035, + tau_brk = 25 + ) vel_profile = VelocityProfile() source = Speed() angle_sensor = AngleSensor() @@ -218,10 +230,14 @@ end end @mtkcompile sys = StickSlip() - prob = DAEProblem(sys, - [D.(unknowns(sys)) .=> 0.0; - [sys.inertia.flange_b.tau => 0.0; unknowns(sys) .=> 0.0...]], - (0, 10.0)) + prob = DAEProblem( + sys, + [ + D.(unknowns(sys)) .=> 0.0; + [sys.inertia.flange_b.tau => 0.0; unknowns(sys) .=> 0.0...] + ], + (0, 10.0) + ) sol = solve(prob, DFBDF()) @test SciMLBase.successful_retcode(sol) @@ -240,7 +256,7 @@ end @components begin fixed = Fixed() inertia1 = Inertia(J = 2) # this one is fixed - spring = Spring(c = 1e4) + spring = Spring(c = 1.0e4) damper = Damper(d = 10) inertia2 = Inertia(J = 2, phi = pi / 2) speed_sensor = SpeedSensor() @@ -251,8 +267,10 @@ end @equations begin connect(fixed.flange, inertia1.flange_b, rel_speed_sensor.flange_b) connect(inertia1.flange_b, torque_sensor.flange_a) - connect(torque_sensor.flange_b, spring.flange_a, damper.flange_a, - speed_sensor.flange, rel_speed_sensor.flange_a) + connect( + torque_sensor.flange_b, spring.flange_a, damper.flange_a, + speed_sensor.flange, rel_speed_sensor.flange_a + ) connect(spring.flange_b, damper.flange_b, inertia2.flange_a) end end @@ -264,17 +282,18 @@ end @test SciMLBase.successful_retcode(sol) @test all(sol[sys.inertia1.w] .== 0) @test all(sol[sys.inertia1.w] .== sol[sys.speed_sensor.w.u]) - @test sol[sys.inertia2.w][end]≈0 atol=1e-3 # all energy has dissipated + @test sol[sys.inertia2.w][end] ≈ 0 atol = 1.0e-3 # all energy has dissipated @test all(sol[sys.rel_speed_sensor.w_rel.u] .== sol[sys.speed_sensor.w.u]) @test all(sol[sys.torque_sensor.tau.u] .== -sol[sys.inertia1.flange_b.tau]) prob = DAEProblem( - sys, D.(unknowns(sys)) .=> prob.f(sol.u[1], prob.p, 0.0), (0, 10.0)) + sys, D.(unknowns(sys)) .=> prob.f(sol.u[1], prob.p, 0.0), (0, 10.0) + ) sol = solve(prob, DFBDF()) @test SciMLBase.successful_retcode(sol) @test all(sol[sys.inertia1.w] .== 0) @test all(sol[sys.inertia1.w] .== sol[sys.speed_sensor.w.u]) - @test sol[sys.inertia2.w][end]≈0 atol=1e-3 # all energy has dissipated + @test sol[sys.inertia2.w][end] ≈ 0 atol = 1.0e-3 # all energy has dissipated @test all(sol[sys.rel_speed_sensor.w_rel.u] .== sol[sys.speed_sensor.w.u]) @test all(sol[sys.torque_sensor.tau.u] .== -sol[sys.inertia1.flange_b.tau]) @@ -298,7 +317,7 @@ end sol = solve(prob, Tsit5()) @test SciMLBase.successful_retcode(sol) tv = 0:0.01:10 - @test sol(tv, idxs = sys.inertia.phi).u≈sin.(2pi .* tv) atol=1e-12 + @test sol(tv, idxs = sys.inertia.phi).u ≈ sin.(2pi .* tv) atol = 1.0e-12 @mtkmodel TestPosition begin @components begin @@ -312,12 +331,14 @@ end end end @mtkcompile sys = TestPosition() - prob = ODEProblem(sys, [ + prob = ODEProblem( + sys, [ sys.inertia.phi => 0, - sys.inertia.w => 0 - ], (0, 10.0)) + sys.inertia.w => 0, + ], (0, 10.0) + ) sol = solve(prob, Tsit5()) @test SciMLBase.successful_retcode(sol) tv = 0:0.01:10 - @test sol(tv, idxs = sys.inertia.phi).u≈sin.(2pi .* tv) atol=1e-1 + @test sol(tv, idxs = sys.inertia.phi).u ≈ sin.(2pi .* tv) atol = 1.0e-1 end diff --git a/test/Mechanical/translational.jl b/test/Mechanical/translational.jl index 380bed51f..79426f205 100644 --- a/test/Mechanical/translational.jl +++ b/test/Mechanical/translational.jl @@ -15,8 +15,10 @@ import ModelingToolkitStandardLibrary.Mechanical.TranslationalPosition as TP free = TV.Free() end - eqs = [connect(a.output, acc.a) - connect(mass.flange, acc.flange, free.flange)] + eqs = [ + connect(a.output, acc.a) + connect(mass.flange, acc.flange, free.flange) + ] System(eqs, t, [], []; name, systems) end @@ -27,7 +29,7 @@ import ModelingToolkitStandardLibrary.Mechanical.TranslationalPosition as TP prob = ODEProblem(sys, [s.mass.s => 0], (0, 0.1)) sol = solve(prob, Rosenbrock23()) - @test sol[s.mass.flange.v][end]≈-0.1 * 10 atol=1e-3 + @test sol[s.mass.flange.v][end] ≈ -0.1 * 10 atol = 1.0e-3 @test sol[s.free.f][end] ≈ 100 * 10 end @@ -45,30 +47,35 @@ end @named gp = TP.Fixed(s_0 = 1) function simplify_and_solve( - damping, spring, body, ground; initialization_eqs = Equation[]) - eqs = [connect(spring.flange_a, body.flange, damping.flange_a) - connect(spring.flange_b, damping.flange_b, ground.flange)] + damping, spring, body, ground; initialization_eqs = Equation[] + ) + eqs = [ + connect(spring.flange_a, body.flange, damping.flange_a) + connect(spring.flange_b, damping.flange_b, ground.flange) + ] @named model = System(eqs, t; systems = [ground, body, spring, damping]) sys = mtkcompile(model) prob = ODEProblem( - sys, [], (0, 20.0); initialization_eqs, fully_determined = true) - sol = solve(prob; abstol = 1e-9, reltol = 1e-9) + sys, [], (0, 20.0); initialization_eqs, fully_determined = true + ) + sol = solve(prob; abstol = 1.0e-9, reltol = 1.0e-9) return sol end solv = simplify_and_solve( - dv, sv, bv, gv; initialization_eqs = [bv.s ~ 3, bv.v ~ 1, sv.delta_s ~ 1]) + dv, sv, bv, gv; initialization_eqs = [bv.s ~ 3, bv.v ~ 1, sv.delta_s ~ 1] + ) solp = simplify_and_solve(dp, sp, bp, gp) @test solv[bv.v][1] == 1.0 - @test solv[bv.v][end]≈0.0 atol=1e-4 + @test solv[bv.v][end] ≈ 0.0 atol = 1.0e-4 @test solp[bp.v][1] == 1.0 - @test solp[bp.v][end]≈0.0 atol=1e-4 + @test solp[bp.v][end] ≈ 0.0 atol = 1.0e-4 end @testset "driven spring damper mass" begin @@ -90,13 +97,17 @@ end @named source = Sine(frequency = 3, amplitude = 2) function TestSystem(damping, spring, body, ground, f, source) - eqs = [connect(f.f, source.output) - connect(f.flange, body.flange) - connect(spring.flange_a, body.flange, damping.flange_a) - connect(spring.flange_b, damping.flange_b, ground.flange)] - - @named model = System(eqs, t; - systems = [ground, body, spring, damping, f, source]) + eqs = [ + connect(f.f, source.output) + connect(f.flange, body.flange) + connect(spring.flange_a, body.flange, damping.flange_a) + connect(spring.flange_b, damping.flange_b, ground.flange) + ] + + @named model = System( + eqs, t; + systems = [ground, body, spring, damping, f, source] + ) return model end @@ -104,7 +115,8 @@ end model = TestSystem(dv, sv, bv, gv, fv, source) sys = mtkcompile(model) prob = ODEProblem( - sys, [bv.s => 0, sv.delta_s => 1], (0, 20.0), fully_determined = true) + sys, [bv.s => 0, sv.delta_s => 1], (0, 20.0), fully_determined = true + ) solv = solve(prob, Rodas4()) model = TestSystem(dp, sp, bp, gp, fp, source) @@ -114,7 +126,7 @@ end for sol in (solv, solp) lb, ub = extrema(solv(15:0.05:20, idxs = bv.v).u) - @test -lb≈ub atol=1e-2 + @test -lb ≈ ub atol = 1.0e-2 @test -0.11 < lb < -0.1 end end @@ -138,13 +150,15 @@ end force_output = RealOutput() end - eqs = [connect(pos.s, src1.output) - connect(force.f, src2.output) - connect(pos.flange, force_sensor.flange_a) - connect(force_sensor.flange_b, spring.flange_a) - connect(spring.flange_b, force.flange, pos_sensor.flange) - connect(pos_value, pos_sensor.output) - connect(force_output, force_sensor.output)] + eqs = [ + connect(pos.s, src1.output) + connect(force.f, src2.output) + connect(pos.flange, force_sensor.flange_a) + connect(force_sensor.flange_b, spring.flange_a) + connect(spring.flange_b, force.flange, pos_sensor.flange) + connect(pos_value, pos_sensor.output) + connect(force_output, force_sensor.output) + ] System(eqs, t, [], []; name, systems) end @@ -158,7 +172,7 @@ end delta_s = 1 / 1000 s_b = 2 - delta_s + 1 - @test sol[s.pos_value.u][end]≈1.0 atol=1e-3 + @test sol[s.pos_value.u][end] ≈ 1.0 atol = 1.0e-3 @test all(sol[s.spring.flange_a.f] .== sol[s.force_output.u]) end @@ -173,10 +187,11 @@ end connect(force.f, source.output), connect(force.flange, mass.flange), connect(acc.flange, mass.flange), - connect(acc_output, acc.output) + connect(acc_output, acc.output), ] @named sys = System( - eqs, t, [], []; systems = [force, source, mass, acc, acc_output]) + eqs, t, [], []; systems = [force, source, mass, acc, acc_output] + ) s = complete(mtkcompile(sys)) prob = ODEProblem(s, [mass.s => 0], (0.0, pi)) sol = solve(prob, Tsit5()) @@ -201,7 +216,7 @@ end connect(force_sensor.flange_b, spring.flange_a), connect(spring.flange_b, mass.flange, pos_sensor.flange), connect(pos_sensor.output, pos_value), - connect(force_sensor.output, force_value) + connect(force_sensor.output, force_value), ] System(eqs, t, [], []; name, systems) end @@ -227,10 +242,11 @@ end connect(force.f, source.output), connect(force.flange, mass.flange), connect(acc.flange, mass.flange), - connect(acc_output, acc.output) + connect(acc_output, acc.output), ] @named sys = System( - eqs, t, [], []; systems = [force, source, mass, acc, acc_output]) + eqs, t, [], []; systems = [force, source, mass, acc, acc_output] + ) s = complete(mtkcompile(sys)) prob = ODEProblem(s, [], (0.0, pi), fully_determined = true) sol = solve(prob, Tsit5()) diff --git a/test/Mechanical/translational_modelica.jl b/test/Mechanical/translational_modelica.jl index 9b2115b87..8f40d1437 100644 --- a/test/Mechanical/translational_modelica.jl +++ b/test/Mechanical/translational_modelica.jl @@ -4,9 +4,9 @@ using ModelingToolkit: t_nounits as t, D_nounits as D using ModelingToolkitStandardLibrary.Blocks: Sine using ModelingToolkitStandardLibrary.Mechanical.TranslationalModelica: Damper, Spring, Mass, - Fixed, Force, - SpringDamper, - Position + Fixed, Force, + SpringDamper, + Position @testset "spring damper mass fixed" begin @mtkmodel SpringDamperMassFixed begin @@ -28,7 +28,7 @@ using ModelingToolkitStandardLibrary.Mechanical.TranslationalModelica: Damper, S sol = solve(prob, ImplicitMidpoint(), dt = 0.01) @test sol[sys.mass.v][1] == 1.0 - @test sol[sys.mass.v][end]≈0.0 atol=1e-4 + @test sol[sys.mass.v][end] ≈ 0.0 atol = 1.0e-4 end @testset "driven spring damper mass" begin @@ -56,7 +56,7 @@ end sol = solve(prob, Rodas4()) lb, ub = extrema(sol(15:0.05:20, idxs = sys.mass.v).u) - @test -lb≈ub atol=1e-2 + @test -lb ≈ ub atol = 1.0e-2 @test -0.11 < lb < -0.1 end @@ -84,7 +84,7 @@ end sol = solve(prob, Rodas4()) lb, ub = extrema(sol(15:0.05:20, idxs = sys.mass.v).u) - @test -lb≈ub atol=1e-2 + @test -lb ≈ ub atol = 1.0e-2 @test -0.11 < lb < -0.1 end @@ -106,5 +106,5 @@ end prob = ODEProblem(sys, [], (0, 2pi)) sol = solve(prob, Rodas4()) tv = 0:0.1:(2pi) - @test sol(tv, idxs = sys.mass.s).u≈@.(2sin(2pi * tv * 3)) atol=1e-2 + @test sol(tv, idxs = sys.mass.s).u ≈ @.(2sin(2pi * tv * 3)) atol = 1.0e-2 end diff --git a/test/Thermal/demo.jl b/test/Thermal/demo.jl index 4ffeb07dc..aee58e136 100644 --- a/test/Thermal/demo.jl +++ b/test/Thermal/demo.jl @@ -15,11 +15,13 @@ using OrdinaryDiffEq: ReturnCode.Success connect(mass1.port, conduction.port_a), connect(conduction.port_b, mass2.port), connect(mass1.port, Tsensor1.port), - connect(mass2.port, Tsensor2.port) + connect(mass2.port, Tsensor2.port), ] - @named model = System(connections, t, - systems = [mass1, mass2, conduction, Tsensor1, Tsensor2]) + @named model = System( + connections, t, + systems = [mass1, mass2, conduction, Tsensor1, Tsensor2] + ) sys = mtkcompile(model) prob = ODEProblem(sys, [conduction.Q_flow => nothing, conduction.dT => nothing], (0, 3.0)) sol = solve(prob, Tsit5()) diff --git a/test/Thermal/motor.jl b/test/Thermal/motor.jl index 580ae6a43..bdad6072e 100644 --- a/test/Thermal/motor.jl +++ b/test/Thermal/motor.jl @@ -24,8 +24,10 @@ using ModelingToolkitStandardLibrary.Blocks environment = PrescribedTemperature() amb = Constant(k = T_amb) core_losses_const = Constant(k = 500) - winding_losses = Step(height = 900, offset = 100, start_time = 360, - duration = Inf, smooth = false) + winding_losses = Step( + height = 900, offset = 100, start_time = 360, + duration = Inf, smooth = false + ) end @equations begin connect(windingLosses.port, winding.port) @@ -51,7 +53,7 @@ using ModelingToolkitStandardLibrary.Blocks @test sol[motor.T_winding.T.u] == sol[motor.winding.T] @test sol[motor.T_core.T.u] == sol[motor.core.T] @test sol[-motor.core.port.Q_flow] ≈ - sol[motor.coreLosses.port.Q_flow + motor.convection.solid.Q_flow + motor.winding2core.port_b.Q_flow] + sol[motor.coreLosses.port.Q_flow + motor.convection.solid.Q_flow + motor.winding2core.port_b.Q_flow] @test sol[motor.T_winding.T.u][end] >= 500 # not good but better than nothing @test sol[motor.T_core.T.u] <= sol[motor.T_winding.T.u] end diff --git a/test/Thermal/piston.jl b/test/Thermal/piston.jl index 62a3d7766..739717b8d 100644 --- a/test/Thermal/piston.jl +++ b/test/Thermal/piston.jl @@ -13,8 +13,8 @@ using ModelingToolkitStandardLibrary.Blocks Tᵧ = 1000, [description = "Temperature of gas"] Tᵪ = 10, [description = "Temperature of coolant"] # R = 1/h; h is convection co-efficient - Rᵧ = 50e-4, [description = "Thermal resistance of gas"] - Rᵪ = 10e-4, [description = "Thermal resistance of coolant"] + Rᵧ = 50.0e-4, [description = "Thermal resistance of gas"] + Rᵪ = 10.0e-4, [description = "Thermal resistance of coolant"] R_wall = 1.5e-4 end @components begin @@ -42,6 +42,6 @@ using ModelingToolkitStandardLibrary.Blocks @test SciMLBase.successful_retcode(sol) # The initial value doesn't add up to absolute zero, while the rest do. To avoid # tolerance on the latter, the test is split in two parts. - @test sol[piston.gas.Q_flow][1]≈-sol[piston.coolant.Q_flow][1] rtol=1e-6 - @test sol[piston.gas.Q_flow][2:end]≈-sol[piston.coolant.Q_flow][2:end] rtol=1e-6 + @test sol[piston.gas.Q_flow][1] ≈ -sol[piston.coolant.Q_flow][1] rtol = 1.0e-6 + @test sol[piston.gas.Q_flow][2:end] ≈ -sol[piston.coolant.Q_flow][2:end] rtol = 1.0e-6 end diff --git a/test/Thermal/thermal.jl b/test/Thermal/thermal.jl index e67d6138d..d878ba711 100644 --- a/test/Thermal/thermal.jl +++ b/test/Thermal/thermal.jl @@ -17,9 +17,11 @@ using OrdinaryDiffEq: ReturnCode.Success @named tem_src = FixedTemperature(T = T) @info "Building a single-body system..." - eqs = [connect(mass1.port, th_conductor.port_a) - connect(th_conductor.port_b, reltem_sensor.port_a) - connect(reltem_sensor.port_b, tem_src.port)] + eqs = [ + connect(mass1.port, th_conductor.port_a) + connect(th_conductor.port_b, reltem_sensor.port_a) + connect(reltem_sensor.port_b, tem_src.port) + ] @named h1 = System(eqs, t, systems = [mass1, reltem_sensor, tem_src, th_conductor]) sys = mtkcompile(h1) @@ -31,15 +33,19 @@ using OrdinaryDiffEq: ReturnCode.Success # when connected to a thermal conductor and a fixed temperature source @test SciMLBase.successful_retcode(sol) @test sol[reltem_sensor.T.u] + sol[tem_src.port.T] == - sol[mass1.T] + sol[th_conductor.dT] + sol[mass1.T] + sol[th_conductor.dT] @info "Building a two-body system..." - eqs = [connect(T_sensor1.port, mass1.port, th_conductor.port_a) - connect(th_conductor.port_b, mass2.port, T_sensor2.port) - final_T ~ (mass1.C * mass1.T + mass2.C * mass2.T) / - (mass1.C + mass2.C)] - @named h2 = System(eqs, t, [final_T], [], - systems = [mass1, mass2, T_sensor1, T_sensor2, th_conductor]) + eqs = [ + connect(T_sensor1.port, mass1.port, th_conductor.port_a) + connect(th_conductor.port_b, mass2.port, T_sensor2.port) + final_T ~ (mass1.C * mass1.T + mass2.C * mass2.T) / + (mass1.C + mass2.C) + ] + @named h2 = System( + eqs, t, [final_T], [], + systems = [mass1, mass2, T_sensor1, T_sensor2, th_conductor] + ) sys = mtkcompile(h2) prob = ODEProblem(sys, [], (0, 3.0)) @@ -47,7 +53,7 @@ using OrdinaryDiffEq: ReturnCode.Success @test SciMLBase.successful_retcode(sol) m1, m2 = sol.u[end] - @test m1≈m2 atol=1e-1 + @test m1 ≈ m2 atol = 1.0e-1 @test sol[T_sensor1.T.u] == sol[sys.mass1.T] @test sol[T_sensor2.T.u] == sol[sys.mass2.T] end @@ -64,14 +70,24 @@ end @named th_ground = FixedTemperature(T = 0) @info "Building a heat-flow system..." - eqs = [connect(mass1.port, th_resistor.port_a, th_conductor.port_a) - connect(th_conductor.port_b, flow_src.port, hf_sensor1.port_a, - hf_sensor2.port_a) - connect(th_resistor.port_b, hf_sensor1.port_b, hf_sensor2.port_b, - th_ground.port)] - @named h2 = System(eqs, t, - systems = [mass1, hf_sensor1, hf_sensor2, - th_resistor, flow_src, th_ground, th_conductor]) + eqs = [ + connect(mass1.port, th_resistor.port_a, th_conductor.port_a) + connect( + th_conductor.port_b, flow_src.port, hf_sensor1.port_a, + hf_sensor2.port_a + ) + connect( + th_resistor.port_b, hf_sensor1.port_b, hf_sensor2.port_b, + th_ground.port + ) + ] + @named h2 = System( + eqs, t, + systems = [ + mass1, hf_sensor1, hf_sensor2, + th_resistor, flow_src, th_ground, th_conductor, + ] + ) sys = mtkcompile(h2) u0 = [mass1.T => 10.0, th_conductor.dT => nothing, th_conductor.Q_flow => nothing, th_resistor.Q_flow => nothing, th_resistor.dT => nothing] @@ -101,17 +117,21 @@ end @named mass = HeatCapacitor(C = 10) @info "Building a radiator..." - eqs = [connect(gas_tem.port, radiator.port_a, base.port_a, dissipator.solid, mass.port) - connect(coolant_tem.port, base.port_b, radiator.port_b, dissipator.fluid)] - @named rad = System(eqs, t, + eqs = [ + connect(gas_tem.port, radiator.port_a, base.port_a, dissipator.solid, mass.port) + connect(coolant_tem.port, base.port_b, radiator.port_b, dissipator.fluid) + ] + @named rad = System( + eqs, t, systems = [ base, gas_tem, radiator, dissipator, coolant_tem, - mass - ]) + mass, + ] + ) sys = mtkcompile(rad) u0 = [mass.T => T_gas] @@ -133,13 +153,19 @@ end @named mass = HeatCapacitor(C = 10) @info "Building a heat collector..." - eqs = [connect(flow_src.port, collector.port_a_1, th_resistor.port_a) - connect(tem_src.port, collector.port_a_2) - connect(hf_sensor.port_a, collector.port_b) - connect(hf_sensor.port_b, mass.port, th_resistor.port_b)] - @named coll = System(eqs, t, - systems = [hf_sensor, flow_src, tem_src, - collector, th_resistor, mass]) + eqs = [ + connect(flow_src.port, collector.port_a_1, th_resistor.port_a) + connect(tem_src.port, collector.port_a_2) + connect(hf_sensor.port_a, collector.port_b) + connect(hf_sensor.port_b, mass.port, th_resistor.port_b) + ] + @named coll = System( + eqs, t, + systems = [ + hf_sensor, flow_src, tem_src, + collector, th_resistor, mass, + ] + ) sys = mtkcompile(coll) prob = ODEProblem(sys, [mass.T => nothing, th_resistor.Q_flow => nothing, th_resistor.dT => nothing], (0, 3.0)) @@ -147,8 +173,8 @@ end @test SciMLBase.successful_retcode(sol) @test sol[collector.port_b.Q_flow] + sol[collector.port_a_1.Q_flow] + - sol[collector.port_a_2.Q_flow] == - zeros(length(sol[collector.port_b.Q_flow])) + sol[collector.port_a_2.Q_flow] == + zeros(length(sol[collector.port_b.Q_flow])) @test sol[collector.port_b.T] == sol[collector.port_a_1.T] == sol[collector.port_a_2.T] end @@ -174,5 +200,5 @@ end heat_flow = sol[test_model.heatflow.port.Q_flow] @test SciMLBase.successful_retcode(sol) # Ensure the simulation is successful - @test all(isapprox.(heat_flow, 1.0, rtol = 1e-6)) # Heat flow value should be equal to the fixed value defined + @test all(isapprox.(heat_flow, 1.0, rtol = 1.0e-6)) # Heat flow value should be equal to the fixed value defined end diff --git a/test/chua_circuit.jl b/test/chua_circuit.jl index 3b95b31a3..cf9f20899 100644 --- a/test/chua_circuit.jl +++ b/test/chua_circuit.jl @@ -11,13 +11,17 @@ using IfElse: ifelse @component function NonlinearResistor(; name, Ga, Gb, Ve) @named oneport = OnePort() @unpack v, i = oneport - pars = @parameters Ga=Ga Gb=Gb Ve=Ve + pars = @parameters Ga = Ga Gb = Gb Ve = Ve eqs = [ - i ~ ifelse(v < -Ve, - Gb * (v + Ve) - Ga * Ve, - ifelse(v > Ve, - Gb * (v - Ve) + Ga * Ve, - Ga * v)) + i ~ ifelse( + v < -Ve, + Gb * (v + Ve) - Ga * Ve, + ifelse( + v > Ve, + Gb * (v - Ve) + Ga * Ve, + Ga * v + ) + ), ] extend(System(eqs, t, [], pars; name = name), oneport) end @@ -27,24 +31,28 @@ using IfElse: ifelse @named G = Conductor(G = 0.565) @named C1 = Capacitor(C = 10, v = 4) @named C2 = Capacitor(C = 100, v = 0.0) - @named Nr = NonlinearResistor(Ga = -0.757576, + @named Nr = NonlinearResistor( + Ga = -0.757576, Gb = -0.409091, - Ve = 1) + Ve = 1 + ) @named Gnd = Ground() - connections = [connect(L.p, G.p) - connect(G.n, Nr.p) - connect(Nr.n, Gnd.g) - connect(C1.p, G.n) - connect(L.n, Ro.p) - connect(G.p, C2.p) - connect(C1.n, Gnd.g) - connect(C2.n, Gnd.g) - connect(Ro.n, Gnd.g)] + connections = [ + connect(L.p, G.p) + connect(G.n, Nr.p) + connect(Nr.n, Gnd.g) + connect(C1.p, G.n) + connect(L.n, Ro.p) + connect(G.p, C2.p) + connect(C1.n, Gnd.g) + connect(C2.n, Gnd.g) + connect(Ro.n, Gnd.g) + ] @named model = System(connections, t, systems = [L, Ro, G, C1, C2, Nr, Gnd]) sys = mtkcompile(model) - prob = ODEProblem(sys, Pair[], (0, 5e4), saveat = 0.01) + prob = ODEProblem(sys, Pair[], (0, 5.0e4), saveat = 0.01) sol = solve(prob, Rodas4()) @test sol.retcode == Success diff --git a/test/multi_domain.jl b/test/multi_domain.jl index 866b9ea31..0958a7447 100644 --- a/test/multi_domain.jl +++ b/test/multi_domain.jl @@ -61,13 +61,13 @@ using OrdinaryDiffEq: ReturnCode.Success @test -0.5 .* sol[dc_motor.emf.i] == sol[dc_motor.emf.flange.tau] @test sol[dc_motor.emf.v] == 0.5 .* sol[dc_motor.emf.w] # test steady-state values - dc_gain = [f/(k^2 + f * R) k/(k^2 + f * R); k/(k^2 + f * R) -R/(k^2 + f * R)] + dc_gain = [f / (k^2 + f * R) k / (k^2 + f * R); k / (k^2 + f * R) -R / (k^2 + f * R)] idx_t = findfirst(sol.t .> 2.5) - @test sol[dc_motor.inertia.w][idx_t]≈(dc_gain * [V_step; 0])[2] rtol=1e-3 - @test sol[dc_motor.emf.i][idx_t]≈(dc_gain * [V_step; 0])[1] rtol=1e-3 + @test sol[dc_motor.inertia.w][idx_t] ≈ (dc_gain * [V_step; 0])[2] rtol = 1.0e-3 + @test sol[dc_motor.emf.i][idx_t] ≈ (dc_gain * [V_step; 0])[1] rtol = 1.0e-3 idx_t = findfirst(sol.t .> 5.5) - @test sol[dc_motor.inertia.w][idx_t]≈(dc_gain * [V_step; -tau_L_step])[2] rtol=1e-3 - @test sol[dc_motor.emf.i][idx_t]≈(dc_gain * [V_step; -tau_L_step])[1] rtol=1e-3 + @test sol[dc_motor.inertia.w][idx_t] ≈ (dc_gain * [V_step; -tau_L_step])[2] rtol = 1.0e-3 + @test sol[dc_motor.emf.i][idx_t] ≈ (dc_gain * [V_step; -tau_L_step])[1] rtol = 1.0e-3 @test_skip begin prob = DAEProblem(dc_motor, D.(unknowns(dc_motor)) .=> 0.0, (0, 6.0)) @@ -77,13 +77,13 @@ using OrdinaryDiffEq: ReturnCode.Success @test -0.5 .* sol[dc_motor.emf.i] == sol[dc_motor.emf.flange.tau] @test sol[dc_motor.emf.v] == 0.5 .* sol[dc_motor.emf.w] # test steady-state values - dc_gain = [f/(k^2 + f * R) k/(k^2 + f * R); k/(k^2 + f * R) -R/(k^2 + f * R)] + dc_gain = [f / (k^2 + f * R) k / (k^2 + f * R); k / (k^2 + f * R) -R / (k^2 + f * R)] idx_t = findfirst(sol.t .> 2.5) - @test sol[dc_motor.inertia.w][idx_t]≈(dc_gain * [V_step; 0])[2] rtol=1e-3 - @test sol[dc_motor.emf.i][idx_t]≈(dc_gain * [V_step; 0])[1] rtol=1e-3 + @test sol[dc_motor.inertia.w][idx_t] ≈ (dc_gain * [V_step; 0])[2] rtol = 1.0e-3 + @test sol[dc_motor.emf.i][idx_t] ≈ (dc_gain * [V_step; 0])[1] rtol = 1.0e-3 idx_t = findfirst(sol.t .> 5.5) - @test sol[dc_motor.inertia.w][idx_t]≈(dc_gain * [V_step; -tau_L_step])[2] rtol=1e-3 - @test sol[dc_motor.emf.i][idx_t]≈(dc_gain * [V_step; -tau_L_step])[1] rtol=1e-3 + @test sol[dc_motor.inertia.w][idx_t] ≈ (dc_gain * [V_step; -tau_L_step])[2] rtol = 1.0e-3 + @test sol[dc_motor.emf.i][idx_t] ≈ (dc_gain * [V_step; -tau_L_step])[1] rtol = 1.0e-3 end # p1 = Plots.plot(sol, vars=[inertia.w], ylabel="Angular Vel. in rad/s", label="") # p2 = Plots.plot(sol, vars=[emf.i], ylabel="Current in A", label="") @@ -147,13 +147,13 @@ end @test sol[sys.emf.v] == 0.5 .* sol[sys.emf.w] # test steady-state values - dc_gain = [f/(k^2 + f * R) k/(k^2 + f * R); k/(k^2 + f * R) -R/(k^2 + f * R)] + dc_gain = [f / (k^2 + f * R) k / (k^2 + f * R); k / (k^2 + f * R) -R / (k^2 + f * R)] idx_t = findfirst(sol.t .> 2.5) - @test sol[sys.inertia.w][idx_t]≈(dc_gain * [V_step; 0])[2] rtol=1e-3 - @test sol[sys.emf.i][idx_t]≈(dc_gain * [V_step; 0])[1] rtol=1e-3 + @test sol[sys.inertia.w][idx_t] ≈ (dc_gain * [V_step; 0])[2] rtol = 1.0e-3 + @test sol[sys.emf.i][idx_t] ≈ (dc_gain * [V_step; 0])[1] rtol = 1.0e-3 idx_t = findfirst(sol.t .> 5.5) - @test sol[sys.inertia.w][idx_t]≈(dc_gain * [V_step; -tau_L_step])[2] rtol=1e-3 - @test sol[sys.emf.i][idx_t]≈(dc_gain * [V_step; -tau_L_step])[1] rtol=1e-3 + @test sol[sys.inertia.w][idx_t] ≈ (dc_gain * [V_step; -tau_L_step])[2] rtol = 1.0e-3 + @test sol[sys.emf.i][idx_t] ≈ (dc_gain * [V_step; -tau_L_step])[1] rtol = 1.0e-3 @test all(sol[sys.inertia.w] .== sol[sys.speed_sensor.w.u]) @test_skip begin @@ -164,13 +164,13 @@ end @test -0.5 .* sol[sys.emf.i] == sol[sys.emf.flange.tau] @test sol[sys.emf.v] == 0.5 .* sol[sys.emf.w] # test steady-state values - dc_gain = [f/(k^2 + f * R) k/(k^2 + f * R); k/(k^2 + f * R) -R/(k^2 + f * R)] + dc_gain = [f / (k^2 + f * R) k / (k^2 + f * R); k / (k^2 + f * R) -R / (k^2 + f * R)] idx_t = findfirst(sol.t .> 2.5) - @test sol[sys.inertia.w][idx_t]≈(dc_gain * [V_step; 0])[2] rtol=1e-3 - @test sol[sys.emf.i][idx_t]≈(dc_gain * [V_step; 0])[1] rtol=1e-3 + @test sol[sys.inertia.w][idx_t] ≈ (dc_gain * [V_step; 0])[2] rtol = 1.0e-3 + @test sol[sys.emf.i][idx_t] ≈ (dc_gain * [V_step; 0])[1] rtol = 1.0e-3 idx_t = findfirst(sol.t .> 5.5) - @test sol[sys.inertia.w][idx_t]≈(dc_gain * [V_step; -tau_L_step])[2] rtol=1e-3 - @test sol[sys.emf.i][idx_t]≈(dc_gain * [V_step; -tau_L_step])[1] rtol=1e-3 + @test sol[sys.inertia.w][idx_t] ≈ (dc_gain * [V_step; -tau_L_step])[2] rtol = 1.0e-3 + @test sol[sys.emf.i][idx_t] ≈ (dc_gain * [V_step; -tau_L_step])[1] rtol = 1.0e-3 # @test all(sol[sys.inertia.w] .== sol[sys.speed_sensor.w.u]) end @@ -182,8 +182,10 @@ end ground = Ground() source = Voltage() voltage_sine = Blocks.Sine(amplitude = 220, frequency = 1) - heating_resistor = Resistor(R = 100, alpha = 1e-3, - T_ref = 293.15, T_dep = true) + heating_resistor = Resistor( + R = 100, alpha = 1.0e-3, + T_ref = 293.15, T_dep = true + ) thermal_conductor = ThermalConductor(G = 50) env = FixedTemperature(T = 273.15 + 20) end