@@ -457,57 +457,68 @@ def H(s: complex):
457457
458458
459459def estimate_spectra (
460- u : np .ndarray , y : np .ndarray , sr : float , nperseg : int
460+ u : ArrayLike ,
461+ y : ArrayLike ,
462+ sr : float ,
463+ with_dc : bool = False ,
464+ ** kwargs ,
461465) -> tuple [np .ndarray , np .ndarray , np .ndarray ]:
462466 """Estimate cross- and autospectral densities using Welch's method.
463467
464468 Args:
465469 u: Input signal.
466470 y: Output signal.
467471 sr: Sampling rate.
468- nperseg: Number of samples per segment.
472+ with_dc: Wether or not to include zero frequency term.
473+ kwargs: Passed to `scipy.signal.csd`.
469474
470475 Returns:
471476 Tuple `(f, S_yu, S_uu)` of frequencies, cross- and autospectral densities.
472477
473478 """
474479 u_ = np .asarray (u )
475480 y_ = np .asarray (y )
481+
476482 # Prep for correct broadcasting in sig.csd
477483 if u_ .ndim == 1 :
478484 u_ = u_ [:, None ]
479485 if y_ .ndim == 1 :
480486 y_ = y_ [:, None ]
481- f , S_yu = sig .csd (u_ [:, None , :], y_ [:, :, None ], fs = sr , nperseg = nperseg , axis = 0 )
482- _ , S_uu = sig .welch (u , fs = sr , nperseg = nperseg , axis = 0 )
487+ f , Syu = sig .csd (u_ [:, None , :], y_ [:, :, None ], fs = sr , ** kwargs , axis = 0 )
488+ _ , Suu = sig .welch (u , fs = sr , ** kwargs , axis = 0 )
489+
483490 # Reshape back with dimensions of arguments
484- S_yu = S_yu .reshape ((nperseg // 2 + 1 ,) + y .shape [1 :] + u .shape [1 :])
485- S_uu = S_uu .reshape ((nperseg // 2 + 1 ,) + u .shape [1 :])
486- return f , S_yu , S_uu
491+ Syu = Syu .reshape ((Syu .shape [0 ],) + y .shape [1 :] + u .shape [1 :])
492+ Suu = Suu .reshape ((Suu .shape [0 ],) + u .shape [1 :])
493+
494+ if not with_dc :
495+ # remove dc term
496+ f = f [1 :]
497+ Syu = Syu [1 :]
498+ Suu = Suu [1 :]
499+
500+ return f , Syu , Suu
487501
488502
489503def fit_csd_matching (
490504 sys : AbstractSystem ,
491- u : ArrayLike ,
492- y : ArrayLike ,
493- sr : float = 1.0 ,
494- nperseg : int = 1024 ,
505+ f : ArrayLike ,
506+ Syu : ArrayLike ,
507+ Suu : ArrayLike ,
495508 reg : float = 0 ,
496509 x_scale : bool = True ,
497510 verbose_mse : bool = True ,
498511 absolute_sigma : bool = False ,
499- fit_dc : bool = False ,
500512 linearize_kwargs : dict | None = None ,
501513 ** kwargs ,
502514) -> OptimizeResult :
503515 """Estimate parameters of linearized system by matching cross-spectral densities.
504516
505517 Args:
506518 sys: Concrete dynamical system.
507- u: Input signal.
508- y: Output signal.
509- sr: Sampling rate.
510- nperseg: Number of samples per segment.
519+ f: Frequencies.
520+ S_yu: Cross-spectral density.
521+ S_uu: Auto-spectral density.
511522 reg: Weight of the :math:`L_2` regularization.
512523 x_scale: Whether parameters are scaled by the initial values.
513524 verbose_mse: Whether the cost is scaled to the mean-squared error during logging
@@ -516,7 +527,6 @@ def fit_csd_matching(
516527 parameter covariance reflects these absolute values. Otherwise, only
517528 the relative magnitudes of the sigma values matter. See also
518529 :func:`scipy.optimize.curve_fit`.
519- fit_dc: Whether to fit the DC term.
520530 linearize_kwargs: Arguments passed to
521531 :py:meth:`~dynax.system.AbstractSystem.linearize`.
522532 kwargs: Optional parameters for `scipy.optimize.least_squares`.
@@ -536,14 +546,6 @@ def fit_csd_matching(
536546 if linearize_kwargs is None :
537547 linearize_kwargs = {}
538548
539- f , Syu , Suu = estimate_spectra (u , y , sr = sr , nperseg = nperseg )
540-
541- if not fit_dc :
542- # remove dc term
543- f = f [1 :]
544- Syu = Syu [1 :]
545- Suu = Suu [1 :]
546-
547549 s = 2 * np .pi * f * 1j
548550 weight = 1 / np .std (Syu , axis = 0 )
549551 init_params , bounds , unravel = ravel_and_bounds (sys )
0 commit comments