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

Commitda55654

Browse files
authored
Merge pull request#1073 from sdahdah/main
Add `combine_tf()` and `split_tf()` functions for transfer matrices
2 parents12dda4e +1cc84a7 commitda55654

File tree

2 files changed

+768
-1
lines changed

2 files changed

+768
-1
lines changed

‎control/bdalg.py‎

Lines changed: 213 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
negate
1111
feedback
1212
connect
13+
combine_tf
14+
split_tf
1315
1416
"""
1517

@@ -63,7 +65,8 @@
6365
from .importxferfcnastf
6466
from .iosysimportInputOutputSystem
6567

66-
__all__= ['series','parallel','negate','feedback','append','connect']
68+
__all__= ['series','parallel','negate','feedback','append','connect',
69+
'combine_tf','split_tf']
6770

6871

6972
defseries(sys1,*sysn,**kwargs):
@@ -507,3 +510,212 @@ def connect(sys, Q, inputv, outputv):
507510
Ytrim[i,y-1]=1.
508511

509512
returnYtrim*sys*Utrim
513+
514+
defcombine_tf(tf_array):
515+
"""Combine array-like of transfer functions into MIMO transfer function.
516+
517+
Parameters
518+
----------
519+
tf_array : list of list of TransferFunction or array_like
520+
Transfer matrix represented as a two-dimensional array or list-of-lists
521+
containing TransferFunction objects. The TransferFunction objects can
522+
have multiple outputs and inputs, as long as the dimensions are
523+
compatible.
524+
525+
Returns
526+
-------
527+
TransferFunction
528+
Transfer matrix represented as a single MIMO TransferFunction object.
529+
530+
Raises
531+
------
532+
ValueError
533+
If timesteps of transfer functions do not match.
534+
ValueError
535+
If ``tf_array`` has incorrect dimensions.
536+
ValueError
537+
If the transfer functions in a row have mismatched output or input
538+
dimensions.
539+
540+
Examples
541+
--------
542+
Combine two transfer functions
543+
544+
>>> s = control.TransferFunction.s
545+
>>> control.combine_tf([
546+
... [1 / (s + 1)],
547+
... [s / (s + 2)],
548+
... ])
549+
TransferFunction([[array([1])], [array([1, 0])]],
550+
[[array([1, 1])], [array([1, 2])]])
551+
552+
Combine NumPy arrays with transfer functions
553+
554+
>>> control.combine_tf([
555+
... [np.eye(2), np.zeros((2, 1))],
556+
... [np.zeros((1, 2)), control.TransferFunction([1], [1, 0])],
557+
... ])
558+
TransferFunction([[array([1.]), array([0.]), array([0.])],
559+
[array([0.]), array([1.]), array([0.])],
560+
[array([0.]), array([0.]), array([1])]],
561+
[[array([1.]), array([1.]), array([1.])],
562+
[array([1.]), array([1.]), array([1.])],
563+
[array([1.]), array([1.]), array([1, 0])]])
564+
"""
565+
# Find common timebase or raise error
566+
dt_list= []
567+
try:
568+
forrowintf_array:
569+
fortfninrow:
570+
dt_list.append(getattr(tfn,"dt",None))
571+
exceptOSError:
572+
raiseValueError("`tf_array` has too few dimensions.")
573+
dt_set=set(dt_list)
574+
dt_set.discard(None)
575+
iflen(dt_set)>1:
576+
raiseValueError("Timesteps of transfer functions are "
577+
f"mismatched:{dt_set}")
578+
eliflen(dt_set)==0:
579+
dt=None
580+
else:
581+
dt=dt_set.pop()
582+
# Convert all entries to transfer function objects
583+
ensured_tf_array= []
584+
forrowintf_array:
585+
ensured_row= []
586+
fortfninrow:
587+
ensured_row.append(_ensure_tf(tfn,dt))
588+
ensured_tf_array.append(ensured_row)
589+
# Iterate over
590+
num= []
591+
den= []
592+
forrow_index,rowinenumerate(ensured_tf_array):
593+
forj_outinrange(row[0].noutputs):
594+
num_row= []
595+
den_row= []
596+
forcolinrow:
597+
ifcol.noutputs!=row[0].noutputs:
598+
raiseValueError(
599+
"Mismatched number of transfer function outputs in "
600+
f"row{row_index}."
601+
)
602+
forj_ininrange(col.ninputs):
603+
num_row.append(col.num[j_out][j_in])
604+
den_row.append(col.den[j_out][j_in])
605+
num.append(num_row)
606+
den.append(den_row)
607+
forrow_index,rowinenumerate(num):
608+
iflen(row)!=len(num[0]):
609+
raiseValueError(
610+
"Mismatched number transfer function inputs in row "
611+
f"{row_index} of numerator."
612+
)
613+
forrow_index,rowinenumerate(den):
614+
iflen(row)!=len(den[0]):
615+
raiseValueError(
616+
"Mismatched number transfer function inputs in row "
617+
f"{row_index} of denominator."
618+
)
619+
returntf.TransferFunction(num,den,dt=dt)
620+
621+
defsplit_tf(transfer_function):
622+
"""Split MIMO transfer function into NumPy array of SISO tranfer functions.
623+
624+
Parameters
625+
----------
626+
transfer_function : TransferFunction
627+
MIMO transfer function to split.
628+
629+
Returns
630+
-------
631+
np.ndarray
632+
NumPy array of SISO transfer functions.
633+
634+
Examples
635+
--------
636+
Split a MIMO transfer function
637+
638+
>>> G = control.TransferFunction(
639+
... [
640+
... [[87.8], [-86.4]],
641+
... [[108.2], [-109.6]],
642+
... ],
643+
... [
644+
... [[1, 1], [1, 1]],
645+
... [[1, 1], [1, 1]],
646+
... ],
647+
... )
648+
>>> control.split_tf(G)
649+
array([[TransferFunction(array([87.8]), array([1, 1])),
650+
TransferFunction(array([-86.4]), array([1, 1]))],
651+
[TransferFunction(array([108.2]), array([1, 1])),
652+
TransferFunction(array([-109.6]), array([1, 1]))]], dtype=object)
653+
"""
654+
tf_split_lst= []
655+
fori_outinrange(transfer_function.noutputs):
656+
row= []
657+
fori_ininrange(transfer_function.ninputs):
658+
row.append(
659+
tf.TransferFunction(
660+
transfer_function.num[i_out][i_in],
661+
transfer_function.den[i_out][i_in],
662+
dt=transfer_function.dt,
663+
)
664+
)
665+
tf_split_lst.append(row)
666+
returnnp.array(tf_split_lst,dtype=object)
667+
668+
def_ensure_tf(arraylike_or_tf,dt=None):
669+
"""Convert an array-like to a transfer function.
670+
671+
Parameters
672+
----------
673+
arraylike_or_tf : TransferFunction or array_like
674+
Array-like or transfer function.
675+
dt : None, True or float, optional
676+
System timebase. 0 (default) indicates continuous
677+
time, True indicates discrete time with unspecified sampling
678+
time, positive number is discrete time with specified
679+
sampling time, None indicates unspecified timebase (either
680+
continuous or discrete time). If None, timestep is not validated.
681+
682+
Returns
683+
-------
684+
TransferFunction
685+
Transfer function.
686+
687+
Raises
688+
------
689+
ValueError
690+
If input cannot be converted to a transfer function.
691+
ValueError
692+
If the timesteps do not match.
693+
"""
694+
# If the input is already a transfer function, return it right away
695+
ifisinstance(arraylike_or_tf,tf.TransferFunction):
696+
# If timesteps don't match, raise an exception
697+
if (dtisnotNone)and (arraylike_or_tf.dt!=dt):
698+
raiseValueError(
699+
f"`arraylike_or_tf.dt={arraylike_or_tf.dt}` does not match "
700+
f"argument `dt={dt}`."
701+
)
702+
returnarraylike_or_tf
703+
ifnp.ndim(arraylike_or_tf)>2:
704+
raiseValueError(
705+
"Array-like must have less than two dimensions to be converted "
706+
"into a transfer function."
707+
)
708+
# If it's not, then convert it to a transfer function
709+
arraylike_3d=np.atleast_3d(arraylike_or_tf)
710+
try:
711+
tfn=tf.TransferFunction(
712+
arraylike_3d,
713+
np.ones_like(arraylike_3d),
714+
dt,
715+
)
716+
exceptTypeError:
717+
raiseValueError(
718+
"`arraylike_or_tf` must only contain array-likes or transfer "
719+
"functions."
720+
)
721+
returntfn

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp