Chapter 8: SystemC AMS

Electrical Linear Networks (ELN)

Modeling conservative continuous-time electrical circuits using the Electrical Linear Networks (ELN) model of computation.

Electrical Linear Networks (ELN)

The Electrical Linear Networks (ELN) model of computation brings traditional schematic-based circuit modeling into SystemC AMS. While LSF relies on abstract mathematical data flows, ELN is specifically designed for conservative continuous-time systems. This means the AMS solver automatically enforces Kirchhoff's Voltage and Current Laws (KVL/KCL) across the network.

If you are accustomed to SPICE netlists, ELN will look very familiar. You build your model by defining electrical nodes (nets) and connecting physical components (like resistors, capacitors, and voltage sources) between them.

Nodes, Terminals, and Primitives

The core difference between ELN and TDF/LSF is how components interact. In TDF, data flows directionally from an output port to an input port. In ELN, energy is exchanged conservatively across bidirectional terminals.

1. Nodes (sca_eln::sca_node)

A node represents a physical electrical connection point (a wire or net). The instantaneous voltage at a node is calculated dynamically by the ELN solver relative to a reference ground.

  • sca_eln::sca_node: A standard electrical net.
  • sca_eln::sca_node_ref: The electrical ground (defined as exactly 0 Volts). Every ELN cluster must have at least one path to a reference node.

2. Terminals (sca_eln::sca_terminal)

ELN components use terminals rather than directional ports. Terminals bind to nodes. By convention, current flows through the terminal into the component, and the voltage drops across the component's positive (p) and negative (n) terminals.

3. Electrical Primitives

The sca_eln namespace provides standard passive electrical components. All of them are instantiated as standard members in an sc_module:

  • sca_eln::sca_r: Resistor.
  • sca_eln::sca_c: Capacitor.
  • sca_eln::sca_l: Inductor.
  • sca_eln::sca_vsource / sca_eln::sca_isource: Independent voltage/current sources.

Converting to/from ELN

You cannot connect a discrete TDF signal directly to a resistor. Instead, you use TDF-to-ELN converter primitives:

  • sca_eln::sca_tdf::sca_vsource: Acts as an ideal voltage source in the ELN domain, where the instantaneous voltage is driven by the sampled TDF input signal.
  • sca_eln::sca_tdf::sca_vsink: Acts as an ideal voltmeter that reads the voltage drop across two ELN nodes and outputs it as a discrete-time TDF signal.

Complete Example: An RLC Low-Pass Filter

The following complete, compilable example demonstrates how to construct a classic Resistor-Inductor-Capacitor (RLC) filter. We will drive the filter with a TDF step-signal and read the continuous-time voltage response of the capacitor back into the TDF domain.

#include <systemc>
#include <systemc-ams.h>
 
// 1. TDF Source: Generates a Step input at 1.0 seconds
SCA_TDF_MODULE(StepSource) {
    sca_tdf::sca_out<double> out;
 
    SCA_CTOR(StepSource) {}
 
    void set_attributes() {
        set_timestep(1.0, sc_core::SC_MS); // 1 ms discrete timestep
    }
 
    void processing() {
        double t = get_time().to_seconds();
        double val = (t >= 1.0) ? 5.0 : 0.0; // 0V to 5V Step
        out.write(val);
    }
};
 
// 2. The ELN RLC Circuit
SC_MODULE(RLC_Circuit) {
    // Interface to the TDF world
    sca_tdf::sca_in<double>  in;
    sca_tdf::sca_out<double> out;
 
    // Electrical Nodes
    sca_eln::sca_node     n_src; // Node between Source and Resistor
    sca_eln::sca_node     n_rl;  // Node between Resistor and Inductor
    sca_eln::sca_node     n_lc;  // Node between Inductor and Capacitor
    sca_eln::sca_node_ref gnd;   // The electrical ground (0V)
 
    // Converter Primitives
    sca_eln::sca_tdf::sca_vsource tdf_v_src;
    sca_eln::sca_tdf::sca_vsink   tdf_v_snk;
 
    // Electrical Primitives
    sca_eln::sca_r resistor;
    sca_eln::sca_l inductor;
    sca_eln::sca_c capacitor;
 
    SC_CTOR(RLC_Circuit)
        : tdf_v_src("tdf_v_src", 1.0) // Scale = 1.0
        , tdf_v_snk("tdf_v_snk", 1.0)
        , resistor("resistor", 10.0)      // R = 10 Ohms
        , inductor("inductor", 0.1)       // L = 100 mH
        , capacitor("capacitor", 0.001)   // C = 1000 uF
    {
        // 1. Drive the circuit using the TDF input
        tdf_v_src.inp(in);         // Bind to TDF discrete port
        tdf_v_src.p(n_src);        // Positive terminal to Source node
        tdf_v_src.n(gnd);          // Negative terminal to Ground
        
        // 2. Resistor in series
        resistor.p(n_src);
        resistor.n(n_rl);
 
        // 3. Inductor in series
        inductor.p(n_rl);
        inductor.n(n_lc);
 
        // 4. Capacitor to ground
        capacitor.p(n_lc);
        capacitor.n(gnd);
 
        // 5. Read the voltage across the capacitor (n_lc to ground)
        tdf_v_snk.p(n_lc);
        tdf_v_snk.n(gnd);
        tdf_v_snk.outp(out);       // Bind to TDF discrete port
    }
};
 
int sc_main(int argc, char* argv[]) {
    // Signals
    sca_tdf::sca_signal<double> sig_step("sig_step");
    sca_tdf::sca_signal<double> sig_response("sig_response");
 
    // Instantiate Modules
    StepSource src("src");
    src.out(sig_step);
 
    RLC_Circuit rlc("rlc");
    rlc.in(sig_step);
    rlc.out(sig_response);
 
    // Setup Tracing
    sca_util::sca_trace_file* tf = sca_util::sca_create_vcd_trace_file("eln_rlc_wave");
    sca_util::sca_trace(tf, sig_step, "Input_Step_Voltage");
    sca_util::sca_trace(tf, sig_response, "Capacitor_Voltage_Response");
    
    // You can also trace internal ELN nodes directly!
    sca_util::sca_trace(tf, rlc.n_rl, "Node_RL_Voltage");
 
    // Start Simulation
    sc_core::sc_start(3.0, sc_core::SC_SEC);
 
    sca_util::sca_close_vcd_trace_file(tf);
    return 0;
}

How the ELN Solver Works

During the elaboration phase, the SystemC AMS kernel identifies all connected ELN primitives (the converters, resistor, inductor, and capacitor) and groups them into an ELN cluster. It automatically formulates a continuous-time matrix of differential equations based on KVL and KCL.

During the simulation, whenever the discrete TDF solver injects a new voltage value via tdf_v_src, the ELN Linear Solver mathematically integrates the continuous-time response of the RLC circuit across that timestep, tracking the energy stored in the inductor and capacitor. It then provides the precise resulting voltage at node n_lc back to the discrete TDF domain via tdf_v_snk. This complex analog numerical integration happens entirely under the hood.

Comments and Corrections