You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
forced_response giving different output depending on Python and/or numpy version #993
Setup 1: Python 3.8, numpy 1.20.3, control 0.9.4
Setup 2: Python 3.11, numpy 1.26.4, control 0.9.4
Setup 3: Python 3.11, numpy 1.26.4, control 0.10.0
Setup 1 gives a different output than setup 2 and 3. The first value of the output of setup 1 is -0.4, and the output never reaches 2.5.
Setup 2 and 3 on the other hand produce -1.2 as their first output value, and the value of 2.5 is surpassed on the first peek.
I don't know which of the disagreeing paries is right, or if they are both wrong. And I dont know if the base installation, numpy or control are to blame for the discrepany. And I am sorry my code does not show up properly. I was using the "code" button, but this does not seem to do anything usefull.
Thank you for your time. So far I've been unable to run any code on Binder. I can see the examples, I can upload files, but I can not figure out how to run them. The run button isn't doing anything. Sorry for beeing so slow and uneducated, I only was ever using Python with Spyder.
Meanwhile, I uninstalled the whole Anaconda distribution which is giving the wrong output (Setup 1 and 2 in the original post),
redownloaded and reinstalled it, and reinstalled the python control library (numpy 1.26.4, control 0.10.0.) I tested the code ( copy-pasted it from your post above to exlude typos) and... it still gives the wrong output, see the attached graph.
In the first space, enter !pip install control, as shown here:
Run it to install control and dependencies, including NumPy and Matplotlib. When it is completed, enter the code from above, and run it. The result will be similar to the following:
Yes, I was using the conda comand to intstall the control systems library, as described in the installation section, and as pointed out in your response.
I've run the code we are talking about on mybinder according to your instructions. Here, it seems to do the right thing, producing the same output value as in your run of the program, and as I get with 'Setup 1'.
Hi guys. I'm also facing issues with the forced_response method. I understand the proposed conda-based installation procedure however, I have reasons to stick with pip installations on my standard Python setup running on Windows 10. In my circumstance, after dozens of tests and evaluations simulating the exact transfer function on both Matlab and Simulink, Julia, and python-control I became doubtful about the numerical results from the latter.
To reproduce my setup here are the versions:
Python 3.11.5 (tags/v3.11.5:cce6ba9)
python-control: 0.10.0
numpy: 1.25.2
matplotlib: 3.7.2
MWE:
importmatplotlib.pyplotaspltimportnumpyasnpimportcontrolfrommathimportpi, sin, coswi=2*pi*1.2# input *angular frequencyAi=0.679# input amplitudeMr=2.718# actual massKd=400.0# impedance stiffnessDd=2*sqrt(Kd) # impedance dampinginput_period=2*pi/witime=np.linspace(0, 2.0*input_period, 600)
x_ref_time=Ai*np.sin(wi*time)
s=control.tf('s')
Z=Dd*s+Kd# s-domain impedanceref_to_error_tf= (Mr*s**2)/(Z+Mr*s**2)
error_response=control.forced_response(ref_to_error_tf, time, x_ref_time, transpose=True)
plt.plot(error_response.t, error_response.x[0])
The error_response time series is scaled about the series observed in the reference simulations. I conducted tests with a range of different values for the parameters Ai, wi, Mr, Kd, Dd, and it was noted that while this time series preserved its shape, it exhibited an amplitude approximately eight to ten times lower than expected.
I'll reproduce the execution of this code snippet on my Ubuntu 22.04 soon.
I took a look at the above issue. I note that in all cases there is some type of access to the state of the underlying realization of the transfer function. In particular, in the original post the initial condition for the state is set and in the latest post the value of the first state is plotted.
This is a potential problem because the state space realization for a transfer function is non-unique and can depend on how the conversion to state space is done. In the current release of python-control, this is done in one of two ways:
If slycot is installed, then statespace._convert_to_statespace will use slycot.td04ad with whatever version of slycot is installed.
If slycot is not installed, then statespace._convert_to_statespace will use scipy.signal.tf2ss for whatever version of SciPy is installed.
Using the ct.ss factor function, you can control what method is used by using the method keyword.
Note that when you specify the initial condition, you get a warning that something funny may happen:
UserWarning: Non-zero initial condition given for transfer function system. Internal conversion
to state space used; may not be consistent with given X0.
This is a hint that something funny may be happening.
With that as background, I took the original example that was posted and ran in Python 3.12 with slycot installed. I converted the transfer function to state space form using ct.ss and the method keyword to control the conversion, the plotted the forced response. Here are the results:
We see that the initial output differs, because the state space representations are different and so setting x0 can create different results. The system is stable and so the transient eventually dies out and the responses match.
I suspect this also explains the second example, where the internal state x is being accessed. The only thing that is guaranteed to be consistent between various implementations (including comparisons to MATLAB or Octave) is the outputs.
Activity
slivingston commentedon Apr 18, 2024
I tried this with Setup 2 and and Setup 3, both of which produce the result that you described for Setup 1:

To test Setup 1, I had some difficulty installing numpy 1.20.3, but I tried Python 3.8, numpy 1.24.4, control 0.9.4. The result is the same as above.
To be certain, here exactly the code that I run:
slivingston commentedon Apr 18, 2024
I installed NumPy 1.20.3 and reproduced the same plot as above for Setup 1 (Python 3.8, numpy 1.20.3, control 0.9.4). As such, I cannot reproduce the different behavior that you described. Can you try to run your code on Google Colab or with Binder as described at https://github.com/python-control/python-control?tab=readme-ov-file#have-a-go-now ?
MatthiasFreiburghaus commentedon Apr 18, 2024
Thank you for your time. So far I've been unable to run any code on Binder. I can see the examples, I can upload files, but I can not figure out how to run them. The run button isn't doing anything. Sorry for beeing so slow and uneducated, I only was ever using Python with Spyder.
MatthiasFreiburghaus commentedon Apr 18, 2024
Meanwhile, I uninstalled the whole Anaconda distribution which is giving the wrong output (Setup 1 and 2 in the original post),

redownloaded and reinstalled it, and reinstalled the python control library (numpy 1.26.4, control 0.10.0.) I tested the code ( copy-pasted it from your post above to exlude typos) and... it still gives the wrong output, see the attached graph.
slivingston commentedon Apr 18, 2024
Did you install it following the instructions at https://python-control.readthedocs.io/en/0.10.0/intro.html#installation? In particular, with Anaconda, you should be able to
slivingston commentedon Apr 18, 2024
As for Binder, go to https://mybinder.org/v2/gh/python-control/python-control/HEAD and then create a Python 3 Notebook; the correct icon is highlighted in red here:

In the first space, enter

!pip install control, as shown here:Run it to install

controland dependencies, including NumPy and Matplotlib. When it is completed, enter the code from above, and run it. The result will be similar to the following:MatthiasFreiburghaus commentedon Apr 19, 2024
Yes, I was using the conda comand to intstall the control systems library, as described in the installation section, and as pointed out in your response.
I've run the code we are talking about on mybinder according to your instructions. Here, it seems to do the right thing, producing the same output value as in your run of the program, and as I get with 'Setup 1'.
qleonardolp commentedon Apr 29, 2024
Hi guys. I'm also facing issues with the
forced_responsemethod. I understand the proposed conda-based installation procedure however, I have reasons to stick with pip installations on my standard Python setup running on Windows 10. In my circumstance, after dozens of tests and evaluations simulating the exact transfer function on both Matlab and Simulink, Julia, and python-control I became doubtful about the numerical results from the latter.To reproduce my setup here are the versions:
Python 3.11.5 (tags/v3.11.5:cce6ba9)
python-control: 0.10.0
numpy: 1.25.2
matplotlib: 3.7.2
MWE:
The
error_responsetime series is scaled about the series observed in the reference simulations. I conducted tests with a range of different values for the parametersAi, wi, Mr, Kd, Dd, and it was noted that while this time series preserved its shape, it exhibited an amplitude approximately eight to ten times lower than expected.I'll reproduce the execution of this code snippet on my Ubuntu 22.04 soon.
murrayrm commentedon May 5, 2024
I took a look at the above issue. I note that in all cases there is some type of access to the state of the underlying realization of the transfer function. In particular, in the original post the initial condition for the state is set and in the latest post the value of the first state is plotted.
This is a potential problem because the state space realization for a transfer function is non-unique and can depend on how the conversion to state space is done. In the current release of python-control, this is done in one of two ways:
statespace._convert_to_statespacewill useslycot.td04adwith whatever version of slycot is installed.statespace._convert_to_statespacewill usescipy.signal.tf2ssfor whatever version of SciPy is installed.Using the
ct.ssfactor function, you can control what method is used by using themethodkeyword.Note that when you specify the initial condition, you get a warning that something funny may happen:
This is a hint that something funny may be happening.
With that as background, I took the original example that was posted and ran in Python 3.12 with slycot installed. I converted the transfer function to state space form using
ct.ssand themethodkeyword to control the conversion, the plotted the forced response. Here are the results:We see that the initial output differs, because the state space representations are different and so setting
x0can create different results. The system is stable and so the transient eventually dies out and the responses match.I suspect this also explains the second example, where the internal state
xis being accessed. The only thing that is guaranteed to be consistent between various implementations (including comparisons to MATLAB or Octave) is the outputs.