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

%RK4  4th order Runge-Kutta integration
%
% Syntax:
%   [x,Y] = rk4(f,dt,x,[P1,P2,P3,Y])
%
% In:
%    f - Name of function in form f(x,P(:)) or
%        inline function taking the same parameters.
%        In chained case the function should be f(x,y,P(:)).
%   dt - Delta time as scalar.
%    x - Value of x from the previous time step.
%   P1 - Values of parameters of the function at initial time t
%        as a cell array (or single plain value). Defaults to empty
%        array (no parameters).
%   P2 - Values of parameters of the function at time t+dt/2 as
%        a cell array (or single plain value). Defaults to P1 and
%        each empty (or missing) value in the cell array is replaced
%        with the corresponding value in P1.
%   P3 - Values of parameters of the function at time t+dt.
%        Defaults to P2 similarly to above.
%    Y - Cell array of partial results y1,y2,y3,y4 in the RK algorithm
%        of the second parameter in the interated function. This can be
%        used for chaining the integrators. Defaults to empty.
% 
% Out:
%    x - Next value of X
%    Y - Cell array of partial results in Runge-Kutta algorithm.
%
% Description:
%   Perform one fourth order Runge-Kutta iteration step
%   for differential equation
%
%       dx/dt = f(x(t),P{:})
%
%   or in the chained case
%
%       dx/dt = f(x(t),y(t),P{:})
%       dy/dt = g(y(t),P{:})
%
%   - Example 1. Simple integration of model
%
%       dx/dt = tanh(x), x(0) = 1
%
%     can be done as follows:
%
%       X = [];
%       x = 1;
%       f = inline('tanh(x)','x');
%       for i=1:100
%         x = rk4(f,0.1,x);
%         X = [X x];
%       end
%
%   - Example 2. Chaining of integrators. Consider a
%     model of the form
%
%       dx/dt = x+y,     x(0)=1
%       dy/dt = tanh(y), y(0)=2
%
%     The equations can be now integrated as follows:
%
%       XY = [];
%       x = 1;
%       y = 2;
%       fx = inline('x+y','x','y');
%       fy = inline('tanh(y)','y');
%       for i=1:100
%         [y,YY] = rk4(fy,0.1,y);
%         x = rk4(fx,0.1,x,{},{},{},YY);
%         XY = [XY [x;y]];
%       end
%
%   which produces exactly the same result as
%
%      XY = [];
%      xy = [1;2];
%      fxy = inline('[xy(1)+xy(2);tanh(xy(2))]','xy');
%      for i=1:100
%         xy = rk4(fxy,0.1,xy);
%         XY = [XY xy];
%      end

% History:
%   14.10.2005  The first official version.
%
% Copyright (C) 2005 Simo Särkkä
%
% $Id: rk4.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 [x,Y] = rk4(f,dt,x,P1,P2,P3,Y)

  %
  % Apply default parameter values
  %
  if nargin < 4
    P1 = {};
  end
  if nargin < 5
    P2 = {};
  end
  if nargin < 6
    P3 = {};
  end
  if nargin < 7
    Y = {};
  end
  
  if ~isempty(P1) & ~iscell(P1)
    P1 = {P1};
  end
  if ~isempty(P2) & ~iscell(P2)
    P2 = {P2};
  end
  if ~isempty(P3) & ~iscell(P3)
    P3 = {P3};
  end
  
  if isempty(P2)
    P2 = P1;
  else
    for i=1:length(P1)
      if length(P2) >= i
	if isempty(P2{i})
	  P2{i} = P1{i};
	end
      else
	P2{i} = P1{i};
      end
    end
  end
  if isempty(P3)
    P3 = P2;
  else
    for i=1:length(P2)
      if length(P3) >= i
	if isempty(P3{i})
	  P3{i} = P2{i};
	end
      else
	P3{i} = P2{i};
      end
    end
  end

  %
  % Perform Runge-Kutta step
  %
  if ~isempty(Y)
    %
    % Chained integration
    %
    if isstr(f) | strcmp(class(f),'function_handle')
      x1  = x;
      dx1 = feval(f,x1,Y{1},P1{:}) * dt;
      x2  = x+0.5*dx1;
      dx2 = feval(f,x2,Y{2},P2{:}) * dt;
      x3  = x+0.5*dx2;
      dx3 = feval(f,x3,Y{3},P2{:}) * dt;
      x4  = x+dx3;
      dx4 = feval(f,x4,Y{4},P3{:}) * dt;
    else
      x1  = x;
      dx1 = f(x1,Y{1},P1{:}) * dt;
      x2  = x+0.5*dx1;
      dx2 = f(x2,Y{2},P2{:}) * dt;
      x3  = x+0.5*dx2;
      dx3 = f(x3,Y{3},P2{:}) * dt;
      x4  = x+dx3;
      dx4 = f(x4,Y{4},P3{:}) * dt;
    end  
  else
    if isstr(f) | strcmp(class(f),'function_handle')
      x1  = x;
      dx1 = feval(f,x1,P1{:}) * dt;
      x2  = x+0.5*dx1;
      dx2 = feval(f,x2,P2{:}) * dt;
      x3  = x+0.5*dx2;
      dx3 = feval(f,x3,P2{:}) * dt;
      x4  = x+dx3;
      dx4 = feval(f,x4,P3{:}) * dt;
    else
      x1  = x;
      dx1 = f(x1,P1{:}) * dt;
      x2  = x+0.5*dx1;
      dx2 = f(x2,P2{:}) * dt;
      x3  = x+0.5*dx2;
      dx3 = f(x3,P2{:}) * dt;
      x4  = x+dx3;
      dx4 = f(x4,P3{:}) * dt;
    end
  end

  Y = {x1,x2,x3,x4};
  x = x + 1/6 * (dx1 + 2*dx2 + 2*dx3 + dx4);