Blocks: 0 Wires: 0 Time: 0.000s Ready © 2025 SysDynLab. All rights reserved.
Block Parameters
Plotter
SysDynLab Help
Quick Start
Block Reference
Scope & Plots
State Machine
Code Generation
Solver Guide
Shortcuts
About & Legal

What is SysDynLab?

SysDynLab is a browser-based block diagram simulator for building and running continuous and discrete-time dynamic systems — entirely in the browser, with no installation required.

Models are built visually by connecting blocks with wires on an infinite canvas. Each block represents a mathematical operation, signal source, or sink. Wires carry numeric signals between blocks in real time.

The simulation engine runs in WebAssembly for near-native speed. It supports variable-step ODE solvers (Euler, RK4, RK45, DOPRI), discrete-time blocks, nested subsystems, state machines, and live plotting via the Plotter block.

Key capabilities:

  • Drag-and-drop block library: Sources, Continuous, Math, Discrete, Nonlinear, Logic, Signal Routing, Sinks
  • Nested subsystems for hierarchical modeling
  • State machines with hierarchical states, parallel regions, junctions, and entry/exit actions
  • Live Plotter with pan, zoom, and multi-channel support
  • Save/load models as XML; import CSV data; export C code
  • Built-in demos covering control systems, oscillators, HVAC, and more

Building Your First Model

1
Add blocks from the sidebar

Click any block in the left sidebar to place it on the canvas. Or drag it to a specific position. Blocks are grouped by category: Sources, Continuous, Math, Discrete, and more.

2
Connect blocks with wires

Click an output port (right side of a block — blue) then click an input port (left side — orange) to draw a wire. Wires route automatically. To delete a wire, click it and press Delete.

3
Configure block parameters

Double-click any block to open its parameter popup. Change values (expressions like 2*pi are accepted) and click Apply. Right-click a block for more options (mirror, rotate, duplicate, help).

4
Set simulation time and run

Set T (duration in seconds) in the toolbar. Leave dt empty for auto step size. Press ▶ Run (or Space) — the button turns red while running. Press again to stop early.

5
View results in the Plotter

Add a Plotter block (Sinks section) and wire signals into it. Double-click the Plotter after running to open the signal viewer. Scroll to zoom, drag to pan. Click Zoom X / Zoom Y then draw a selection rectangle on the plot.

6
Save and load models

Use Ctrl+S to save your model as an XML file. Ctrl+O loads a saved model. Models include all blocks, wires, and parameter values.

Try a demo first! Click the Demo button in the toolbar and select any built-in example to see how a complete model looks. Demos are a great way to explore what SysDynLab can do.

Your First Simulation (step-by-step)

  1. Click Sine Wave in the Sources section of the sidebar.
  2. Click Plotter in the Sinks section.
  3. Click the output port of the Sine Wave block, then click the input port of the Plotter.
  4. Set T = 5 in the toolbar and press ▶ Run.
  5. Double-click the Plotter to see the sine wave plot.

Common Tasks

TaskHow
Select multiple blocksDrag a selection box on empty canvas, or Shift+click blocks
Move blocksDrag any block; wires follow automatically
Delete selectionDelete or Backspace
Undo / RedoCtrl+Z / Ctrl+Y
Copy & pasteCtrl+C then Ctrl+V
Fit all blocks in viewClick Fit button in toolbar
Create a subsystemSelect blocks → right-click → Create Subsystem. Double-click to enter.
Export simulation dataAdd a CSV Sink block — it saves a .csv file when simulation ends
Generate C codeRight-click any block or subsystem → Generate C Code

Loading block reference…

Plotter Block (Scope)

The Plotter block records signals during simulation and lets you view them as time-series plots. It is the primary data visualization tool in SysDynLab.

Setting Up a Plotter

  1. Drag Plotter from the Sinks section of the sidebar onto the canvas.
  2. Double-click the block to set nInputs — the number of signal channels (1–10).
  3. Wire signals from other blocks into the input ports.
  4. Run the simulation (Space or the Run button).
  5. Double-click the Plotter block again to open the signal viewer.

Viewer Toolbar Controls

Button / ActionWhat it does
Zoom XActivate X-axis (time) zoom mode. Click once for the start point, click again for the end point — the time axis zooms to that range. Blue band previews the selection.
Zoom YActivate Y-axis (value) zoom mode. Same two-click selection, but locks the value axis.
↔+ / ↔−Zoom in / out horizontally (time axis) by a fixed factor.
↕+ / ↕−Zoom in / out vertically (value axis) by a fixed factor.
ResetReturn to the full auto-scaled view (all data visible).
NamesToggle the channel-name panel. Type a custom label for each channel. Names appear on the plot legend and in cursor readouts, and are saved with the model.

Mouse Interaction on the Plot

ActionHow
Pan left / right / up / downClick and drag on the canvas
Zoom in / outScroll wheel anywhere on the canvas
Read cursor valuesMove the mouse over the canvas — a vertical cursor snaps to the nearest data point and shows time + value for every channel

Channel Names

Click Names in the viewer toolbar. A row of text boxes appears below the toolbar — one per physical input port. Type a descriptive label such as Speed or Error. The name appears:

  • In the inline legend on the right side of the plot
  • In the hover cursor readout (Speed = 3.142)
  • As the row label when subplot mode is active

Names are stored in the block parameters and saved with the model XML.

Mux Input → Overlay Mode

If the Plotter has nInputs = 1 and the single port is wired from a Mux block, SysDynLab automatically expands the vector and draws all elements as separate colored traces on one shared plot. This is the easiest way to compare several signals side-by-side without adding multiple Plotter blocks.

Example: Mux 3 signals (reference, output, error) → single Plotter input → three colored lines in the same plot.

Multi-Input → Subplot Mode

If the Plotter has nInputs > 1, each physical input port gets its own subplot row. All rows share the same time axis so you can compare timing across signals. Each row auto-scales its Y axis independently.

If a port in subplot mode is itself wired from a Mux, that row shows all Mux elements overlaid within its subplot — giving you both subplot isolation and overlay comparison simultaneously.

Typical Patterns

GoalSetup
Compare 3 signals on one plotMux 3 → Plotter (nInputs = 1)
Compare 3 signals each on its own rowPlotter nInputs = 3, one signal per port
Overlay a vector + show another signal separatelyPlotter nInputs = 2; port 1 ← Mux(3); port 2 ← scalar signal
Name channelsOpen viewer → click Names → type labels
Zoom into transient at t=5sClick Zoom X → click at t=4.8 → click at t=5.5

XY Scope Block

The XY Scope block plots one signal against another in phase-plane style — there is no time axis. Input 1 maps to the X axis; Input 2 maps to the Y axis. The result is a parametric trajectory curve.

Common uses: visualizing limit cycles, attractors, Lissajous figures, and velocity vs. position phase portraits.

Example: Connect a Sine Wave to Input 1 and a Cosine (Sine with phase = π/2) to Input 2 to draw a circle.

Display Block

The Display block shows the current numeric value of its input in a green LCD-style readout — updated live at every simulation step. Use it to monitor a single value without opening a scope.

  • If the input is a scalar, one row is shown.
  • If the input is a vector (from a Mux), each element gets its own row. The block height grows automatically.
  • Values use automatic precision: small/large values are shown in scientific notation.
  • The display also shows the last value frozen at the end of simulation, useful for checking final steady-state.

CSV Sink

The CSV Sink records all input channels during simulation and saves them as a comma-separated file when the simulation ends. The filename is the block label.

  • Set nInputs to the number of channels to record.
  • Connect a Mux to record multiple signals as separate columns.
  • The file has a time column followed by one column per channel.
  • Use this to post-process data in Excel, Python (pandas), or MATLAB.

What Is the State Machine Block?

The State Machine block implements statecharts with hierarchical states, parallel (AND) regions, junctions, entry/exit actions, transition conditions, local variables, and arbitrary input/output ports. The entire statechart runs inside the WASM simulation engine at each time step.

Adding a State Machine

  1. Drag State Machine from the Signal Routing section of the sidebar.
  2. Double-click the block to open the graphical editor.
  3. Use the Ports tab at the top to add input ports, output ports, and local variables.
  4. Build the statechart on the editor canvas.
  5. Close the editor — it auto-saves.
  6. Wire the block inputs and outputs like any other block and run the simulation.

Editor Layout

AreaPurpose
Left paletteDrag elements onto the canvas: State, Junction (diamond), Initial marker (green circle)
Center canvasMain editing area — place states, draw transitions, arrange the chart
Right properties panelShows editable fields for the selected element (name, actions, condition, order, etc.)
Ports tab (top)Define input ports, output ports, and local variables for the statechart

States

States are the building blocks of the chart. Only one state (per region) is active at any time.

OperationHow
Create a stateDrag State from the left palette, or right-click empty canvas → Add State
Rename a stateDouble-click the state name text and type a new name
Move a stateDrag the state header (top bar)
Resize a stateDrag the bottom-right corner handle
Set as Initial stateRight-click the state → Set as Initial (gives it a green dot). Every top-level chart needs one Initial state.
Entry actionSelect the state → type in the Entry field in the properties panel. Runs once when the state is entered.
Exit actionSelect the state → type in the Exit field. Runs once when the state is left.
Delete a stateSelect it → press Delete or use the trash icon
Tip: Every statechart must have exactly one element marked as Initial — either a state or a junction. The simulator enters that element first when the simulation starts. If a state is an AND superstate (parallel regions), no Initial marker is required inside it — all regions activate simultaneously.

Transitions

Transitions connect states. When a condition is true, the chart follows the transition: exits the source state (running exit actions), runs the transition action, then enters the target state (running entry actions).

OperationHow
Draw a transitionClick and drag from the border of one state to another state (or to a junction)
Transition conditionSelect the transition → type a boolean expression in the Condition field (e.g. error > 0.5). Leave empty to always fire.
Transition actionSelect the transition → type assignment(s) in the Action field (e.g. output = 1; counter = 0)
Execution orderWhen multiple transitions leave the same state, each gets a number badge. The lowest-numbered transition whose condition is true fires first. Change the order in the Order field in the properties panel.
Bend the curveDrag the circular midpoint handle on the transition to curve it
Move the labelDrag the transition label text to reposition it along the curve
Reattach endpointsDrag the small circles at the start or end of the transition to reposition where it connects to the state border
Delete a transitionClick the transition to select it → press Delete

Junctions

Junctions are diamond-shaped routing nodes. They do not have entry/exit actions and are never "active" — they are evaluation waypoints.

TypeHow it worksWhen to use
Routing junction Has multiple outgoing transitions with different conditions. When control reaches it, the first matching outgoing transition is followed. if/else branching without duplicating the source state; fan-out from one source to many targets based on conditions
Action junction (dead-end) Has no outgoing transitions whose condition matches (or no outgoing transitions at all). Runs all actions along the path from the source state, then stays in the source state — the current state does not change. Conditional side effects: run an action only under certain conditions without a state change (e.g. increment a counter)

To set a junction as the Initial entry point, right-click it → Set as Initial. The chart evaluates the junction's outgoing transitions on start to find the initial state.

Parallel (AND) Regions

A state can be divided into parallel regions — all are active simultaneously, each running its own sub-statechart independently.

  • To create parallel regions: right-click a composite state → Add Parallel Region, or drag the dashed region separator.
  • Each region needs its own Initial marker.
  • Regions can read and write the same output ports and local variables. This lets one region's transition condition check values set by another region's action.
  • Transitions between different regions of the same parent state are not allowed — use shared variables to coordinate instead.

Hierarchical (Composite) States

States can contain other states, creating a hierarchy. The inner states are only active when the outer (composite) state is active.

  • Create a composite state by dragging a new state inside an existing state.
  • A transition to a composite state enters its Initial inner state.
  • A transition from a composite state is a "super-transition" — it fires regardless of which inner state is currently active, exits the entire composite, and runs all exit actions from inside out.

Ports Tab — Inputs, Outputs & Locals

Click the Ports tab at the top of the editor to configure the statechart interface:

SectionPurposeUsage in expressions
Input portsSignals flowing into the block from the canvas. Add with the + button, give each a name.Read-only in conditions and actions: speed > 10
Output portsSignals the block sends out to connected blocks. Add with + button, give each a name.Assign in actions: mode = 2. Read in conditions: mode == 1
Local variablesInternal state variables that persist between time steps but are not visible outside the block. Zero-initialized; reset each time simulation starts.Read and assign freely: counter = counter + 1

Port order in the list determines the pin position on the block (top = first pin). Rename ports by clicking their name field. The block on the canvas updates its pin count automatically when you add or remove ports.

Expression Language

Conditions and actions share a small expression language. Both paths (WASM runtime and C code generator) support the same operators.

Operators

CategoryOperatorsExample
Arithmetic+   -   *   /speed * 0.1 + bias
Unary minus-x-error
Comparison>   >=   <   <=   ==   !=error >= threshold
Logic&&   ||   !a > 0 && b < 1
Bitwise&   |   ^   ~   <<   >>flags & 0x03
Modulo%step % 4 (uses fmod internally)
Assignment (action only)=output = input + 1
Multi-statement (action only);y = 1; counter = 0

Built-in Functions

FunctionDescription
abs(x)Absolute value
sqrt(x)Square root
sin(x) cos(x) tan(x)Trigonometry (radians)
asin(x) acos(x) atan(x)Inverse trig (radians)
atan2(y, x)Four-quadrant arctangent
exp(x)ex
log(x)Base-10 logarithm
ln(x)Natural logarithm
pow(x, y)x raised to the power y
min(a, b)   max(a, b)Minimum / maximum of two values
floor(x)   ceil(x)   round(x)Rounding functions
sign(x)−1, 0, or +1 based on sign
rise(x)Returns true on a rising edge of x (0→non-zero). Condition-only.
fall(x)Returns true on a falling edge of x (non-zero→0). Condition-only.
pi   eMathematical constants π and e

Example Patterns

GoalConditionAction
Transition when error exceeds thresholdabs(error) > 0.5output = 1
Count steps in a state(empty — always fires from junction)counter = counter + 1
Reset counter on entryEntry: counter = 0
Trigger on rising edgerise(trigger)output = 1; timer = 0
Stay in state for N stepscounter >= Ncounter = 0
Two-condition if/else via junctionsTrans A: x > 0   Trans B: x <= 0Route from junction to StateA or StateB

Running the Simulation

After closing the editor, the State Machine block looks like any other block — wire its input and output ports, set simulation time, and press Run. The statechart evaluates at every simulation step: reads inputs, checks transition conditions (in order), fires matching transitions, runs actions, and writes outputs.

  • Output ports hold their last assigned value between steps — they are not reset to zero unless an action sets them.
  • Local variables are zero-initialized at t=0 and persist for the entire simulation.
  • Parallel regions run concurrently — both are evaluated every step.
  • Use a Display block on an output port to watch the active state value live.
Tip: To inspect which state is active, add an output port named mode and assign a distinct integer in each state's entry action (e.g. mode = 1, mode = 2). Connect it to a Display block to monitor the active state during simulation.

Generating C Code from a State Machine

SysDynLab can export the State Machine block as self-contained C or Python code — the same logic that runs in the WASM simulation engine, translated to portable source code ready for embedded targets or desktop applications.

Right-click the State Machine block on the canvas and select ▶ Generate Code. See the Code Generation tab for full details on options and output structure.

  • The generated C code includes the full statechart logic: state transitions, guards, entry/exit actions, local variables, and output assignments.
  • State is stored in a generated struct — safe for multi-instance use (no global variables).
  • The step function signature is: void name_step(const Inputs *u, Outputs *y, State *s)
  • An optional test main() is generated to drive a simple step-response test.

Overview

SysDynLab can generate self-contained C (ANSI C89 or C99) or Python code from any Subsystem or State Machine block. The generated code can be compiled and run independently of SysDynLab — no library dependencies beyond the C standard library or NumPy.

The code generator performs the same topological sort and subsystem flattening as the WASM simulation engine, so generated code matches the simulation numerically.

How to Open the Code Generator

  1. Right-click a Subsystem block or a State Machine block on the canvas.
  2. Select ▶ Generate Code from the context menu.
  3. Configure options in the left panel.
  4. Click ▶ Generate.
  5. Use Copy to copy to clipboard or ↓ Download to save as a file.

You can also right-click a block that is inside a subsystem when you have entered that subsystem level — the generator targets the current subsystem context.

Generator Options — C Language

OptionValuesNotes
Function / Class NameAny identifier (default: subsystem_step)Prefix for all generated function and struct names. Use a descriptive name like pid_controller or motor_drive.
Data Typedouble (default), floatdouble matches the simulation engine precision. Use float for embedded targets where 64-bit FPU is not available.
C StandardC99 (default), ANSI C89/C90C99 allows // comments and mixed declarations/code. ANSI mode is compatible with older compilers (e.g. MSVC without /std:c99, or older embedded toolchains). State machine blocks require C99 for designated initializers.
Optimization Level-O0, -O1, -O2 (default), -O3, -OsEmbeds a #pragma GCC optimize or equivalent hint. -O2 is the recommended default. Use -Os for code-size-constrained flash targets.
Linkagestatic (default), externstatic confines the functions to a single translation unit — safest for embedded. extern declares functions for use across multiple .c files.
always_inline hintOn (default)Adds __attribute__((always_inline)) to helper functions. Eliminates call overhead on GCC/Clang targets.
const input pointerOn (default)Marks the input struct pointer const, allowing the compiler to optimize reads. Disable if your toolchain does not support it.
volatile stateOff (default)Marks the state struct volatile — required when the state is shared between an ISR and the main loop on bare-metal targets.
NaN / Inf guardOff (default)Adds isnan/isinf checks on outputs at the end of each step. Useful for debugging numerically unstable models but adds per-step overhead.
Generate header (.h)Off (default)Prepends a matching #ifndef-guarded header block with struct typedefs and the function prototype. Paste the header part into a separate .h file.
Generate test main()Off (default)Appends a main() function that calls the step function for 100 steps and prints output values. Useful for verifying the generated code compiles and runs correctly: gcc -o test model.c -lm && ./test
Inline commentsOn (default)Adds comments to the generated code identifying each block by name and type. Turn off for cleaner output on code-size-constrained targets.

Generator Options — Python

OptionValuesNotes
BackendNumPy (default), Pure PythonNumPy generates vectorized operations using numpy — faster for batch simulation. Pure Python generates plain math with no dependencies — portable to MicroPython or constrained environments.
Inline commentsOn (default)Same as C — adds block-name comments to the generated code.

Generated Code Structure — C

For a subsystem named my_ctrl with the default options, the generator produces:

SectionContents
my_ctrl_InputsStruct with one field per subsystem input port (named after the connected inport block label).
my_ctrl_OutputsStruct with one field per subsystem output port.
my_ctrl_StateStruct holding all persistent state: integrator values, filter states, PID integrator, delay buffers, state machine locals, etc.
my_ctrl_init(State *s)Initializes the state struct to zero / initial conditions. Call once before the first step.
my_ctrl_step(const Inputs *u, Outputs *y, State *s)Runs one simulation step: reads inputs, evaluates all blocks in topological order, writes outputs, updates state. Call at every sample period.

Typical Embedded Integration

#include "my_ctrl.h"

static my_ctrl_State ctrl_state;
static my_ctrl_Inputs ctrl_in;
static my_ctrl_Outputs ctrl_out;

void system_init(void) {
    my_ctrl_init(&ctrl_state);
}

/* Call from timer ISR at sample rate */
void control_isr(void) {
    ctrl_in.reference = adc_read_reference();
    ctrl_in.feedback  = adc_read_feedback();
    my_ctrl_step(&ctrl_in, &ctrl_out, &ctrl_state);
    dac_write(ctrl_out.control_signal);
}

State Machine Code Generation

Right-click a State Machine block → ▶ Generate Code. The generator translates the full statechart to C:

  • Each state becomes an integer constant (STATE_IDLE = 0, etc.).
  • Active state is stored as a field in the State struct (s->active_state).
  • Local variables become fields in the State struct.
  • Entry/exit actions and transition conditions are emitted as inline if chains.
  • Parallel regions are emitted as independent active-state fields and evaluated sequentially.
  • Hierarchical states are emitted with nested switch-case blocks for each level.

The step function evaluates every active state's outgoing transitions in order, runs matching actions, and exits/enters states in the correct sequence — identical logic to the WASM runtime.

Subsystem Code Generation

Right-click a Subsystem block → ▶ Generate Code. The generator:

  1. Flattens the subsystem hierarchy (resolves Port In / Port Out blocks to direct connections).
  2. Resolves Tag Send / Tag Read pairs within the subsystem scope.
  3. Topologically sorts the flattened block graph (respecting direct-feedthrough flags).
  4. Schedules stateful blocks (integrators, filters, delay buffers) into a separate phase that runs after the algebraic blocks.
  5. Emits _init and _step functions.

Nested subsystems are inlined — the generated code is always a flat function, not recursive calls. This makes it suitable for real-time targets with no dynamic memory or recursion.

Algebraic Loop Warning

If the model has a feedback loop with no state-holding block in the loop (a true algebraic loop), the generator emits a // WARNING: algebraic loop detected comment and places blocks in a best-effort order. The generated code may not numerically match the simulation, and the loop may need an Integrator, Unit Delay, or similar block inserted to break it.

Compilation

The generated C file is self-contained — no SysDynLab headers are needed. Compile with any C99-compatible compiler:

gcc -O2 -std=c99 -o my_model my_model.c -lm
clang -O2 -std=c99 -o my_model my_model.c -lm

For embedded (ARM Cortex-M example):

arm-none-eabi-gcc -O2 -std=c99 -mcpu=cortex-m4 -mfpu=fpv4-sp-d16 -mfloat-abi=hard \
  -c my_model.c -o my_model.o

Solver Selection

Auto (recommended) — SysDynLab analyzes your model and picks the best solver automatically. It detects stiff dynamics from transfer functions, filters, and PID gains.

SolverOrderTypeBest For
Euler1Fixed, Non-Stiff Quick previews, educational. Fast but least accurate — needs very small dt.
Heun (RK2)2Fixed, Non-Stiff Moderate accuracy at low cost. Good balance for simple systems.
RK44Fixed, Non-Stiff Default choice. Excellent accuracy for most models. The workhorse solver.
Implicit Euler1Fixed, Stiff Unconditionally stable for stiff systems but low accuracy. Use when stability matters more than precision.
Trapezoidal2Fixed, Stiff Good accuracy + stiff stability. Recommended fixed-step choice for stiff models.
RK45 Dormand-Prince5Variable, Non-Stiff Highest accuracy. Adapts step size internally for optimal performance. Best for smooth, non-stiff dynamics.
ESDIRK233Variable, Stiff Adaptive + stiff-capable. For models with wide time-constant spread (fast & slow modes together).

When Is a System “Stiff”?

A system is stiff when it has both very fast and very slow dynamics simultaneously. Examples:

  • High-bandwidth low-pass filter (cutoff > 100 Hz) in a slow control loop
  • Transfer function with widely separated poles (e.g., s + 0.1 and s + 1000)
  • PID with large derivative gain driving a slow plant

Non-stiff solvers (Euler, Heun, RK4, RK45) require very small dt for stiff systems — they can blow up or oscillate. Stiff solvers (Implicit Euler, Trapezoidal, ESDIRK23) remain stable even with larger dt.

Step Size (dt) Guide

Leave dt empty (recommended) — SysDynLab auto-suggests dt from your model’s fastest dynamics (sine frequencies, filter cutoffs, transfer function poles).

SolverSamples per PeriodRule of Thumb
Euler~50dt < 1 / (50 × fmax)
Heun~30dt < 1 / (30 × fmax)
RK4~15dt < 1 / (15 × fmax)
Implicit Euler~15Stable at any dt, but accuracy needs ~15/period
Trapezoidal~10dt < 1 / (10 × fmax)
RK45~10Adapts automatically — dt sets the output resolution
ESDIRK23~7Adapts automatically — dt sets the output resolution

fmax = fastest frequency in your model (highest sine freq, filter cutoff, or natural frequency).

Examples

ModelRecommended SolverTypical dt
Step → 1st order TF (1/(s+1)) → ScopeRK40.01 – 0.05
Sine (10 Hz) → Gain → ScopeRK40.005
Step → PID → Plant with fast pole (1/(0.001s+1))Trapezoidal or ESDIRK230.0001 – 0.001
Chirp (0.1–100 Hz) → LP filter (50 Hz) → ScopeRK45auto (0.001)
Discrete PID + Sample Delay (no continuous blocks)Euler (any)Match sample time

Discrete Blocks

Discrete blocks (Sample Delay, Discrete TF, Discrete PID, etc.) operate at every simulation step. Set Ts = -1 (default) to use the simulation dt as sample time, or set a specific Ts value. If your model is purely discrete with no continuous blocks, any solver works — dt determines the sample rate.

Troubleshooting

  • Output explodes / NaN: dt is too large, or you need a stiff solver. Reduce dt or switch to Trapezoidal / ESDIRK23.
  • Oscillating output: Euler on a stiff system. Switch to Implicit Euler or Trapezoidal.
  • Simulation too slow: dt is too small or solver is inefficient. Try RK4 (fewer steps needed) or RK45 (auto-adapts).
  • Step response looks stepped: dt is too large to capture the dynamics. Reduce dt.
  • Plotter looks wrong at high zoom: Increase T (duration) or reduce dt for more data points.

Simulator & Solver Limitations

SysDynLab is designed for education and rapid prototyping. The following constraints apply:

Hard Limits (compile-time constants in the WASM engine)

ResourceLimitNotes
Blocks512Total flattened blocks after subsystem expansion. A subsystem with 50 blocks uses 50 of the 512 slots, not 1.
Wires2 048Total connections across the whole model.
Ports per block8Applies to both inputs and outputs. Sum, Mux, etc. are also capped at 8 inputs.
Continuous state slots6 144 (512 × 12)Integrator, filter, and TF state variables combined.
Implicit solver state size16Newton iteration limit for stiff solvers (Implicit Euler / ESDIRK23). Systems with more than 16 simultaneous state variables may not converge.
SM states per block64Includes all hierarchy levels and parallel region states within one State Machine block.
SM transitions per block128Total transitions (all levels) within one State Machine block.
SM local variables16Per State Machine block.
Scope ring buffer2 M doubles (~16 MB)Shared across all Plotter channels. Wraps (oldest data overwritten) when full on long runs.

Numerical Precision

ItemLimitation
Floating-point precisionAll signals are 64-bit doubles (IEEE 754). Underflow near ±5×10−324 and overflow near ±1.8×10308 produce ±Inf or NaN — the simulation does not automatically detect or recover from this.
Fixed-step accuracyEuler and Heun accumulate global error proportional to dt. Halving dt roughly halves (Euler) or quarters (Heun) the error. For high-accuracy results use RK4 or variable-step RK45.
Variable-step resolutionRK45 and ESDIRK23 adapt step size internally but still record output at the user-specified dt intervals. Very coarse dt hides the fine-grained solution — reduce dt to improve plot resolution even with adaptive solvers.
Stiff systems with non-stiff solversEuler/Heun/RK4 require dt < 2 / |λmax| for stability. A fast pole (e.g. τ = 0.001 s) forces dt < 0.002 — which is often impractical. Switch to a stiff solver.

Model Constraints

ConstraintDetail
Algebraic loopsA feedback path with no state-holding block (Integrator, Unit Delay, Transfer Function, etc.) is an algebraic loop. The simulator warns and uses best-effort ordering, but results may be incorrect. Insert an Integrator or Unit Delay to break the loop.
Transfer function orderThe denominator polynomial must have degree ≥ numerator degree (proper or strictly proper). An improper TF (e.g. s/(s+1) is fine; s²/(s+1) is not) will cause incorrect or unstable behaviour.
Discrete sample time mixingAll discrete blocks share the simulation step dt as their base sample time. Blocks with different Ts values are evaluated at each step but only update when their counter triggers — this is not true multirate scheduling and can introduce up to one dt of sample-time error.
Mux / signal widthMux blocks expand signals for the Plotter only. Arithmetic blocks (Gain, Sum, etc.) operate on scalar signals — vector math is not supported.
Delay blockThe Transport Delay uses a ring buffer sized to ceil(delay / dt) samples. Very large delay-to-dt ratios consume memory proportionally. A delay of 10 s at dt = 0.0001 s allocates 100 000 doubles per delay block.
State machine expressionsSupports scalar arithmetic and logic only. No string handling, no arrays, no function calls to user code. The ternary operator ?: is not supported.
No zero-crossing detectionState machine transitions are evaluated at each time step, not at the exact moment a condition becomes true. A fast event shorter than dt may be missed. Reduce dt or use a discrete block with a matching Ts.

Browser & WASM Constraints

ConstraintDetail
WASM memory ceilingInitial heap is 64 MB; the runtime can grow up to 512 MB as needed. Very large scope buffers or many delay blocks may push into this range on long simulations.
Plotter data retentionScope data is held in browser memory. A 100 s simulation at dt = 0.0001 s stores 1 million data points per channel — this can slow plot rendering.
Single-threaded executionThe simulation runs on the main browser thread. Very long simulations will block the UI momentarily per frame.
No persistent storageModels are not saved automatically. Use Ctrl+S to download an XML file. Closing or refreshing the tab loses all unsaved work.
File accessCSV import, model load/save, and code download all use the browser file picker — there is no direct filesystem access.

What SysDynLab Does Not Support

  • Partial differential equations (PDEs) — only lumped (ODE) systems.
  • Distributed-parameter delay — only fixed transport delay with a ring buffer.
  • Multi-body physics or 3-D simulation.
  • Real-time hardware I/O — simulation is as-fast-as-possible, not wall-clock locked.
  • Symbolic math — all parameters must be numeric constants evaluated before simulation starts.
  • Automatic differentiation for sensitivity or gradient computation.
  • Optimization or parameter sweeps — run multiple simulations manually and compare Plotter traces.
Tip: For most control and signal-processing models these limits are never hit. If you encounter NaN outputs, check for algebraic loops first, then reduce dt. If the simulation is unexpectedly slow, switch from Euler to RK4 — it needs far fewer steps for the same accuracy.

Keyboard Shortcuts

ActionShortcut
Run / Stop simulationSpace  or click ▶ Run
UndoCtrl+Z
RedoCtrl+Y
Save modelCtrl+S
Open modelCtrl+O
Copy selectionCtrl+C
Cut selectionCtrl+X
PasteCtrl+V
Duplicate selectionCtrl+D
Select allCtrl+A
Delete selectionDelete  or  Backspace
Cancel wire / exit subsystemEscape
Apply block popupEnter (while popup is open)

Mouse & Canvas

ActionHow
Pan the canvasMiddle-click drag, or hold Space + drag
Zoom in / outScroll wheel on canvas
Select multiple blocksDrag a selection box on empty canvas
Add block to selectionShift+click a block
Open block propertiesDouble-click block
Open context menuRight-click block or wire
Start a wireClick an output port (blue, right side)
Complete a wireClick an input port (orange, left side)
Enter subsystemDouble-click a Subsystem block
Exit subsystemClick parent name in breadcrumb, or Escape
Open scope viewerDouble-click Plotter block after running
Zoom scope X or YClick Zoom X / Zoom Y → draw rectangle on plot
Pan scope plotDrag on the scope canvas
Zoom scope with wheelScroll on scope canvas
Reset scope viewClick Reset in scope toolbar

Block Context Menu

ItemWhat it does
PropertiesOpen block parameter popup
Mirror H / Mirror VFlip block horizontally or vertically
Rotate CW / CCWRotate block 90°
DuplicateCopy block in place
DeleteRemove block and its wires
Block HelpShow documentation for this block type
Create SubsystemGroup selected blocks into a new Subsystem
Generate C CodeOpen C code generator for this block/subsystem

About SysDynLab

SysDynLab is a browser-based block diagram simulator for building and running continuous and discrete-time dynamic systems. It runs entirely in the browser using WebAssembly — no installation, no server-side computation.

Built with vanilla JavaScript, WebAssembly (Emscripten / C), and no external frameworks.

Disclaimer

No Warranty. Use at Your Own Risk.

SysDynLab is provided "as is", without warranty of any kind, express or implied, including but not limited to warranties of merchantability, fitness for a particular purpose, or numerical accuracy.

The simulation results produced by SysDynLab are approximations based on the numerical methods and model parameters you configure. Results may differ from real-world behaviour due to solver discretization error, model simplifications, floating-point rounding, or incorrect parameter values.

The user assumes full responsibility for verifying the correctness of any simulation result before using it for design, engineering, safety analysis, or any other purpose. SysDynLab and its authors accept no liability for decisions made based on simulation output.

Do not rely on SysDynLab results in safety-critical applications without independent verification by qualified engineers using certified tools.

License

A note on the future of SysDynLab:
If there is enough community interest and people are willing to contribute, I am open to releasing SysDynLab as a fully open-source project on GitHub — so that everyone can improve it together. If you would like to see that happen, send a message via the Feedback button. Enough voices will make it happen.

SysDynLab is currently distributed under a Source-Available License. The source code is published for transparency and personal study. It is not open-source under OSI definitions.

SysDynLab Source-Available License
Copyright (c) 2025 SysDynLab. All rights reserved.

Permission is granted, free of charge, to any individual to:
  - Use this software for personal, academic, or educational purposes.
  - Read and study the source code for learning purposes.
  - Build and run the software locally for non-commercial use.
  - Create and share simulation models (.xml files) made with this software.

The following are expressly PROHIBITED without prior written permission
from the copyright holder:

  1. Hosting or deploying this software (or any modified version of it)
     as a public or private web service, website, or application.
  2. Redistributing, sublicensing, or publishing the source code or any
     substantial portion of it, whether modified or unmodified.
  3. Using this software or its source code as the basis for a competing
     product or service, commercial or otherwise.
  4. Removing or altering this license notice or any copyright attribution.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, OR NONINFRINGEMENT. IN NO EVENT SHALL
THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY
ARISING FROM THE USE OF OR INABILITY TO USE THIS SOFTWARE.

To request a commercial license or special permission, contact:
sysdynlab.simulator@gmail.com

Third-Party Components

ComponentPurposeLicense
EmscriptenCompiles the C simulation engine to WebAssemblyMIT / University of Illinois
WebAssemblyBrowser runtime for the simulation engineW3C open standard
Send Feedback

Your feedback directly improves the simulator. Thank you!

▶ Code Generation Subsystem
Language
Function / Class Name
Data Type
C Standard
Optimization Level
Linkage
Backend