ParallelResonance
ParallelResonance
models two parallel RLC resonance circuits, each driven by a current source with variable frequency and amplitude.
This component simulates two independent parallel RLC circuits. The first circuit is driven by a sinusoidal current source, and the second by a cosinusoidal current source. The frequency of both current sources is controlled by a common ramp signal, causing a frequency sweep. The amplitude of both current sources is determined by a common constant signal. Each RLC circuit consists of a resistor, an inductor, and a capacitor connected in parallel with the current source and a voltage sensor. The ground components provide a common reference potential.
Usage
ParallelResonance()
Behavior
Source
# `ParallelResonance` models two parallel RLC resonance circuits, each driven by a current source with variable frequency and amplitude.
#
# This component simulates two independent parallel RLC circuits. The first circuit is driven by a sinusoidal current source,
# and the second by a cosinusoidal current source. The frequency of both current sources is controlled by a common ramp signal,
# causing a frequency sweep. The amplitude of both current sources is determined by a common constant signal.
# Each RLC circuit consists of a resistor, an inductor, and a capacitor connected in parallel with the current source
# and a voltage sensor. The ground components provide a common reference potential.
example component ParallelResonance
# First RLC circuit's ideal current source for the first RLC circuit.
current_source1 = CurrentSource() [{
"Dyad": {
"placement": {"icon": {"x1": 100, "y1": 100, "x2": 300, "y2": 300, "rot": 270}}
}
}]
# First RLC circuit's ground reference for the first RLC circuit.
ground1 = Ground() [{
"Dyad": {"placement": {"icon": {"x1": 100, "y1": 400, "x2": 300, "y2": 600, "rot": 0}}}
}]
# First RLC circuit's resistor in the first parallel RLC circuit.
resistor1 = Resistor(R=0.5) [{
"Dyad": {"placement": {"icon": {"x1": 400, "y1": 100, "x2": 600, "y2": 300, "rot": 90}}}
}]
# First RLC circuit's inductor in the first parallel RLC circuit.
inductor1 = Inductor(L=0.1/(2*pi)) [{
"Dyad": {"placement": {"icon": {"x1": 700, "y1": 100, "x2": 900, "y2": 300, "rot": 90}}}
}]
# First RLC circuit's capacitor in the first parallel RLC circuit.
capacitor1 = Capacitor(C=0.001/(2*pi)) [{
"Dyad": {
"placement": {"icon": {"x1": 1000, "y1": 100, "x2": 1200, "y2": 300, "rot": 90}}
}
}]
# First RLC circuit's voltage sensor across the first RLC circuit.
voltage_sensor1 = VoltageSensor() [{
"Dyad": {
"placement": {"icon": {"x1": 1300, "y1": 100, "x2": 1500, "y2": 300, "rot": 90}}
}
}]
# Generates a sine wave with variable frequency and amplitude for the first current source.
input_signal1 = BlockComponents.SineVariableFrequencyAndAmplitude() [{
"Dyad": {"placement": {"icon": {"x1": -200, "y1": 100, "x2": 0, "y2": 300, "rot": 0}}}
}]
# Generates a cosine wave with variable frequency and amplitude for the second current source.
input_signal2 = BlockComponents.CosineVariableFrequencyAndAmplitude() [{
"Dyad": {"placement": {"icon": {"x1": -200, "y1": 700, "x2": 0, "y2": 900, "rot": 0}}}
}]
# Generates a ramp signal to control the frequency of the input signals.
ramp = BlockComponents.Ramp(start_time=0, duration=1, offset=0, height=200) [{
"Dyad": {
"placement": {"icon": {"x1": -600, "y1": 250, "x2": -400, "y2": 450, "rot": 0}}
}
}]
# Generates a constant signal to control the amplitude of the input signals.
const_signal = BlockComponents.Constant(k=1) [{
"Dyad": {
"placement": {"icon": {"x1": -600, "y1": 550, "x2": -400, "y2": 750, "rot": 0}}
}
}]
# Second RLC circuit's ideal current source for the second RLC circuit (cosine wave).
current_source2 = CurrentSource() [{
"Dyad": {
"placement": {"icon": {"x1": 100, "y1": 700, "x2": 300, "y2": 900, "rot": 270}}
}
}]
# Second RLC circuit's ground reference for the second RLC circuit.
ground2 = Ground() [{
"Dyad": {
"placement": {"icon": {"x1": 100, "y1": 1000, "x2": 300, "y2": 1200, "rot": 0}}
}
}]
# Second RLC circuit's resistor in the second parallel RLC circuit.
resistor2 = Resistor(R=0.5) [{
"Dyad": {"placement": {"icon": {"x1": 400, "y1": 700, "x2": 600, "y2": 900, "rot": 90}}}
}]
# Second RLC circuit's inductor in the second parallel RLC circuit.
inductor2 = Inductor(L=0.1/(2*pi)) [{
"Dyad": {"placement": {"icon": {"x1": 700, "y1": 700, "x2": 900, "y2": 900, "rot": 90}}}
}]
# Second RLC circuit's capacitor in the second parallel RLC circuit.
capacitor2 = Capacitor(C=0.001/(2*pi)) [{
"Dyad": {
"placement": {"icon": {"x1": 1000, "y1": 700, "x2": 1200, "y2": 900, "rot": 90}}
}
}]
# Second RLC circuit's voltage sensor across the second RLC circuit.
voltage_sensor2 = VoltageSensor() [{
"Dyad": {
"placement": {"icon": {"x1": 1300, "y1": 700, "x2": 1500, "y2": 900, "rot": 90}}
}
}]
relations
initial inductor1.i = 0
initial inductor2.i = 0
initial capacitor1.v = 0
initial capacitor2.v = 0
connect(ramp.y, input_signal1.frequency, input_signal2.frequency) [{
"Dyad": {
"edges": [
{"S": -1, "E": 1},
{"S": -1, "M": [{"x": -350, "y": 240}], "E": 2},
{"S": -1, "M": [{"x": -350, "y": 840}], "E": 3}
],
"junctions": [{"x": -350, "y": 350}]
}
}]
connect(const_signal.y, input_signal1.amplitude, input_signal2.amplitude) [{
"Dyad": {
"edges": [
{"S": -1, "E": 1},
{"S": -1, "M": [{"x": -300, "y": 160}], "E": 2},
{"S": -1, "M": [{"x": -300, "y": 760}], "E": 3}
],
"junctions": [{"x": -300, "y": 650}]
}
}]
connect(input_signal1.y, current_source1.I) [{"Dyad": {"edges": [{"S": 1, "E": 2}]}}]
connect(input_signal2.y, current_source2.I) [{"Dyad": {"edges": [{"S": 1, "E": 2}]}}]
connect(current_source1.n, resistor1.p, inductor1.p, capacitor1.p, voltage_sensor1.p) [{
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 200, "y": 50}], "E": -1},
{"S": -1, "E": 2},
{"S": -1, "M": [{"x": 800, "y": 50}], "E": 3},
{"S": -1, "M": [{"x": 1100, "y": 50}], "E": 4},
{"S": -1, "M": [{"x": 1400, "y": 50}], "E": 5}
],
"junctions": [{"x": 500, "y": 50}]
}
}]
connect(ground1.g, current_source1.p, resistor1.n, inductor1.n, capacitor1.n, voltage_sensor1.n) [{
"Dyad": {
"edges": [
{"S": 1, "E": -1},
{"S": 2, "E": -1},
{"S": -1, "M": [{"x": 500, "y": 350}], "E": 3},
{"S": -1, "M": [{"x": 800, "y": 350}], "E": 4},
{"S": -1, "M": [{"x": 1100, "y": 350}], "E": 5},
{"S": -1, "M": [{"x": 1400, "y": 350}], "E": 6}
],
"junctions": [{"x": 200, "y": 350}]
}
}]
connect(current_source2.n, resistor2.p, inductor2.p, capacitor2.p, voltage_sensor2.p) [{
"Dyad": {
"edges": [
{"S": -1, "M": [{"x": 200, "y": 650}], "E": 1},
{"S": -1, "E": 2},
{"S": -1, "M": [{"x": 800, "y": 650}], "E": 3},
{"S": -1, "M": [{"x": 1100, "y": 650}], "E": 4},
{"S": -1, "M": [{"x": 1400, "y": 650}], "E": 5}
],
"junctions": [{"x": 500, "y": 650}]
}
}]
connect(ground2.g, current_source2.p, resistor2.n, inductor2.n, capacitor2.n, voltage_sensor2.n) [{
"Dyad": {
"edges": [
{"S": -1, "E": 1},
{"S": -1, "E": 2},
{"S": -1, "M": [{"x": 500, "y": 950}], "E": 3},
{"S": -1, "M": [{"x": 800, "y": 950}], "E": 4},
{"S": -1, "M": [{"x": 1100, "y": 950}], "E": 5},
{"S": -1, "M": [{"x": 1400, "y": 950}], "E": 6}
],
"junctions": [{"x": 200, "y": 950}]
}
}]
metadata {
"Dyad": {
"tests": {
"case1": {"stop": 1, "expect": {"signals": ["voltage_sensor1.v", "voltage_sensor2.v"]}}
}
}
}
end
Flattened Source
# `ParallelResonance` models two parallel RLC resonance circuits, each driven by a current source with variable frequency and amplitude.
#
# This component simulates two independent parallel RLC circuits. The first circuit is driven by a sinusoidal current source,
# and the second by a cosinusoidal current source. The frequency of both current sources is controlled by a common ramp signal,
# causing a frequency sweep. The amplitude of both current sources is determined by a common constant signal.
# Each RLC circuit consists of a resistor, an inductor, and a capacitor connected in parallel with the current source
# and a voltage sensor. The ground components provide a common reference potential.
example component ParallelResonance
# First RLC circuit's ideal current source for the first RLC circuit.
current_source1 = CurrentSource() [{
"Dyad": {
"placement": {"icon": {"x1": 100, "y1": 100, "x2": 300, "y2": 300, "rot": 270}}
}
}]
# First RLC circuit's ground reference for the first RLC circuit.
ground1 = Ground() [{
"Dyad": {"placement": {"icon": {"x1": 100, "y1": 400, "x2": 300, "y2": 600, "rot": 0}}}
}]
# First RLC circuit's resistor in the first parallel RLC circuit.
resistor1 = Resistor(R=0.5) [{
"Dyad": {"placement": {"icon": {"x1": 400, "y1": 100, "x2": 600, "y2": 300, "rot": 90}}}
}]
# First RLC circuit's inductor in the first parallel RLC circuit.
inductor1 = Inductor(L=0.1/(2*pi)) [{
"Dyad": {"placement": {"icon": {"x1": 700, "y1": 100, "x2": 900, "y2": 300, "rot": 90}}}
}]
# First RLC circuit's capacitor in the first parallel RLC circuit.
capacitor1 = Capacitor(C=0.001/(2*pi)) [{
"Dyad": {
"placement": {"icon": {"x1": 1000, "y1": 100, "x2": 1200, "y2": 300, "rot": 90}}
}
}]
# First RLC circuit's voltage sensor across the first RLC circuit.
voltage_sensor1 = VoltageSensor() [{
"Dyad": {
"placement": {"icon": {"x1": 1300, "y1": 100, "x2": 1500, "y2": 300, "rot": 90}}
}
}]
# Generates a sine wave with variable frequency and amplitude for the first current source.
input_signal1 = BlockComponents.SineVariableFrequencyAndAmplitude() [{
"Dyad": {"placement": {"icon": {"x1": -200, "y1": 100, "x2": 0, "y2": 300, "rot": 0}}}
}]
# Generates a cosine wave with variable frequency and amplitude for the second current source.
input_signal2 = BlockComponents.CosineVariableFrequencyAndAmplitude() [{
"Dyad": {"placement": {"icon": {"x1": -200, "y1": 700, "x2": 0, "y2": 900, "rot": 0}}}
}]
# Generates a ramp signal to control the frequency of the input signals.
ramp = BlockComponents.Ramp(start_time=0, duration=1, offset=0, height=200) [{
"Dyad": {
"placement": {"icon": {"x1": -600, "y1": 250, "x2": -400, "y2": 450, "rot": 0}}
}
}]
# Generates a constant signal to control the amplitude of the input signals.
const_signal = BlockComponents.Constant(k=1) [{
"Dyad": {
"placement": {"icon": {"x1": -600, "y1": 550, "x2": -400, "y2": 750, "rot": 0}}
}
}]
# Second RLC circuit's ideal current source for the second RLC circuit (cosine wave).
current_source2 = CurrentSource() [{
"Dyad": {
"placement": {"icon": {"x1": 100, "y1": 700, "x2": 300, "y2": 900, "rot": 270}}
}
}]
# Second RLC circuit's ground reference for the second RLC circuit.
ground2 = Ground() [{
"Dyad": {
"placement": {"icon": {"x1": 100, "y1": 1000, "x2": 300, "y2": 1200, "rot": 0}}
}
}]
# Second RLC circuit's resistor in the second parallel RLC circuit.
resistor2 = Resistor(R=0.5) [{
"Dyad": {"placement": {"icon": {"x1": 400, "y1": 700, "x2": 600, "y2": 900, "rot": 90}}}
}]
# Second RLC circuit's inductor in the second parallel RLC circuit.
inductor2 = Inductor(L=0.1/(2*pi)) [{
"Dyad": {"placement": {"icon": {"x1": 700, "y1": 700, "x2": 900, "y2": 900, "rot": 90}}}
}]
# Second RLC circuit's capacitor in the second parallel RLC circuit.
capacitor2 = Capacitor(C=0.001/(2*pi)) [{
"Dyad": {
"placement": {"icon": {"x1": 1000, "y1": 700, "x2": 1200, "y2": 900, "rot": 90}}
}
}]
# Second RLC circuit's voltage sensor across the second RLC circuit.
voltage_sensor2 = VoltageSensor() [{
"Dyad": {
"placement": {"icon": {"x1": 1300, "y1": 700, "x2": 1500, "y2": 900, "rot": 90}}
}
}]
relations
initial inductor1.i = 0
initial inductor2.i = 0
initial capacitor1.v = 0
initial capacitor2.v = 0
connect(ramp.y, input_signal1.frequency, input_signal2.frequency) [{
"Dyad": {
"edges": [
{"S": -1, "E": 1},
{"S": -1, "M": [{"x": -350, "y": 240}], "E": 2},
{"S": -1, "M": [{"x": -350, "y": 840}], "E": 3}
],
"junctions": [{"x": -350, "y": 350}]
}
}]
connect(const_signal.y, input_signal1.amplitude, input_signal2.amplitude) [{
"Dyad": {
"edges": [
{"S": -1, "E": 1},
{"S": -1, "M": [{"x": -300, "y": 160}], "E": 2},
{"S": -1, "M": [{"x": -300, "y": 760}], "E": 3}
],
"junctions": [{"x": -300, "y": 650}]
}
}]
connect(input_signal1.y, current_source1.I) [{"Dyad": {"edges": [{"S": 1, "E": 2}]}}]
connect(input_signal2.y, current_source2.I) [{"Dyad": {"edges": [{"S": 1, "E": 2}]}}]
connect(current_source1.n, resistor1.p, inductor1.p, capacitor1.p, voltage_sensor1.p) [{
"Dyad": {
"edges": [
{"S": 1, "M": [{"x": 200, "y": 50}], "E": -1},
{"S": -1, "E": 2},
{"S": -1, "M": [{"x": 800, "y": 50}], "E": 3},
{"S": -1, "M": [{"x": 1100, "y": 50}], "E": 4},
{"S": -1, "M": [{"x": 1400, "y": 50}], "E": 5}
],
"junctions": [{"x": 500, "y": 50}]
}
}]
connect(ground1.g, current_source1.p, resistor1.n, inductor1.n, capacitor1.n, voltage_sensor1.n) [{
"Dyad": {
"edges": [
{"S": 1, "E": -1},
{"S": 2, "E": -1},
{"S": -1, "M": [{"x": 500, "y": 350}], "E": 3},
{"S": -1, "M": [{"x": 800, "y": 350}], "E": 4},
{"S": -1, "M": [{"x": 1100, "y": 350}], "E": 5},
{"S": -1, "M": [{"x": 1400, "y": 350}], "E": 6}
],
"junctions": [{"x": 200, "y": 350}]
}
}]
connect(current_source2.n, resistor2.p, inductor2.p, capacitor2.p, voltage_sensor2.p) [{
"Dyad": {
"edges": [
{"S": -1, "M": [{"x": 200, "y": 650}], "E": 1},
{"S": -1, "E": 2},
{"S": -1, "M": [{"x": 800, "y": 650}], "E": 3},
{"S": -1, "M": [{"x": 1100, "y": 650}], "E": 4},
{"S": -1, "M": [{"x": 1400, "y": 650}], "E": 5}
],
"junctions": [{"x": 500, "y": 650}]
}
}]
connect(ground2.g, current_source2.p, resistor2.n, inductor2.n, capacitor2.n, voltage_sensor2.n) [{
"Dyad": {
"edges": [
{"S": -1, "E": 1},
{"S": -1, "E": 2},
{"S": -1, "M": [{"x": 500, "y": 950}], "E": 3},
{"S": -1, "M": [{"x": 800, "y": 950}], "E": 4},
{"S": -1, "M": [{"x": 1100, "y": 950}], "E": 5},
{"S": -1, "M": [{"x": 1400, "y": 950}], "E": 6}
],
"junctions": [{"x": 200, "y": 950}]
}
}]
metadata {
"Dyad": {
"tests": {
"case1": {"stop": 1, "expect": {"signals": ["voltage_sensor1.v", "voltage_sensor2.v"]}}
}
}
}
end
Test Cases
This is setup code, that must be run before each test case.
using ElectricalComponents
using ModelingToolkit, OrdinaryDiffEqDefault
using Plots
using CSV, DataFrames
snapshotsdir = joinpath(dirname(dirname(pathof(ElectricalComponents))), "test", "snapshots")
"/home/actions-runner-10/.julia/packages/ElectricalComponents/bmmPM/test/snapshots"
Test Case case1
@mtkbuild model_case1 = ParallelResonance()
u0_case1 = []
prob_case1 = ODEProblem(model_case1, u0_case1, (0, 1))
sol_case1 = solve(prob_case1)
retcode: Success
Interpolation: 3rd order Hermite
t: 4822-element Vector{Float64}:
0.0
8.533321759274957e-5
0.00012402352128278656
0.00020053874052136555
0.000266177163981122
0.0003578401880100186
0.00045502457439345256
0.000579813655399151
0.0007266869994155729
0.0009180233344093003
⋮
0.9987405860319664
0.9989101246761419
0.999078809158732
0.9992573911273945
0.9994294107516979
0.9996037665583521
0.9997756340790755
0.9999473839433828
1.0
u: 4822-element Vector{Vector{Float64}}:
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
[4.575263503143031e-6, 4.575263503143031e-6, 6.367621392059595e-7, 0.32856679292223834, 9.041991076445639e-10, 0.0010369879067195023]
[9.664691232681612e-6, 9.664691232681612e-6, 1.7713785771330322e-6, 0.39428580548826764, 3.6923365287112465e-9, 0.0019221023309033223]
[2.5268323853865586e-5, 2.5268323853865586e-5, 6.261513738282452e-6, 0.458609552320222, 2.172761410662315e-8, 0.003997227015036623]
[4.451654547991291e-5, 4.451654547991291e-5, 1.2774402252991423e-5, 0.48042540948025697, 6.010445607552386e-8, 0.005940009195967064]
[8.045593662844021e-5, 8.045593662844021e-5, 2.6225429895305837e-5, 0.49120422722388085, 1.6994324708386698e-7, 0.008744665105747973]
[0.00013009169509890393, 0.00013009169509890393, 4.614462502397451e-5, 0.4936831713453033, 3.8792230784862293e-7, 0.011754118912657405]
[0.00021123055838310613, 0.00021123055838310613, 8.031038136361486e-5, 0.49306544848530975, 8.773616426357049e-7, 0.015623904626258482]
[0.00033179867672391503, 0.00033179867672391503, 0.00013287973008187178, 0.491086505169024, 1.8507964717452991e-6, 0.020165385616893777]
[0.0005295260242299606, 0.0005295260242299606, 0.00022132134352030282, 0.4881871325937557, 3.957334823676652e-6, 0.026051966396910417]
⋮
[626.7369010408527, 626.7369010408527, -0.4966383497394134, -0.042528705839674205, 0.002151779440531485, -0.02487203445412845]
[626.9496993281382, 626.9496993281382, -0.4944292539523966, 0.06330590548013994, -0.0031485192706092627, -0.02476127344896844]
[627.1614613526015, 627.1614613526015, -0.47008772669678495, 0.16580209787798364, -0.008280654373205373, -0.023542550847705544]
[627.3856873840169, 627.3856873840169, -0.4214003467695424, 0.26615076583455893, -0.01330551832726803, -0.021108383171808572]
[627.6017116846639, 627.6017116846639, -0.354593101021109, 0.3503000643246227, -0.01751723774990812, -0.01776312567027865]
[627.8207077368048, 627.8207077368048, -0.27002360754097243, 0.41895578005307876, -0.02095394427250453, -0.013531289239262273]
[628.0366158159994, 628.0366158159994, -0.17401737930333755, 0.4670833519989153, -0.023362030015181258, -0.008727097686226554]
[628.252413170656, 628.252413170656, -0.06997830873912683, 0.4935114694696237, -0.024684509348782874, -0.0035221754104227346]
[628.3185307179598, 628.3185307179598, -0.03724776163697283, 0.49713482165320244, -0.024861823713631392, -0.0018840442550798248]
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.voltage_sensor1.v])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "ParallelResonance_case1_sig0.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.voltage_sensor1.v], width=2, label="Actual value of voltage_sensor1.v")
if !isnothing(dfr_case1)
scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of voltage_sensor1.v")
end
plt
df_case1 = DataFrame(:t => sol_case1[:t], :actual => sol_case1[model_case1.voltage_sensor2.v])
dfr_case1 = try CSV.read(joinpath(snapshotsdir, "ParallelResonance_case1_sig1.ref"), DataFrame); catch e; nothing; end
plt = plot(sol_case1, idxs=[model_case1.voltage_sensor2.v], width=2, label="Actual value of voltage_sensor2.v")
if !isnothing(dfr_case1)
scatter!(plt, dfr_case1.t, dfr_case1.expected, mc=:red, ms=3, label="Expected value of voltage_sensor2.v")
end
plt
Related
Examples
Experiments
Analyses