Skip to content

Commit b382abf

Browse files
committed
implement NamedSignal's for frequency responses
1 parent 5df6fb7 commit b382abf

2 files changed

Lines changed: 54 additions & 4 deletions

File tree

control/frdata.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020

2121
from . import config
2222
from .exception import pandas_check
23-
from .iosys import InputOutputSystem, _process_iosys_keywords, common_timebase
23+
from .iosys import InputOutputSystem, NamedSignal, _process_iosys_keywords, \
24+
common_timebase
2425
from .lti import LTI, _process_frequency_response
2526

2627
__all__ = ['FrequencyResponseData', 'FRD', 'frd']
@@ -243,19 +244,22 @@ def __init__(self, *args, **kwargs):
243244

244245
@property
245246
def magnitude(self):
246-
return np.abs(self.fresp)
247+
return NamedSignal(
248+
np.abs(self.fresp), self.output_labels, self.input_labels)
247249

248250
@property
249251
def phase(self):
250-
return np.angle(self.fresp)
252+
return NamedSignal(
253+
np.angle(self.fresp), self.output_labels, self.input_labels)
251254

252255
@property
253256
def frequency(self):
254257
return self.omega
255258

256259
@property
257260
def response(self):
258-
return self.fresp
261+
return NamedSignal(
262+
self.fresp, self.output_labels, self.input_labels)
259263

260264
def __str__(self):
261265
"""String representation of the transfer function."""

control/tests/frd_test.py

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,3 +609,49 @@ def test_frequency_response():
609609
assert mag_nosq_sq.shape == mag_default.shape
610610
assert phase_nosq_sq.shape == phase_default.shape
611611
assert omega_nosq_sq.shape == omega_default.shape
612+
613+
614+
def test_signal_labels():
615+
# Create a system response for a SISO system
616+
sys = ct.rss(4, 1, 1)
617+
fresp = ct.frequency_response(sys)
618+
619+
# Make sure access via strings works
620+
np.testing.assert_equal(
621+
fresp.magnitude['y[0]'], fresp.magnitude[0])
622+
np.testing.assert_equal(
623+
fresp.phase['y[0]'], fresp.phase[0])
624+
625+
# Make sure errors are generated if key is unknown
626+
with pytest.raises(ValueError, match="unknown signal name 'bad'"):
627+
fresp.magnitude['bad']
628+
629+
# Create a system response for a MIMO system
630+
sys = ct.rss(4, 2, 2)
631+
fresp = ct.frequency_response(sys)
632+
633+
# Make sure access via strings works
634+
np.testing.assert_equal(
635+
fresp.magnitude['y[0]', 'u[1]'],
636+
fresp.magnitude[0, 1])
637+
np.testing.assert_equal(
638+
fresp.phase['y[0]', 'u[1]'],
639+
fresp.phase[0, 1])
640+
np.testing.assert_equal(
641+
fresp.response['y[0]', 'u[1]'],
642+
fresp.response[0, 1])
643+
644+
# Make sure access via lists of strings works
645+
np.testing.assert_equal(
646+
fresp.response[['y[1]', 'y[0]'], 'u[0]'],
647+
fresp.response[[1, 0], 0])
648+
649+
# Make sure errors are generated if key is unknown
650+
with pytest.raises(ValueError, match="unknown signal name 'bad'"):
651+
fresp.magnitude['bad']
652+
653+
with pytest.raises(ValueError, match="unknown signal name 'bad'"):
654+
fresp.response[['y[1]', 'bad']]
655+
656+
with pytest.raises(ValueError, match=r"unknown signal name 'y\[0\]'"):
657+
fresp.response['y[1]', 'y[0]'] # second index = input name

0 commit comments

Comments
 (0)