Skip to content

Commit 13fb8ef

Browse files
author
Samuel Folorunsho
committed
Updated commit
1 parent 967a09d commit 13fb8ef

21 files changed

+414
-7
lines changed

.DS_Store

0 Bytes
Binary file not shown.

BaCLNS.egg-info/PKG-INFO

Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
Metadata-Version: 2.1
2+
Name: BaCLNS
3+
Version: 0.1.0
4+
Summary: Efficient Backstepping Control for Linear and Nonlinear Dynamic Systems
5+
Home-page: https://github.com/sof-danny/BaCLNS
6+
Author: Samuel O. Folorunsho
7+
Author-email: [email protected]
8+
Classifier: Programming Language :: Python :: 3
9+
Classifier: License :: OSI Approved :: MIT License
10+
Classifier: Operating System :: OS Independent
11+
Requires-Python: >=3.6
12+
Description-Content-Type: text/markdown
13+
License-File: LICENSE
14+
Requires-Dist: numpy
15+
Requires-Dist: sympy
16+
Requires-Dist: matplotlib
17+
18+
# BaCLNS: Efficient Backstepping Control for Linear and Nonlinear Dynamic Systems
19+
20+
BaCLNS (Backstepping Control for Linear and Nonlinear Systems) is a Python package designed to provide efficient and robust control solutions for dynamic systems (Control Affine Systems) using backstepping techniques. This package offers a flexible and user-friendly interface for designing, simulating, and analyzing control systems, with options for plotting and saving results.
21+
22+
Introduction to Backstepping Control
23+
24+
Backstepping is a systematic and recursive control design technique primarily used for stabilizing nonlinear systems. Unlike traditional control methods that might struggle with complex nonlinearities, backstepping breaks down the control problem into smaller, more manageable sub-problems. These sub-problems are then solved sequentially, "stepping back" from the output to the input, hence the name "backstepping."
25+
26+
Key Concepts:
27+
28+
Virtual Control: Intermediate control laws are designed for each state, leading to the final control input.
29+
Lyapunov Function: A mathematical function that helps ensure system stability. Backstepping uses this function to guide the control design process.
30+
Recursive Design: The control input is designed by recursively stabilizing each state in the system.
31+
32+
Worked examples can be found in [this paper]( https://doi.org/10.1016/B978-0-12-817582-8.00008-8)
33+
34+
35+
## Installation
36+
37+
To install the package, simply run:
38+
39+
```bash
40+
pip install BaCLNS
41+
```
42+
43+
## Usage
44+
45+
1. Importing the Package
46+
To use the package, import the necessary functions:
47+
48+
```bash
49+
import sympy as sp
50+
import numpy as np
51+
from baclns import generic_backstepping_controller, simulate_system, plot_responses, save_responses
52+
```
53+
54+
2. Define the System
55+
First, define your system's state equations and parameters. For example, if you have a 3D system:
56+
57+
```bash
58+
# Define system parameters
59+
num_states = 2
60+
61+
x1, x2, x3 = sp.symbols('x1 x2 x3')
62+
u = sp.Symbol('u')
63+
a, b, c = sp.symbols('a b c')
64+
65+
# Define the state equations for a 3D system
66+
state_equations = [
67+
a * x1 + x2,
68+
b * x2 + x3,
69+
c * x3 + u
70+
]
71+
72+
# Define the gains
73+
gains_vals = [10.0, 10.0, 15.0]
74+
```
75+
3. Creating the Control Law
76+
Use the 'generic_backstepping_controller' function to create the control law for your system:
77+
78+
```bash
79+
final_control_law, states, gains = generic_backstepping_controller(num_states, state_equations, 'u', gains_vals)
80+
```
81+
82+
4. Simulating the System
83+
Simulate the system using the 'simulate_system' function. You can configure it to print the control law, plot the results, and save the responses:
84+
85+
```bash
86+
# Simulation parameters
87+
time = np.linspace(0, 10, 1000) # 10 seconds of simulation with 1000 time steps
88+
initial_conditions = [0.1, 0.0, 0.1] # Initial conditions for x1, x2, x3
89+
params_subs = {a: 1.0, b: 0.5, c: 0.2, 'k1': gains_vals[0], 'k2': gains_vals[1], 'k3': gains_vals[2]}
90+
91+
# Simulate the system
92+
state_values, control_inputs, errors = simulate_system(
93+
final_control_law, states, gains_vals, initial_conditions, time, state_equations, params_subs,
94+
plot=True, save_path='results.json', print_law=True
95+
)
96+
```
97+
98+
5. Plotting the Results
99+
If you haven't plotted the results directly in the simulation, you can use the plot_responses function to plot the states, control inputs, and errors on separate plots:
100+
101+
```bash
102+
plot_responses(time, state_values, control_inputs, errors)
103+
```
104+
105+
6. Saving the Results
106+
The results can be saved to a JSON file for later analysis. The simulate_system function allows you to save the results directly during the simulation by specifying the save_path:
107+
108+
```bash
109+
simulate_system(final_control_law, states, gains_vals, initial_conditions, time, state_equations, params_subs, save_path='results.json')
110+
```
111+
112+
Alternatively, you can save the results after the simulation using the 'save_responses' function:
113+
114+
```bash
115+
save_responses('results.json', time, state_values, control_inputs)
116+
```
117+
118+
## Example Workflow: 2D Linear system
119+
120+
```bash
121+
import sympy as sp
122+
import numpy as np
123+
from baclns import generic_backstepping_controller, simulate_system, plot_responses, save_responses
124+
125+
# 1. Define system parameters and state equations
126+
127+
num_states = 2
128+
x1, x2 = sp.symbols('x1 x2')
129+
u = sp.Symbol('u')
130+
a, b = sp.symbols('a b')
131+
132+
# Define the state equations for a 2D system
133+
state_equations = [
134+
a * x1 + x2,
135+
b * x2 + u
136+
]
137+
138+
# Define the gains
139+
gains_vals = [10.0, 15.0]
140+
141+
# 2. Create the control law using generic_backstepping_controller
142+
143+
final_control_law, states, gains = generic_backstepping_controller(num_states, state_equations, 'u', gains_vals)
144+
145+
# 3. Define simulation parameters
146+
147+
time = np.linspace(0, 10, 500) # 10 seconds of simulation with 500 time steps
148+
initial_conditions = [1.0, 0.0] # Initial conditions for x1, x2
149+
params_subs = {a: 1.0, b: 0.5, 'k1': gains_vals[0], 'k2': gains_vals[1]}
150+
151+
# 4. Simulate the system
152+
153+
state_values, control_inputs, errors = simulate_system(
154+
final_control_law, states, gains_vals, initial_conditions, time, state_equations, params_subs,
155+
plot=True, print_law=True
156+
)
157+
158+
# 5. Plot the results
159+
160+
plot_responses(time, state_values, control_inputs, errors)
161+
162+
# 6. Save the results to a JSON file
163+
164+
save_responses(time, state_values, control_inputs, 'test_results.json', errors)
165+
```
166+
167+
168+
## Example Results
169+
170+
### State Response
171+
![State Response](https://github.com/sof-danny/BaCLNS/blob/main/tests/states_response.png)
172+
173+
### Errors Over Time
174+
![Errors](https://github.com/sof-danny/BaCLNS/blob/main/tests/errors.png)
175+
176+
### Control Input
177+
![Control Input](https://github.com/sof-danny/BaCLNS/blob/main/tests/control_input.png)
178+
179+
...
180+
181+
## License
182+
This project is licensed under the MIT License - see the [LICENSE](https://github.com/sof-danny/BaCLNS/blob/main/LICENSE) file for details.
183+
184+
185+
186+
## Contact
187+
If you have questions or issues using the package or understanding Backstepping techniques, please reach out to [Samuel Folorunsho](https://github.com/sof-danny)
188+
189+
## Citation
190+
If you find this useful for your class or research, please cite:
191+
192+
[BaCLNS: Efficient Control for Dynamic Systems](https://github.com/sof-danny/BaCLNS)
193+

BaCLNS.egg-info/SOURCES.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
LICENSE
2+
README.md
3+
setup.py
4+
BaCLNS.egg-info/PKG-INFO
5+
BaCLNS.egg-info/SOURCES.txt
6+
BaCLNS.egg-info/dependency_links.txt
7+
BaCLNS.egg-info/requires.txt
8+
BaCLNS.egg-info/top_level.txt
9+
baclns/__init__.py
10+
baclns/controller.py
11+
baclns/plotting.py
12+
baclns/saving.py
13+
baclns/simulation.py
14+
tests/test_script.py
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

BaCLNS.egg-info/requires.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
numpy
2+
sympy
3+
matplotlib

BaCLNS.egg-info/top_level.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
baclns
683 Bytes
Binary file not shown.

baclns/plotting.py

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import matplotlib.pyplot as plt
2+
import os
23

3-
def plot_responses(time, state_values, control_inputs, errors):
4-
plt.figure(figsize=(12, 8))
5-
4+
def plot_responses(time, state_values, control_inputs, errors, save_folder=None):
65
# Plot state variables
6+
plt.figure(figsize=(8, 6))
7+
78
for i, state in enumerate(state_values):
89
plt.plot(time, state, label=f'State x{i+1}')
910

@@ -13,7 +14,13 @@ def plot_responses(time, state_values, control_inputs, errors):
1314
plt.grid(True)
1415
plt.legend()
1516

16-
plt.figure(figsize=(12, 8))
17+
# Save the plot if save_folder is specified
18+
if save_folder:
19+
if not os.path.exists(save_folder):
20+
os.makedirs(save_folder)
21+
plt.savefig(os.path.join(save_folder, 'system_response.png'))
22+
23+
plt.figure(figsize=(8, 6))
1724

1825
# Plot control inputs
1926
plt.plot(time[:-1], control_inputs, label='Control Input u')
@@ -24,7 +31,11 @@ def plot_responses(time, state_values, control_inputs, errors):
2431
plt.grid(True)
2532
plt.legend()
2633

27-
plt.figure(figsize=(12, 8))
34+
# Save the plot if save_folder is specified
35+
if save_folder:
36+
plt.savefig(os.path.join(save_folder, 'control_input.png'))
37+
38+
plt.figure(figsize=(8, 6))
2839

2940
# Plot errors
3041
for i, error_list in enumerate(zip(*errors)):
@@ -36,4 +47,9 @@ def plot_responses(time, state_values, control_inputs, errors):
3647
plt.grid(True)
3748
plt.legend()
3849

50+
# Save the plot if save_folder is specified
51+
if save_folder:
52+
plt.savefig(os.path.join(save_folder, 'state_errors.png'))
53+
54+
# Show all plots
3955
plt.show()

build/lib/baclns/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .controller import generic_backstepping_controller
2+
from .simulation import simulate_system
3+
from .plotting import plot_responses
4+
from .saving import save_responses

build/lib/baclns/controller.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import sympy as sp
2+
3+
def generic_backstepping_controller(num_states, state_equations, control_input, gains):
4+
# Define symbolic variables
5+
states = sp.symbols(f'x1:{num_states+1}') # Create symbols x1, x2, ..., xn
6+
u = sp.Symbol(control_input)
7+
8+
errors = states
9+
10+
# Unpack the gains
11+
gains = [sp.Symbol(f'k{i}') for i in range(1, num_states+1)]
12+
13+
# Step 1: Initialize the error terms and control laws
14+
control_laws = []
15+
error_terms = []
16+
17+
# Iteratively compute the virtual controls and error terms
18+
for i in range(num_states - 1):
19+
# Define the virtual control phi
20+
if i == 0:
21+
phi = -gains[i] * errors[i]
22+
else:
23+
phi = -gains[i] * error_terms[i-1]
24+
25+
# Define the error term z
26+
z = errors[i+1] - phi
27+
error_terms.append(z)
28+
29+
# Compute the derivative of the error term (z_dot)
30+
z_dot = sum(sp.simplify(sp.diff(z, states[j]) * state_equations[j]) for j in range(num_states))
31+
32+
# Store the control law
33+
control_laws.append(sp.simplify(z_dot + gains[i+1] * z))
34+
35+
# Step 2: Derive the final control law for u
36+
final_control_law = sp.simplify(sp.solve(control_laws[-1], u)[0])
37+
38+
# Return the derived control law, and optionally, the errors and references
39+
return final_control_law, states, gains

0 commit comments

Comments
 (0)