@@ -369,6 +369,21 @@ def minreal(sys, tol=None, verbose=True):
369369 return sysr
370370
371371
372+ def _block_hankel (Y , m , n ):
373+ """Create a block Hankel matrix from impulse response"""
374+ q , p , _ = Y .shape
375+ YY = Y .transpose (0 ,2 ,1 ) # transpose for reshape
376+
377+ H = np .zeros ((q * m ,p * n ))
378+
379+ for r in range (m ):
380+ # shift and add row to Hankel matrix
381+ new_row = YY [:,r :r + n ,:]
382+ H [q * r :q * (r + 1 ),:] = new_row .reshape ((q ,p * n ))
383+
384+ return H
385+
386+
372387def eigensys_realization (arg , r , m = None , n = None , dt = True , transpose = False ):
373388 r"""eigensys_realization(YY, r)
374389
@@ -389,8 +404,8 @@ def eigensys_realization(arg, r, m=None, n=None, dt=True, transpose=False):
389404 * ``sysd, S = eigensys_realization(data, r)``
390405 * ``sysd, S = eigensys_realization(YY, r)``
391406
392- where `response ` is an `TimeResponseData` object, and `YY` is 1D or 3D
393- array and r is an integer.
407+ where `data ` is a `TimeResponseData` object, `YY` is a 1D or 3D
408+ array, and r is an integer.
394409
395410 Parameters
396411 ----------
@@ -406,10 +421,10 @@ def eigensys_realization(arg, r, m=None, n=None, dt=True, transpose=False):
406421 n : integer, optional
407422 Number of columns in Hankel matrix. Default is 2*r.
408423 dt : True or float, optional
409- True indicates discrete time with unspecified sampling time,
410- positive number is discrete time with specified sampling time. It
411- can be used to scale the StateSpace model in order to match the
412- impulse response of this library . Default is True.
424+ True indicates discrete time with unspecified sampling time and a
425+ positive float is discrete time with the specified sampling time.
426+ It can be used to scale the StateSpace model in order to match the
427+ unit-area impulse response of python-control . Default is True.
413428 transpose : bool, optional
414429 Assume that input data is transposed relative to the standard
415430 :ref:`time-series-convention`. For TimeResponseData this parameter
@@ -439,20 +454,6 @@ def eigensys_realization(arg, r, m=None, n=None, dt=True, transpose=False):
439454 >>> response = ct.impulse_response(ct.tf([1], [1, 0.5], True), T)
440455 >>> sysd, _ = ct.eigensys_realization(response, r=1)
441456 """
442- def block_hankel_matrix (Y , m , n ):
443- """Create a block Hankel matrix from Impulse response"""
444- q , p , _ = Y .shape
445- YY = Y .transpose (0 ,2 ,1 ) # transpose for reshape
446-
447- H = np .zeros ((q * m ,p * n ))
448-
449- for r in range (m ):
450- # shift and add row to Hankel matrix
451- new_row = YY [:,r :r + n ,:]
452- H [q * r :q * (r + 1 ),:] = new_row .reshape ((q ,p * n ))
453-
454- return H
455-
456457 if isinstance (arg , TimeResponseData ):
457458 YY = np .array (arg .outputs , ndmin = 3 )
458459 if arg .transpose :
@@ -475,7 +476,7 @@ def block_hankel_matrix(Y, m, n):
475476 if (l - 1 ) < m + n :
476477 raise ValueError ("not enough data for requested number of parameters" )
477478
478- H = block_hankel_matrix (YY [:,:,1 :], m , n + 1 ) # Hankel matrix (q*m, p*(n+1))
479+ H = _block_hankel (YY [:,:,1 :], m , n + 1 ) # Hankel matrix (q*m, p*(n+1))
479480 Hf = H [:,:- p ] # first p*n columns of H
480481 Hl = H [:,p :] # last p*n columns of H
481482
@@ -486,7 +487,7 @@ def block_hankel_matrix(Y, m, n):
486487 # balanced realizations
487488 Sigma_inv = np .diag (1. / np .sqrt (S [0 :r ]))
488489 Ar = Sigma_inv @ Ur .T @ Hl @ Vhr .T @ Sigma_inv
489- Br = Sigma_inv @ Ur .T @ Hf [:,0 :p ]* dt
490+ Br = Sigma_inv @ Ur .T @ Hf [:,0 :p ]* dt # dt scaling for unit-area impulse
490491 Cr = Hf [0 :q ,:] @ Vhr .T @ Sigma_inv
491492 Dr = YY [:,:,0 ]
492493
0 commit comments