GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — add reference gain design pattern to create_statefbk_iosystem by murrayrm · Pull Request #1071 · python-control/python-control

Conversation

@murrayrm

@murrayrm murrayrm commented Dec 2, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

This PR adds a second design pattern to the create_statefbk_iosystem function, allowing controllers that use a static gain on the reference input instead of the desired state and input. As described in the user documentation:

The ~control.create_statefbk_iosystem function can be used to create an I/O system consisting of a state feedback gain (with optional integral action and gain scheduling) and an estimator. A basic state feedback controller of the form

$u = u_d - K (x - x_\text{d})$

can be created with the command::

ctrl, clsys = ct.create_statefbk_iosystem(sys, K)

where sys is the process dynamics and K is the state feedback gain (e.g., from LQR). The function returns the controller ctrl and the closed loop systems clsys, both as I/O systems. The input to the controller is the vector of desired states $x_\text{d}$, desired inputs $u_\text{d}$, and system states $x$.

The above design pattern is referred to as the "trajectory generation" ('trajgen') pattern, since it assumes that the input to the controller is a feasible trajectory $(x_\text{d}, u_\text{d})$. Alternatively, a controller using the "reference gain" pattern can be created, which implements a state feedback controller of the form

$u = k_\text{f}, r - K x$,

where $r$ is the reference input and $k_\text{f}$ is the feedforward gain (normally chosen so that the steady state output $y_\text{ss}$ will be equal to $r$).

A reference gain controller can be created with the command::

ctrl, clsys = ct.create_statefbk_iosystem(sys, K, kf, feedfwd_pattern='refgain')

The reference gain design pattern is described in more detail in Section 7.2 of FBS2e (Stabilization by State Feedback) and the trajectory generation design pattern is described in Section 8.5 (State Space Controller Design).

In addition, this PR includes some changes that make the error messages for setting up a state space system more informative, but giving the expected size of matrices that do not have the right dimensions. (This could go in a separate PR, but it is here because I got frustrated with the error messages while debugging some examples.)

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@coveralls

coveralls commented Dec 2, 2024 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Coverage Status

coverage: 94.737% (+0.02%) from 94.721%
when pulling bb52b70 on murrayrm:create_statefbk-29Nov2024
into 12dda4e on python-control:main.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@slivingston
slivingston self-requested a review December 3, 2024 07:30
@slivingston

slivingston commented Dec 4, 2024

Copy link
Copy Markdown
Member

I will review this today.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

slivingston
slivingston requested changes Dec 5, 2024
View reviewed changes
Comment thread control/statefbk.py Outdated
(proportional and integral) are evaluated using the scheduling
variables specified by `gainsched_indices`.
Input/output system representing the controller. For the 'trajgen'
design patter (default), this system takes as inputs the desired

@slivingston slivingston Dec 3, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
design patter (default), this system takes as inputs the desired
design pattern (default), this system takes as inputs the desired

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread control/statefbk.py Outdated
state `x_d`, the desired input `u_d`, and either the system state
`x` or the estimated state `xhat`. It outputs the controller
action `u` according to the formula `u = u_d - K(x - x_d)`. For
the 'refgain' design patter, the system takes as inputs the

@slivingston slivingston Dec 3, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
the 'refgain' design patter, the system takes as inputs the
the 'refgain' design pattern, the system takes as inputs the

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread doc/iosys.rst Outdated
ctrl, clsys = ct.create_statefbk_iosystem(sys, K, kf, feedfwd_pattern='refgain')

This reference gain design pattern is described in more detail in Section
7.2 of FBS2e (Stabilization by State Feedback) and the trajectory

@slivingston slivingston Dec 5, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might have missed something, but some readers will not know the reference "FBS2e". One idea is to make FBS2e_ a link to the book website. This can be done with the following changes:

diff --git a/doc/conf.py b/doc/conf.py
index 75981d6..a523713 100644
--- a/doc/conf.py
+++ b/doc/conf.py
@@ -285,3 +285,7 @@ import control.flatsys as fs
 import control.phaseplot as pp
 ct.reset_defaults()
 """
+
+rst_prolog = """
+..  _FBS2e: https://fbswiki.org/wiki/index.php/Feedback_Systems:_An_Introduction_for_Scientists_and_Engineers
+"""
diff --git a/doc/iosys.rst b/doc/iosys.rst
index e67f4dc..413f4d4 100644
--- a/doc/iosys.rst
+++ b/doc/iosys.rst
@@ -57,7 +57,7 @@ Example
 
 To illustrate the use of the input/output systems module, we create a
 model for a predator/prey system, following the notation and parameter
-values in FBS2e.
+values in FBS2e_.
 
 We begin by defining the dynamics of the system

Feel free to apply this change to your PR, or I can open another PR that adds this and possibly other docs enhancements.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread control/tests/statefbk_test.py

else:
ctrl, clsys = ct.create_statefbk_iosystem(
sys, K, Kf, feedfwd_pattern='refgain')

@slivingston slivingston Dec 5, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_statefbk_iosystem() is a big function now with several different ways of being called and a docstring of 180 lines. One design pattern to handle this is changing the function to be internal and then creating user-facing functions that have names implying values of arguments like feedfwd_pattern; e.g., create_statefbk_trajgen(), which is implemented by calling _create_statefbk_iosystem() with feedfwd_pattern='trajgen'. However, this alternative may not help users in practice.

In the scope of this PR, it suffices to ensure that mistakes when calling create_statefbk_iosystem() are caught. To that end, can you add a case for when feedfwd_pattern has an unknown value? E.g.,

Suggested change
sys, K, Kf, feedfwd_pattern='refgain')
sys, K, Kf, feedfwd_pattern='refgain')
with pytest.raises(NotImplementedError, match="unknown pattern"):
ct.create_statefbk_iosystem(sys, K, Kf, feedfwd_pattern='refgai')

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@slivingston slivingston Dec 5, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Related to the above, there may be existing code that calls create_statefbk_iosystem() with 3 positional arguments, thus giving integral_action without using the keyword. With this PR, that would effectively be a call to create_statefbk_iosystem() with a value to feedfwd_gain but feedfwd_pattern still at its default. I modified the test test_lqr_integral_continuous to demonstrate this case, and the resulting error is

        if isinstance(gain, np.ndarray):
            K = gain
            if K.shape != (sys_ninputs, estimator.noutputs + nintegrators):
>               raise ControlArgument(
                    f'control gain must be an array of size {sys_ninputs}'
                    f' x {sys_nstates}' +
                    (f'+{nintegrators}' if nintegrators > 0 else ''))
E               control.exception.ControlArgument: control gain must be an array of size 2 x 4

control/statefbk.py:831: ControlArgument

It is good that an exception is raised, but users may be confused about the cause.

I think that having feedfwd_gain as the third parameter is intuitive and worth keeping, so I propose that a ControlArgument exception is raised if feedfwd_gain is not None but feedfwd_pattern != 'refgain'.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions

@murrayrm murrayrm Dec 7, 2024

Copy link
Copy Markdown
Member Author

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left the single function for now, though I agree this function is getting big and complicated. I'm not sure that splitting it in two simplifies things much, and the current naming matches the create_estimator_iosystem and create_mpc_iosystem naming pattern (and functionality).

I created the exception suggested above + unit test.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Comment thread control/tests/statefbk_test.py Outdated
Comment on lines +1148 to +1149
(1, 1), (1, None),
(2, np.diag([1, 1])), (2, None),

@slivingston slivingston Dec 5, 2024

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
(1, 1), (1, None),
(2, np.diag([1, 1])), (2, None),
(1, 1),
(1, None),
(2, np.diag([1, 1])),
(2, None),

Easier to read if we have one case (i.e., one assignment of parameters) per line

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
murrayrm added 4 commits December 6, 2024 14:35
@murrayrm
add feedfwd keyword arguments (no functionality yet)
8780bdc
@murrayrm
update StateSpace size checks/error messages to be more informative
391d29c
@murrayrm
initial implementation, docstrings for refgain pattern
9ed4817
@murrayrm
documentation updates
96b7b73
@murrayrm
murrayrm force-pushed the create_statefbk-29Nov2024 branch 2 times, most recently from 604a3df to 96b7b73 Compare December 7, 2024 03:06
@slivingston
slivingston self-requested a review December 7, 2024 03:10
@murrayrm
addressed @slivingston review comments
bb52b70
slivingston
slivingston approved these changes Dec 7, 2024
View reviewed changes
@murrayrm
murrayrm merged commit d700ad7 into python-control:main Dec 7, 2024
@murrayrm murrayrm added this to the 0.10.2 milestone Feb 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@slivingston slivingston slivingston approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

0.10.2

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

3 participants

@murrayrm @coveralls @slivingston
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.