Implement ERA, change api to TimeResponseData#1024
Implement ERA, change api to TimeResponseData#1024murrayrm merged 8 commits intopython-control:mainfrom
Conversation
55ac0ed to
614a080
Compare
murrayrm
left a comment
There was a problem hiding this comment.
Overall this looks good. I found a few small things that you might want to update.
control/modelsimp.py
Outdated
| impulse-response data from which the StateSpace model is estimated, | ||
| 1D or 3D array. |
There was a problem hiding this comment.
impulse → Impulse (start sentence with a capital letter) and try to fit on one line (if less than 75 characters).
control/modelsimp.py
Outdated
| impulse-response data from which the StateSpace model is estimated, | ||
| 1D or 3D array. | ||
| data : TimeResponseData | ||
| impulse-response data from which the StateSpace model is estimated. |
control/modelsimp.py
Outdated
| Number of rows in Hankel matrix. | ||
| Default is 2*r. |
There was a problem hiding this comment.
Put on a single line (here and below).
control/modelsimp.py
Outdated
| True indicates discrete time with unspecified sampling time, | ||
| positive number is discrete time with specified sampling time. | ||
| It can be used to scale the StateSpace model in order to match | ||
| the impulse response of this library. | ||
| Default values is True. |
There was a problem hiding this comment.
Can probably have fewer lines by going out to column 75 before wrapping. Default value sentence doesn't need to start on a new line.
There was a problem hiding this comment.
Tried and Done!
control/modelsimp.py
Outdated
| def era(arg, r, m=None, n=None, dt=True, transpose=False): | ||
| r"""era(YY, r) |
There was a problem hiding this comment.
Optional: to be consistent with the longer naming style we are using in python-control, I suggest we call the function eigensys_realization and then define era = eigensys_realization at the bottom of the file (see freqplot.py for some example). We should also (but not here) redefine the other functions in this file (minimal_realization, balanced_realization, etc).
|
I get a warning ../python-control/doc/generated/control.era.rst: WARNING: document isn't included in any toctreeI could not exclude the alias name era from autosummary. __all__=[eigensys_realization, era]How to exclude era from autosummary? SOLUTION: The Solution is, to delete the generated folder in doc. Then the sphinx/autosummary does not use old files. |
c5f0cbe to
4ea1d82
Compare
4ea1d82 to
250c448
Compare
roryyorke
left a comment
There was a problem hiding this comment.
some minor suggestions, and a question.
control/modelsimp.py
Outdated
| where `response` is an `TimeResponseData` object, and `YY` is 1D or 3D | ||
| array and r is an integer. |
There was a problem hiding this comment.
| where `response` is an `TimeResponseData` object, and `YY` is 1D or 3D | |
| array and r is an integer. | |
| where `data` is a `TimeResponseData` object, `YY` is a 1D or 3D | |
| array, and r is an integer. |
response is more specific than data, perhaps better?
There was a problem hiding this comment.
response or data? Not sure.
For me, the function time_response_plot which uses data for time_response, is the blueprint.
The plotting functions use data for input.
bode_plot
The response data types use response for input.
NyquistResponseData
There was a problem hiding this comment.
OK, in my PR #1022 I initially used response instead of data. I will go with data for now.
@roryyorke @murrayrm what should we use?
There was a problem hiding this comment.
I prefer response as it's more specific, but the main thing is to be consistent within the ERA docstring(s).
control/modelsimp.py
Outdated
| Number of columns in Hankel matrix. Default is 2*r. | ||
| dt : True or float, optional | ||
| True indicates discrete time with unspecified sampling time, | ||
| positive number is discrete time with specified sampling time. It |
There was a problem hiding this comment.
| positive number is discrete time with specified sampling time. It | |
| and a positive float means discrete time with the specified sampling time. It |
control/modelsimp.py
Outdated
| True indicates discrete time with unspecified sampling time, | ||
| positive number is discrete time with specified sampling time. It | ||
| can be used to scale the StateSpace model in order to match the | ||
| impulse response of this library. Default is True. |
There was a problem hiding this comment.
I don't understand the idea of "impulse response of this library" - what does library mean here?
There was a problem hiding this comment.
This library "python-control" uses a unit area impulse "delta = 1/dt" for dt > 0 and a unit impulse "delta = 1" for dt = True.
The dt parameter is used to create a discrete time state space system (A,B,C,D,dt) to match an impulse response generated by control.impulse_response.
There was a problem hiding this comment.
Done!
I change the text to " It can be used to scale the StateSpace model in order to match the unit-area impulse response of python-control. "
Is there a better way to explain that behavior. Should we add something to Library conventions in order to explain the unit-area impulse response of python-control?
There was a problem hiding this comment.
Ah, thanks, now I understand.
One possibly-not-obvious side-effect of using True is that it has a value of 1, so one gets debatably natural discrete-time behaviour in that case.
The unit-area convention is documented in timeresp.impulse_resp under Notes, I suggest a reference to that.
control/modelsimp.py
Outdated
| >>> sysd, _ = ct.eigensys_realization(response, r=1) | ||
| """ | ||
| raise NotImplementedError('This function is not implemented yet.') | ||
| def block_hankel_matrix(Y, m, n): |
There was a problem hiding this comment.
suggest making this top-level _block_hankel.
| A reduced order model sys=StateSpace(Ar,Br,Cr,Dr,dt). | ||
| S : array | ||
| Singular values of Hankel matrix. Can be used to choose a good r | ||
| value. |
There was a problem hiding this comment.
given this, is there an alternative interface with a minsigma argument which could be used to choose r based on the singular values instead? (or maybe tol, with minsigma = tol * maxsigma ?)
This probably a bit out-of-scope, and if the user needs this capability it is simple enough to implement in their own code.
There was a problem hiding this comment.
I have thought about it, but I will not be adding this feature at this time.
I don't know the literature on this topic well enough, but I know that there are papers that study the choice of r.
There was a problem hiding this comment.
Postponed. Possible improvement in the future.
control/modelsimp.py
Outdated
| # balanced realizations | ||
| Sigma_inv = np.diag(1./np.sqrt(S[0:r])) | ||
| Ar = Sigma_inv @ Ur.T @ Hl @ Vhr.T @ Sigma_inv | ||
| Br = Sigma_inv @ Ur.T @ Hf[:,0:p]*dt |
There was a problem hiding this comment.
It looks like the reference here is "Algorithm 1" of the arxiv paper.
Why does dt makes an appearance here? I don't see any mention of sample rate or sample period in the referenced paper. It must be needed since you have dt=0.1 in the spring-damper model unit test -- I guess I'm missing something obvious?
There was a problem hiding this comment.
ERA in the paper assumes a unit impulse response "delta = 1". There is no dt in the paper.
However, python control generates a unit-area impulse response "delta = 1/dt". See also: #812, #977.
In other words, the impulse responses of StateSpace(A,B,C,D,dt=True) and StateSpace(A,B,C,D,dt=0.1) differ by a scaling.
The dt parameter in era can be used to create the right StateSpace model.
Alternative:
We could also rescale the output data by Y=Y*dt in order to get the unit impulse response instead of the unit-area impulse response.
Overall, my goal is that impulse_response, era, markov and StateSpace should work well together.
There was a problem hiding this comment.
Done. I added a little comment to indicate the intentional use of Br*dt.
Is there a more elegant way to achieve this?
roryyorke
left a comment
There was a problem hiding this comment.
LGTM. If you think it's useful, add a reference to timeresp.impulse_response.
This PR implements the ERA method. Related to #1002 and #847