function [settlingStruct, complete] = ...
  getSettling(x, t, upperLevel, lowerLevel, Tolerance, tSeek, ...
               tm, iPre, iPost, discardIncomplete)
%GETSETTLING Settling Time of Pulse Transitions
%
% For each incoming transition, starting at the transition occurrence
% instant and proceeding for the specified duration, record the last
% instant where the signal strayed from the tolerance specified of the
% transition's final state.  
%
% Report the duration it took from the transition occurrence as well the
% instant and level where the signal entered the tolerance threshold.
%
% If the last sample encountered within the seek region of the waveform is
% not within the state boundary or we detect an intervening transition, we 
% report a NaN for each settling metrics of that transition.
%
% If not enough samples have been captured to compute the settling duration
% of the last transition, we report a NaN or discard the results of the
% incomplete capture based upon the discardIncomplete flag.
%
% Follows IEEE Std 181-2003 Sec 5.3.7.

%   Copyright 2011-2021 The MathWorks, Inc.
%#codegen

  n = numel(tm.Polarity);

  if n>0
    postRef = signal.internal.polaritySelect(tm.Polarity, upperLevel, lowerLevel);
    ampRef = upperLevel - lowerLevel;

    tFinal = tm.MiddleCross + tSeek;
    tSetInstant = zeros(n, 1);
    lSetLevel = zeros(n, 1);

    if n>1
      for i=1:(n-1)
        iStop = find(t(iPost(i):end) > tFinal(i), 1, 'first') + iPost(i) - 1;
        if isempty(iStop) || iStop(1)>iPre(i+1) || tFinal(i) < t(iPost(i))
          tSetInstant(i) = NaN;
          lSetLevel(i) = NaN;
        else
          [tSetInstant(i), lSetLevel(i)] = ...
            getSettlingPoint(x, t, iPre(i), iStop(1), postRef(i), ampRef, Tolerance);
        end
      end
    end

    % test final transition
    iStop = find(t(iPost(n):end) > tFinal(n), 1, 'first') + iPost(n) - 1;
    complete = ~isempty(iStop);
    if complete
      if tFinal(n) < t(iPost(n))
        tSetInstant(n) = NaN;
        lSetLevel(n) = NaN;
      else
        [tSetInstant(n),lSetLevel(n)] = ... 
        getSettlingPoint(x, t, iPre(n), iStop(1), postRef(n), ampRef, Tolerance);
      end
    elseif ~discardIncomplete
      tSetInstant(n) = NaN;
      lSetLevel(n) = NaN;
    else
      %throw away metrics for this incomplete transition.
      n = n - 1;
    end

    tSetDuration = tSetInstant(1:n, 1) - tm.MiddleCross(1:n, 1);

    settlingStruct = struct('Duration',tSetDuration(1:n), ...
                            'Level',   lSetLevel(1:n), ...
                            'Instant', tSetInstant(1:n));
  else
    settlingStruct = struct('Duration',zeros(0,1), ...
                            'Level',   zeros(0,1), ...
                            'Instant', zeros(0,1));

    complete = true;
  end
end

function [tSettle, lSettle] = ...
     getSettlingPoint(x, t, iPre, iStop, postRef, ampRef, Tolerance)
  iLast = find(abs(x(iPre:iStop)-postRef) > ampRef*Tolerance/100, ...
               1, 'last') + iPre - 1;
             
             
  if iLast(1) == iStop
    tSettle = NaN;
    lSettle = NaN;
  else
    intercept = sign(x(iLast)-postRef)*ampRef*Tolerance/100;
    tSettle = signal.internal.linterp(t(iLast), t(iLast+1), ...
                               x(iLast)-postRef, x(iLast+1)-postRef, intercept);
    lSettle = signal.internal.linterp(x(iLast), x(iLast+1), t(iLast), t(iLast+1), tSettle);
  end
end

