Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add diode component #343

Merged
merged 5 commits into from
Nov 21, 2024
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
2 changes: 2 additions & 0 deletions docs/src/API/electrical.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ Conductor
Capacitor
Inductor
IdealOpAmp
Diode
HeatingDiode
```

## Analog Sensors
Expand Down
82 changes: 82 additions & 0 deletions src/Electrical/Analog/ideal_components.jl
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ Temperature dependent electrical resistor
v ~ i * R
end
end

"""
EMF(; name, k)

Expand Down Expand Up @@ -261,3 +262,84 @@ Electromotoric force (electric/mechanic transformer)
flange.tau ~ -k * i
end
end

"""
Diode(; name, Is = 1e-6, n = 1, T = 300.15)

Ideal diode based on the Shockley diode equation.

# States

- See [OnePort](@ref)

# Connectors

- `p` Positive pin
- `n` Negative pin

# Parameters

- `Is`: [`A`] Saturation current
- `n`: Ideality factor
- `T`: [K] Ambient temperature
"""
@mtkmodel Diode begin
begin
k = 1.380649e-23 # Boltzmann constant (J/K)
q = 1.602176634e-19 # Elementary charge (C)
end

@extend v, i = oneport = OnePort(; v = 0.0)
@parameters begin
Is = 1e-6, [description = "Saturation current (A)"]
n = 1, [description = "Ideality factor"]
T = 300.15, [description = "Ambient temperature"]
end
@equations begin
i ~ Is * (exp(v * q / (n * k * T)) - 1)
end
end

"""
HeatingDiode(; name, Is = 1e-6, n = 1)

Temperature dependent diode based on the Shockley diode equation.

# States

- See [OnePort](@ref)

# Connectors

- `p` Positive pin
- `n` Negative pin
- `port` [HeatPort](@ref) Heat port to model the temperature dependency

# Parameters:

- `Is`: [`A`] Saturation current
- `n`: Ideality factor
"""
@mtkmodel HeatingDiode begin
begin
k = 1.380649e-23 # Boltzmann constant (J/K)
q = 1.602176634e-19 # Elementary charge (C)
end

@extend v, i = oneport = OnePort(; v = 0.0)
@components begin
port = HeatPort()
end
@parameters begin
Is = 1e-6, [description = "Saturation current (A)"]
n = 1, [description = "Ideality factor"]
end
@variables begin
Vt(t), [description = "Thermal voltage"]
end
@equations begin
Vt ~ k * port.T / q # Thermal voltage equation
i ~ Is * (exp(v / (n * Vt)) - 1) # Shockley diode equation
port.Q_flow ~ -v * i # -LossPower
end
end
2 changes: 1 addition & 1 deletion src/Electrical/Electrical.jl
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ include("utils.jl")

export Capacitor,
Ground, Inductor, Resistor, Conductor, Short, IdealOpAmp, EMF,
HeatingResistor
HeatingResistor, Diode, HeatingDiode
include("Analog/ideal_components.jl")

export CurrentSensor, PotentialSensor, VoltageSensor, PowerSensor, MultiSensor
Expand Down
114 changes: 114 additions & 0 deletions test/Electrical/analog.jl
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ using ModelingToolkitStandardLibrary.Blocks: Step,
Constant, Sine, Cosine, ExpSine, Ramp,
Square, Triangular
using ModelingToolkitStandardLibrary.Blocks: square, triangular
using ModelingToolkitStandardLibrary.Thermal: FixedTemperature
using OrdinaryDiffEq: ReturnCode.Success

# using Plots
Expand Down Expand Up @@ -372,3 +373,116 @@ end
# savefig(plt, "test_current_$(source.name)")
end
end

@testset "Diode component test" begin
# Parameter values
R = 1.0
C = 1.0
V = 10.0
n = 1.0
Is = 1e-3
f = 1.0

# Components
@named resistor = Resistor(R = R)
@named capacitor = Capacitor(C = C, v = 0.0)
@named source = Voltage()
@named diode = Diode(n = n, Is = Is)
@named ac = Sine(frequency = f, amplitude = V)
@named ground = Ground()

# Connections
connections = [connect(ac.output, source.V)
connect(source.p, diode.p)
connect(diode.n, resistor.p)
connect(resistor.n, capacitor.p)
connect(capacitor.n, source.n, ground.g)]

# Model
@named model = ODESystem(connections, t;
systems = [resistor, capacitor, source, diode, ac, ground])
sys = structural_simplify(model)
prob = ODEProblem(sys, Pair[], (0.0, 10.0))
sol = solve(prob)

# Extract solutions for testing
diode_voltage = sol[diode.v]
diode_current = sol[diode.i]
resistor_current = sol[resistor.i]
capacitor_voltage = sol[capacitor.v]

# Tests
@test all(diode_current .>= -Is)
@test capacitor_voltage[end].≈V rtol=3e-1

# For visual inspection
# plt = plot(sol; vars = [diode.i, resistor.i, capacitor.v],
# size = (800, 600), dpi = 300,
# labels = ["Diode Current" "Resistor Current" "Capacitor Voltage"],
# title = "Diode Test")
# savefig(plt, "diode_test")
end

@testset "HeatingDiode component test" begin
# Parameter values
R = 1.0
C = 1.0
V = 10.0
T = 300.0 # Ambient temperature in Kelvin
n = 2.0
Is = 1e-6
f = 1.0

# Components
@named resistor = Resistor(R = R)
@named capacitor = Capacitor(C = C, v = 0.0)
@named source = Voltage()
@named heating_diode = HeatingDiode(n = n, Is = Is)
@named ac = Sine(frequency = f, amplitude = V)
@named ground = Ground()
@named temp = FixedTemperature(T = T)

# Connections
connections = [connect(ac.output, source.V),
connect(source.p, heating_diode.p),
connect(heating_diode.n, resistor.p),
connect(resistor.n, capacitor.p),
connect(capacitor.n, ground.g),
connect(source.n, ground.g),
connect(temp.port, heating_diode.port)]

# Model
@named model = ODESystem(connections, t;
systems = [resistor, capacitor, source, heating_diode, ac, ground, temp])
sys = structural_simplify(model)
prob = ODEProblem(sys, Pair[], (0.0, 10.0))
sol = solve(prob)

# Extract solutions for testing
diode_voltage = sol[heating_diode.v]
diode_current = sol[heating_diode.i]
resistor_current = sol[resistor.i]
capacitor_voltage = sol[capacitor.v]

# Expected thermal voltage at given temperature
k = 1.380649e-23 # Boltzmann constant (J/K)
q = 1.602176634e-19 # Elementary charge (C)

# Tests
@test all(diode_current .>= -Is) # Diode current should not exceed reverse saturation
@test capacitor_voltage[end]≈V rtol=3e-1 # Final capacitor voltage close to input voltage

# For visual inspection
# plt = plot(sol; vars = [heating_diode.i, resistor.i, capacitor.v],
# size = (800, 600), dpi = 300,
# labels = ["HeatingDiode Current" "Resistor Current" "Capacitor Voltage"],
# title = "HeatingDiode Test")
# savefig(plt, "heating_diode_test")

# Remake model with higher amb. temperature, final capacitor voltage should be lower
T = 400.0
model = remake(prob; p = [temp.T => T])
sol = solve(model)
@test SciMLBase.successful_retcode(sol)
@test sol[capacitor.v][end] < capacitor_voltage[end]
end
Loading