diff --git a/wetb/dlc/high_level.py b/wetb/dlc/high_level.py
index 6c29c4589245b066667d89bf4b55cf05593eaa87..418de910337dafd4fb557fdb99e75e126d8b1f27 100644
--- a/wetb/dlc/high_level.py
+++ b/wetb/dlc/high_level.py
@@ -44,6 +44,36 @@ def Weibull2(u, k, wsp_lst):
     edges = np.r_[wsp_lst[0] - (wsp_lst[1] - wsp_lst[0]) / 2, (wsp_lst[1:] + wsp_lst[:-1]) / 2, wsp_lst[-1] + (wsp_lst[-1] - wsp_lst[-2]) / 2]
     return [-cdf(e1) + cdf(e2) for wsp, e1, e2 in zip(wsp_lst, edges[:-1], edges[1:])]
 
+def Weibull_IEC(Vref, Vhub_lst):
+    """Weibull distribution according to IEC 61400-1:2005, page 24
+    
+    Parameters
+    ----------
+    Vref : int or float
+        Vref of wind turbine class
+    Vhub_lst : array_like
+        Wind speed at hub height. Must be equally spaced.
+    
+    Returns
+    -------
+    nd_array : list of probabilities
+        
+    Examples
+    --------
+    >>> Weibull_IEC(50, [4,6,8]) 
+    [ 0.11002961  0.14116891  0.15124155]
+    """
+    Vhub_lst = np.array(Vhub_lst)
+    #Average wind speed
+    Vave=.2*Vref
+    #Rayleigh distribution
+    Pr = lambda x : 1 - np.exp(-np.pi*(x/(2*Vave))**2)
+    #Wsp bin edges: [4,6,8] -> [3,5,7,9] 
+    wsp_bin_edges = np.r_[Vhub_lst[0] - (Vhub_lst[1] - Vhub_lst[0]) / 2, (Vhub_lst[1:] + Vhub_lst[:-1]) / 2, Vhub_lst[-1] + (Vhub_lst[-1] - Vhub_lst[-2]) / 2]
+    #probabilities of 3-5, 5-7, 7-9
+    return np.array([-Pr(e1) + Pr(e2) for e1, e2 in zip(wsp_bin_edges[:-1], wsp_bin_edges[1:])])
+
+
 
 class DLCHighLevel(object):
 
@@ -159,7 +189,7 @@ class DLCHighLevel(object):
 
         dist = self.dlc_df[dist_key][row]
         if str(dist).lower() == "weibull" or str(dist).lower() == "rayleigh":
-            dist = Weibull2(self.vref * .2, self.shape_k, values)
+            dist = Weibull_IEC(self.vref, values)
         else:
             def fmt(v):
                 if "#" in str(v):
diff --git a/wetb/dlc/tests/test_high_level.py b/wetb/dlc/tests/test_high_level.py
index 82a658835e669e305807d92ab36f62d26de7f78f..473e81bd6d36eb1adc54304b2d75ede8b0413fdc 100644
--- a/wetb/dlc/tests/test_high_level.py
+++ b/wetb/dlc/tests/test_high_level.py
@@ -10,7 +10,7 @@ from __future__ import absolute_import
 from future import standard_library
 standard_library.install_aliases()
 import unittest
-from wetb.dlc.high_level import DLCHighLevel, Weibull
+from wetb.dlc.high_level import DLCHighLevel, Weibull, Weibull_IEC
 import os
 import numpy as np
 
@@ -109,7 +109,10 @@ class TestDLCHighLevel(unittest.TestCase):
         p_tot = np.array([value for key, value in weibull.items()]).sum()
         self.assertTrue(np.allclose(p_tot, 1.0))
 
-
+    def test_weibull_IEC(self):
+        Vref = 50
+        np.testing.assert_array_almost_equal(Weibull_IEC(Vref, [4,6,8]), [ 0.11002961,  0.14116891,  0.15124155])
+        
 
 if __name__ == "__main__":
     #import sys;sys.argv = ['', 'Test.testName']
diff --git a/wetb/signal/__init__.py b/wetb/signal/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..42d8da654fe6b7fc28c9998298c8d8ef5c397ac5
--- /dev/null
+++ b/wetb/signal/__init__.py
@@ -0,0 +1,12 @@
+
+d = None
+d = dir()
+
+from .interpolation import interpolate
+
+
+__all__ = [m for m in set(dir()) - set(d)]
+
+
+
+
diff --git a/wetb/signal/filters/__init__.py b/wetb/signal/filters/__init__.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..ebe5b72cdfc049ea8a1f5a485d5949ccd8782bcd 100644
--- a/wetb/signal/filters/__init__.py
+++ b/wetb/signal/filters/__init__.py
@@ -0,0 +1,2 @@
+from ._despike import *
+from ._differentiation import *
\ No newline at end of file
diff --git a/wetb/signal/filters/despike.py b/wetb/signal/filters/_despike.py
similarity index 85%
rename from wetb/signal/filters/despike.py
rename to wetb/signal/filters/_despike.py
index f7256c68b1bd499faf78987afa83b644ff8f4dee..7fda9e33462d907b229b3339c87a98d0197d0359 100644
--- a/wetb/signal/filters/despike.py
+++ b/wetb/signal/filters/_despike.py
@@ -4,8 +4,7 @@ Created on 13/07/2016
 @author: MMPE
 '''
 import numpy as np
-from wetb.signal.filters.first_order import low_pass
-from wetb.signal.filters import replacer
+from wetb.signal.filters import replacer, frq_filters
 
 
 replace_by_nan = replacer.replace_by_nan
@@ -42,15 +41,15 @@ def univeral_thresshold_finder(data, variation='mad', plt=None):
     thresshold = np.sqrt(2 * np.log(data.shape[0])) * variation  # Universal thresshold (expected maximum of n random variables)
     return thresshold_finder(data, thresshold, plt)
 
-def despike(data, dt, spike_finder=univeral_thresshold_finder, spike_replacer=replace_by_nan, plt=None):
+def despike(data, spike_length, spike_finder=univeral_thresshold_finder, spike_replacer=replace_by_nan, plt=None):
     """Despike data
 
     Parameters
     ---------
     data : array_like
         data
-    dt : int or float
-        time step
+    spike_length : int
+        Typical spike duration [samples]
     spike_finder : function
         Function returning indexes of the spikes
     spike_replacer : function
@@ -63,8 +62,10 @@ def despike(data, dt, spike_finder=univeral_thresshold_finder, spike_replacer=re
     if plt:
         plt.plot(data, label='Input')
     data = np.array(data).copy()
-    lp_data = low_pass(data, dt, 1)
+    lp_data = low_pass(data, spike_length, 1)
     hp_data = data - lp_data
+    hp_data = frq_filters.high_pass(data, spike_length*4, 1, order=2)
+        #spike_length, sample_frq/2, 1, order=1)
     spike_mask = spike_finder(hp_data, plt=plt)
     despike_data = spike_replacer(data, spike_mask)
     if plt:
diff --git a/wetb/signal/filters/_differentiation.py b/wetb/signal/filters/_differentiation.py
new file mode 100644
index 0000000000000000000000000000000000000000..16caa027209d4b5ec1ba3ae59ffcc8be93f14910
--- /dev/null
+++ b/wetb/signal/filters/_differentiation.py
@@ -0,0 +1,37 @@
+'''
+Created on 29. mar. 2017
+
+@author: mmpe
+'''
+from wetb.signal.filters.frq_filters import low_pass
+import numpy as np
+def differentiation(x,sample_frq=None, cutoff_frq=None):
+    """Differentiate the signal
+    
+    Parameters
+    ----------
+    x : array_like
+        The input signal
+    sample_frq : int, float or None, optional
+        sample frequency of signal (only required if low pass filer is applied)
+    cutoff_frq : int, float or None, optional
+        Low pass filter cut off (frequencies higher than this frequency will be suppressed)
+    Returns
+    -------
+    y : ndarray
+        differentiated signal
+    
+    
+    Examples
+    --------
+    >>> differentiation([1,2,1,0,1,1])
+    """ 
+ 
+            
+    if cutoff_frq is not None:
+        assert sample_frq is not None, "Argument sample_frq must be set to apply low pass filter"
+        x = low_pass(x, sample_frq, cutoff_frq)
+    else:
+        x = np.array(x) 
+    dy = np.r_[x[1]-x[0], (x[2:]-x[:-2])/2, x[-1]-x[-2]]
+    return dy
\ No newline at end of file
diff --git a/wetb/signal/filters/frq_filters.py b/wetb/signal/filters/frq_filters.py
new file mode 100644
index 0000000000000000000000000000000000000000..58dec73c5078a9a3bb58709b0cedfd0be500f4a5
--- /dev/null
+++ b/wetb/signal/filters/frq_filters.py
@@ -0,0 +1,144 @@
+'''
+Created on 27. mar. 2017
+
+@author: mmpe
+'''
+import numpy as np
+from scipy import signal
+
+def sine_generator(sample_frq, sine_frq, duration):
+    """Create a sine signal for filter test
+    
+    Parameters
+    ----------
+    sample_frq : int, float
+        Sample frequency of returned signal [Hz]
+    sine_frq : int, float
+        Frequency of sine signal [Hz]
+    duration : int, float
+        Duration of returned signal [s]
+        
+    Returns
+    -------
+    t,sig : ndarray, ndarray
+        time (t) and sine signal (sig)
+    
+    Examples
+    --------
+    >>> sine_generator(10,1,2) 
+    """
+    T = duration
+    nsamples = sample_frq * T
+    w = 2. * np.pi * sine_frq
+    t = np.linspace(0, T, nsamples, endpoint=False)
+    sig = np.sin(w * t)
+    return t, sig
+
+
+def low_pass(x, sample_frq, cutoff_frq, order=5):
+    """Low pass filter (butterworth)
+    
+    Parameters
+    ----------
+    x : array_like
+        Input signal
+    sample_frq : int, float
+        Sample frequency [Hz]
+    cutoff_frq : int, float
+        Cut off frequency [Hz]
+    order : int
+        Order of the filter (1th order: 20db per decade, 2th order:)
+    
+    Returns
+    -------
+    y : ndarray
+        Low pass filtered signal
+    
+    
+    Examples
+    --------
+    >>> 
+    """
+    nyquist_frq = 0.5 * sample_frq
+    normal_cutoff = cutoff_frq / nyquist_frq
+    b,a = signal.butter(order, normal_cutoff, btype='low', analog=False)
+    return signal.filtfilt(b, a, x)
+
+def high_pass(x, sample_frq, cutoff_frq, order=5):
+    """Low pass filter (butterworth)
+    
+    Parameters
+    ----------
+    x : array_like
+        Input signal
+    sample_frq : int, float
+        Sample frequency [Hz]
+    cutoff_frq : int, float
+        Cut off frequency [Hz]
+    order : int
+        Order of the filter (1th order: 20db per decade, 2th order:)
+    
+    Returns
+    -------
+    y : ndarray
+        Low pass filtered signal
+    
+    
+    Examples
+    --------
+    >>> 
+    """
+    nyquist_frq = 0.5 * sample_frq
+    normal_cutoff = cutoff_frq / nyquist_frq
+    b,a = signal.butter(order, normal_cutoff, btype='high', analog=False)
+    return signal.filtfilt(b, a, x)
+
+def frequency_response(sample_frq, cutoff_frq, type, order, plt=None):
+    """Frequency response of low/high pass filter (butterworth
+    
+    Parameters
+    ----------
+    sample_frq : int, float
+        Sample frequency [Hz]
+    cutoff_frq : int, float
+        Cut off frequency [Hz]
+    type : {'low','high'}
+        Low or high pass filter
+    order : int
+        Order of the filter (1th order: 20db per decade, 2th order: 40db per decade)
+    plt : pyplot, optional
+        If specified, the frequency response is plotted
+    
+    Returns
+    -------
+    w,h : ndarray, ndarray
+        Frequency (w) in Hz and filter response in db
+    
+    
+    Examples
+    --------
+    >>>  
+    """
+    nyquist_frq = 0.5 * sample_frq
+    normal_cutoff = cutoff_frq / nyquist_frq
+    assert 0<normal_cutoff<1, "cutoff frequency must be <= nyquist frequency"
+    b,a = signal.butter(order, cutoff_frq, btype=type, analog=True)
+    w, h = signal.freqs(b, a)
+    h_db = 20 * np.log10(abs(h))
+    if plt:
+        plt.plot(w, h_db, label='%d order filter response'%order)
+
+        plt.legend(loc=0)
+        
+        title = 'Butterworth filter frequency response'
+        if plt.axes().get_title()!=title:
+            plt.title(title)
+            plt.xlabel('Frequency [Hz]')
+            plt.ylabel('Amplitude [dB]')
+            plt.margins(.1, .1)
+            plt.xscale('log')
+            
+            plt.grid(which='both', axis='both')
+            plt.axvline(cutoff_frq, color='green') # cutoff frequency
+        
+    return w,h_db
\ No newline at end of file
diff --git a/wetb/signal/fit/__init__.py b/wetb/signal/fit/__init__.py
index 2578ab2dde2c387e6801224980c9c13848c1b548..4e0ddd1f8dc62eccddc5845fe9e21e9f38cdc892 100644
--- a/wetb/signal/fit/__init__.py
+++ b/wetb/signal/fit/__init__.py
@@ -4,5 +4,6 @@ d = dir()
 from wetb.signal.fit._linear_fit import *
 from wetb.signal.fit._bin_fit import *
 from wetb.signal.fit._fourier_fit import *
+from wetb.signal.fit._spline_fit import *
 
 __all__ = sorted([m for m in set(dir()) - set(d)])
diff --git a/wetb/signal/fit/_bin_fit.py b/wetb/signal/fit/_bin_fit.py
index f1124ff6fb0919a22f2ef8a1e45ad14a597ce9eb..fcaf5879f9e0f89c99ded6cf8b69f32f48997e9e 100644
--- a/wetb/signal/fit/_bin_fit.py
+++ b/wetb/signal/fit/_bin_fit.py
@@ -103,14 +103,9 @@ def bin_fit(x,y, bins=10, kind='linear', bin_func=np.nanmean, bin_min_count=3, l
         else:
             raise NotImplementedError("Argument for handling upper observations, %s, not implemented"%upper)
         
-    #Create mean function
-    def fit(x):
-        x = x[:].copy().astype(np.float)
-        x[x<bin_x_fit[0]] = np.nan
-        x[x>bin_x_fit[-1]] = np.nan
-        return interp1d(bin_x_fit, bin_y_fit, kind)(x[:])
+
     
-    return bin_x_fit, fit
+    return bin_x_fit, _interpolate_fit(bin_x_fit, bin_y_fit, kind)
     
 def perpendicular_bin_fit(x, y, bins = 30, fit_func=None, bin_min_count=3, plt=None):
     """Fit a curve to the values, (x,y) using bins that are perpendicular to an initial fit
@@ -190,6 +185,15 @@ def perpendicular_bin_fit(x, y, bins = 30, fit_func=None, bin_min_count=3, plt=N
         plt.plot(pbfx, pbfy, 'gray', label="perpendicular fit")
         plt.legend()
     #PlotData(None, bfx,bfy)
-    
-    return np.array(pc).T
+    bin_x_fit, bin_y_fit = np.array(pc).T 
+    return bin_x_fit, _interpolate_fit(bin_x_fit, bin_y_fit, kind="linear")
+
+#Create mean function
+def _interpolate_fit(bin_x_fit, bin_y_fit, kind='linear'):
+    def fit(x):
+        x = x[:].copy().astype(np.float)
+        x[x<bin_x_fit[0]] = np.nan
+        x[x>bin_x_fit[-1]] = np.nan
+        return interp1d(bin_x_fit, bin_y_fit, kind)(x[:])
+    return fit
 
diff --git a/wetb/signal/fit/_spline_fit.py b/wetb/signal/fit/_spline_fit.py
new file mode 100644
index 0000000000000000000000000000000000000000..1fa074f9f359861797b42f3652fe8947fd938645
--- /dev/null
+++ b/wetb/signal/fit/_spline_fit.py
@@ -0,0 +1,74 @@
+import numpy as np
+def spline_fit(xp,yp):
+
+        def akima(x, y):
+            n = len(x)
+            var = np.zeros((n + 3))
+            z = np.zeros((n))
+            co = np.zeros((n, 4))
+            for i in range(n - 1):
+                var[i + 2] = (y[i + 1] - y[i]) / (x[i + 1] - x[i])
+            var[n + 1] = 2 * var[n] - var[n - 1]
+            var[n + 2] = 2 * var[n + 1] - var[n]
+            var[1] = 2 * var[2] - var[3]
+            var[0] = 2 * var[1] - var[2]
+
+            for i in range(n):
+                wi1 = abs(var[i + 3] - var[i + 2])
+                wi = abs(var[i + 1] - var[i])
+                if (wi1 + wi) == 0:
+                    z[i] = (var[i + 2] + var[i + 1]) / 2
+                else:
+                    z[i] = (wi1 * var[i + 1] + wi * var[i + 2]) / (wi1 + wi)
+
+            for i in range(n - 1):
+                dx = x[i + 1] - x[i]
+                a = (z[i + 1] - z[i]) * dx
+                b = y[i + 1] - y[i] - z[i] * dx
+                co[i, 0] = y[i]
+                co[i, 1] = z[i]
+                co[i, 2] = (3 * var[i + 2] - 2 * z[i] - z[i + 1]) / dx
+                co[i, 3] = (z[i] + z[i + 1] - 2 * var[i + 2]) / dx ** 2
+            co[n - 1, 0] = y[n - 1]
+            co[n - 1, 1] = z[n - 1]
+            co[n - 1, 2] = 0
+            co[n - 1, 3] = 0
+            return co
+
+        p_lst = [lambda x_, c=c, x0=x0: np.poly1d(c[::-1])(x_-x0) for c,x0 in zip(akima(xp,yp), xp)]
+        
+        def spline(x):
+            y = np.empty_like(x)+np.nan
+            segment = np.searchsorted(xp,x, 'right')-1
+            for i in np.unique(segment):
+                m = segment==i
+                y[m] = p_lst[i](x[m])
+            return y
+#         def coef2spline(x, xp, co):
+#             
+#             print (np.searchsorted(xp,x)-1)
+#             x, y = [], []
+#             for i, c in enumerate(co.tolist()[:-1]):
+#                 p = np.poly1d(c[::-1])
+#                 z = np.linspace(0, s[i + 1] - s[i ], 10, endpoint=i >= co.shape[0] - 2)
+#                 x.extend(s[i] + z)
+#                 y.extend(p(z))
+#             return y
+#         
+        return spline
+        #x, y, z = [coef2spline(curve_z_nd, akima(curve_z_nd, self.c2def[:, i])) for i in range(3)]
+        #return x, y, z
+    
+if __name__=="__main__":
+    import matplotlib.pyplot as plt
+    x = np.random.randint(0,100,10)
+    t = np.arange(0,100,10)
+    plt.plot(t,x,'.',label='points')
+    
+    t_ = np.arange(100)
+    spline = spline_fit(t,x)
+    print (np.abs(np.diff(np.diff(np.interp(t_, t,x)))).max())
+    print (np.abs(np.diff(np.diff(spline(t_)))).max())
+    plt.plot(t_, np.interp(t_, t,x))
+    plt.plot(t_, spline(t_),label='spline')
+    plt.show()
diff --git a/wetb/signal/fix/__init__.py b/wetb/signal/fix/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..d78316911251e8084e53f096c205f3f3620b9c22
--- /dev/null
+++ b/wetb/signal/fix/__init__.py
@@ -0,0 +1 @@
+from ._rotor_position import *
\ No newline at end of file
diff --git a/wetb/signal/fix/_rotor_position.py b/wetb/signal/fix/_rotor_position.py
new file mode 100644
index 0000000000000000000000000000000000000000..22aac76de54ba82a0cd4d21f501885e9a7364cb9
--- /dev/null
+++ b/wetb/signal/fix/_rotor_position.py
@@ -0,0 +1,113 @@
+'''
+Created on 30. mar. 2017
+
+@author: mmpe
+'''
+import numpy as np
+from wetb.signal.fit._spline_fit import spline_fit
+def fix_rotor_position(rotor_position, sample_frq, rotor_speed, fix_dt=None, plt=None):
+    """Rotor position fitted with spline
+    
+    Parameters
+    ----------
+    rotor_position : array_like
+        Rotor position [deg] (0-360)
+    sample_frq : int or float
+        Sample frequency [Hz]
+    rotor_speed : array_like
+        Rotor speed [RPM]
+    fix_dt : int, float or None, optional
+        Time distance [s] between spline fix points\n
+        If None (default) a range of seconds is tested and the result that minimize the RMS 
+        between differentiated rotor position fit and rotor speed is used.\n 
+        Note that a significant speed up is achievable by specifying the parameter
+    plt : PyPlot or None
+        If PyPlot a visual interpretation is plotted
+            
+    Returns
+    -------
+    y : nd_array
+        Fitted rotor position
+    """
+    
+    from wetb.signal.subset_mean import revolution_trigger
+    
+    t = np.arange(len(rotor_position))
+    indexes = revolution_trigger(rotor_position[:], sample_frq, rotor_speed, max_no_round_diff=4)
+    
+    rp = rotor_position[:].copy()
+    
+    for i in indexes:
+        rp[i:] += 360
+        
+    if fix_dt is None:
+        fix_dt = find_fix_dt(rotor_position, sample_frq, rotor_speed)
+        
+    N = int(np.round(fix_dt*sample_frq))
+    N2 = N//2
+    if plt:
+        a = (rp.max()-rp.min())/t.max()
+        plt.plot(t/sample_frq,rp-t*a,label='Continus rotor position (detrended)')
+    
+    points = []
+    for j, i in enumerate(range(0,len(rp), N)):
+        #indexes for subsets for overlapping a and b polynomials
+        i1 = max(0,i-N2)
+        i2 = min(len(rp),i+N2)
+        
+        #fit a polynomial
+        if i1<len(rp):
+            poly_coef = np.polyfit(t[i1:i2]-t[i1], rp[i1:i2], 1)
+            points.append((t[i],np.poly1d(poly_coef)(t[i]-t[i1])))
+            if plt:
+                plt.plot(t[i1:i2]/sample_frq, np.poly1d(poly_coef)(t[i1:i2]-t[i1])- t[i1:i2]*a, 'mc'[j%2], label=('', "Line fit for points (detrended)")[j<2])
+                
+    x,y = np.array(points).T
+    
+    if plt:
+        plt.plot(x/sample_frq,y-x*a,'.', label='Fit points (detrended)')
+        plt.plot(t/sample_frq, spline_fit(x,y)(t)-t*a, label='Spline (detrended)')
+        plt.legend()
+        plt.show()
+    return spline_fit(x,y)(t)%360
+
+def find_fix_dt(rotor_position, sample_frq, rotor_speed, plt=None):
+    """Find the optimal fix_dt parameter for fix_rotor_position (function above).
+    Optimal is defined as the value that minimizes the sum of squared differences 
+    between differentiated rotor position and rotor speed 
+    
+    Parameters
+    ----------
+    rotor_position : array_like
+        Rotor position [deg] (0-360)
+    sample_frq : int or float
+        Sample frequency [Hz]
+    rotor_speed : array_like
+        Rotor speed [RPM]
+    plt : pyplot or None
+        If pyplot, a visual interpretation is plotted
+        
+    Returns
+    -------
+    y : int
+        Optimal value for the fix_dt parameter for fix_rotor_position
+    
+    """
+    from wetb.signal.filters import differentiation
+    def err(i):
+        rpm_pos = differentiation(fix_rotor_position(rotor_position, sample_frq, rotor_speed, i))%180 / 360 * sample_frq * 60
+        return np.sum((rpm_pos - rotor_speed)**2)
+    
+    best = 27
+    for step in [9,3,1]:
+        
+        x_lst = np.arange(-2,3)*step + best
+        res = [err(x) for x in x_lst]
+        if plt is not None:
+            plt.plot(x_lst, res,'.-')
+        best = x_lst[np.argmin(res)]
+    if plt is not None:
+        plt.show()
+    
+    return best 
+    
\ No newline at end of file
diff --git a/wetb/signal/interpolation.py b/wetb/signal/interpolation.py
new file mode 100644
index 0000000000000000000000000000000000000000..098a25b76f741eb215802ae0348807130b40e0b6
--- /dev/null
+++ b/wetb/signal/interpolation.py
@@ -0,0 +1,85 @@
+
+import numpy as np
+import numpy.ma as ma
+#from pylab import *
+def interpolate(x, xp, yp, max_xp_step=None, max_dydxp=None, cyclic_range=None, max_repeated=None):
+    """Interpolation similar to numpy.interp that handles nan and missing values
+
+    Parameters
+    ----------
+    x : array_like
+        The x-coordinates of the interpolated values.
+    xp : 1-D sequence of floats
+        The x-coordinates of the data points, must be increasing.
+    yp : 1-D sequence of floats
+        The y-coordinates of the data points, same length as xp.
+    max_xp_step : int, float or None, optional
+        Maximum xp-time step that is interpolated to x.\n
+        If time step > max_xp_step then NAN is returned for intermediate x values
+        If None, default, then this fix is not applied
+    max_dydxp : int, float, None, optional
+        Maximum absolute dydxp (slop of yp) that is interpolated to y.\n
+        If dydxp > max_dydxp then NAN is returned for intermediate y values
+        If None, default, then this fix is not applied
+    cyclick_range : int, float, None, optional
+        Range of posible values, e.g. 360 for degrees (both 0..360 and -180..180)
+        If None (default), data not interpreted as cyclic
+    max_repeated : int, float, None, optional
+        Maximum xp that yp are allowed to be repeated
+        if yp[i]==yp[i+1]==..==yp[i+j] and xp[i+j]-xp[i]>max_repeated_yp then
+        NAN is returned for xp[i]<x<=xp[i+j]
+
+
+    Returns
+    -------
+    y : {float, ndarray}
+        The interpolated values, same shape as x.
+
+    Examples
+    --------
+    >>> interpolate(x=[1,1.5,2,3], xp=[0.5,1.5,3], yp=[5,15,30])
+    [10,15,20,30]
+    >>> interpolate(x=[0, 1, 2, 7, 12], xp=[0, 2, 12], yp=[359, 0, 350], max_dydxp=45)
+    [359,nan,0,175,350]
+    """
+
+    xp = np.array(xp, dtype=np.float)
+    yp = np.array(yp, dtype=np.float)
+    assert xp.shape[0] == yp.shape[0], "xp and yp must have same length (%d!=%d)" % (xp.shape[0], yp.shape[0])
+    non_nan = ~(np.isnan(xp) & np.isnan(yp))
+    yp = yp[non_nan]
+    xp = xp[non_nan]
+    y = np.interp(x, xp, yp, np.nan, np.nan)
+
+
+    if cyclic_range is not None:
+        cr = cyclic_range
+        y2 = np.interp(x, xp, (yp + cr / 2) % cr - cr / 2, np.nan, np.nan) % cr
+        y = np.choose(np.r_[0, np.abs(np.diff(y)) > np.abs(np.diff(y2))], np.array([y, y2]))
+
+    if max_xp_step:
+        diff = np.diff(xp)
+        diff[np.isnan(diff)] = 0
+
+        indexes = (np.where(diff > max_xp_step)[0])
+        for index in indexes:
+            y[(x > xp[index]) & (x < xp[index + 1])] = np.nan
+    if max_dydxp:
+        if cyclic_range is None:
+            abs_dydxp = np.abs(np.diff(yp) / np.diff(xp))
+        else:
+            abs_dydxp = np.min([np.abs(np.diff((yp + cyclic_range / 2) % cyclic_range)) , np.abs(np.diff(yp % cyclic_range)) ], 0) / np.diff(xp)
+        abs_dydxp[np.isnan(abs_dydxp)] = 0
+
+        indexes = (np.where(abs_dydxp > max_dydxp)[0])
+        for index in indexes:
+            y[(x > xp[index]) & (x < xp[index + 1])] = np.nan
+    if max_repeated:
+        rep = np.r_[False, yp[1:] == yp[:-1], False]
+        tr = rep[1:] ^ rep[:-1]
+        itr = np.where(tr)[0]
+        for start, stop, l in zip (itr[::2] , itr[1::2], xp[itr[1::2]] - xp[itr[::2]]):
+            if l >= max_repeated:
+                y[(x > xp[start]) & (x <= xp[stop])] = np.nan
+    return y
+#print (interpolate(x=[0, 1, 2, 3, 4], xp=[0, 1, 2, 4], yp=[5, 5, 6, 6], max_repeated=1))
diff --git a/wetb/signal/nan_replace.py b/wetb/signal/nan_replace.py
new file mode 100644
index 0000000000000000000000000000000000000000..ffc691d0588eb7d22ce3894ea1dfe65b95ea48a1
--- /dev/null
+++ b/wetb/signal/nan_replace.py
@@ -0,0 +1,22 @@
+'''
+Created on 02/11/2015
+
+@author: MMPE
+'''
+
+import numpy as np
+from wetb.signal.filters import replacer
+def replace_by_mean(x):
+    return replacer.replace_by_mean(x, np.isnan(x))
+
+
+def replace_by_line(x):
+    return replacer.replace_by_line(x, np.isnan(x))
+
+def replace_by_polynomial(x, deg=3, no_base_points=12):
+    return replacer.replace_by_polynomial(x, np.isnan(x), deg, no_base_points)
+
+def max_no_nan(x):
+    return replacer.max_cont_mask_length(np.isnan(x))
+
+
diff --git a/wetb/signal/subset_mean.py b/wetb/signal/subset_mean.py
index 89ed1499cfa548a7c65403c444c6fb9a0f079dec..0de3ea896f8185e932998ddd85229b97523e2a9a 100644
--- a/wetb/signal/subset_mean.py
+++ b/wetb/signal/subset_mean.py
@@ -136,7 +136,53 @@ def cycle_trigger(values, trigger_value=None, step=1, ascending=True, tolerance=
     else:
         return np.where((values[1:] < trigger_value - tolerance) & (values[:-1] >= trigger_value + tolerance))[0][::step]
 
-def revolution_trigger(values, rpm_dt=None, dmin=5, dmax=10, ):
+def revolution_trigger(rotor_position, sample_frq, rotor_speed, max_no_round_diff=1):
+    """Returns one index per revolution (minimum rotor position)
+    
+    Parameters
+    ----------
+    rotor_position : array_like
+        Rotor position [deg] (0-360)
+    sample_frq : int or float
+        Sample frequency [Hz]
+    rotor_speed : array_like
+        Rotor speed [RPM]
+        
+    Returns
+    -------
+    nd_array : Array of indexes
+    """
+    if isinstance(rotor_speed, (float, int)):
+        rotor_speed = np.ones_like(rotor_position)*rotor_speed
+    deg_per_sample = rotor_speed*360/60/sample_frq
+    sample_per_round = 1/(rotor_speed/60/sample_frq)
+    thresshold = deg_per_sample.max()*2
+    
+    nround_rotor_speed = np.nansum(rotor_speed/60/sample_frq)
+    
+    mod = [v for v in [5,10,30,60,90] if v>thresshold][0]
+    
+    nround_rotor_position = np.nansum(np.diff(rotor_position)%mod)/360
+    #assert abs(nround_rotor_position-nround_rotor_speed)<max_no_round_diff, "No of rounds from rotor_position (%.2f) mismatch with no_rounds from rotor_speed (%.2f)"%(nround_rotor_position, nround_rotor_speed)
+    #print (nround_rotor_position, nround_rotor_speed)
+    
+    rp = np.array(rotor_position).copy()
+    #filter degree increase > thresshold
+    rp[np.r_[False, np.diff(rp)>thresshold]] = 180
+    
+    upper_indexes = np.where((rp[:-1]>(360-thresshold))&(rp[1:]<(360-thresshold)))[0]
+    lower_indexes = np.where((rp[:-1]>thresshold)&(rp[1:]<thresshold))[0] +1 
+    
+    # Best lower is the first lower after upper
+    best_lower = lower_indexes[np.searchsorted(lower_indexes, upper_indexes)]
+    upper2lower = best_lower - upper_indexes
+    best_lower = best_lower[upper2lower<upper2lower.mean()*2]
+    #max_dist_error = max([np.abs((i2-i1)- np.mean(sample_per_round[i1:i2])) for i1,i2 in zip(best_lower[:-1], best_lower[1:])])
+    #assert max_dist_error < sample_frq/5, max_dist_error
+    return best_lower
+    
+
+def revolution_trigger_old(values, rpm_dt=None, dmin=5, dmax=10, ):
     """Return indexes where values are > max(values)-dmin and decreases more than dmax
     If RPM and time step is provided, triggers steps < time of 1rpm is removed   
     
diff --git a/wetb/signal/tests/test_differentiation.py b/wetb/signal/tests/test_differentiation.py
new file mode 100644
index 0000000000000000000000000000000000000000..87538cdc68ca0efa1a3ce733e57cc98f0ee1ab86
--- /dev/null
+++ b/wetb/signal/tests/test_differentiation.py
@@ -0,0 +1,20 @@
+'''
+Created on 29. mar. 2017
+
+@author: mmpe
+'''
+import unittest
+import numpy as np
+from wetb.signal.filters._differentiation import differentiation
+
+class Test(unittest.TestCase):
+
+
+    def testDifferentiation(self):
+        np.testing.assert_array_equal(differentiation([1,2,1,0,1,1]), [1,0,-1,0,.5,0])
+        
+
+
+if __name__ == "__main__":
+    #import sys;sys.argv = ['', 'Test.testDifferentiation']
+    unittest.main()
\ No newline at end of file
diff --git a/wetb/signal/tests/test_fit.py b/wetb/signal/tests/test_fit.py
index ecdfd2cc69796b268d7351a376552d2d401a23ef..92c2c269a7759a9bfaeea492ff5e111c3d8a215d 100644
--- a/wetb/signal/tests/test_fit.py
+++ b/wetb/signal/tests/test_fit.py
@@ -10,6 +10,7 @@ import os
 import unittest
 from wetb.signal.fit import fourier_fit
 from wetb.signal.error_measures import rms
+from wetb.signal.fit import spline_fit
 tfp = os.path.join(os.path.dirname(__file__), 'test_files/')
 
 class TestFit(unittest.TestCase):
@@ -88,11 +89,11 @@ class TestFit(unittest.TestCase):
         x,y = ds('Wsp_metmast'), ds('Power')
         if 0:
             import matplotlib.pyplot as plt
-            fx, fy = perpendicular_bin_fit(x,y,30,plt=plt)
+            fx, fit = perpendicular_bin_fit(x,y,30,plt=plt)
             plt.show()
 
         else:
-            fx, fy = perpendicular_bin_fit(x,y,30)
+            fx, fit = perpendicular_bin_fit(x,y,30)
         self.assertEqual(len(fx), 30)
             
             
@@ -143,6 +144,24 @@ class TestFit(unittest.TestCase):
 #         plt.plot(fourier_fit.F2x(np.fft.fft(y) / len(y)), label='fft')
 #         plt.legend()
 #         plt.show()
+
+    def test_spline(self):
+        
+        x = np.random.randint(0,100,10)
+        t = np.arange(0,100,10)
+        
+        t_ = np.arange(100)
+        spline = spline_fit(t,x)
+        acc_lin = np.diff(np.diff(np.interp(t_, t,x)))
+        acc_spline = np.diff(np.diff(spline(t_)))
+        self.assertLess(np.abs(acc_spline).max(), np.abs(acc_lin).max())
+        if 0:
+            import matplotlib.pyplot as plt
+            plt.plot(t,x,'.',label='points')
+            plt.plot(t_, spline(t_),label='spline')
+            plt.legend()
+            plt.show()
+
 if __name__ == "__main__":
     #import sys;sys.argv = ['', 'Test.testName']
     unittest.main()
\ No newline at end of file
diff --git a/wetb/signal/tests/test_fix.py b/wetb/signal/tests/test_fix.py
new file mode 100644
index 0000000000000000000000000000000000000000..8663986285a6fdb9f3a37f487b751b619bd9cc83
--- /dev/null
+++ b/wetb/signal/tests/test_fix.py
@@ -0,0 +1,48 @@
+'''
+Created on 30. mar. 2017
+
+@author: mmpe
+'''
+import os
+import unittest
+from wetb import gtsdf
+from wetb.signal.fix._rotor_position import fix_rotor_position, find_fix_dt
+from wetb.signal.filters._differentiation import differentiation
+
+
+tfp = os.path.join(os.path.dirname(__file__), 'test_files/')
+import numpy as np
+class TestFix(unittest.TestCase):
+
+
+    def testRotorPositionFix(self):
+        ds = gtsdf.Dataset(tfp+'azi.hdf5')
+        sample_frq = 25
+         
+        #import matplotlib.pyplot as plt
+        #print (find_fix_dt(ds.azi, sample_frq, ds.Rot_cor, plt))
+        rp_fit = fix_rotor_position(ds.azi, sample_frq, ds.Rot_cor)
+                  
+        rpm_pos = differentiation(rp_fit)%180 / 360 * sample_frq * 60
+        err_sum = np.sum((rpm_pos - ds.Rot_cor)**2)
+         
+        self.assertLess(err_sum,40)
+        if 0:
+            import matplotlib.pyplot as plt
+            t = ds.Time-ds.Time[0]
+            plt.plot(t, differentiation(ds.azi)%180 / 360 * sample_frq * 60, label='fit')
+            plt.plot(t, ds.Rot_cor)
+            plt.plot(t, differentiation(rp_fit)%180 / 360 * sample_frq * 60, label='fit')
+            plt.ylim(10,16)
+            plt.show()
+    
+    def test_find_fix_dt(self):
+        ds = gtsdf.Dataset(tfp+'azi.hdf5')
+        sample_frq = 25
+         
+        self.assertEqual(find_fix_dt(ds.azi, sample_frq, ds.Rot_cor), 4)
+        
+
+if __name__ == "__main__":
+    #import sys;sys.argv = ['', 'Test.testRotorPositionFix']
+    unittest.main()
\ No newline at end of file
diff --git a/wetb/signal/tests/test_frq_filters.py b/wetb/signal/tests/test_frq_filters.py
new file mode 100644
index 0000000000000000000000000000000000000000..b4537de2c1f7986c67204db1046a22c1a5277247
--- /dev/null
+++ b/wetb/signal/tests/test_frq_filters.py
@@ -0,0 +1,94 @@
+'''
+Created on 27. mar. 2017
+
+@author: mmpe
+'''
+import unittest
+
+import numpy as np
+from wetb.signal.filters.frq_filters import sine_generator, low_pass, \
+    frequency_response, high_pass
+
+
+class Test(unittest.TestCase):
+
+
+    def test_sine_generator(self):
+        t,y = sine_generator(10,1,2)
+        self.assertEqual(np.diff(t).mean(),.1)
+        self.assertAlmostEqual(t.max(),1.9)
+        if 0:
+            import matplotlib.pyplot as plt
+            plt.plot(*sine_generator(10,1,2), label="1Hz sine")
+            plt.plot(*sine_generator(100,2,2), label="2Hz sine")
+            plt.legend()
+            plt.show()
+    
+    def test_low_pass(self):
+        sf = 100 # sample frequency
+        t,y1 = sine_generator(sf,1,5) # 1Hz sine
+        t,y10 = sine_generator(sf,10,5) # 10Hz sine
+        sig = y1+y10
+        y_lp = low_pass(sig, sf, 1, order=1)
+        
+        # 1 order: 
+        # cut off frq: -3db
+        # Above cut off: 20db/decade 
+        np.testing.assert_almost_equal(y_lp[100:400], y1[100:400]*.501, 1)
+        np.testing.assert_almost_equal((y_lp-y1*.501)[100:400], y10[100:400]*.01, 1)
+        
+        if 0:
+            import matplotlib.pyplot as plt
+            plt.plot(t,sig, label='Input signal')
+            plt.plot(t, y1*0.501, label='1Hz sine (-3db)')
+            plt.plot(t,y_lp, label='Output signal')
+            plt.plot(t,y_lp - y1*0.501, label="Output - 1Hz sine(-3db)")
+            plt.plot(t, y10*0.01, label='10Hz sine (-20db)')
+            plt.plot(t, y_lp - y1*0.501 -  y10*.01, label="(Output - 1Hz sine(-3db)) - 10Hz sine (-20db)")
+            plt.legend()
+            plt.show()
+            
+    def test_frq_response(self):
+        w,h = frequency_response(100,10,'low',1)
+        self.assertAlmostEqual(np.interp(10, w, h), -3.01,2) # cut off frq -3.01 db
+        self.assertAlmostEqual(np.interp(100, w, h), -20,1) # -20 db per decade
+        if 0:
+            import matplotlib.pyplot as plt
+            frequency_response(100,10,'low',1, plt=plt)
+            frequency_response(100,10,'low',2, plt=plt)
+            frequency_response(100,10,'low',5, plt=plt)
+            frequency_response(100,10,'low',8, plt=plt)
+            frequency_response(100,10,'low',10, plt=plt)
+            frequency_response(100,10,'high',1, plt=plt)
+            frequency_response(100,10,'high',2, plt=plt)
+            plt.show()
+        
+    def test_high_pass(self):
+        sf = 100 # sample frequency
+        t,y1 = sine_generator(sf,1,5) # 1Hz sine
+        t,y10 = sine_generator(sf,10,5) # 10Hz sine
+        sig = y1+y10
+        y_lp = high_pass(sig, sf, 10, order=1)
+        
+        # 1 order: 
+        # cut off frq: -3db
+        # Below cut off: 20db/decade 
+        np.testing.assert_almost_equal(y_lp[100:400], y10[100:400]*.501, 1)
+        np.testing.assert_almost_equal((y_lp-y10*.501)[100:400], y1[100:400]*.01, 1)
+        
+        if 0:
+            import matplotlib.pyplot as plt
+            plt.plot(t,sig, label='Input signal')
+            plt.plot(t, y10*0.501, label='10Hz sine (-3db)')
+            plt.plot(t,y_lp, label='Output signal')
+            plt.plot(t,y_lp - y10*0.501, label="Output - 10Hz sine(-3db)")
+            plt.plot(t, y1*0.01, label='1Hz sine (-20db)')
+            plt.plot(t, y_lp - y10*0.501 -  y1*.01, label="(Output - 10Hz sine(-3db)) - 1Hz sine (-20db)")
+            plt.legend()
+            plt.show()
+         
+            
+
+if __name__ == "__main__":
+    #import sys;sys.argv = ['', 'Test.test_sine_generator']
+    unittest.main()
\ No newline at end of file
diff --git a/wetb/signal/tests/test_interpolation.py b/wetb/signal/tests/test_interpolation.py
new file mode 100644
index 0000000000000000000000000000000000000000..6fb71e8131a5d0f3765d25c154fd3910c2e410ca
--- /dev/null
+++ b/wetb/signal/tests/test_interpolation.py
@@ -0,0 +1,104 @@
+'''
+Created on 19/12/2014
+
+@author: MMPE
+'''
+import unittest
+
+from matplotlib.pyplot  import *
+import numpy as np
+from wetb import signal
+from wetb import gtsdf
+import os
+from wetb.gtsdf.unix_time import from_unix
+import datetime
+
+
+class TestInterpolation(unittest.TestCase):
+
+    def test_interpolate1(self):
+        x = [1, 1.5, 2, 3]
+        xp = [0.5, 1.5, 3]
+        yp = [5, 15, 30]
+        np.testing.assert_array_equal(signal.interpolate(x, xp, yp), [10., 15., 20, 30.])
+        np.testing.assert_array_equal(signal.interpolate(x, xp, yp, 1), [10., 15., np.nan, 30.])
+
+
+
+
+    def test_interpolate2(self):
+        x = np.arange(0, 100, 5, dtype=np.float)
+        xp = np.arange(0, 100, 10, dtype=np.float)
+        xp = np.r_[xp[:3], xp[5:]]
+        yp = np.arange(10, dtype=np.float)
+        yp[7:8] = np.nan
+        yp = np.r_[yp[:3], yp[5:]]
+
+        #x = [ 0.   5.  10.  15.  20.  25.  30.  35.  40.  45.  50.  55.  60.  65.  70.  75.  80.  85.  90.  95.]
+        #xp = [0.0, 10.0, 20.0, 50.0, 60.0, 70.0, 80.0, 90.0]
+        #yp = [0.0, 1.0, 2.0, 5.0, 6.0, nan, 8.0, 9.0]
+
+        y = signal.interpolate(x, xp, yp)
+        np.testing.assert_array_equal(y[~np.isnan(y)], [0., 0.5, 1. , 1.5, 2. , 2.5, 3. , 3.5, 4. , 4.5, 5. , 5.5, 8. , 8.5, 9. ])
+
+        y = signal.interpolate(x, xp, yp, 10)
+        np.testing.assert_array_equal(y[~np.isnan(y)], [ 0. , 0.5, 1. , 1.5, 2. , 5. , 5.5, 8. , 8.5, 9. ])
+
+
+
+    def test_interpolate_max_dydxp(self):
+        x = np.arange(7)
+        xp = [0, 2, 4, 6]
+        yp = [358, 359, 0, 1]
+        y = signal.interpolate(x, xp, yp, max_dydxp=30)
+        np.testing.assert_array_equal(y, [ 358., 358.5, 359., np.nan, 0., 0.5, 1. ])
+
+        y = signal.interpolate(x, xp, yp, max_dydxp=180)
+        np.testing.assert_array_equal(y, [ 358., 358.5, 359., 179.5, 0., 0.5, 1. ])
+
+
+    def test_interpolate_max_dydxp_cyclic(self):
+        x = np.arange(7)
+        xp = [0, 2, 4, 6]
+        yp = [358, 359, 0, 1]
+
+        y = signal.interpolate(x, xp, [178, 179, -180, -179], max_dydxp=30, cyclic_range=360)
+        np.testing.assert_array_equal(y, [ 178. , 178.5, 179. , -0.5, -180. , -179.5, -179. ])
+
+        y = signal.interpolate(x, xp, yp, max_dydxp=30, cyclic_range=360)
+        np.testing.assert_array_equal(y, [ 358., 358.5, 359., 359.5, 0., 0.5, 1. ])
+
+        y = signal.interpolate(xp, x, [ 358., 358.5, 359., 359.5, 0., 0.5, 1. ], max_dydxp=30, cyclic_range=360)
+        np.testing.assert_array_equal(y, [ 358., 359., 0., 1. ])
+
+        y = signal.interpolate(x, xp, yp, max_dydxp=180)
+        np.testing.assert_array_equal(y, [ 358., 358.5, 359., 179.5, 0., 0.5, 1. ])
+
+    def test_interpolate_max_repeated(self):
+        x = np.arange(7)
+        xp = [0, 1, 2, 3, 4, 5, 6]
+        yp = [4, 5, 5, 5, 6, 6, 7]
+        y = signal.interpolate(x, xp, yp, max_repeated=2)
+        np.testing.assert_array_equal(y, [ 4, 5, np.nan, np.nan, 6, 6, 7])
+
+
+        x = np.arange(7)
+        xp = [0, 3, 4, 5, 6]
+        yp = [5, 5, 7, 6, 6]
+        y = signal.interpolate(x, xp, yp, max_repeated=2)
+        np.testing.assert_array_equal(y, [ 5, np.nan, np.nan, np.nan, 7, 6, 6])
+
+        xp = [0, 2, 3, 4, 6]
+        y = signal.interpolate(x, xp, yp, max_repeated=1)
+        np.testing.assert_array_equal(y, [ 5, np.nan, np.nan, 7, 6, np.nan, np.nan])
+
+
+        xp = [0, 1, 2, 3, 6]
+        y = signal.interpolate(x, xp, yp, max_repeated=2)
+        np.testing.assert_array_equal(y, [ 5, 5, 7, 6, np.nan, np.nan, np.nan])
+
+
+
+if __name__ == "__main__":
+    #import sys;sys.argv = ['', 'Test.testName']
+    unittest.main()
diff --git a/wetb/signal/tests/test_nan_replace.py b/wetb/signal/tests/test_nan_replace.py
new file mode 100644
index 0000000000000000000000000000000000000000..6211ce029a04ee604af3a3589f0df31ffe3838f5
--- /dev/null
+++ b/wetb/signal/tests/test_nan_replace.py
@@ -0,0 +1,66 @@
+'''
+Created on 02/11/2015
+
+@author: MMPE
+'''
+import unittest
+import numpy as np
+from wetb.signal.nan_replace import replace_by_mean, replace_by_line, \
+    replace_by_polynomial, max_no_nan
+from matplotlib.pyplot import plot, show
+class TestNan_replace(unittest.TestCase):
+
+
+    def test_nan_replace_by_mean(self):
+        a = np.array([1, 5, 6, 4, 5, np.nan, 3, 1, 5, 6, 4.])
+        np.testing.assert_array_equal(replace_by_mean(a), [1, 5, 6, 4, 5, 4, 3, 1, 5, 6, 4.])
+        a = np.array([1, 5, 6, 4, 5, np.nan, np.nan, 1, 5, 6, 4.])
+        np.testing.assert_array_equal(replace_by_mean(a), [1, 5, 6, 4, 5, 3, 3, 1, 5, 6, 4.])
+        a = np.array([np.nan, 5, 6, 4, 5, np.nan, 3, 1, 5, 6, np.nan])
+        np.testing.assert_array_equal(replace_by_mean(a), [5, 5, 6, 4, 5, 4, 3, 1, 5, 6, 6])
+
+
+    def test_nan_replace_by_line(self):
+        a = np.array([1, 5, 6, 4, 5, np.nan, 3, 1, 5, 6, 4.])
+        np.testing.assert_array_equal(replace_by_line(a), [1, 5, 6, 4, 5, 4, 3, 1, 5, 6, 4.])
+        a = np.array([1, 5, 6, 4, 5, np.nan, np.nan, 2, 5, 6, 4.])
+        np.testing.assert_array_equal(replace_by_line(a), [1, 5, 6, 4, 5, 4, 3, 2, 5, 6, 4.])
+        a = np.array([np.nan, 5, 6, 4, 5, np.nan, 3, 1, 5, 6, np.nan])
+        np.testing.assert_array_equal(replace_by_line(a), [5, 5, 6, 4, 5, 4, 3, 1, 5, 6, 6])
+
+
+    def test_nan_replace_by_polynomial(self):
+        a = np.array([np.nan, 5, 6, 4, 5, np.nan, 3, 1, 5, 6, np.nan])
+        np.testing.assert_array_equal(replace_by_polynomial(a), [5, 5, 6, 4, 5, 4, 3, 1, 5, 6, 6])
+        a = np.array([1, 5, 6, 4, 5, np.nan, np.nan, 1, 5, 6, 4.])
+        np.testing.assert_array_almost_equal(replace_by_polynomial(a, 3, 2), [1, 5, 6, 4, 5, 3.3, 1.2, 1, 5, 6, 4.])
+
+        if 0:
+            plot(a)
+            plot(replace_by_polynomial(a, 3, 2))
+            show()
+
+
+    def test_nan_replace_by_polynomial2(self):
+        a = np.r_[np.arange(10), np.repeat(np.nan, 100), 10 - np.arange(10)]
+        self.assertLessEqual(replace_by_polynomial(a, 3, 9).max(), np.nanmax(a))
+
+        if 0:
+            plot(a, '.r')
+            plot(replace_by_polynomial(a, 3, 9), 'g-')
+            show()
+
+
+    def test_max_no_nan(self):
+        a = np.array([1, 5, 6, 4, 5, np.nan, 3, 1, 5, np.nan, 4.])
+        self.assertEqual(max_no_nan(a), 1)
+        a = np.array([1, 5, 6, 4, 5, np.nan, np.nan, 1, 5, np.nan, 4.])
+        self.assertEqual(max_no_nan(a), 2)
+        a = np.array([np.nan, np.nan, np.nan, 4, 5, np.nan, np.nan, 1, 5, np.nan, 4.])
+        self.assertEqual(max_no_nan(a), 3)
+        a = np.array([1, 5, 6, 4, 5, np.nan, 4, 1, 5, np.nan, np.nan])
+        self.assertEqual(max_no_nan(a), 2)
+
+if __name__ == "__main__":
+    #import sys;sys.argv = ['', 'Test.test_nanreplace']
+    unittest.main()
diff --git a/wetb/signal/tests/test_subset_mean.py b/wetb/signal/tests/test_subset_mean.py
index 21f92445cba215d4e75357457e376fa85da1873a..23642ae7509bc80188499122807d5b22ddfce2fc 100644
--- a/wetb/signal/tests/test_subset_mean.py
+++ b/wetb/signal/tests/test_subset_mean.py
@@ -9,7 +9,7 @@ import unittest
 import numpy as np
 from wetb import gtsdf
 from wetb.signal.subset_mean import time_trigger, subset_mean, \
-    non_nan_index_trigger, revolution_trigger
+    non_nan_index_trigger, revolution_trigger_old, revolution_trigger
 from wetb.utils.geometry import rpm2rads
 
 
@@ -68,10 +68,10 @@ class TestSubsetMean(unittest.TestCase):
         ds = gtsdf.Dataset(tfp+'azi.hdf5')
         azi, rpm, time = [ds(x)[8403:8803] for x in ['azi','Rot_cor','Time']]
         
-        trigger = revolution_trigger(azi)
+        trigger = revolution_trigger_old(azi)
         np.testing.assert_array_equal(trigger, [ 17, 128, 241, 354])
         azi[64] = 358
-        trigger = revolution_trigger(azi, (ds('Rot_cor'), np.diff(time).mean()))
+        trigger = revolution_trigger_old(azi, (ds('Rot_cor'), np.diff(time).mean()))
         
 #         import matplotlib.pyplot as plt
 #         t = np.arange(len(azi))
@@ -82,5 +82,31 @@ class TestSubsetMean(unittest.TestCase):
         np.testing.assert_array_equal(trigger, [ (128,241),(241,354)])
 
 
+    def test_revolution_trigger(self):
+        rotor_position = np.arange(0.,360*10,4)
+        rotor_position += np.random.random(len(rotor_position))
+        rotor_position = rotor_position % 360
+        if 0:
+            x1 = np.random.randint(0, len(rotor_position),10)
+            print (list(x1))
+            x2 = np.random.randint(0, len(rotor_position),10)
+            print (list(x2))
+        else:
+            x1 = [447, 854, 595, 804, 847, 488, 412, 199, 675, 766]
+            x2 = [92, 647, 821, 422, 33, 159, 369, 99, 157, 464]
+            
+        rotor_position[x1] += 360
+        rotor_position[x2] -= 360
+        rotor_position[90] = 180
+        
+        indexes = revolution_trigger(rotor_position, 20,1/(90/20/60))
+        np.testing.assert_array_equal(indexes, [ 91, 180, 270, 360, 450, 540, 630, 720, 810])
+        if 0:
+            import matplotlib.pyplot as plt
+            plt.plot(rotor_position)
+            plt.plot(indexes, np.zeros_like(indexes),'.')
+            plt.show()
+        
+
 if __name__ == "__main__":
     unittest.main()
diff --git a/wetb/wind/shear.py b/wetb/wind/shear.py
index dd6122470e3a5a460660b7673371fb9042a147dd..dd3281b0ff5139253d76487a7be6893ad538e6f2 100644
--- a/wetb/wind/shear.py
+++ b/wetb/wind/shear.py
@@ -99,7 +99,7 @@ def fit_power_shear_ref(z_u_lst, z_ref, plt=None):
     """
     def shear_error(x, z_u_lst, z_ref):
         alpha, u_ref = x
-        return np.sum([(u - u_ref * (z / z_ref) ** alpha) ** 2 for z, u in z_u_lst])
+        return np.nansum([(u - u_ref * (z / z_ref) ** alpha) ** 2 for z, u in z_u_lst])
     z_u_lst = [(z, np.mean(u)) for z, u in z_u_lst]
     alpha, u_ref = fmin(shear_error, (.1, 10), (z_u_lst, z_ref), disp=False)
     if plt:
@@ -107,6 +107,9 @@ def fit_power_shear_ref(z_u_lst, z_ref, plt=None):
         plt.plot(u, z, '.')
         z = np.linspace(min(z), max(z), 100)
         plt.plot(power_shear(alpha, z_ref, u_ref)(z), z)
+        plt.margins(.1)
+    if alpha==.1 and u_ref==10: # Initial conditions
+        return np.nan, np.nan
     return alpha, u_ref
 
 
diff --git a/wetb/wind/tests/test_Shear.py b/wetb/wind/tests/test_Shear.py
index 38f1d0db03c0148b86911304d103f607aa43108e..44a369a2cbac3cb665138272089a69f242935d7e 100644
--- a/wetb/wind/tests/test_Shear.py
+++ b/wetb/wind/tests/test_Shear.py
@@ -49,6 +49,24 @@ class TestShear(unittest.TestCase):
         14: WSP gl. coo.,Vz 21
         """
 
+    def test_power_shear_fit(self):
+        z = [30,50,70]
+        a,u_ref = .3,10
+        u = power_shear(a,50,u_ref)(z)
+        np.testing.assert_array_almost_equal(fit_power_shear_ref(zip(z,u), 50), [a,u_ref],3)
+        if 0:
+            import matplotlib.pyplot as plt
+            fit_power_shear_ref(zip(z,u), 50, plt)
+            plt.show()
+        
+    def test_power_shear_fit_nan(self):
+        z = [30,50,70]
+        a,u_ref = .3,10
+        u = power_shear(a,50,u_ref)(z)
+        u[2] = np.nan
+        np.testing.assert_array_almost_equal(fit_power_shear_ref(zip(z,u), 50), [a,u_ref],3)
+        u[:] = np.nan
+        np.testing.assert_array_almost_equal(fit_power_shear_ref(zip(z,u), 50), [np.nan, np.nan],3)
 
     def test_power_shear(self):
         if all: