6
6
7
7
import control as ct
8
8
from control import c2d , tf , tf2ss , NonlinearIOSystem
9
- from control .lti import (LTI , common_timebase , damp , dcgain , isctime , isdtime ,
10
- issiso , pole , timebaseEqual , zero )
9
+ from control .lti import (LTI , common_timebase , evalfr , damp , dcgain , isctime ,
10
+ isdtime , issiso , pole , timebaseEqual , zero )
11
11
from control .tests .conftest import slycotonly
12
12
from control .exception import slycot_check
13
13
@@ -179,11 +179,20 @@ def test_isdtime(self, objfun, arg, dt, ref, strictref):
179
179
[1 , 1 , 2 , [0.1 , 1 , 10 ], None , (1 , 2 , 3 )], # MISO
180
180
[2 , 1 , 2 , [0.1 , 1 , 10 ], True , (2 , 3 )],
181
181
[3 , 1 , 2 , [0.1 , 1 , 10 ], False , (1 , 2 , 3 )],
182
+ [1 , 1 , 2 , 0.1 , None , (1 , 2 )],
183
+ [1 , 1 , 2 , 0.1 , True , (2 ,)],
184
+ [1 , 1 , 2 , 0.1 , False , (1 , 2 )],
182
185
[1 , 2 , 2 , [0.1 , 1 , 10 ], None , (2 , 2 , 3 )], # MIMO
183
186
[2 , 2 , 2 , [0.1 , 1 , 10 ], True , (2 , 2 , 3 )],
184
- [3 , 2 , 2 , [0.1 , 1 , 10 ], False , (2 , 2 , 3 )]
187
+ [3 , 2 , 2 , [0.1 , 1 , 10 ], False , (2 , 2 , 3 )],
188
+ [1 , 2 , 2 , 0.1 , None , (2 , 2 )],
189
+ [2 , 2 , 2 , 0.1 , True , (2 , 2 )],
190
+ [3 , 2 , 2 , 0.1 , False , (2 , 2 )],
185
191
])
186
- def test_squeeze (self , fcn , nstate , nout , ninp , omega , squeeze , shape ):
192
+ @pytest .mark .parametrize ("omega_type" , ["numpy" , "native" ])
193
+ def test_squeeze (self , fcn , nstate , nout , ninp , omega , squeeze , shape ,
194
+ omega_type ):
195
+ """Test correct behavior of frequencey response squeeze parameter."""
187
196
# Create the system to be tested
188
197
if fcn == ct .frd :
189
198
sys = fcn (ct .rss (nstate , nout , ninp ), [1e-2 , 1e-1 , 1 , 1e1 , 1e2 ])
@@ -193,15 +202,23 @@ def test_squeeze(self, fcn, nstate, nout, ninp, omega, squeeze, shape):
193
202
else :
194
203
sys = fcn (ct .rss (nstate , nout , ninp ))
195
204
196
- # Convert the frequency list to an array for easy of use
197
- isscalar = not hasattr (omega , '__len__' )
198
- omega = np .array (omega )
205
+ if omega_type == "numpy" :
206
+ omega = np .asarray (omega )
207
+ isscalar = omega .ndim == 0
208
+ # keep the ndarray type even for scalars
209
+ s = np .asarray (omega * 1j )
210
+ else :
211
+ isscalar = not hasattr (omega , '__len__' )
212
+ if isscalar :
213
+ s = omega * 1J
214
+ else :
215
+ s = [w * 1J for w in omega ]
199
216
200
217
# Call the transfer function directly and make sure shape is correct
201
- assert sys (omega * 1j , squeeze = squeeze ).shape == shape
218
+ assert sys (s , squeeze = squeeze ).shape == shape
202
219
203
220
# Make sure that evalfr also works as expected
204
- assert ct .evalfr (sys , omega * 1j , squeeze = squeeze ).shape == shape
221
+ assert ct .evalfr (sys , s , squeeze = squeeze ).shape == shape
205
222
206
223
# Check frequency response
207
224
mag , phase , _ = sys .frequency_response (omega , squeeze = squeeze )
@@ -216,22 +233,22 @@ def test_squeeze(self, fcn, nstate, nout, ninp, omega, squeeze, shape):
216
233
217
234
# Make sure the default shape lines up with squeeze=None case
218
235
if squeeze is None :
219
- assert sys (omega * 1j ).shape == shape
236
+ assert sys (s ).shape == shape
220
237
221
238
# Changing config.default to False should return 3D frequency response
222
239
ct .config .set_defaults ('control' , squeeze_frequency_response = False )
223
240
mag , phase , _ = sys .frequency_response (omega )
224
241
if isscalar :
225
242
assert mag .shape == (sys .noutputs , sys .ninputs , 1 )
226
243
assert phase .shape == (sys .noutputs , sys .ninputs , 1 )
227
- assert sys (omega * 1j ).shape == (sys .noutputs , sys .ninputs )
228
- assert ct .evalfr (sys , omega * 1j ).shape == (sys .noutputs , sys .ninputs )
244
+ assert sys (s ).shape == (sys .noutputs , sys .ninputs )
245
+ assert ct .evalfr (sys , s ).shape == (sys .noutputs , sys .ninputs )
229
246
else :
230
247
assert mag .shape == (sys .noutputs , sys .ninputs , len (omega ))
231
248
assert phase .shape == (sys .noutputs , sys .ninputs , len (omega ))
232
- assert sys (omega * 1j ).shape == \
249
+ assert sys (s ).shape == \
233
250
(sys .noutputs , sys .ninputs , len (omega ))
234
- assert ct .evalfr (sys , omega * 1j ).shape == \
251
+ assert ct .evalfr (sys , s ).shape == \
235
252
(sys .noutputs , sys .ninputs , len (omega ))
236
253
237
254
@pytest .mark .parametrize ("fcn" , [ct .ss , ct .tf , ct .frd , ct .ss2io ])
@@ -243,13 +260,17 @@ def test_squeeze_exceptions(self, fcn):
243
260
244
261
with pytest .raises (ValueError , match = "unknown squeeze value" ):
245
262
sys .frequency_response ([1 ], squeeze = 1 )
246
- sys ([1 ], squeeze = 'siso' )
247
- evalfr (sys , [1 ], squeeze = 'siso' )
263
+ with pytest .raises (ValueError , match = "unknown squeeze value" ):
264
+ sys ([1j ], squeeze = 'siso' )
265
+ with pytest .raises (ValueError , match = "unknown squeeze value" ):
266
+ evalfr (sys , [1j ], squeeze = 'siso' )
248
267
249
268
with pytest .raises (ValueError , match = "must be 1D" ):
250
269
sys .frequency_response ([[0.1 , 1 ], [1 , 10 ]])
251
- sys ([[0.1 , 1 ], [1 , 10 ]])
252
- evalfr (sys , [[0.1 , 1 ], [1 , 10 ]])
270
+ with pytest .raises (ValueError , match = "must be 1D" ):
271
+ sys ([[0.1j , 1j ], [1j , 10j ]])
272
+ with pytest .raises (ValueError , match = "must be 1D" ):
273
+ evalfr (sys , [[0.1j , 1j ], [1j , 10j ]])
253
274
254
275
with pytest .warns (DeprecationWarning , match = "LTI `inputs`" ):
255
276
ninputs = sys .inputs
0 commit comments