Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,5 @@ authors:
orcid: "https://orcid.org/0000-0002-1987-9268"
affiliation: "McGill University"
title: "decargroup/dkpy"
version: v0.1.12
version: v0.1.9
url: "https://github.com/decargroup/dkpy"
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,6 @@ If you use this software in your research, please cite it as below or see
url={https://github.com/decargroup/dkpy},
publisher={Zenodo},
author={Steven Dahdah and Timothy Everett Adams and James Richard Forbes},
version = {{v0.1.12}},
version = {{v0.1.9}},
year={2025},
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/_static/example_8/8_sval_actuator.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/_static/example_8/8_sval_residual_max.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions doc/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information

project = "dkpy"
copyright = "2024, Steven Dahdah, Timothy Everett Adams and James Richard Forbes"
copyright = "2025, Steven Dahdah, Timothy Everett Adams and James Richard Forbes"
author = "Steven Dahdah, Timothy Everett Adams and James Richard Forbes"
version = "0.1.12"
release = "0.1.12"
version = "0.1.9"
release = "0.1.9"

# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
Expand Down
41 changes: 35 additions & 6 deletions doc/examples.rst
Original file line number Diff line number Diff line change
Expand Up @@ -178,13 +178,14 @@ particular, the response of the system states and actuator inputs are shown.

.. image:: _static/example_6/6_plot_inputs.png

Multi-Model Uncertainty Characterization
----------------------------------------
Multi-Model Uncertainty Characterization: Academic Model
--------------------------------------------------------

In this example, an unstructured uncertainty set is characterized from a set
of nominal and off-nominal frequency responses. The off-nominal models are
generated from a nominal model by randomly perturbing the parameters within a
known bound.
In this example, an unstructured uncertainty set is characterized from a set of
nominal and off-nominal frequency responses. This is an academic example as the
uncertain model in this problem is arbitrarily selected for the purpose of
demonstration. The off-nominal models are generated from a nominal model by
randomly perturbing the parameters within a known bound.

.. literalinclude:: ../examples/7_uncertainty_characterization.py
:language: python
Expand Down Expand Up @@ -240,7 +241,35 @@ set. The optimal weight frequency responses and fitted weights are shown below.

.. image:: _static/example_7/7_uncertainty_weight.png

Multi-Model Uncertainty Characterization: Aircraft Actuator Model
-----------------------------------------------------------------

In this example, an unstructured uncertainty set is characterized from a set of
nominal and off-nominal frequency responses. In this example, the uncertainty
of an aircraft actuator model is characterized using an actuator model from an
example given in Section 14.1 of [M04]_.

.. literalinclude:: ../examples/8_aircraft_actuator_uncertainty_characterization.py
:language: python

The off-nominal frequency response data is generated by sampling valid
perturbations from the uncertainty model provided in the problem statement.

.. image:: _static/example_8/8_sval_actuator.png

Three different candidate uncertainty models are evaluated: additive
uncertainty, multiplicative input uncertainty, and inverse multiplicative
input uncertainty. The multiplicative input uncertainty is selected as it
yields the smallest residual singular values.

.. image:: _static/example_8/8_sval_residual_max.png

The left uncertainty weight is constrained to be scalar whereas the right uncertainty
weight is constrained to the identity matrix. Given that the right uncertainty
weight is the identity matrix, a fit does not need to be performed for this weight
as it will be neglected in the generalized plant.

.. image:: _static/example_8/8_magnitude_uncertainty_weight.png



Expand Down
4 changes: 2 additions & 2 deletions examples/6_dk_iteration_non_square_perturbation.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def example_dk_iter_list_order_aircraft():
# DK-iteration controller synthesis
dk_iter = dkpy.DkIterListOrder(
controller_synthesis=dkpy.HinfSynLmi(
lmi_strictness=5e-7, # Have to play with tolerances.
lmi_strictness=5e-7,
solver_params=dict(
solver="MOSEK",
eps=5e-8,
Expand All @@ -74,7 +74,7 @@ def example_dk_iter_list_order_aircraft():
),
),
d_scale_fit=dkpy.DScaleFitSlicot(),
fit_orders=[4, 4],
fit_orders=[4, 4, 4],
)
# Alternative MATLAB block structure description
# block_structure = np.array([[n_u_delta, n_y_delta], [n_w, n_z]])
Expand Down
74 changes: 35 additions & 39 deletions examples/7_uncertainty_characterization.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,33 +8,12 @@
def example_uncertainty_characterization():
"""Multi-model uncertainty characterization from frequency response data."""

# Generate example data
# Load example data
eg = dkpy.example_multimodel_uncertainty()
response_nom = eg["complex_response_nominal"]
response_offnom_list = eg["complex_response_offnominal_list"]
omega = eg["omega"]

# Plot: Magnitude response of nominal and off-nominal systems
fig, _ = dkpy.plot_magnitude_response_uncertain_model_set(
response_nom,
response_offnom_list,
omega,
)

# Plot: Phase response of nominal and off-nominal systems
fig, _ = dkpy.plot_phase_response_uncertain_model_set(
response_nom,
response_offnom_list,
omega,
)

# Plot: Singular value response of nominal and off-nominal systems
fig, ax = dkpy.plot_singular_value_response_uncertain_model_set(
response_nom,
response_offnom_list,
omega,
)

# Uncertainty models
uncertainty_models = {
"additive",
Expand All @@ -44,41 +23,58 @@ def example_uncertainty_characterization():
"inverse_multiplicative_input",
"inverse_multiplicative_output",
}

# Compute uncertainty residual frequency response
response_residuals_dict = dkpy.compute_uncertainty_residual_response(
response_nom,
response_offnom_list,
uncertainty_models,
)

# Plot: Singular value response of uncerainty residuals
figure_dict = dkpy.plot_singular_value_response_residual(
response_residuals_dict, omega
)

# Plot: Comparison of singular value response of uncerainty residuals for each
# uncertainty model
fig, _ = dkpy.plot_singular_value_response_residual_comparison(
response_residuals_dict, omega
)

# Compute uncertainty weight frequency response
response_weight_left, response_weight_right = (
dkpy.compute_optimal_uncertainty_weight_response(
dkpy.compute_uncertainty_weight_response(
response_residuals_dict["inverse_additive"], "diagonal", "diagonal"
)
)

# Fit overbounding stable and minimum-phase uncertainty weight system
weight_left = dkpy.fit_overbounding_uncertainty_weight(
response_weight_left, omega, [4, 5]
weight_left = dkpy.fit_uncertainty_weight(response_weight_left, omega, [4, 5])
weight_right = dkpy.fit_uncertainty_weight(response_weight_right, omega, [3, 5])

# Plot: Magnitude response of nominal and off-nominal systems
dkpy.plot_magnitude_response_uncertain_model_set(
response_nom,
response_offnom_list,
omega,
)

# Plot: Phase response of nominal and off-nominal systems
dkpy.plot_phase_response_uncertain_model_set(
response_nom,
response_offnom_list,
omega,
)
weight_right = dkpy.fit_overbounding_uncertainty_weight(
response_weight_right, omega, [3, 5]

# Plot: Singular value response of nominal and off-nominal systems
dkpy.plot_singular_value_response_uncertain_model_set(
response_nom,
response_offnom_list,
omega,
)

# Plot: Singular value response of uncerainty residuals
dkpy.plot_singular_value_response_residual(response_residuals_dict, omega)

# Plot: Comparison of singular value response of uncerainty residuals for each
# uncertainty model
dkpy.plot_singular_value_response_residual_comparison(
response_residuals_dict, omega
)

# Plot: Magnitude response of uncertainty weight frequency response and overbounding
# fit
fig, _ = dkpy.plot_magnitude_response_uncertainty_weight(
dkpy.plot_magnitude_response_uncertainty_weight(
response_weight_left,
response_weight_right,
omega,
Expand Down
64 changes: 64 additions & 0 deletions examples/8_aircraft_actuator_uncertainty_characterization.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
"""Multi-model aircraft actuator uncertainty characterization from frequency response
data.

"""

from matplotlib import pyplot as plt

import dkpy


def example_aircraft_uncertainty_characterization():
"""Multi-model aircraft actuator uncertainty characterization from frequency
response data.
"""
# Load example data
eg = dkpy.example_aircraft_actuator_uncertainty()
response_actuator = eg["response_actuator_nominal"]
response_actuator_offnom_list = eg["response_actuator_offnominal"]
omega = eg["omega"]

# Compute the residual response for different uncertainty models
response_residual = dkpy.compute_uncertainty_residual_response(
response_actuator,
response_actuator_offnom_list,
{"additive", "multiplicative_input", "inverse_multiplicative_input"},
)

# Compute the optimal uncertainty weights with a given structure
response_weight_left, response_weight_right = (
dkpy.compute_uncertainty_weight_response(
response_residual["multiplicative_input"],
"scalar",
"identity",
)
)

# Fit an overbounding LTI system to the optimal uncertainty weight response
weight_left = dkpy.fit_uncertainty_weight(response_weight_left, omega, 1)

# Plot: Singular value response of nominal and off-nominal systems
dkpy.plot_singular_value_response_uncertain_model_set(
response_actuator, response_actuator_offnom_list, omega, hz=True
)

# Plot: Comparison of singular value response of uncerainty residuals for each
# uncertainty model
dkpy.plot_singular_value_response_residual_comparison(
response_residual, omega, hz=True
)

# Plot: Magnitude response of uncertainty weight frequency response and overbounding
# fit
dkpy.plot_magnitude_response_uncertainty_weight(
response_weight_left,
response_weight_right,
omega,
weight_left=weight_left,
hz=True,
)
plt.show()


if __name__ == "__main__":
example_aircraft_uncertainty_characterization()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "dkpy"
version = "0.1.12"
version = "0.1.9"
dependencies = [
"numpy>=1.21.0",
"scipy>=1.7.0",
Expand Down
Loading
Loading