function [ sk ] = spirit_kernel(mc, Nk)
%
%  sk = spirit_kernel(mc, Nk)
%
%  Compute the SPIRiT kernel for a calibration region mc
%
%  mc -- calibration region
%  Nk -- kernel size, should be odd (like 5)
%
%  sk -- SPIRiT kernel 
%        sk is [Nk Nk Nc Nc] in size
%

[Nx Ny Nc] = size(mc);

% set up a matrix with all of the calibration data 
nd = [];
for kk=1:Nc,
    nd = [nd im2col(mc(:,:,kk),[Nk Nk], 'sliding').'];
end;

% regularization parameter, from Miki Lustig's code
lambda = norm(nd'*nd,'fro')/size(nd,2)*0.01;

% initialize kernel
sk = zeros(Nk,Nk,Nc,Nc);

% offset of the synthesized sample for first coil
ndx1 = floor(Nk*Nk/2)+1;

% calculate weights for each channel
for k=1:Nc,
    
   % index of synthesized sample for coil k
   ndx = ndx1 + (k-1)*Nk*Nk;
   
   % find weights by removing corresponding column and fitting to it
   A = [nd(:,1:ndx-1) nd(:,ndx+1:end)];
   AtA = A'*A;
   temp = inv(AtA + eye(size(AtA))*lambda)*A'*nd(:,ndx);
   
   % add a zero placeholder at synthesized sample so we can implement as
   % convolution later
   temp = [temp(1:ndx-1).' 0 temp(ndx:end).'];
   
   % save kernel
   sk(:,:,:,k)  = reshape(temp,Nk,Nk,Nc);
   
end;

end



