@@ -369,6 +369,21 @@ def minreal(sys, tol=None, verbose=True):
369
369
return sysr
370
370
371
371
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
+
372
387
def eigensys_realization (arg , r , m = None , n = None , dt = True , transpose = False ):
373
388
r"""eigensys_realization(YY, r)
374
389
@@ -389,8 +404,8 @@ def eigensys_realization(arg, r, m=None, n=None, dt=True, transpose=False):
389
404
* ``sysd, S = eigensys_realization(data, r)``
390
405
* ``sysd, S = eigensys_realization(YY, r)``
391
406
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.
394
409
395
410
Parameters
396
411
----------
@@ -406,10 +421,10 @@ def eigensys_realization(arg, r, m=None, n=None, dt=True, transpose=False):
406
421
n : integer, optional
407
422
Number of columns in Hankel matrix. Default is 2*r.
408
423
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.
413
428
transpose : bool, optional
414
429
Assume that input data is transposed relative to the standard
415
430
: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):
439
454
>>> response = ct.impulse_response(ct.tf([1], [1, 0.5], True), T)
440
455
>>> sysd, _ = ct.eigensys_realization(response, r=1)
441
456
"""
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
-
456
457
if isinstance (arg , TimeResponseData ):
457
458
YY = np .array (arg .outputs , ndmin = 3 )
458
459
if arg .transpose :
@@ -475,7 +476,7 @@ def block_hankel_matrix(Y, m, n):
475
476
if (l - 1 ) < m + n :
476
477
raise ValueError ("not enough data for requested number of parameters" )
477
478
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))
479
480
Hf = H [:,:- p ] # first p*n columns of H
480
481
Hl = H [:,p :] # last p*n columns of H
481
482
@@ -486,7 +487,7 @@ def block_hankel_matrix(Y, m, n):
486
487
# balanced realizations
487
488
Sigma_inv = np .diag (1. / np .sqrt (S [0 :r ]))
488
489
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
490
491
Cr = Hf [0 :q ,:] @ Vhr .T @ Sigma_inv
491
492
Dr = YY [:,:,0 ]
492
493
0 commit comments