Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/src/connectors/connections.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ nothing # hide
As can be seen, we get exactly the same result. The only difference here is that we are solving an extra equation, which allows us to plot the body position as well.

```@example connections
prob = ODEProblem(sys, [], (0, 10.0), fully_determined=true)
prob = ODEProblem(sys, [], (0, 10.0), fully_determined = true)
sol_p = solve(prob)

p1 = plot(sol_p, idxs = [body.v])
Expand Down Expand Up @@ -281,7 +281,7 @@ function simplify_and_solve(damping, spring, body, ground; initialization_eqs =

println.(full_equations(sys))

prob = ODEProblem(sys, [], (0, 10.0); initialization_eqs, fully_determined=true)
prob = ODEProblem(sys, [], (0, 10.0); initialization_eqs, fully_determined = true)
sol = solve(prob; abstol = 1e-9, reltol = 1e-9)

return sol
Expand Down
23 changes: 14 additions & 9 deletions docs/src/tutorials/MOSFET_calibration.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# MOSFET I-V Curves
In this example, first we'll demonstrate the I-V curves of the NMOS transistor model.
# MOSFET I-V Curves

In this example, first we'll demonstrate the I-V curves of the NMOS transistor model.
First of all, we construct a circuit using the NMOS transistor. We'll need to import ModelingToolkit and the Electrical standard library that holds the transistor models.

```@example NMOS
Expand All @@ -12,6 +13,7 @@ using Plots
```

Here we just connect the source pin to ground, the drain pin to a voltage source named `Vcc`, and the gate pin to a voltage source named `Vb`.

```@example NMOS
@mtkmodel SimpleNMOSCircuit begin
@components begin
Expand All @@ -20,8 +22,8 @@ Here we just connect the source pin to ground, the drain pin to a voltage source
Vb = Voltage()
ground = Ground()

Vcc_const = Constant(k=V_cc)
Vb_const = Constant(k=V_b)
Vcc_const = Constant(k = V_cc)
Vb_const = Constant(k = V_b)
end

@parameters begin
Expand All @@ -48,7 +50,8 @@ prob = ODEProblem(sys, Pair[], (0.0, 10.0))
sol = solve(prob)
```

Now to make sure that the transistor model is working like it's supposed to, we can examine the plots of the drain-source voltage vs. the drain current, otherwise knowns as the I-V curve of the transistor.
Now to make sure that the transistor model is working like it's supposed to, we can examine the plots of the drain-source voltage vs. the drain current, otherwise knowns as the I-V curve of the transistor.

```@example NMOS
v_cc_list = collect(0.05:0.1:10.0)

Expand All @@ -58,7 +61,7 @@ I_D_lists = []
for V_b in [1.0, 1.4, 1.8, 2.2, 2.6]
I_D_list = []
for V_cc in v_cc_list
@mtkbuild sys = SimpleNMOSCircuit(V_cc=V_cc, V_b=V_b)
@mtkbuild sys = SimpleNMOSCircuit(V_cc = V_cc, V_b = V_b)
prob = ODEProblem(sys, Pair[], (0.0, 10.0))
sol = solve(prob)
push!(I_D_list, sol[sys.Q1.d.i][1])
Expand All @@ -67,8 +70,10 @@ for V_b in [1.0, 1.4, 1.8, 2.2, 2.6]
end

reduce(hcat, I_D_lists)
plot(v_cc_list, I_D_lists, title="NMOS IV Curves", label=["V_GS: 1.0 V" "V_GS: 1.4 V" "V_GS: 1.8 V" "V_GS: 2.2 V" "V_GS: 2.6 V"], xlabel = "Drain-Source Voltage (V)", ylabel = "Drain Current (A)")
plot(v_cc_list, I_D_lists, title = "NMOS IV Curves",
label = ["V_GS: 1.0 V" "V_GS: 1.4 V" "V_GS: 1.8 V" "V_GS: 2.2 V" "V_GS: 2.6 V"],
xlabel = "Drain-Source Voltage (V)", ylabel = "Drain Current (A)")
```

We can see that we get exactly what we would expect: as the drain-source voltage increases, the drain current increases, until the the transistor gets in to the saturation region of operation.
Then the only increase in drain current is due to the channel-length modulation effect. Additionally, we can see that the maximum current reached increases as the gate voltage increases.
We can see that we get exactly what we would expect: as the drain-source voltage increases, the drain current increases, until the the transistor gets in to the saturation region of operation.
Then the only increase in drain current is due to the channel-length modulation effect. Additionally, we can see that the maximum current reached increases as the gate voltage increases.
9 changes: 6 additions & 3 deletions docs/src/tutorials/dc_motor_pi.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,12 @@ T(s) &= \dfrac{P(s)C(s)}{I + P(s)C(s)}

```@example dc_motor_pi
using ControlSystemsBase
matrices_S, simplified_sys = Blocks.get_sensitivity(
matrices_S,
simplified_sys = Blocks.get_sensitivity(
model, :y, op = Dict(unknowns(sys) .=> 0.0))
So = ss(matrices_S...) |> minreal # The output-sensitivity function as a StateSpace system
matrices_T, simplified_sys = Blocks.get_comp_sensitivity(
matrices_T,
simplified_sys = Blocks.get_comp_sensitivity(
model, :y, op = Dict(unknowns(sys) .=> 0.0))
To = ss(matrices_T...)# The output complementary sensitivity function as a StateSpace system
bodeplot([So, To], label = ["S" "T"], plot_title = "Sensitivity functions",
Expand All @@ -120,7 +122,8 @@ bodeplot([So, To], label = ["S" "T"], plot_title = "Sensitivity functions",
Similarly, we may compute the loop-transfer function and plot its Nyquist curve

```@example dc_motor_pi
matrices_L, simplified_sys = Blocks.get_looptransfer(
matrices_L,
simplified_sys = Blocks.get_looptransfer(
model, :y, op = Dict(unknowns(sys) .=> 0.0))
L = -ss(matrices_L...) # The loop-transfer function as a StateSpace system. The negative sign is to negate the built-in negative feedback
Ms, ωMs = hinfnorm(So) # Compute the peak of the sensitivity function to draw a circle in the Nyquist plot
Expand Down
4 changes: 2 additions & 2 deletions docs/src/tutorials/input_component.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ my_interpolation = LinearInterpolation(df.data, df.time)

@mtkmodel MassSpringDamperSystem2 begin
@components begin
src = Interpolation(itp=my_interpolation)
src = Interpolation(itp = my_interpolation)
clk = ContinuousClock()
model = MassSpringDamper()
end
Expand Down Expand Up @@ -174,7 +174,7 @@ plot(sol2)
```

!!! note

Note that when changing the data, the length of the new data must be the same as the length of the original data.

## Custom Component with External Data
Expand Down
10 changes: 6 additions & 4 deletions src/Blocks/continuous.jl
Original file line number Diff line number Diff line change
Expand Up @@ -572,11 +572,13 @@ linearized around the operating point `x₀, u₀`, we have `y0, u0 = h(x₀, u
]
# 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)
[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]
[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])
Expand Down
4 changes: 2 additions & 2 deletions src/Blocks/nonlinear.jl
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ 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)
Expand Down
4 changes: 2 additions & 2 deletions src/Blocks/utils.jl
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ Base class for a multiple input multiple output (MIMO) continuous system block.
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]...
Expand Down
22 changes: 11 additions & 11 deletions src/Electrical/Analog/mosfets.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,21 +68,20 @@ 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,
d.i ~
ifelse(d.v < s.v, -1, 1) * ifelse(V_GS < V_tn,
V_DS / R_DS,
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 * (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
)
)

g.i ~ 0
s.i ~ -d.i
end
end



"""
PMOS(;name, V_tp, R_DS, lambda)

Expand Down Expand Up @@ -151,16 +150,17 @@ 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,
d.i ~
-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),
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,
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
)
)

g.i ~ 0
s.i ~ -d.i
end
end
end
10 changes: 6 additions & 4 deletions src/Electrical/Analog/transistors.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,9 @@ Early voltage effect.

I_sub ~ ifelse(use_substrate, -C_CS * D(V_CS), -C_CS * D(V_sub))

c.i ~ (ICC - IEC) * ifelse(use_Early, (1 - V_BC * V_A), 1.0) - IEC / B_R -
(C_jC + C_DC) * D(V_BC) - I_sub
c.i ~
(ICC - IEC) * ifelse(use_Early, (1 - V_BC * V_A), 1.0) - IEC / B_R -
(C_jC + C_DC) * D(V_BC) - I_sub
b.i ~ IEC / B_R + ICC / B_F + (C_jC + C_DC) * D(V_BC) + (C_jE + C_DE) * D(V_BE)
e.i ~ -c.i - b.i - I_sub
end
Expand Down Expand Up @@ -323,8 +324,9 @@ Early voltage effect.

I_sub ~ ifelse(use_substrate, -C_CS * D(V_CS), -C_CS * D(V_sub))

c.i ~ IEC / B_R - (ICC - IEC) * ifelse(use_Early, (1 - V_CB * V_A), 1.0) +
(C_jC + C_DC) * D(V_CB) - I_sub
c.i ~
IEC / B_R - (ICC - IEC) * ifelse(use_Early, (1 - V_CB * V_A), 1.0) +
(C_jC + C_DC) * D(V_CB) - I_sub
b.i ~ -IEC / B_R - ICC / B_F - (C_jC + C_DC) * D(V_CB) - (C_jE + C_DE) * D(V_EB)
e.i ~ -c.i - b.i - I_sub
end
Expand Down
5 changes: 3 additions & 2 deletions src/Mechanical/MultiBody2D/components.jl
Original file line number Diff line number Diff line change
Expand Up @@ -67,8 +67,9 @@
m * ddy_cm ~ m * g + fy1 + fy2

# torques
I * ddA ~ -fy1 * (x2 - x1) / 2 + fy2 * (x2 - x1) / 2 + fx1 * (y2 - y1) / 2 -
fx2 * (y2 - y1) / 2
I * ddA ~
-fy1 * (x2 - x1) / 2 + fy2 * (x2 - x1) / 2 + fx1 * (y2 - y1) / 2 -
fx2 * (y2 - y1) / 2

# geometry
x2 ~ l * cos(A) + x1
Expand Down
8 changes: 5 additions & 3 deletions src/Mechanical/Rotational/components.jl
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,8 @@ This element characterizes any type of gear box which is fixed in the ground and
- `use_support`: If support flange enabled, otherwise implicitly grounded. By default it is `false`
"""
@mtkmodel IdealGear begin
@extend phi_support, flange_a, flange_b = partial_element = PartialElementaryTwoFlangesAndSupport2(;
@extend phi_support, flange_a,
flange_b = partial_element = PartialElementaryTwoFlangesAndSupport2(;
use_support = false)
@parameters begin
ratio, [description = "Transmission ratio"]
Expand Down Expand Up @@ -261,7 +262,8 @@ Friction model: "Armstrong, B. and C.C. de Wit, Friction Modeling and Compensati
w_coul = w_brk / 10
end
@equations begin
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
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
end
end
3 changes: 2 additions & 1 deletion src/Mechanical/Rotational/sources.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
@mtkmodel PartialTorque begin
@extend flange, phi_support = partial_element = PartialElementaryOneFlangeAndSupport2(;
@extend flange,
phi_support = partial_element = PartialElementaryOneFlangeAndSupport2(;
use_support = false)
@variables begin
phi(t),
Expand Down
1 change: 0 additions & 1 deletion test/Blocks/sources.jl
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,6 @@ end
end

@testset "Interpolation in model macro" begin

function MassSpringDamper(; name)
@named input = RealInput()
@variables f(t) x(t)=0 dx(t)=0 ddx(t)
Expand Down
12 changes: 8 additions & 4 deletions test/Blocks/test_analysis_points.jl
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,8 @@ 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(
matrices,
_ = get_sensitivity(
sys_outer, [sys_outer.inner.plant_input, sys_outer.inner.plant_output])

Ps = tf(1, [1, 1]) |> ss
Expand All @@ -348,7 +349,8 @@ So = CS.feedback(1, Ps * Cs)
@test tf(G[1, 2]) ≈ tf(-CS.feedback(Cs, Ps))
@test tf(G[2, 1]) ≈ tf(CS.feedback(Ps, Cs))

matrices, _ = get_comp_sensitivity(
matrices,
_ = get_comp_sensitivity(
sys_outer, [sys_outer.inner.plant_input, sys_outer.inner.plant_output])

G = CS.ss(matrices...) |> sminreal
Expand All @@ -372,15 +374,17 @@ 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(
matrices,
_ = 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)
@test sminreal(L[1, 2]) ≈ ss(-1)
@test tf(L[2, 1]) ≈ tf(Ps)

matrices, _ = linearize(
matrices,
_ = 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))
Loading
Loading