def fit(
        self,
        series: TimeSeries,
        covariates: Optional[TimeSeries] = None,
        num_block_rows: Optional[int] = None,
    ) -> "KalmanFilter":
        """
        Initializes the Kalman filter using the N4SID algorithm.

        Parameters
        ----------
        series : TimeSeries
            The series of outputs (observations) used to infer the underlying state space model.
            This must be a deterministic series (containing one sample).
        covariates : Optional[TimeSeries]
            An optional series of inputs (control signal) that will also be used to infer the underlying state space
            model. This must be a deterministic series (containing one sample).
        num_block_rows : Optional[int]
            The number of block rows to use in the block Hankel matrices used in the N4SID algorithm.
            See the documentation of nfoursid.nfoursid.NFourSID for more information.
            If not provided, the dimensionality of the state space model will be used, with a maximum of 10.

        Returns
        -------
        self
            Fitted Kalman filter.
        """
        if covariates is not None:
            self._expect_covariates = True
            covariates = covariates.slice_intersect(series)
            raise_if_not(
                series.has_same_time_as(covariates),
                "The number of timesteps in the series and the covariates must match.",
            )

        # TODO: Handle multiple timeseries. Needs reimplementation of NFourSID?
        self.dim_y = series.width
        outputs = series.to_dataframe(copy=False)
        outputs.columns = [f"y_{i}" for i in outputs.columns]

        if covariates is not None:
            self.dim_u = covariates.width
            inputs = covariates.to_dataframe(copy=False)
            inputs.columns = [f"u_{i}" for i in inputs.columns]
            input_columns = list(inputs.columns)
            measurements = pd.concat([outputs, inputs], axis=1)
        else:
            measurements = outputs
            input_columns = None

        if num_block_rows is None:
            num_block_rows = max(10, self.dim_x)
        nfoursid = NFourSID(
            measurements,
            output_columns=list(outputs.columns),
            input_columns=input_columns,
            num_block_rows=num_block_rows,
        )
        nfoursid.subspace_identification()
        state_space_identified, covariance_matrix = nfoursid.system_identification(
            rank=self.dim_x
        )

        self.kf = Kalman(state_space_identified, covariance_matrix)

        return self

        Initializes the Kalman filter using the N4SID algorithm.

        Parameters
        ----------
        series : TimeSeries
            The series of outputs (observations) used to infer the underlying state space model.
            This must be a deterministic series (containing one sample).
        covariates : Optional[TimeSeries]
            An optional series of inputs (control signal) that will also be used to infer the underlying state space
            model. This must be a deterministic series (containing one sample).
        num_block_rows : Optional[int]
            The number of block rows to use in the block Hankel matrices used in the N4SID algorithm.
            See the documentation of nfoursid.nfoursid.NFourSID for more information.
            If not provided, the dimensionality of the state space model will be used, with a maximum of 10.

        Returns
        -------
        self
            Fitted Kalman filter.
        
darts/models/filtering/kalman_filter.py