Skip to content

Architecture & Design Philosophy

OpenSMC is built on a modular, object-oriented architecture that mirrors the mathematical structure of Sliding Mode Control. This design philosophy enables seamless experimentation and allows researchers to swap out individual components without rewriting the entire control loop.

The Modular Components

At the heart of OpenSMC are five primary base classes defined in opensmc.core:

  1. SlidingSurface: Defines the sliding manifold \(s(e, t) = 0\). Examples include Linear, Terminal, and Integral surfaces.
  2. ReachingLaw: Dictates the dynamics of the sliding variable \(s\) during the reaching phase, typically aiming for \(\dot{s} = f(s)\).
  3. Plant: The mathematical model of the system to be controlled, representing its state-space dynamics \(\dot{x} = f(x, u, d)\).
  4. Controller: The higher-level logic that uses the Surface and Reaching Law to compute the final control input \(u\).
  5. Estimator: Optional components like observers or differentiators that provide estimates of unmeasured states or disturbances.

Simulator Loop

The Simulator class manages the interaction between these components. A typical simulation step follows this flow:

┌──────────────────────────────────────────────────────────┐
│                    SIMULATION STEP (RK4)                 │
├──────────────────────────────────────────────────────────┤
│                                                          │
│  1. Get Current State (x) from Plant                     │
│               │                                          │
│  2. Pass State to Estimator (Optional)                   │
│               │  └─> Get State/Disturbance Estimates (x̂)  │
│               │                                          │
│  3. Calculate Error (e = x_ref - x̂)                      │
│               │                                          │
│  4. Pass Error to Controller                             │
│       │                                                  │
│       ├─> Surface calculates s(e)                        │
│       ├─> Reaching Law calculates required ṡ             │
│       └─> Controller computes Control Input (u)          │
│               │                                          │
│  5. Inject Control Input (u) into Plant                  │
│               │                                          │
│  6. Plant updates state via ODE solver                   │
│                                                          │
└──────────────────────────────────────────────────────────┘

Composing Custom Controllers

To create a custom SMC variant, you can inherit from the base classes in opensmc.core. For example, a custom surface would only need to implement the calculate_surface and calculate_derivative methods:

from opensmc.core import SlidingSurface

class MyCustomSurface(SlidingSurface):
    def __init__(self, my_param):
        self.my_param = my_param

    def calculate_surface(self, error):
        # Implementation of s(e)
        pass

    def calculate_derivative(self, error):
        # Implementation of partial s / partial e
        pass

This modularity ensures that any new surface you create is immediately compatible with all existing reaching laws and controllers.