function [tMiddle, polarity, iPre, iPost, iLast] ...
  = getMidCross(x, t, upperBound, lowerBound, midRef)
%GETMIDCROSS Extract indices and instants that bound transitions.
% This function finds the transitions of the waveform between the specified
% lower and upper reference levels as described in IEEE Std 181-2003 Sec
% 5.3 and returns results with respect to positive and negative going
% transitions.
% 
% For each identified transition it returns the transition instants
% that correspond to the 50% crossing between level1 and level2.
%
% Input Arguments:
%  x           a column vector containing the sample amplitude values
%  t           a vector containing the corresponding sample instants.
%
%  upperBound  the state boundaries of the upper and lower level
%  lowerBound  used to detect transitions
%
%  midRef      The reference level used to determine the transition instant.
%              This is typically the 50% reference level.
%
% Output Arguments:
%
%  tMiddle    The transition instants that correspond to where the
%             signal crosses the 50% point between level1 and level2.
%
%  polarity   the polarities of each transition
%             (+1) for a rising  (positive going)
%             (-1) for a falling (negative-going) transition.
%
%  iPre     The indices just before each transition begins.
%
%  iPost    The indices just after each transition ends.
%  
%  iLast    The index of the last sample known to be in either state.

%   Copyright 2011-2021 The MathWorks, Inc.
%#codegen
   
  %find indices located outside a transition region
  iState     = find(x<lowerBound | x>upperBound);
  iStatePre  = iState(1:(end-1));
  iStatePost = iState(2:end);
  
  % look for positive going and negative going transitions.
  iTrans    = find(x(iStatePre) < lowerBound & upperBound < x(iStatePost) | ...
                   x(iStatePre) > upperBound & lowerBound > x(iStatePost) );
  
  iPre      = iStatePre(iTrans);
  iPost     = iStatePost(iTrans);

  % Mark the polarities of each transition
  polarity = 2 * (x(iPre) < lowerBound) - 1;
  
  %Now loop through and extract the transition occurrence instants
  %see IEEE Standard 181-2003 section 5.3.3.1
  numTrans = numel(iTrans);
  iRMid  = coder.nullcopy(zeros(numTrans, 1));
  
  for i = 1:numTrans
    %define convenience indices for compactness 
    iA = iPre(i);
    iB = iPost(i);

    if polarity(i) > 0
      %look for the first positive crossing of midRef (5.3.3.1)
      iX = find((x(iA:iB-1) <= midRef & midRef < x(iA+1:iB)), 1, 'first');
      iRMid(i) = iX(1) + iA - 1;
    else
      %look for the first negative crossing of midRef (5.3.3.1)
      iX = find(x(iA:iB-1)>= midRef & midRef > x(iA+1:iB), 1, 'first');
      iRMid(i) = iX(1) + iA - 1;
    end
  end

  if numTrans > 0
    %interpolate to find the corresponding reference level instant
    tMiddle = signal.internal.linterp(t(iRMid), t(iRMid+1), x(iRMid), x(iRMid+1), midRef);
  else
    tMiddle = zeros(0,1);
  end
  
  %Now extract the index of the last known state.  This will help us know
  %how much of the waveform needs to be saved when seeking the next
  %transition.
  if numel(iState) > 0
    iLast = iState(end);
  else
    iLast = 1;
  end
  
end
