Nested Subsystems
Demonstration of hierarchical modeling using nested subsystems for a Van der Pol oscillator.
You can also find this example as a single file in the GitHub repository.
Why Use Subsystems?
Subsystems allow you to:
- Organize complex systems into logical modules
- Reuse components across different models
- Abstract implementation details
- Scale to large systems with many components
- Debug and test individual modules separately
The Van der Pol Oscillator Revisited
The stiff Van der Pol oscillator is described by:
MATHDISPLAY0ENDMATH MATHDISPLAY1ENDMATH
With MATHINLINE2ENDMATH (very stiff!)
Hierarchical Structure
This example demonstrates hierarchical modeling using Subsystem and Interface blocks for modular system design.
System Parameters
Level 1: ODE Function Subsystem
First, we create a subsystem that computes MATHINLINE0ENDMATH
This subsystem:
- Takes two inputs: MATHINLINE1ENDMATH and MATHINLINE2ENDMATH
- Returns one output: the computed derivative
- Is self-contained and reusable

The Interface block defines the subsystem's inputs and outputs and this is how it looks like in pathsim:
Level 2: Van der Pol Subsystem
Now we create a subsystem that contains:
- Two integrators (for MATHINLINE0ENDMATH and MATHINLINE1ENDMATH)
- The ODE function subsystem we just created

This implements the complete Van der Pol ODE system:
Level 3: Top-Level System
Finally, we create the top-level system that contains:
- The VDP subsystem
- A Scope for visualization

At this level, the VDP subsystem looks like a simple block with two outputs, hiding all its internal complexity
Simulation Setup
We use a stiff solver (ESDIRK43) because :math:`\mu = 1000makes this a very stiff system.
12:43:50 - INFO - LOGGING (log: True) 12:43:50 - INFO - BLOCKS (total: 2, dynamic: 1, static: 1, eventful: 0) 12:43:50 - INFO - GRAPH (nodes: 2, edges: 1, alg. depth: 1, loop depth: 0, runtime: 0.028ms) 12:43:50 - INFO - STARTING -> TRANSIENT (Duration: 2000.00s) 12:43:51 - INFO - -------------------- 1% | 0.6s<13.4s | 37.8 it/s 12:43:51 - INFO - #####--------------- 27% | 0.9s<1.2s | 24.6 it/s 12:43:52 - INFO - ########------------ 40% | 1.6s<10.7s | 18.8 it/s 12:43:54 - INFO - ########------------ 41% | 3.7s<12.5s | 51.1 it/s 12:43:54 - INFO - #############------- 67% | 4.1s<0.6s | 24.2 it/s 12:43:55 - INFO - ################---- 80% | 4.6s<2.2s | 25.0 it/s 12:43:57 - INFO - ################---- 81% | 6.4s<8.1s | 62.5 it/s 12:43:57 - INFO - #################### 100% | 6.7s<--:-- | 25.0 it/s 12:43:57 - INFO - FINISHED -> TRANSIENT (total steps: 341, successful: 234, runtime: 6707.70 ms)
Results: Time Series
The Van der Pol oscillator with MATHINLINE0ENDMATH exhibits relaxation oscillations - fast transitions between slow phases. This requires a stiff solver to handle efficiently.
Subsystem Benefits Demonstrated
This example shows several advantages of subsystems:
- Modularity: The ODE function is completely separate from the integration
- Reusability: The
Fnsubsystem could be used in other models - Clarity: The top level is clean - just VDP and Scope
- Debugging: Each subsystem can be tested independently
- Abstraction: Inner complexity is hidden from higher levels
Comparison with ODE Block
Compare this hierarchical approach with using a single ODE block:
# Alternative: Using ODE block (simpler but less modular)
def vdp_ode(x, u, t):
return np.array([x[1], mu*(1 - x[0]**2)*x[1] - x[0]])
VDP = ODE(vdp_ode, np.array([x1_0, x2_0]))
Both approaches work! Use subsystems when:
- You need modularity and reusability
- The system is complex with many components
- You want to visualize internal signals
- You're building block diagram models