function [REM,ETM,REMlimit,h_echo,sort_ix,P_k,N_bins,N_discard] = jonsson_3cy_01_09_28_21(filename,f_c,REMmax,REMoffset,N_discard,N_seg,N,df,show_plot)
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
% DEALINGS IN THE SOFTWARE.

%%% check arguments %%%
if((exist('f_c')~=1) || isempty(f_c))
  f_c = 4e9;
end
if((exist('REMmax')~=1) || isempty(REMmax))
  REMmax = -30;
end
if((exist('REMoffset')~=1) || isempty(REMoffset))
  REMoffset = 20;
end
if((exist('N_discard')~=1) || isempty(N_discard))
  N_discard = 12;
end
if((exist('N_seg')~=1) || isempty(N_seg))
  N_seg = 4;
end
if((exist('N')~=1) || isempty(N))
  N = 4096/2;
end
if((exist('df')~=1) || isempty(df))
  df = 2.5e6;
end
if((exist('show_plot')~=1) || isempty(show_plot))
  show_plot = 1;
end

%%% initialize variables
N_bins = N/N_seg;

%%% read Touchstone file with S-parameters %%%
[s,f,comments,par,sdd]=rtouchstone( filename );
s11 = sdd{1,1};
s12 = sdd{1,2};
if(f(1) ~= 0)
  f = [0 f];
  s11 = [0 sdd{1,1}];
  s12 = [s12(1) s12];
end

%%% plot S11 and S12 against limits %%%
f_ix = find(f < 9e9);
f_MHz = f(f_ix)/1e6;
IL_limit = 0.00135*f_MHz + 0.3564*(f_MHz.^0.45) + 0.495*(f_MHz/7500).^6;
RL_limit = min(20,max(8,20-10*log10(f_MHz/480)));
if(show_plot)
  figure
  plot(f,20*log10(abs(s11)))
  hold on
  plot(f,20*log10(abs(s12)));
  plot(f_MHz*1e6,-IL_limit,'r','LineWidth',2);
  plot(f_MHz*1e6,-RL_limit,'k','LineWidth',2);
  title('Cable insertion loss and return loss');
  axis([0 9e9 -50 0])
  grid on
  xlabel('Frequency [Hz]')
  ylabel('Gain [dB]')
  legend('S_{11}','S_{12}','IL Limit','RL Limit');
end

%%% find REM limit value %%%
IL_fc = -20*log10(abs(spline(f,s12,f_c)));
REMlimit = min(REMmax,-IL_fc-REMoffset);

%%% verify frequency spacing and adusting if needed %%%
if(any(diff(f)-df))
  warning('The frequency spacing is not correct in .s4p file')
  warning('Converting to correct frequency spacing - this will affect the results')

  %%% test date from .S4P file %%%
  if(f(end) < N*df)
    warning('The frequency range is not sufficient in the .s4p file - compensating');
    N = floor(f(end)/df/2)*2
    N_bins = N/N_seg;
  end
  
  %%% convert to "correct" frequency spacing %%%
  fq = df*[0:N];
  sq = spline(f,s11,fq);
  
  %%% show original and interpolated data for comparison %%%
  if(show_plot)
    figure
    plot(f,abs(s11),'b');
    hold on;
    plot(fq,abs(sq),'r.');
    title('Verify interpolation');
    grid on
    xlabel('Frequency [Hz]')
    ylabel('Gain [dB]')
    legend('values from file','interpolated values')
  end
  
  %%% work with interpolated data from now on
  f = fq;
  s11 = sq;
end
 
%%% calculate REM and EMT %%%
[REM,ETM,h_echo,sort_ix,P_k] = jonsson_3cy_01a_03_23_21(f,s11,N_bins,N_seg,N_discard,0);

%%% show REM value and limit %%%
if(show_plot)
  figure
  plot([1:N_bins],REM,'b',[1:N_bins],ETM,'g',N_discard+1,REM(N_discard+1),'ok',[0 2*N_discard],REMlimit*[1 1],'r','LineWidth',2)
  title('Evaluate REM value')
  grid on
  legend('REM values','ETM values','REM metric','REM metric limit')
  xlabel('Bins')
  ylabel('Gain [dB]')
  
  figure
  plot(20*log10(abs(h_echo)))
  title('Channel Echo Response')
  grid on
  axis([0 N -100 0])
  xlabel('Samples')
  ylabel('Gain [dB]')
end

end



%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

function [s,f,comments,par,sdd]=rtouchstone( filename )
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
% OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
% FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
% DEALINGS IN THE SOFTWARE.

% NOTE: This function is made to be as simple as possible, so it has limited 
% error checks and may struggle with reading files with incorrect line ending


  %%% parse extention for S-matrix size %%%
  [filepath,name,ext] = fileparts(filename);
  M = str2num(ext(3:end-1)); %%% this is a primitive way of finding size of S matrix
  
  %%% read file %%%
  [fp, emessage] = fopen( filename, 'rt' );
  if (fp < 0)
    error( emessage );
  end

  %%% read data from file %%%
  comments = {};
  st = 0;
  v = [];
  while ((isempty(v)==1) & (st ~= -1))
    v=fscanf(fp,'%g');
    if (isempty(v))
      st = fgets(fp);
      comments{end+1} = st;
      if (st(1) == '#')
        %par = strsplit(st);
        par = regexp(st, '\s+', 'split');
      end
    end
  end
  fclose(fp);
  
  %%% reshape the S parameter data %%%
  N=length(v);
  M2 = M*M;
  ML = 2*M2 + 1;
  v = reshape(v,ML,N/ML);

  %%% convert file data into linear complex number data %%%
  dformat = par{4};
  switch(lower(dformat))
    case 'ri'
      A = zeros(M2+1,ML);
      A(1,1) = 1;
      for n = 1:M2
        A(n+1,2*n+[0 1]) = [1 i];
      end
      v = A*v;
    case 'db'
      tmp = 10.^(v(2:2:end,:)/20).*exp(i*pi/180*v(3:2:end,:));
      v = [v(1,:); tmp];
    otherwise
      error(['unknown format: ' par{4}]);
  end
 
  %%% convert frequency to Hz %%%
  switch(lower(par{2}))
    case 'hz'
      f_scale = 1;
    case 'khz'
      f_scale = 1e3;
    case 'mhz'
      f_scale = 1e6;
    case 'ghz'
      f_scale = 1e9;
    case 'thz'
      f_scale = 1e12;
    otherwise
      error(['unknown frequency unit: ' par{2}])
  end
  f = f_scale * v(1,:);

  %%% convert to square S-matrix %%% 
  for m = 1:M,
    for n = 1:M,
      ix = (m-1)*M + (n-1) + 2;
      s{m,n} = v(ix,:);
    end
  end

  %%% create diffrential-differential matrix (if requested) %%%
  seq = [1:4];
  if(nargout > 4)
    sdd{2,2} = 0;
    Mdd = M/2;
    for m = 1:Mdd,
      for n = 1:Mdd,
        m1 = seq(m);
        n1 = seq(n);
        m2 = seq(m+Mdd);
        n2 = seq(n+Mdd);
        sdd{m,n} = 0.5*(s{m1,n1}-s{m1,n2}-s{m2,n1}+s{m2,n2});
      end
    end
  end
end

  