Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

print a connection table for interconnected systems#925

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
murrayrm merged 12 commits intopython-control:mainfromsawyerbfuller:connections
Sep 16, 2023

Conversation

sawyerbfuller
Copy link
Contributor

@sawyerbfullersawyerbfuller commentedJul 24, 2023
edited
Loading

This PR prints out a table of each signal name, where it comes from (source), and where it goes (destination). It is intended primarily for systems that have been connected implicitly, because in that case all of the signal names have been defined. It doesn't really work for systems that have been connected explicitly, because their signal names may not be unique

It was is inspired by a similar table printout inbdsim and the need to have a means to debug interconnections of many systems.

Example:

>>>P=ct.ss(1,1,1,0,inputs='u',outputs='y')>>>C=ct.tf(10, [.1,1],inputs='e',outputs='u')>>>L=ct.interconnect([C,P],inputs='e',outputs='y')>>>L.connection_table()signal|source|destination--------------------------------------------------------------e|input|system0u|system0|system1y|system1|output

(edit: in the code above,signal_table has been changed toconnection_table)
Remarks:

  • it does not list systems by their name by default because the because default system names (e.g.sys[17]) are not very descriptive or helpful when you're connecting systems implicitly with signal names. instead the table just references them by the order they appear in the interconnect list, with an option to print names instead.
  • it would be convenient if instead systems were listed by the name of the variable referencing them, e.g. if the first row looked likee | input | C, but this is not straightforward in Python because it is possible to have many variable names pointing to the same object in memory.
  • Maybe this could be achieved using a change to the library that automatically populates the 'name' field in new systems with the variable name it is first assigned to, but I am not sure if this is possible or Pythonic
  • this PR also includes a couple of docstring cleanups to remove references to the namedio class

@coveralls
Copy link

coveralls commentedJul 24, 2023
edited
Loading

Coverage Status

coverage: 94.969% (+0.001%) from 94.968% when pulling5c23f1a on sawyerbfuller:connections into42c6fb1 on python-control:main.

@murrayrm
Copy link
Member

This looks very useful for sorting out what is connected to what. A couple of questions and comments:

  • What happens if the list of systems is longer than 32 characters. Is there a way to either truncate the field (perhaps end in "...") or adjust thespacing variable to make sure that the table stays lined up?
  • Is there a way to generate a warning if the system was not generated using common signal names?
  • A more general functionality seems like it would be possible by looking through theconnect_map,input_map, andoutput_map arrays, which describe how everything is connected.

As an experiment, I tried modifying the example above to use a more typical form with a reference input:

P = ct.ss(1,1,1,0, inputs='u', outputs='y')C = ct.tf(10, [.1, 1], inputs='e', outputs='u')sumblk = ct.summing_junction(inputs=['r', '-y'], outputs='e')T = ct.interconnect([C, P, sumblk], inputs='r', outputs='y')T.signal_table()

which gives

signal    | source                        | destination--------------------------------------------------------------------------e         | system 2                      | system 0                      y         | system 1                      | output, system 2              r         | input                         | system 2                      u         | system 0                      | system 1

That looks right to me, but it it might be nice to see the fact thaty goes into system 2 (the summing junction) with a negative gain.

@sawyerbfuller
Copy link
ContributorAuthor

sawyerbfuller commentedAug 2, 2023
edited
Loading

This looks very useful for sorting out what is connected to what. A couple of questions and comments:

* What happens if the list of systems is longer than 32 characters.  Is there a way to either truncate the field (perhaps end in "...") or adjust the `spacing` variable to make sure that the table stays lined up?

Right now it just breaks alignment. I think a good solution might be to add an elipsis as you suggest, and to allow the user to set the spacing parameter. update forthcoming.

* Is there a way to generate a warning if the system was not generated using common signal names?* A more general functionality seems like it would be possible by looking through the `connect_map`, `input_map`, and `output_map` arrays, which describe how everything is connected.

On further thought, I would propose the following:

  1. change the name of this function to be more generic, such as "connection_table", rather than "signal_table", allowing for a future PR that perhaps produces a different kind of table for explicitly-connected systems.
  2. which would pave the way for a future PR geared toward explicitly-connected systems that perhaps uses those maps. OTOH I think that such interconnections might better be presented in a table that puts the system name first, followed by its input and output systems. Perhaps a flag could be added to to theInterconnectedSystem class, specifying whether it was connected implicitly or explicitly, and choose the table type based on that.
  3. (edit) add in a warning for the time being

As an experiment, I tried modifying the example above to use a more typical form with a reference input:

P = ct.ss(1,1,1,0, inputs='u', outputs='y')C = ct.tf(10, [.1, 1], inputs='e', outputs='u')sumblk = ct.summing_junction(inputs=['r', '-y'], outputs='e')T = ct.interconnect([C, P, sumblk], inputs='r', outputs='y')T.signal_table()

which gives

signal    | source                        | destination--------------------------------------------------------------------------e         | system 2                      | system 0                      y         | system 1                      | output, system 2              r         | input                         | system 2                      u         | system 0                      | system 1

That looks right to me, but it it might be nice to see the fact thaty goes into system 2 (the summing junction) with a negative gain.

Great. I agree this could be useful. Open to it going into a future PR? I am not sure this information is stored anywhere in theinterconnectedSystem class: the negative sign appears as one of the elements in summing junction's D matrix.

@sawyerbfuller
Copy link
ContributorAuthor

sawyerbfuller commentedAug 14, 2023
edited
Loading

@murrayrm I incorporated (most of) your suggested updates:

  • function warns if connections were made explicitly
    • to do this, I added a field toInterconnectedSystem.connection_type that indicates how connections were made: 'explicit'-ly, 'implicit'-ly, or not at all (None)
  • table adds an elipsis if any column gets too long; user can now specify column width. Example:
P1=ct.ss(1,1,1,0,inputs='u',outputs='y',name='Plant1')P2=ct.tf(10, [.1,1],inputs='e',outputs='y',name='Plant2')P3=ct.tf(10, [.1,1],inputs='x',outputs='y',name='Plant3')L=ct.interconnect([P1,P2,P3],inputs=['e','u','x'],outputs='y')L.connection_table(show_names=True,column_width=23)signal|source|destination--------------------------------------------------------x|input|Plant3e|input|Plant2u|input|Plant1y|Plant1,Plant2,Pl..|output
  • renamed functionconnection_table to make it more general, allowing for it to print a similar, but probably differently-formatted table for explicit connectiosn in the future
  • I don't know of an obvious way to indicate negative connections. perhaps a future PR?


Parameters
----------
show_names : bool (optional)
Copy link
Member

Choose a reason for hiding this comment

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

Numpydoc standard notation isbool, optional (comma instead of parens). I'm not sure if Sphinx will parse or not, but probably better to change so that it is consistent with other documentation.

each system. Default is False because system name is not usually
specified when performing implicit interconnection using
:func:`interconnect`.
column_width : int (optional)
Copy link
Member

Choose a reason for hiding this comment

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

(optional) → , optional

@@ -1955,7 +2032,7 @@ def interconnect(
signals are given names, then the forms 'sys.sig' or ('sys', 'sig')
are also recognized. Finally, for multivariable systems the signal
index can be given as a list, for example '(subsys_i, [inp_j1, ...,
inp_jn])'; as a slice, for example, 'sys.sig[i:j]'; or as a base
inp_jn])';oras a slice, for example, 'sys.sig[i:j]'; or as a base
Copy link
Member

Choose a reason for hiding this comment

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

Wasn't this correct before? Now it says 'a; or b; or c' instead of 'a; b; or c'.

Comment on lines 2582 to 2617

def connection_table(sys, show_names=False, column_width=32):
"""Print table of connections inside an interconnected system model.

Intended primarily for :class:`InterconnectedSystems` that have been
connected implicitly using signal names.

Parameters
----------
sys : :class:`InterconnectedSystem`
Interconnected system object
show_names : bool (optional)
Instead of printing out the system number, print out the name of
each system. Default is False because system name is not usually
specified when performing implicit interconnection using
:func:`interconnect`.
column_width : int (optional)
Character width of printed columns


Examples
--------
>>> P = ct.ss(1,1,1,0, inputs='u', outputs='y', name='P')
>>> C = ct.tf(10, [.1, 1], inputs='e', outputs='u', name='C')
>>> L = ct.interconnect([C, P], inputs='e', outputs='y')
>>> L.connection_table(show_names=True) # doctest: +SKIP
signal | source | destination
--------------------------------------------------------------
e | input | C
u | C | P
y | P | output
"""
assert isinstance(sys, InterconnectedSystem), "system must be"\
"an InterconnectedSystem."

sys.connection_table(show_names=show_names, column_width=column_width)
Copy link
Member

Choose a reason for hiding this comment

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

Not something that we need to fix in this PR, but we should eventually adopt some mechanism for creating duplicate docstrings from a single primary docstring (see, for example, the discussionhere).

@@ -1459,7 +1459,7 @@ class LinearICSystem(InterconnectedSystem, StateSpace):

"""

def __init__(self, io_sys, ss_sys=None):
def __init__(self, io_sys, ss_sys=None, connection_type=None):
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason to allow the connection type to be overridden? It seems like this should just be inherited from the underlyingInterconnectedSystem.

@murrayrmmurrayrm merged commit405bf77 intopython-control:mainSep 16, 2023
@murrayrmmurrayrm added this to the0.10.0 milestoneMar 31, 2024
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@murrayrmmurrayrmmurrayrm left review comments

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
0.10.0
Development

Successfully merging this pull request may close these issues.

3 participants
@sawyerbfuller@coveralls@murrayrm

[8]ページ先頭

©2009-2025 Movatter.jp