Noninvasive Fetal ECG: The PhysioNet/Computing in Cardiology Challenge 2013 1.0.0

File: <base>/sources/mhaghpanahi_at_gmail.com/tf_smooth.m (3,103 bytes)
%TF_SMOOTH  Two filter based Smoother
%
% Syntax:
%   [M,P] = TF_SMOOTH(M,P,Y,A,Q,H,R,[use_inf])
%
% In:
%   M - NxK matrix of K mean estimates from Kalman filter
%   P - NxNxK matrix of K state covariances from Kalman Filter
%   Y - Sequence of K measurement as DxK matrix
%   A - NxN state transition matrix.
%   Q - NxN process noise covariance matrix.
%   H - DxN Measurement matrix.
%   R - DxD Measurement noise covariance.
%   use_inf - If information filter should be used (default 1)
%
% Out:
%   M - Smoothed state mean sequence
%   P - Smoothed state covariance sequence
%   
% Description:
%   Two filter linear smoother algorithm. Calculate "smoothed"
%   sequence from given Kalman filter output sequence
%   by conditioning all steps to all measurements.
%
% Example:
%   m = m0;
%   P = P0;
%   MM = zeros(size(m,1),size(Y,2));
%   PP = zeros(size(m,1),size(m,1),size(Y,2));
%   for k=1:size(Y,2)
%     [m,P] = kf_predict(m,P,A,Q);
%     [m,P] = kf_update(m,P,Y(:,k),H,R);
%     MM(:,k) = m;
%     PP(:,:,k) = P;
%   end
%   [SM,SP] = tf_smooth(MM,PP,A,Q,H,R,Y);
%
% See also:
%   KF_PREDICT, KF_UPDATE

% History:
%   
%   02.8.2007 JH Changed the name to tf_smooth
%   26.3.2007 JH Fixed a bug in backward filter with observations having
%                having more than one dimension.
%             
% Copyright (C) 2006 Simo Särkkä
%               2007 Jouni Hartikainen
%
% $Id: tf_smooth.m 111 2007-09-04 12:09:23Z ssarkka $
%
% This software is distributed under the GNU General Public 
% Licence (version 2 or later); please refer to the file 
% Licence.txt, included with the software, for details.
%

function [M,P] = tf_smooth(M,P,Y,A,Q,H,R,use_inf)

  %
  % Check which arguments are there
  %
  if nargin < 4
    error('Too few arguments');
  end
  if nargin < 8
    use_inf = [];
  end
  
  if isempty(use_inf)
    use_inf = 1;
  end
  
  %
  % Run the backward filter
  %
  if use_inf
    zz = zeros(size(M));
    SS = zeros(size(P));
    IR = inv(R);
    IQ = inv(Q);
    z = zeros(size(M,1),1);
    S = zeros(size(M,1),size(M,1));
    for k=size(M,2):-1:1
      G = S / (S + IQ);
      S = A' * (eye(size(M,1)) - G) * S * A;
      z = A' * (eye(size(M,1)) - G) * z;
      zz(:,k)   = z;
      SS(:,:,k) = S;
      S = S + H'*IR*H;
      z = z + H'*IR*Y(:,k);
    end
  else
    BM = zeros(size(M));
    BP = zeros(size(P));
    IA = inv(A);
    IQ = IA*Q*IA';  
    fm = zeros(size(M,1),1);
    fP = 1e12*eye(size(M,1));
    BM(:,end) = fm;
    BP(:,:,end) = fP;
    for k=(size(M,2)-1):-1:1
      [fm,fP] = kf_update(fm,fP,Y(:,k+1),H,R);
      [fm,fP] = kf_predict(fm,fP,IA,IQ);
      BM(:,k) = fm;
      BP(:,:,k) = fP;
    end
  end

  %
  % Combine estimates
  %
  if use_inf
    for k=1:size(M,2)-1
      G = P(:,:,k) * SS(:,:,k) / (eye(size(M,1)) + P(:,:,k) * SS(:,:,k));
      P(:,:,k) = inv(inv(P(:,:,k)) + SS(:,:,k));
      M(:,k) = M(:,k) + P(:,:,k) * zz(:,k) - G * M(:,k);
    end
  else
    for k=1:size(M,2)-1
      tmp = inv(inv(P(:,:,k)) + inv(BP(:,:,k)));
      M(:,k) = tmp * (P(:,:,k)\M(:,k) + BP(:,:,k)\BM(:,k));
      P(:,:,k) = tmp;
    end
  end