2. Quickstart#

This quickstart builds a tiny system with a linear source feeding an integrator. You will connect the components, run a simulation, and plot the results.

2.1. Import SysSimX#

We use the CoSimComponent, System, and Connection classes, plus matplotlib for plotting.

import numpy as np
import matplotlib.pyplot as plt

from syssimx import CoSimComponent, Connection, System, SystemGraphVisualizer
from syssimx.core import PortSpec, PortType

2.2. Define the Components#

We define a linear source y = a * t + b and a simple integrator that accumulates its input over time.

class LinearSource(CoSimComponent):
    """Linear source: y(t) = a * t + b."""

    def __init__(self, name: str, a: float = 1.0, b: float = 0.0):
        super().__init__(name, group="Source")
        self.a = a
        self.b = b
        self.output_specs.update({
            "y": PortSpec(name="y", type=PortType.REAL, direction="out")
        })

    def _initialize_component(self, t0: float) -> None:
        pass

    def _do_step_internal(self, t: float, dt: float) -> None:
        pass

    def _update_output_states(self, t: float | None = None, event_names=None):
        self.outputs["y"].set(self.a * t + self.b, t)


class Integrator(CoSimComponent):
    """Integrator with explicit Euler stepping."""

    def __init__(self, name: str, x0: float = 0.0):
        super().__init__(name, group="Integrator")
        self.x0 = x0
        self.input_specs.update({
            "u": PortSpec(name="u", type=PortType.REAL, direction="in")
        })
        self.output_specs.update({
            "y": PortSpec(name="y", type=PortType.REAL, direction="out")
        })

    def _initialize_component(self, t0: float) -> None:
        self.x = self.x0

    def _do_step_internal(self, t: float, dt: float) -> None:
        u = self.inputs["u"].get()
        self.x += u * dt

    def _update_output_states(self, t: float | None = None, event_names=None):
        self.outputs["y"].set(self.x, t)

2.3. Build the System#

We connect the source output to the integrator input and initialize the system.

source = LinearSource(name="LinearSource", a=1.0, b=0.0)
integrator = Integrator(name="Integrator", x0=0.0)

system = System(name="QuickstartSystem")
system.add_component(source)
system.add_component(integrator)

system.add_connection(Connection(
    src_comp=source.name,
    src_port=source.output_specs["y"].name,
    dst_comp=integrator.name,
    dst_port=integrator.input_specs["u"].name,
))

system.initialize(t0=0.0)

2.4. Visualize the System Graph#

visualizer = SystemGraphVisualizer(system)
visualizer.visualize()
visualizer.save("first_system_graph.svg")
../_images/eec062ada5f22c746e4987fcfdc37e99e4f0a669003b42b4f8c804e15b36b06a.svg

2.5. Run the Simulation#

We simulate for 5 seconds with a fixed step size.

t0 = 0.0
tf = 5.0
dt = 0.1

system.run(t0=t0, tf=tf, dt=dt)

2.6. Visualize Results#

The integrator output is the integral of the linear source. For a=1 and b=0, the expected shape is quadratic.

y_analytical = lambda t: 0.5 * t**2
dt_an = 1e-4
t_vals_an = np.arange(t0, tf + dt_an, dt_an)
y_analytical_vals = y_analytical(t_vals_an)
history = system.get_history()

t_vals, data = history["Integrator"]
y_vals = data["y"]

Hide code cell source

plt.figure(figsize=(8, 4))
plt.plot(t_vals, t_vals, label="Linear source output (y = t)")
plt.plot(t_vals, y_vals, label="Integrator output", marker=".")
plt.plot(t_vals_an, y_analytical_vals, label=r"Analytical solution $y(t) = 0.5 \cdot t^2$", color="black", linestyle="--")
plt.xlabel(r"Time $t$ in s")
plt.ylabel("Output")
plt.title("Quickstart: Linear Source $\\to$ Integrator")
plt.grid()
plt.legend()
plt.show()
../_images/4ccc6c60f0c6c6eab40a556292419ce0af44b178d4c116188f03740fd5c9960c.png

2.7. Next Steps#