Skip to content

Commit 1827d63

Browse files
Merge pull request #343 from langestefan/diode
Add diode component
2 parents aa4e281 + c079a66 commit 1827d63

File tree

4 files changed

+199
-1
lines changed

4 files changed

+199
-1
lines changed

docs/src/API/electrical.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ Conductor
3131
Capacitor
3232
Inductor
3333
IdealOpAmp
34+
Diode
35+
HeatingDiode
3436
```
3537

3638
## Analog Sensors

src/Electrical/Analog/ideal_components.jl

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ Temperature dependent electrical resistor
218218
v ~ i * R
219219
end
220220
end
221+
221222
"""
222223
EMF(; name, k)
223224
@@ -261,3 +262,84 @@ Electromotoric force (electric/mechanic transformer)
261262
flange.tau ~ -k * i
262263
end
263264
end
265+
266+
"""
267+
Diode(; name, Is = 1e-6, n = 1, T = 300.15)
268+
269+
Ideal diode based on the Shockley diode equation.
270+
271+
# States
272+
273+
- See [OnePort](@ref)
274+
275+
# Connectors
276+
277+
- `p` Positive pin
278+
- `n` Negative pin
279+
280+
# Parameters
281+
282+
- `Is`: [`A`] Saturation current
283+
- `n`: Ideality factor
284+
- `T`: [K] Ambient temperature
285+
"""
286+
@mtkmodel Diode begin
287+
begin
288+
k = 1.380649e-23 # Boltzmann constant (J/K)
289+
q = 1.602176634e-19 # Elementary charge (C)
290+
end
291+
292+
@extend v, i = oneport = OnePort(; v = 0.0)
293+
@parameters begin
294+
Is = 1e-6, [description = "Saturation current (A)"]
295+
n = 1, [description = "Ideality factor"]
296+
T = 300.15, [description = "Ambient temperature"]
297+
end
298+
@equations begin
299+
i ~ Is * (exp(v * q / (n * k * T)) - 1)
300+
end
301+
end
302+
303+
"""
304+
HeatingDiode(; name, Is = 1e-6, n = 1)
305+
306+
Temperature dependent diode based on the Shockley diode equation.
307+
308+
# States
309+
310+
- See [OnePort](@ref)
311+
312+
# Connectors
313+
314+
- `p` Positive pin
315+
- `n` Negative pin
316+
- `port` [HeatPort](@ref) Heat port to model the temperature dependency
317+
318+
# Parameters:
319+
320+
- `Is`: [`A`] Saturation current
321+
- `n`: Ideality factor
322+
"""
323+
@mtkmodel HeatingDiode begin
324+
begin
325+
k = 1.380649e-23 # Boltzmann constant (J/K)
326+
q = 1.602176634e-19 # Elementary charge (C)
327+
end
328+
329+
@extend v, i = oneport = OnePort(; v = 0.0)
330+
@components begin
331+
port = HeatPort()
332+
end
333+
@parameters begin
334+
Is = 1e-6, [description = "Saturation current (A)"]
335+
n = 1, [description = "Ideality factor"]
336+
end
337+
@variables begin
338+
Vt(t), [description = "Thermal voltage"]
339+
end
340+
@equations begin
341+
Vt ~ k * port.T / q # Thermal voltage equation
342+
i ~ Is * (exp(v / (n * Vt)) - 1) # Shockley diode equation
343+
port.Q_flow ~ -v * i # -LossPower
344+
end
345+
end

src/Electrical/Electrical.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ include("utils.jl")
1515

1616
export Capacitor,
1717
Ground, Inductor, Resistor, Conductor, Short, IdealOpAmp, EMF,
18-
HeatingResistor
18+
HeatingResistor, Diode, HeatingDiode
1919
include("Analog/ideal_components.jl")
2020

2121
export CurrentSensor, PotentialSensor, VoltageSensor, PowerSensor, MultiSensor

test/Electrical/analog.jl

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ using ModelingToolkitStandardLibrary.Blocks: Step,
44
Constant, Sine, Cosine, ExpSine, Ramp,
55
Square, Triangular
66
using ModelingToolkitStandardLibrary.Blocks: square, triangular
7+
using ModelingToolkitStandardLibrary.Thermal: FixedTemperature
78
using OrdinaryDiffEq: ReturnCode.Success
89

910
# using Plots
@@ -372,3 +373,116 @@ end
372373
# savefig(plt, "test_current_$(source.name)")
373374
end
374375
end
376+
377+
@testset "Diode component test" begin
378+
# Parameter values
379+
R = 1.0
380+
C = 1.0
381+
V = 10.0
382+
n = 1.0
383+
Is = 1e-3
384+
f = 1.0
385+
386+
# Components
387+
@named resistor = Resistor(R = R)
388+
@named capacitor = Capacitor(C = C, v = 0.0)
389+
@named source = Voltage()
390+
@named diode = Diode(n = n, Is = Is)
391+
@named ac = Sine(frequency = f, amplitude = V)
392+
@named ground = Ground()
393+
394+
# Connections
395+
connections = [connect(ac.output, source.V)
396+
connect(source.p, diode.p)
397+
connect(diode.n, resistor.p)
398+
connect(resistor.n, capacitor.p)
399+
connect(capacitor.n, source.n, ground.g)]
400+
401+
# Model
402+
@named model = ODESystem(connections, t;
403+
systems = [resistor, capacitor, source, diode, ac, ground])
404+
sys = structural_simplify(model)
405+
prob = ODEProblem(sys, Pair[], (0.0, 10.0))
406+
sol = solve(prob)
407+
408+
# Extract solutions for testing
409+
diode_voltage = sol[diode.v]
410+
diode_current = sol[diode.i]
411+
resistor_current = sol[resistor.i]
412+
capacitor_voltage = sol[capacitor.v]
413+
414+
# Tests
415+
@test all(diode_current .>= -Is)
416+
@test capacitor_voltage[end].V rtol=3e-1
417+
418+
# For visual inspection
419+
# plt = plot(sol; vars = [diode.i, resistor.i, capacitor.v],
420+
# size = (800, 600), dpi = 300,
421+
# labels = ["Diode Current" "Resistor Current" "Capacitor Voltage"],
422+
# title = "Diode Test")
423+
# savefig(plt, "diode_test")
424+
end
425+
426+
@testset "HeatingDiode component test" begin
427+
# Parameter values
428+
R = 1.0
429+
C = 1.0
430+
V = 10.0
431+
T = 300.0 # Ambient temperature in Kelvin
432+
n = 2.0
433+
Is = 1e-6
434+
f = 1.0
435+
436+
# Components
437+
@named resistor = Resistor(R = R)
438+
@named capacitor = Capacitor(C = C, v = 0.0)
439+
@named source = Voltage()
440+
@named heating_diode = HeatingDiode(n = n, Is = Is)
441+
@named ac = Sine(frequency = f, amplitude = V)
442+
@named ground = Ground()
443+
@named temp = FixedTemperature(T = T)
444+
445+
# Connections
446+
connections = [connect(ac.output, source.V),
447+
connect(source.p, heating_diode.p),
448+
connect(heating_diode.n, resistor.p),
449+
connect(resistor.n, capacitor.p),
450+
connect(capacitor.n, ground.g),
451+
connect(source.n, ground.g),
452+
connect(temp.port, heating_diode.port)]
453+
454+
# Model
455+
@named model = ODESystem(connections, t;
456+
systems = [resistor, capacitor, source, heating_diode, ac, ground, temp])
457+
sys = structural_simplify(model)
458+
prob = ODEProblem(sys, Pair[], (0.0, 10.0))
459+
sol = solve(prob)
460+
461+
# Extract solutions for testing
462+
diode_voltage = sol[heating_diode.v]
463+
diode_current = sol[heating_diode.i]
464+
resistor_current = sol[resistor.i]
465+
capacitor_voltage = sol[capacitor.v]
466+
467+
# Expected thermal voltage at given temperature
468+
k = 1.380649e-23 # Boltzmann constant (J/K)
469+
q = 1.602176634e-19 # Elementary charge (C)
470+
471+
# Tests
472+
@test all(diode_current .>= -Is) # Diode current should not exceed reverse saturation
473+
@test capacitor_voltage[end]V rtol=3e-1 # Final capacitor voltage close to input voltage
474+
475+
# For visual inspection
476+
# plt = plot(sol; vars = [heating_diode.i, resistor.i, capacitor.v],
477+
# size = (800, 600), dpi = 300,
478+
# labels = ["HeatingDiode Current" "Resistor Current" "Capacitor Voltage"],
479+
# title = "HeatingDiode Test")
480+
# savefig(plt, "heating_diode_test")
481+
482+
# Remake model with higher amb. temperature, final capacitor voltage should be lower
483+
T = 400.0
484+
model = remake(prob; p = [temp.T => T])
485+
sol = solve(model)
486+
@test SciMLBase.successful_retcode(sol)
487+
@test sol[capacitor.v][end] < capacitor_voltage[end]
488+
end

0 commit comments

Comments
 (0)