Subsystem Block
Hierarchical block container - encapsulates nested blocks into reusable units
Open Subsystem in BlockWerk →# Subsystem Block
Overview
The Subsystem block creates a hierarchical encapsulation of blocks, allowing you to group complex control logic into reusable, self-contained units. This is essential for managing large, complex diagrams.
Concept
A Subsystem is a "block within blocks":
┌─────────────────────────────┐
│ Subsystem │
│ ┌──────────────────────┐ │
│ │ Internal Blocks │ │
│ │ (PID, Filters, etc) │ │
│ └──────────────────────┘ │
└─────────────────────────────┘
From outside: Subsystem looks like a single block From inside: Contains its own blocks and internal connections
Ports
Subsystem ports are defined by InPort and OutPort blocks placed inside it.
Example Structure
MyController (Subsystem)
├── error [InPort]
├── PID
├── Saturation
├── filter [OutPort]
From outside, you see:
- Input:
error - Output:
filter
Parameters
subsystemName
Display name for the subsystem.
Default: "MySubsystem"
description
Optional description of subsystem function.
Default: "Hierarchical block container"
How to Use
1. Create Subsystem
- Drag Subsystem block into canvas
- Set name (e.g., "PID Controller")
2. Enter Subsystem
- Double-click the Subsystem block
- UI navigates into subsystem hierarchy
- See breadcrumb:
Root > PID Controller
3. Add Ports
Inside the subsystem, add:
- InPort blocks for inputs
- OutPort blocks for outputs
- Connect to internal blocks
4. Wire Internal Logic
- Connect InPort → internal blocks → OutPort
- Build your control algorithm
- Internal state is isolated
5. Exit & Use
- Back button or breadcrumb click to exit
- Connect Subsystem inputs/outputs like normal blocks
Architecture
Internal Block Scope
- Blocks inside subsystem see only internal connections
- InPort/OutPort provide boundary crossing
State Isolation
- Each subsystem instance has isolated internal state
- Multiple instances don't interfere with each other
Hierarchical Paths
- Root level: Block "A"
- In Subsystem#1: Block "B" has path
Subsystem#1/B - Prevents name conflicts
Connection Resolution
- Internal: A → B (automatic local resolution)
- Cross-boundary: External → InPort (automatic at boundary)
- Scoped: Full path resolution for nested hierarchies
Example Workflow
Goal: Create Reusable PID Unit
Step 1: Create Subsystem "PIDUnit"
{
"id": "pidunit1",
"type": "Subsystem",
"params": { "subsystemName": "PIDUnit" }
}
Step 2: Enter and build inside
Kp [constant]
Ki [constant]
Kd [constant]
error [InPort] ──→ × (multiply) ──→ output [OutPort]
├────→ integral ────→ ×
└────→ derivative ──→ ×
↓
Sum ──→
Step 3: Exit (breadcrumb click)
Step 4: Use in main diagram
setpoint ──→ −─→ PIDUnit ──→ plant
↑________________↓
feedback
Step 5: Reuse multiple times
- Copy PIDUnit#1
- Paste as PIDUnit#2
- Each has independent state
Nesting
Subsystems can be nested (subsystem in subsystem):
Control System
├── Estimation Subsystem
│ ├── Kalman Filter
│ └── Sensor Fusion
├── Decision Subsystem
│ ├── Logic Gates
│ └── State Machine
└── Actuation Subsystem
├── PID
└── Limits
Limited depth recommended (3-4 levels) for performance.
Best Practices
✅ DO
- Name subsystems clearly (e.g., "MotorController", "TempRegulator")
- Document subsystem purpose in description
- Keep internal logic focused (single responsibility)
- Use meaningful port names ("speed_error", not "in1")
- Test subsystem independently before using
❌ DON'T
- Create too-deep nesting (>5 levels)
- Use subsystem when single block suffices
- Leave unnamed inputs/outputs
- Create circular dependencies
- Mix unrelated logic in one subsystem
Ports (InPort/OutPort)
InPort (Input Interface)
- Receives: Value from external connection
- Outputs: To internal blocks
- Default: Can have default value if external not connected
OutPort (Output Interface)
- Receives: Value from internal block
- Outputs: To external connections
Port Mapping
[External Block A]
↓
[External Connection]
↓
[InPort "speed"]
↓
[Internal Connection]
↓
[PID Block]
↓
[Internal Connection]
↓
[OutPort "command"]
↓
[External Connection]
↓
[External Block B]
Technical Notes
Simulation Execution
1. Enter subsystem scope 2. Evaluate InPort (pass external → internal) 3. Execute internal blocks 4. Evaluate OutPort (pass internal → external) 5. Exit subsystem scope
State Management
- Each subsystem instance maintains separate
internal_stateHashMap - Paths used to locate correct state:
Subsystem#1/Block/state_key
Performance
- Subsystem adds minimal overhead (scope lookup)
- Negligible impact vs. flat hierarchy
- Enables much cleaner organization
Remarks
- Modularity: Subsystems help manage large diagrams by grouping related logic into reusable units
- Ports: Use InPort and OutPort blocks inside the subsystem to define its external interface
- Navigation: Double-click a subsystem to open its internal canvas; use the breadcrumb trail to navigate back
- Nested subsystems: Subsystems can contain other subsystems, allowing deep hierarchical organisation
- Performance: Subsystem scope resolution adds negligible overhead; hierarchical structure has no meaningful performance cost
See Also
- InPort: Input interface block
- OutPort: Output interface block
- Comparator: For logic inside subsystems
- PIDController: Common subsystem contents
Known Limitations (Current)
🔄 Implementation Note: Subsystem requires store refactoring to fully enable:
- Hierarchical scope navigation
- Port binding across boundaries
- Nested execution context
Currently: Block definition ready, WASM execution needs store layer work.