Skip to content

Commit 57b5307

Browse files
authored
Merge pull request #1064 from murrayrm/fix_frd_timebase-20Nov2024
fix timebase processing in frd, zpk
2 parents 20a73de + 8b29e45 commit 57b5307

File tree

4 files changed

+49
-6
lines changed

4 files changed

+49
-6
lines changed

control/frdata.py

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -124,13 +124,24 @@ def __init__(self, *args, **kwargs):
124124
To construct frequency response data for an existing LTI
125125
object, other than an FRD, call FRD(sys, omega).
126126
127+
The timebase for the frequency response can be provided using an
128+
optional third argument or the 'dt' keyword.
129+
127130
"""
128-
# TODO: discrete-time FRD systems?
129131
smooth = kwargs.pop('smooth', False)
130132

131133
#
132134
# Process positional arguments
133135
#
136+
if len(args) == 3:
137+
# Discrete time transfer function
138+
dt = args[-1]
139+
if 'dt' in kwargs:
140+
warn("received multiple dt arguments, "
141+
"using positional arg dt = %s" % dt)
142+
kwargs['dt'] = dt
143+
args = args[:-1]
144+
134145
if len(args) == 2:
135146
if not isinstance(args[0], FRD) and isinstance(args[0], LTI):
136147
# not an FRD, but still a system, second argument should be
@@ -200,11 +211,11 @@ def __init__(self, *args, **kwargs):
200211

201212
# Process iosys keywords
202213
defaults = {
203-
'inputs': self.fresp.shape[1], 'outputs': self.fresp.shape[0],
204-
'dt': None}
214+
'inputs': self.fresp.shape[1], 'outputs': self.fresp.shape[0]}
215+
if arg_dt is not None:
216+
defaults['dt'] = arg_dt # choose compatible timebase
205217
name, inputs, outputs, states, dt = _process_iosys_keywords(
206218
kwargs, defaults, end=True)
207-
dt = common_timebase(dt, arg_dt) # choose compatible timebase
208219

209220
# Process signal names
210221
InputOutputSystem.__init__(

control/tests/docstrings_test.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
control.bode_plot: ['sharex', 'sharey', 'margin_info'], # deprecated
5555
control.eigensys_realization: ['arg'], # quasi-positional
5656
control.find_operating_point: ['method'], # internal use
57+
control.zpk: ['args'] # 'dt' (manual)
5758
}
5859

5960
# Decide on the level of verbosity (use -rP when running pytest)

control/tests/timebase_test.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,34 @@ def test_composition_override(dt):
9797
with pytest.raises(ValueError, match="incompatible timebases"):
9898
sys3 = ct.interconnect(
9999
[sys1, sys2], inputs='u1', outputs='y2', dt=dt)
100+
101+
102+
# Make sure all system creation functions treat timebases uniformly
103+
@pytest.mark.parametrize(
104+
"fcn, args", [
105+
(ct.ss, [-1, 1, 1, 1]),
106+
(ct.tf, [[1, 2], [3, 4, 5]]),
107+
(ct.zpk, [[-1], [-2, -3], 1]),
108+
(ct.frd, [[1, 1, 1], [1, 2, 3]]),
109+
(ct.nlsys, [lambda t, x, u, params: -x, None]),
110+
])
111+
@pytest.mark.parametrize(
112+
"kwargs, expected", [
113+
({}, 0),
114+
({'dt': 0}, 0),
115+
({'dt': 0.1}, 0.1),
116+
({'dt': True}, True),
117+
({'dt': None}, None),
118+
])
119+
def test_default(fcn, args, kwargs, expected):
120+
sys = fcn(*args, **kwargs)
121+
assert sys.dt == expected
122+
123+
# Some commands allow dt via extra argument
124+
if fcn in [ct.ss, ct.tf, ct.zpk, ct.frd] and kwargs.get('dt'):
125+
sys = fcn(*args, kwargs['dt'])
126+
assert sys.dt == expected
127+
128+
# Make sure an error is generated if dt is redundant
129+
with pytest.warns(UserWarning, match="received multiple dt"):
130+
sys = fcn(*args, kwargs['dt'], **kwargs)

control/xferfcn.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1677,7 +1677,7 @@ def tf(*args, **kwargs):
16771677
raise ValueError("Needs 1 or 2 arguments; received %i." % len(args))
16781678

16791679

1680-
def zpk(zeros, poles, gain, dt=None, **kwargs):
1680+
def zpk(zeros, poles, gain, *args, **kwargs):
16811681
"""zpk(zeros, poles, gain[, dt])
16821682
16831683
Create a transfer function from zeros, poles, gain.
@@ -1732,7 +1732,7 @@ def zpk(zeros, poles, gain, dt=None, **kwargs):
17321732
17331733
"""
17341734
num, den = zpk2tf(zeros, poles, gain)
1735-
return TransferFunction(num, den, dt=dt, **kwargs)
1735+
return TransferFunction(num, den, *args, **kwargs)
17361736

17371737

17381738
def ss2tf(*args, **kwargs):

0 commit comments

Comments
 (0)