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

Commit1502d38

Browse files
authored
Merge pull request#514 from murrayrm/mimo_impulse_step_response
MIMO impulse and step response
2 parents0a08ff2 +28bbe7f commit1502d38

File tree

5 files changed

+342
-111
lines changed

5 files changed

+342
-111
lines changed

‎control/config.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
_control_defaults= {
1818
'control.default_dt':0,
1919
'control.squeeze_frequency_response':None,
20-
'control.squeeze_time_response':True,
2120
'control.squeeze_time_response':None,
2221
'forced_response.return_x':False,
2322
}

‎control/iosys.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1428,8 +1428,9 @@ def input_output_response(sys, T, U=0., X0=0, params={}, method='RK45',
14281428
foriinrange(len(T)):
14291429
u=U[i]iflen(U.shape)==1elseU[:,i]
14301430
y[:,i]=sys._out(T[i], [],u)
1431-
return_process_time_response(sys,T,y, [],transpose=transpose,
1432-
return_x=return_x,squeeze=squeeze)
1431+
return_process_time_response(
1432+
sys,T,y,np.array((0,0,np.asarray(T).size)),
1433+
transpose=transpose,return_x=return_x,squeeze=squeeze)
14331434

14341435
# create X0 if not given, test if X0 has correct shape
14351436
X0=_check_convert_array(X0, [(nstates,), (nstates,1)],

‎control/tests/matlab2_test.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -121,25 +121,25 @@ def test_step(self, SISO_mats, MIMO_mats, mplcleanup):
121121
#print("gain:", dcgain(sys))
122122

123123
subplot2grid(plot_shape, (0,0))
124-
t,y=step(sys)
124+
y,t=step(sys)
125125
plot(t,y)
126126

127127
subplot2grid(plot_shape, (0,1))
128128
T=linspace(0,2,100)
129129
X0=array([1,1])
130-
t,y=step(sys,T,X0)
130+
y,t=step(sys,T,X0)
131131
plot(t,y)
132132

133133
# Test output of state vector
134-
t,y,x=step(sys,return_x=True)
134+
y,t,x=step(sys,return_x=True)
135135

136136
#Test MIMO system
137137
A,B,C,D=MIMO_mats
138138
sys=ss(A,B,C,D)
139139

140140
subplot2grid(plot_shape, (0,2))
141-
t,y=step(sys)
142-
plot(t,y)
141+
y,t=step(sys)
142+
plot(t,y[:,0,0])
143143

144144
deftest_impulse(self,SISO_mats,mplcleanup):
145145
A,B,C,D=SISO_mats
@@ -168,8 +168,8 @@ def test_impulse_mimo(self, MIMO_mats, mplcleanup):
168168
#Test MIMO system
169169
A,B,C,D=MIMO_mats
170170
sys=ss(A,B,C,D)
171-
t,y=impulse(sys)
172-
plot(t,y,label='MIMO System')
171+
y,t=impulse(sys)
172+
plot(t,y[:, :,0],label='MIMO System')
173173

174174
legend(loc='best')
175175
#show()

‎control/tests/timeresp_test.py

Lines changed: 109 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ def test_impulse_response_mimo(self, mimo_ss2):
347347
yref_notrim=np.zeros((2,len(t)))
348348
yref_notrim[:1, :]=yref
349349
_t,yy=impulse_response(sys,T=t,input=0)
350-
np.testing.assert_array_almost_equal(yy,yref_notrim,decimal=4)
350+
np.testing.assert_array_almost_equal(yy[:,0,:],yref_notrim,decimal=4)
351351

352352
@pytest.mark.skipif(StrictVersion(sp.__version__)<"1.3",
353353
reason="requires SciPy 1.3 or greater")
@@ -639,9 +639,10 @@ def test_time_vector(self, tsystem, fun, squeeze, matarrayout):
639639
ifhasattr(tsystem,'t'):
640640
# tout should always match t, which has shape (n, )
641641
np.testing.assert_allclose(tout,tsystem.t)
642-
ifsqueezeisFalseorsys.outputs>1:
642+
643+
ifsqueezeisFalseornotsys.issiso():
643644
assertyout.shape[0]==sys.outputs
644-
assertyout.shape[1]==tout.shape[0]
645+
assertyout.shape[-1]==tout.shape[0]
645646
else:
646647
assertyout.shape==tout.shape
647648

@@ -725,21 +726,22 @@ def test_time_series_data_convention_2D(self, siso_ss1):
725726

726727
@pytest.mark.usefixtures("editsdefaults")
727728
@pytest.mark.parametrize("fcn", [ct.ss,ct.tf,ct.ss2io])
728-
@pytest.mark.parametrize("nstate, nout, ninp, squeeze, shape", [
729-
[1,1,1,None, (8,)],
730-
[2,1,1,True, (8,)],
731-
[3,1,1,False, (1,8)],
732-
[3,2,1,None, (2,8)],
733-
[4,2,1,True, (2,8)],
734-
[5,2,1,False, (2,8)],
735-
[3,1,2,None, (1,8)],
736-
[4,1,2,True, (8,)],
737-
[5,1,2,False, (1,8)],
738-
[4,2,2,None, (2,8)],
739-
[5,2,2,True, (2,8)],
740-
[6,2,2,False, (2,8)],
729+
@pytest.mark.parametrize("nstate, nout, ninp, squeeze, shape1, shape2", [
730+
# state out in squeeze in/out out-only
731+
[1,1,1,None, (8,), (8,)],
732+
[2,1,1,True, (8,), (8,)],
733+
[3,1,1,False, (1,1,8), (1,8)],
734+
[3,2,1,None, (2,1,8), (2,8)],
735+
[4,2,1,True, (2,8), (2,8)],
736+
[5,2,1,False, (2,1,8), (2,8)],
737+
[3,1,2,None, (1,2,8), (1,8)],
738+
[4,1,2,True, (2,8), (8,)],
739+
[5,1,2,False, (1,2,8), (1,8)],
740+
[4,2,2,None, (2,2,8), (2,8)],
741+
[5,2,2,True, (2,2,8), (2,8)],
742+
[6,2,2,False, (2,2,8), (2,8)],
741743
])
742-
deftest_squeeze(self,fcn,nstate,nout,ninp,squeeze,shape):
744+
deftest_squeeze(self,fcn,nstate,nout,ninp,squeeze,shape1,shape2):
743745
# Figure out if we have SciPy 1+
744746
scipy0=StrictVersion(sp.__version__)<'1.0'
745747

@@ -750,27 +752,56 @@ def test_squeeze(self, fcn, nstate, nout, ninp, squeeze, shape):
750752
else:
751753
sys=fcn(ct.rss(nstate,nout,ninp,strictly_proper=True))
752754

753-
# Keep track of expect users warnings
754-
warntype=UserWarningifsys.inputs>1elseNone
755-
756755
# Generate the time and input vectors
757756
tvec=np.linspace(0,1,8)
758757
uvec=np.dot(
759758
np.ones((sys.inputs,1)),
760759
np.reshape(np.sin(tvec), (1,8)))
761760

761+
#
762762
# Pass squeeze argument and make sure the shape is correct
763-
withpytest.warns(warntype,match="Converting MIMO system"):
764-
_,yvec=ct.impulse_response(sys,tvec,squeeze=squeeze)
765-
assertyvec.shape==shape
763+
#
764+
# For responses that are indexed by the input, check against shape1
765+
# For responses that have no/fixed input, check against shape2
766+
#
766767

767-
_,yvec=ct.initial_response(sys,tvec,1,squeeze=squeeze)
768-
assertyvec.shape==shape
768+
# Impulse response
769+
ifisinstance(sys,StateSpace):
770+
# Check the states as well
771+
_,yvec,xvec=ct.impulse_response(
772+
sys,tvec,squeeze=squeeze,return_x=True)
773+
ifsys.issiso():
774+
assertxvec.shape== (sys.states,8)
775+
else:
776+
assertxvec.shape== (sys.states,sys.inputs,8)
777+
else:
778+
_,yvec=ct.impulse_response(sys,tvec,squeeze=squeeze)
779+
assertyvec.shape==shape1
769780

770-
withpytest.warns(warntype,match="Converting MIMO system"):
781+
# Step response
782+
ifisinstance(sys,StateSpace):
783+
# Check the states as well
784+
_,yvec,xvec=ct.step_response(
785+
sys,tvec,squeeze=squeeze,return_x=True)
786+
ifsys.issiso():
787+
assertxvec.shape== (sys.states,8)
788+
else:
789+
assertxvec.shape== (sys.states,sys.inputs,8)
790+
else:
771791
_,yvec=ct.step_response(sys,tvec,squeeze=squeeze)
772-
assertyvec.shape==shape
792+
assertyvec.shape==shape1
793+
794+
# Initial response (only indexed by output)
795+
ifisinstance(sys,StateSpace):
796+
# Check the states as well
797+
_,yvec,xvec=ct.initial_response(
798+
sys,tvec,1,squeeze=squeeze,return_x=True)
799+
assertxvec.shape== (sys.states,8)
800+
else:
801+
_,yvec=ct.initial_response(sys,tvec,1,squeeze=squeeze)
802+
assertyvec.shape==shape2
773803

804+
# Forced response (only indexed by output)
774805
ifisinstance(sys,StateSpace):
775806
# Check the states as well
776807
_,yvec,xvec=ct.forced_response(
@@ -779,52 +810,54 @@ def test_squeeze(self, fcn, nstate, nout, ninp, squeeze, shape):
779810
else:
780811
# Just check the input/output response
781812
_,yvec=ct.forced_response(sys,tvec,uvec,0,squeeze=squeeze)
782-
assertyvec.shape==shape
813+
assertyvec.shape==shape2
783814

784815
# Test cases where we choose a subset of inputs and outputs
785816
_,yvec=ct.step_response(
786817
sys,tvec,input=ninp-1,output=nout-1,squeeze=squeeze)
787-
# Possible code if we implemenet a squeeze='siso' option
788818
ifsqueezeisFalse:
789819
# Shape should be unsqueezed
790-
assertyvec.shape== (1,8)
820+
assertyvec.shape== (1,1,8)
791821
else:
792822
# Shape should be squeezed
793823
assertyvec.shape== (8, )
794824

795-
# For InputOutputSystems, also testinput_output_response
825+
# For InputOutputSystems, also testinput/output response
796826
ifisinstance(sys,ct.InputOutputSystem)andnotscipy0:
797827
_,yvec=ct.input_output_response(sys,tvec,uvec,squeeze=squeeze)
798-
assertyvec.shape==shape
828+
assertyvec.shape==shape2
799829

800830
#
801831
# Changing config.default to False should return 3D frequency response
802832
#
803833
ct.config.set_defaults('control',squeeze_time_response=False)
804834

805-
withpytest.warns(warntype,match="Converting MIMO system"):
806-
_,yvec=ct.impulse_response(sys,tvec)
807-
assertyvec.shape== (sys.outputs,8)
835+
_,yvec=ct.impulse_response(sys,tvec)
836+
ifsqueezeisnotTrueorsys.inputs>1orsys.outputs>1:
837+
assertyvec.shape== (sys.outputs,sys.inputs,8)
808838

809-
_,yvec=ct.initial_response(sys,tvec,1)
810-
assertyvec.shape== (sys.outputs,8)
839+
_,yvec=ct.step_response(sys,tvec)
840+
ifsqueezeisnotTrueorsys.inputs>1orsys.outputs>1:
841+
assertyvec.shape== (sys.outputs,sys.inputs,8)
811842

812-
withpytest.warns(warntype,match="Converting MIMO system"):
813-
_,yvec=ct.step_response(sys,tvec)
814-
assertyvec.shape== (sys.outputs,8)
843+
_,yvec=ct.initial_response(sys,tvec,1)
844+
ifsqueezeisnotTrueorsys.outputs>1:
845+
assertyvec.shape== (sys.outputs,8)
815846

816847
ifisinstance(sys,ct.StateSpace):
817848
_,yvec,xvec=ct.forced_response(
818849
sys,tvec,uvec,0,return_x=True)
819850
assertxvec.shape== (sys.states,8)
820851
else:
821852
_,yvec=ct.forced_response(sys,tvec,uvec,0)
822-
assertyvec.shape== (sys.outputs,8)
853+
ifsqueezeisnotTrueorsys.outputs>1:
854+
assertyvec.shape== (sys.outputs,8)
823855

824856
# For InputOutputSystems, also test input_output_response
825857
ifisinstance(sys,ct.InputOutputSystem)andnotscipy0:
826858
_,yvec=ct.input_output_response(sys,tvec,uvec)
827-
assertyvec.shape== (sys.noutputs,8)
859+
ifsqueezeisnotTrueorsys.outputs>1:
860+
assertyvec.shape== (sys.outputs,8)
828861

829862
@pytest.mark.parametrize("fcn", [ct.ss,ct.tf,ct.ss2io])
830863
deftest_squeeze_exception(self,fcn):
@@ -861,3 +894,37 @@ def test_squeeze_0_8_4(self, nstate, nout, ninp, squeeze, shape):
861894

862895
_,yvec=ct.initial_response(sys,tvec,1,squeeze=squeeze)
863896
assertyvec.shape==shape
897+
898+
@pytest.mark.parametrize(
899+
"nstate, nout, ninp, squeeze, ysh_in, ysh_no, xsh_in", [
900+
[4,1,1,None, (8,), (8,), (8,4)],
901+
[4,1,1,True, (8,), (8,), (8,4)],
902+
[4,1,1,False, (8,1,1), (8,1), (8,4)],
903+
[4,2,1,None, (8,2,1), (8,2), (8,4,1)],
904+
[4,2,1,True, (8,2), (8,2), (8,4,1)],
905+
[4,2,1,False, (8,2,1), (8,2), (8,4,1)],
906+
[4,1,2,None, (8,1,2), (8,1), (8,4,2)],
907+
[4,1,2,True, (8,2), (8,), (8,4,2)],
908+
[4,1,2,False, (8,1,2), (8,1), (8,4,2)],
909+
[4,2,2,None, (8,2,2), (8,2), (8,4,2)],
910+
[4,2,2,True, (8,2,2), (8,2), (8,4,2)],
911+
[4,2,2,False, (8,2,2), (8,2), (8,4,2)],
912+
])
913+
deftest_response_transpose(
914+
self,nstate,nout,ninp,squeeze,ysh_in,ysh_no,xsh_in):
915+
sys=ct.rss(nstate,nout,ninp)
916+
T=np.linspace(0,1,8)
917+
918+
# Step response - input indexed
919+
t,y,x=ct.step_response(
920+
sys,T,transpose=True,return_x=True,squeeze=squeeze)
921+
assertt.shape== (T.size, )
922+
asserty.shape==ysh_in
923+
assertx.shape==xsh_in
924+
925+
# Initial response - no input indexing
926+
t,y,x=ct.initial_response(
927+
sys,T,1,transpose=True,return_x=True,squeeze=squeeze)
928+
assertt.shape== (T.size, )
929+
asserty.shape==ysh_no
930+
assertx.shape== (T.size,sys.states)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp