Skip to content
TUTORIAL

Acausal Modeling and Creating Components ​

In this tutorial, we will build a simple RLC circuit from scratch (no external libraries like ElectricalComponents), and solve it using Dyad.

To get started, create a new component library, as indicated on the Getting started page.

Connector ​

First, let's start with the connector. Modeling physical systems always starts by defining connectors. This is because connectors are used to represent the information exchanged by components that interact with each other.

An electrical connector carries voltage and current. The declaration below illustrates its physical interface. This tutorial uses Dyad's built-in Pin, which also supplies the electrical port icons; keep that built-in definition when following the examples.

dyad
connector Pin
  potential v::Voltage
  flow i::Current
end

Connecting two electrical pins makes their voltages equal. Current balance determines how current divides when several pins meet at a node.

The RLC circuit needs only potential and flow fields. Other connector fields include:

  • stream: intensive quantities, such as specific enthalpy, carried by the flow.

  • path: a quantity defined in exactly one place across a network of connectors.

  • input and output: causal signals.

See Connectors for details.

Dyad includes connectors and units for the primary engineering domains. You can use them directly without adding a component library dependency.

The `flow` variable is generally the time derivative of a conserved quantity.

  • Current (time derivative of charge)

  • Torque (time derivative of angular momentum)

  • Force (time derivative of linear momentum)

  • Mass flow rate (time derivative of stored mass)

The sign convention used in Dyad is that flow is always positive into a component. Without a symmetric convention like this, it would matter which way you oriented a resistor or capacitor (which do not have an inherent orientation). For components where orientation matters, the icon will indicate how the orientation aligns with behavior.

If a component doesn't store the conserved quantity, the sum of all flow variables across all connectors associated with that quantity should be zero.

The potential variables are the quantities that drive this flow, e.g., differences in pressure, temperature, position, voltage, etc.

The built in connectors in Dyad are shown in the table below along with their choices for potential and flow variables:

ConnectorDomainpotentialflow
PinElectricalv::Voltagei::Current
HeatPortThermalT::TemperatureQ_flow::HeatFlowRate
FlangeTranslationals::Positionf::Force
SplineRotationalphi::Angletau::Torque

The physical types Voltage and Current are built into Dyad.

Components ​

Components declare parameters, variables, connectors, and relations. Create dyad/rlc_parts.dyad for the component definitions developed below.

A resistor is simply a component with two pins that obeys Ohm's law:

In Dyad, we can define this as follows:

dyad
component Resistor
  p = Pin()
  n = Pin()
  variable v::Voltage
  variable i::Current
  # Resistance of this resistor
  parameter R::Resistance
relations
  v = p.v - n.v
  i = p.i
  p.i + n.i = 0
  # Ohm's Law
  v = i * R
end

Similarly, we could define a capacitor:

dyad
component Capacitor
  p = Pin()
  n = Pin()
  variable v::Voltage
  variable i::Current
  # Capacitance of this capacitor
  parameter C::Capacitance
relations
  v = p.v - n.v
  i = p.i
  p.i + n.i = 0
  C * der(v) = i
end

But let's avoid repeating ourselves - you can notice the structural similarity between the resistor and capacitor.

Partial components ​

A partial component holds the shared interface and equations. Here, OnePort leaves the voltage–current law open: Resistor supplies Ohm's law, while Capacitor supplies C * der(v) = i.

OnePort shares the two pins, voltage difference, and current balance. Its port metadata selects the built-in positive and negative pin icons and places them on opposite edges, using the placement from ElectricalComponents' TwoPin interface. Derived components inherit these placements.

Copy this complete definition into rlc_parts.dyad; it includes the metadata omitted from the viewer's Code pane:

dyad
partial component OnePort
  p = Pin() {^p}
  n = Pin() {^n}
  variable v::Voltage
  variable i::Current
relations
  v = p.v - n.v
  i = p.i
  p.i + n.i = 0
metadata {
  "_links": {
    "p": {
      "Dyad": {
        "placement": {"icon": {"iconName": "pos", "x1": -50, "y1": 450, "x2": 50, "y2": 550}}
      }
    },
    "n": {
      "Dyad": {
        "placement": {"icon": {"iconName": "neg", "x1": 950, "y1": 450, "x2": 1050, "y2": 550}}
      }
    }
  }
}
end

Then define the complete components by extending OnePort:

RLC Model ​

With all these components in place, we can build an RLC circuit model. In the dyad folder, create a new file named rlc.dyad and include the code below.

The connection connect(inductor.p, resistor.p, capacitor.p) places all three pins at the same voltage. Their currents balance at that node. The capacitor starts at 10 V and the inductor starts with zero current. StepVoltage() supplies 0 V before 5 seconds, then 32 V for the rest of this simulation.

Analysis ​

An analysis defines a workflow to run on a model, such as transient simulation or linearization. You can also write custom analyses in Julia with access to the model's symbolic equations.

Add the following analysis to dyad/rlc.dyad. It simulates the circuit from 0 to 10 seconds.

dyad
analysis SimRLC
  extends TransientAnalysis(stop=10, abstol=1m, reltol=1m)
  model = RLC()
end

Simulating ​

Save the model and analysis files, then click the Run Analysis play button beside SimRLC in the Analyses sidebar. The simulation opens a result plot and makes its result available as solution in the Julia REPL. To plot that result again from the REPL, run:

julia
using Plots
plot(solution)

The plot starts from the specified capacitor voltage and inductor current. At 5 seconds, the source voltage steps from 0 to 32 V and the circuit responds to the new voltage.