text: """
  .. module:: skrf.time
  ========================================
  time (:mod:`skrf.time`)
  ========================================
  
  time domain functions 
  
  Methods
  ------------
  
  .. autosummary::
      :toctree: generated/
  
      time_gate
      detect_span 
      find_n_peaks
      indexes
      
  
      
  """
  
  from .util import  find_nearest_index
  
  
  from scipy.ndimage.filters import convolve1d
  from scipy import  signal
  import numpy as npy
  import numpy as np # so i dont have to change indexes (from peakutils)
  from numpy import fft
  
  def indexes(y, thres=0.3, min_dist=1):
      """Peak detection routine.
  
      Finds the numeric index of the peaks in *y* by taking its first order difference. By using
      *thres* and *min_dist* parameters, it is possible to reduce the number of
      detected peaks. *y* must be signed.
  
      Parameters
      ----------
      y : ndarray (signed)
          1D amplitude data to search for peaks.
      thres : float between [0., 1.]
          Normalized threshold. Only the peaks with amplitude higher than the
          threshold will be detected.
      min_dist : int
          Minimum distance between each detected peak. The peak with the highest
          amplitude is preferred to satisfy this constraint.
  
      Returns
      -------
      ndarray
          Array containing the numeric indexes of the peaks that were detected
      
      Notes
      --------
      This function was taken from peakutils-1.1.0 
      http://pythonhosted.org/PeakUtils/index.html
      
      """
      #This function  was taken from peakutils, and is covered 
      # by the MIT license, inlcuded below: 
      
      #The MIT License (MIT)
  
      #Copyright (c) 2014 Lucas Hermann Negri
  
      #Permission is hereby granted, free of charge, to any person obtaining a copy
      #of this software and associated documentation files (the "Software"), to deal
      #in the Software without restriction, including without limitation the rights
      #to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      #copies of the Software, and to permit persons to whom the Software is
      #furnished to do so, subject to the following conditions:
  
      #The above copyright notice and this permission notice shall be included in
      #all copies or substantial portions of the Software.
  
      #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.
      
      if isinstance(y, np.ndarray) and np.issubdtype(y.dtype, np.unsignedinteger):
          raise ValueError("y must be signed")
  
      thres = thres * (np.max(y) - np.min(y)) + np.min(y)
      min_dist = int(min_dist)
  
      # compute first order difference
      dy = np.diff(y)
  
      # propagate left and right values successively to fill all plateau pixels (0-value)
      zeros,=np.where(dy == 0)
      
      # check if the singal is totally flat
      if len(zeros) == len(y) - 1:
          return np.array([])
      
      while len(zeros):
          # add pixels 2 by 2 to propagate left and right value onto the zero-value pixel
          zerosr = np.hstack([dy[1:], 0.])
          zerosl = np.hstack([0., dy[:-1]])
  
          # replace 0 with right value if non zero
          dy[zeros]=zerosr[zeros]
          zeros,=np.where(dy == 0)
  
          # replace 0 with left value if non zero
          dy[zeros]=zerosl[zeros]
          zeros,=np.where(dy == 0)
  
      # find the peaks by using the first order difference
      peaks = np.where((np.hstack([dy, 0.]) < 0.)
                       & (np.hstack([0., dy]) > 0.)
                       & (y > thres))[0]
  
      # handle multiple peaks, respecting the minimum distance
      if peaks.size > 1 and min_dist > 1:
          highest = peaks[np.argsort(y[peaks])][::-1]
          rem = np.ones(y.size, dtype=bool)
          rem[peaks] = False
  
          for peak in highest:
              if not rem[peak]:
                  sl = slice(max(0, peak - min_dist), peak + min_dist + 1)
                  rem[sl] = True
                  rem[peak] = False
  
          peaks = np.arange(y.size)[~rem]
  
      return peaks
  
  def find_n_peaks(x,n, thres=.9, **kw):
      '''
      Find a given number of peaks in a signal
      '''
      
      for dummy  in range(10):
          
          idx = indexes(x, **kw)
          if len(idx) < n:
              thres*=.5
              
          else:
              peak_vals = sorted(x[idx], reverse=True)[:n]
              peak_idxs =[x.tolist().index(k) for k in peak_vals]
  
              return peak_idxs
      raise ValueError('Couldnt find %i peaks'%n)
      
  def detect_span(ntwk):
      '''
      detect the correct time-span between two largest peaks
      '''
      x = ntwk.s_time_db.flatten()
      p1,p2 = find_n_peaks(x,n=2)
      #distance to nearest neighbor peak
      span = abs(ntwk.frequency.t_ns[p1]-ntwk.frequency.t_ns[p2])
      return span 
      
  def time_gate(ntwk, start=None, stop=None, center=None, span=None,
                mode='bandpass', window=('kaiser', 6),media=None, 
                boundary='reflect',return_all=False):
      '''
      Time-gate one-port s-parameters.
      
      The gate can be defined with start/stop times, or by 
      center/span. all times are in units of nanoseconds. common 
      windows are:
       * ('kaiser', 6)
       * 6 # integers are interpreted as kaiser beta-values
       * 'hamming'
       * 'boxcar'  # a staightup rect
       
      If no parameters are passed this will try to auto-gate the largest
      peak. 
  
      Parameters
      ------------
      start : number, or None
          start of time gate, (ns). 
      stop : number, or None
          stop of time gate (ns). 
      center : number, or None
          center of time gate, (ns). If None, and span is given, 
          the gate will be centered on the peak.
      span : number, or None
          span of time gate, (ns).  If None span will be half of the 
          distance to the second tallest peak
      mode: ['bandpass','bandstop']
          mode of gate 
      boundary:  {'reflect', 'constant', 'nearest', 'mirror', 'wrap'},
          passed to `scipy.ndimage.filters.convolve1d`
      window : string, float, or tuple 
          passed to `window` arg of `scipy.signal.get_window`
      
      Notes
      ------
      You cant gate things that are 'behind' strong reflections. This 
      is due to the multiple reflections that occur. 
      
      If `center!=0`, then the ntwk's time response is shifted 
      to t=0, gated, then shifted back to where it was. This is 
      done in frequency domain using `ntwk.delay()`. If the media being
      gated is dispersive (ie waveguide), then the gate `span` will be 
      span at t=0, which is different.
      
      If you need to time-gate an N-port network, then you should 
      gate each s-parameter independently. 
      
      Returns
      --------
      ntwk : Network
          copy of ntwk with time-gated s-parameters
  
      .. warning::
          Depending on sharpness of the gate, the  band edges may be 
          inaccurate, due to properties of FFT. We do not re-normalize
          anything.
  
  
      '''
      if ntwk.nports >1:
          raise ValueError('Time-gating only works on one-ports. try taking ntwk.s11 or ntwk.s21 first')
  
      if start is not None and stop is not None:
          start *= 1e-9
          stop *= 1e-9
          span = abs(stop-start)
          center = (stop+start)/2.
      
      else:
          if center is None:    
              # they didnt provide center, so find the peak
              n = ntwk.s_time_mag.argmax()
              center = ntwk.frequency.t_ns[n]
              
          if span is None:
              span = detect_span(ntwk)
              
          center *= 1e-9
          span *= 1e-9
          start = center - span / 2.
          stop = center + span / 2.
  
      
      # find start/stop gate indecies
      t = ntwk.frequency.t
      start_idx = find_nearest_index(t, start)
      stop_idx = find_nearest_index(t, stop)
  
      # create window
      window_width = abs(stop_idx - start_idx)
      window = signal.get_window(window, window_width)
  
      # create the gate by padding the window with zeros
      gate = npy.r_[npy.zeros(start_idx),
                             window,
                             npy.zeros(len(t) - stop_idx)]
  
      #IFFT the gate, so we have it's frequency response, aka kernel
      kernel=fft.fftshift(fft.ifft(fft.ifftshift(gate, axes=0), axis=0))
      kernel =abs(kernel).flatten() # take mag and flatten
      kernel=kernel/sum(kernel) # normalize kernel
      
      out = ntwk.copy()
      
      # conditionally delay ntwk, to center at t=0, this is 
      # equivalent to gating at center.  (this is probably very inefficient)
      if center!=0:
          out = out.delay(-center*1e9, 'ns',port=0,media=media)
      
      # waste of code to handle convolve1d suck
      re = out.s_re[:,0,0]
      im = out.s_im[:,0,0]
      s = convolve1d(re,kernel, mode=boundary)+\
       1j*convolve1d(im,kernel, mode=boundary)
      out.s[:,0,0] = s
      # conditionally  un-delay ntwk
      if center!=0:
          out = out.delay(center*1e9, 'ns',port=0,media=media)
  
      if mode == 'bandstop':
          out = ntwk-out
      elif mode=='bandpass':
          pass
      else:
          raise ValueError('mode should be \'bandpass\' or \'bandstop\'')
  
      if return_all:
          # compute the gate ntwk and add delay
          gate_ntwk = out.s11.copy()
          gate_ntwk.s = kernel
          gate_ntwk= gate_ntwk.delay(center*1e9, 'ns', media=media)
          
          return {'gated_ntwk':out,
                  'gate':gate_ntwk}
      else:
          return out
      
  
  
  
  