Ejemplo n.º 1
0
    def absorptive_helper(self, array, axes, window_function="none", window_length=0):
        """
        helper function for absorptive

        This is a function to Fourier Transform experimental 2DIR spectra, ie, spectra with a time and frequency axis. It basically repeats the Fourier function for all pixels.

        INPUT:
        - array (numpy.ndarray): a 2d array of time * pixels
        - window_function (name, "none"): "none", "guassian" etc
        - window_length (int, 0): length of the window. 0 means the whole range
        - flag_plot (BOOL, False): will plot the windowed time domain

        CHANGELOG:
        20101204/RB: started as fourier_helper
        20110909/RB: continued
        20130131/RB: re-implemented as absorptive-helper. The FFT is now done in this function instead of in the Mathematics module. That function had a load of overhead which was not needed.
        
        """

        x, y = numpy.shape(array)

        if axes == 2 or axes == [1, 1]:
            array[:, 0] /= 2
            array[0, :] /= 2

            # prepare output
            # it needs to have the correct size and it should be complex
            if self.zeropad_to != None:
                x = self.zeropad_to
            ft_array = numpy.reshape(numpy.zeros(x * y, dtype=numpy.cfloat), (x, y))

            # do fft
            if window_function != "none":
                self.printWarning("No 2D window functions have been implemented", inspect.stack())

            ft_array[:, :] = numpy.fft.fft2(array, n=self.zeropad_to)

        else:

            if axes == 1 or axes == [0, 1]:
                array = array.T

            # prepare output
            # it needs to have the correct size and it should be complex
            if self.zeropad_to != None:
                x = self.zeropad_to
            ft_array = numpy.reshape(numpy.zeros(x * y, dtype=numpy.cfloat), (x, y))

            # do fft
            for i in range(y):
                array[:, i] /= 2  # correct first element
                if window_function != "none":
                    array[:, i] = MATH.window_functions(array[:, i], window_function, window_length)
                ft_array[:, i] = numpy.fft.fft(array[:, i], n=self.zeropad_to)

            if axes == 1 or axes == [0, 1]:
                ft_array = ft_array.T

        return ft_array
Ejemplo n.º 2
0
def calculate_gvd(range_L, n_steps, SC):
    """
    Function to calculate the Group Velocity (VG) and Group Velocity Dispersion (GVD) using the Sellmeier Equation.
    
    The index of refraction as a function of wavelength is described by the Sellmeier equation. The VG is the first derivative of this, the GVD the second derivative. 
    
    This is calculated using a fairly simple (y2-y1)/(x2-x1) calculation. To accomodate this, these are all calculated for a range of values.
    
    CHANGELOG:
    20110909/RB: started
    20150805/RB: copied to Crocodile. Added documentation. 
    
    INPUT:
    range_L (array, 2 elements): minimum and maximum in micron
    n_steps (int): number of steps for the calculation. It is best to use a large number of steps. 
    SC (array): Sellmeier Coefficients
    
    OUPUT:
    n_x: x-axis for Sellmeier (wavelengths in micron) 
    n_y: index of refraction
    vg_x: x-axis (wavelengths in nm) for group velocity
    vg_y: group velocity
    gvd_x: x-axis (wavelengths in nm) 
    gvd_y: group velocity dispersion
    
    """

    # calculate the index of refraction over the defined range
    n_x = numpy.linspace(range_L[0], range_L[1], num = n_steps)
    n_y = E.Sellmeier(SC, n_x)
    
    # calculate the derivatives
    [d1x, d1y] = numpy.array(M.derivative(n_x, n_y))
    [d2x, d2y] = numpy.array(M.derivative(d1x, d1y))
    
    # define the x axes
    vg_x = d1x
    gvd_x = d2x
    
    vg_y = (C.c_ms / (vg_x)) / (1 - (vg_x / n_y[1:-1]) * d1y)
    gvd_y = (gvd_x**3/(2*numpy.pi*C.c_ms*C.c_ms)) * d2y
    
    gvd_y *= 1e21
    
    return n_x, n_y, vg_x, vg_y, gvd_x, gvd_y
Ejemplo n.º 3
0
    def find_w1_peaks(self, flag_verbose = False):

        data = self.mess.s[self.w1_peaks_y_i[0]:self.w1_peaks_y_i[1], self.w1_peaks_x_i[0]:self.w1_peaks_x_i[1]]
        y_axis = self.mess.s_axis[0][self.w1_peaks_y_i[0]:self.w1_peaks_y_i[1]]        

        y = numpy.sum(data,1)

        A_out = MATH.fit(y_axis, y, EQ.rb_lorentzian, self.w1_peaks_A_in)

        self.w1_peaks[0] = A_out[1]
Ejemplo n.º 4
0
    def fit_double_lorentzian(self, flag_plot = False, flag_verbose = False):
        """
        For a selection of points on the w1-axis, take a cut (giving w3 vs z (intensity) plot) and fit it with a double Lorentzian. 
        self.dl_x_i[0] etc are the min/max indices to be fitted
        """

        if flag_verbose:
            self.verbose("Fit double Lorentzian for " + self.objectname, flag_verbose = flag_verbose)
            self.verbose("  x_min: " + str(self.dl_x_i[0]) + " " + str(self.mess.s_axis[2][self.dl_x_i[0]]), flag_verbose = flag_verbose)
            self.verbose("  x_max: " + str(self.dl_x_i[1]) + " " + str(self.mess.s_axis[2][self.dl_x_i[1]]), flag_verbose = flag_verbose)
            self.verbose("  y_min: " + str(self.dl_y_i[0]) + " " + str(self.mess.s_axis[0][self.dl_y_i[0]]), flag_verbose = flag_verbose)
            self.verbose("  y_max: " + str(self.dl_y_i[1]) + " " + str(self.mess.s_axis[0][self.dl_y_i[1]]), flag_verbose = flag_verbose)

        # select the part of the data to be fitted
        data = self.mess.s[self.dl_y_i[0]:self.dl_y_i[1], self.dl_x_i[0]:self.dl_x_i[1]]
        x_axis = self.mess.s_axis[2][self.dl_x_i[0]:self.dl_x_i[1]]
        y_axis = self.mess.s_axis[0][self.dl_y_i[0]:self.dl_y_i[1]]
        
        # arrays for the results
        n_y, n_x = numpy.shape(data)
        y_max = numpy.zeros(n_y)                # index of the maximum
        y_min = numpy.zeros(n_y)                # index of the minimum
        y_out_array = numpy.zeros((n_y, 8))     # fitting parameters

        if flag_plot:
            plt.figure()
            color_array = ["b", "g", "r", "c", "m", "y", "k"]

        # calculate the fit for the cut of w1
        for i in range(n_y):

            y = data[i,:]

            A_out = MATH.fit(x_axis, y, EQ.rb_two_lorentzians, self.dl_A_in)        

            y_out_array[i,:] = A_out

            x_fit = numpy.arange(x_axis[0], x_axis[-1], 0.1)
            y_fit = EQ.rb_two_lorentzians(A_out, x_fit)

            if flag_plot:  
                plt.plot(x_fit, y_fit, c = color_array[i%len(color_array)])
                plt.plot(x_axis, y, ":", c = color_array[i%len(color_array)])

            y_max[i] = x_fit[numpy.argmax(y_fit)]
            y_min[i] = x_fit[numpy.argmin(y_fit)]

        self.dl_ble = y_min
        self.dl_esa = y_max
        self.dl_A = y_out_array

        if flag_plot:
            plt.show()
Ejemplo n.º 5
0
    def fit_tilt(self, flag_verbose = False):

        if flag_verbose:
            self.verbose("Fit tilt for " + self.objectname, flag_verbose = flag_verbose)
            self.verbose("  x_min: " + str(self.dl_x_i[0]) + " " +  str(self.mess.s_axis[2][self.dl_x_i[0]]), flag_verbose = flag_verbose)
            self.verbose("  x_max: " + str(self.dl_x_i[1]) + " " +  str(self.mess.s_axis[2][self.dl_x_i[1]]), flag_verbose = flag_verbose)
            self.verbose("  y_min: " + str(self.dl_y_i[0] + self.l_i[0]) + " " +  str(self.mess.s_axis[0][self.dl_y_i[0] + self.l_i[0]]), flag_verbose = flag_verbose)
            self.verbose("  y_max: " + str(self.dl_y_i[0] + self.l_i[1]) + " " +  str(self.mess.s_axis[0][self.dl_y_i[0] + self.l_i[1]]), flag_verbose = flag_verbose)

        y = self.mess.s_axis[0][self.dl_y_i[0] + self.l_i[0]:self.dl_y_i[0] + self.l_i[1]]     

        x = self.dl_ble[self.l_i[0]:self.l_i[1]]
        self.l_A_ble = MATH.fit(x, y, EQ.linear, self.l_A_in)

        x = self.dl_esa[self.l_i[0]:self.l_i[1]]
        self.l_A_esa = MATH.fit(x, y, EQ.linear, self.l_A_in)

        self.l_angle_ble = 90 - numpy.arctan(self.l_A_ble[1]) * 180 / numpy.pi
        self.l_angle_esa = 90 - numpy.arctan(self.l_A_esa[1]) * 180 / numpy.pi

        self.l_slope_ble = 1 / self.l_A_ble[1]
        self.l_slope_esa = 1 / self.l_A_esa[1]
Ejemplo n.º 6
0
    def make_plot(self, ax = False, normalize = False, fit = False):
        """
        Make a plot of scan spectrum data. 
    
        INPUT:
        - ax (plt axis instance, or False): If False, a new figure and axis instance will be made. 
        - normalize (bool, False): If True, the minimum is subtract from the data, then it is divided by the maximum. 
        - fit (Bool, False): If True, a fit will be made and will also be plotted. The fitting parameters are written to the terminal. 
    
        CHANGELOG:
        201604-RB: started function
    
        """
        if ax == False:
            fig = plt.figure()
            ax = fig.add_subplot(111)
        
        if normalize:
            for ds in range(self.r_n[2]):
                self.r[:,0,ds,0,0,0,0,0] -= numpy.nanmin(self.r[:,0,ds,0,0,0,0,0])
                self.r[:,0,ds,0,0,0,0,0] /= numpy.nanmax(self.r[:,0,ds,0,0,0,0,0])

        ax.plot(self.r_axes[0], self.r[:,0,0,0,0,0,0,0], color = "g")
        ax.plot(self.r_axes[0], self.r[:,0,1,0,0,0,0,0], color = "r")
             
             
        
        if fit:
            colors = ["lightgreen", "orange"]
            labels = ["probe", "reference"]
            sigma = (self.r_axes[0][0] - self.r_axes[0][-1]) / 4

                      
            print("           mu       sigma   offset    scale")
            for ds in range(self.r_n[2]):
                A = [sigma, self.r_axes[0][numpy.argmax(self.r[:,0,ds,0,0,0,0,0])], 0, 1] # initial guess
            
                A_final = M.fit(self.r_axes[0], self.r[:,0,ds,0,0,0,0,0], EQ.rb_gaussian, A)
                ax.plot(self.r_axes[0], EQ.rb_gaussian(A_final, self.r_axes[0]), color = colors[ds])
                
                print("{label:10} {mu:.5}   {sigma:.3}   {offset:.3}   {scale:.3}".format(label = labels[ds], mu = A_final[1], sigma = A_final[0], offset = A_final[2], scale = A_final[3]))
Ejemplo n.º 7
0
def calculate_pulse_length(data, A = [], dt = CONST.hene_fringe_fs, plot_results = True, print_results = True, fwhm_limit = 200, mu_shift = 10, flag_recursive_limit = False):

    """
    Calculate the pulse length
    
    INPUT:
    data (array): the result of a measure phase measurement for one pulse pair. Usually measure phase is saved as two measurements of two pulse pairs. 
    A (list, default = []): [sigma, mu, offset, scale, frequency, phase] if A is empty, some reasonable default values are used.
    dt (float, HeNe-fringe in fs): to convert from indices to time
    plot (BOOL, True): plot the results
    print_res (BOOL, True): print the results
    fwhm_limit (float, 200): if FWHM is above this limit, it will try again by shifting the mean a bit (by mu_shift)
    mu_shift (float, 10): shift the mean a bit
    flag_recursive_limit (BOOL, False): function will try again if set to False. To prevent endless recursion.
    
    OUTPUT:
    - the output can be plotted to confirm the fit
    - the fitting results can be printed
    - the FWHM is returned
    
    CHANGELOG:
    20130408/RB: started function
    """

    # input for a single IR pulse    
    if A == []:
        A = default_A()
    
    data /= numpy.amax(data)
    
    # make the time axis
    t = numpy.arange(len(data)) - len(data)/2
    t *= dt
    
    # fit the single pulse by convoluting it with itself and fitting it to the data
    A_out = MA.fit(t, data, fit_convolve, A)
    
    # calculate the fitted pulse and convoluted pulse
    y_single = pulse(A_out, t)
    y_conv = fit_convolve(A_out, t)

    # calculate the envelope
    sigma = A_out[0] 
    mu = A_out[1]
    offset = A_out[2] 
    scale = A_out[3] 
    A = [sigma, mu, offset, scale]
    y_env = envelope(A,t)

    # for the FWHM we need a higher time resolution
    t2 = numpy.arange(len(data)*10) - 5*len(data)
    t2 *= dt / 10
    y_fwhm = envelope(A,t2)
     # use the envelope to calculate the FWHM
    # make it positive
    if y_fwhm[int(len(t2)/2)] < 0:
        y_fwhm = -y_fwhm
    max_fwhm = numpy.amax(y_fwhm)
    # select the part of the list
    l = numpy.where(y_fwhm > max_fwhm/2)[0]
    # the length of the list in indices, multiply with time distance
    FWHM = len(l) * dt / 10
 
    if FWHM > fwhm_limit and flag_recursive_limit == False:
        # FWHM is above the limit, try again by shifting the mean a bit
        print("Trying again...")
        A = default_A()
        A[1] = mu_shift
        FWHM = calculate_pulse_length(data, A = A, dt = dt, plot_results = plot_results, print_results = print_results, flag_recursive_limit = True)
    
    else:
        # yay! a reasonable result. plot and print the results.
        if plot_results:
            plot_res(t, data, y_conv, y_single, y_env)
        if print_results:
            print_res(A_out, FWHM, dt)
    
    return FWHM
Ejemplo n.º 8
0
 def test_fit(self):
     x = numpy.arange(10)
     y = numpy.sin(x)
     A = [0,1,2,3]
     A = MATH.fit(x, y, EQ.rb_cos, A)
     print(A)
Ejemplo n.º 9
0
    def super_absorptive(self, axes, window_function="none", window_length=0, flag_verbose=False):
        """
        Calculate the absorptive spectrum.
        
        This function does the Fourier transform. It phases the spectrum. It makes the axes.
        
        INPUT:
        - axes (number or list): 0 or [1,0] for first axis, 1 or [0,1] for second axis, 2 or [1,1] for both axes
        - window_function (name, "none"): "none", "guassian" etc
        - window_length (int, 0): length of the window. 0 means the whole range
        - flag_plot (BOOL, False): will plot the windowed time domain
        
        CHANGELOG:
        20101204/RB: started
        20110909/RB: continued 
        20130131/RB: copied from croc to Crocodile. The function should now work for time-freq, freq-time and time-time domain. Only the FFT will give an error, the other problems give a warning.
        20130208/RB: now checks used variables before the calculation instead of try/except during the calculation
        
        WARNING:
        Realistically, only the time-freq FFT is performed. The others may have problems.
        
        """

        self.verbose("Super absorptive", flag_verbose)

        # VARIABLE CHECKING

        # r should be a list with numpy.ndarrays
        # if not the case, return False
        if type(self.r) != list:
            self.printError("r should be a list.", inspect.stack())
            return False
        elif type(self.r[0]) != numpy.ndarray or type(self.r[1]) != numpy.ndarray:
            self.printError("r[0] or r[1] should be a numpy.ndarray. Did you assign r?", inspect.stack())
            return False

        # r_axis should be a list
        # index 0 and 2 should be a numpy.ndarray
        # if not the case, skip making the axes
        flag_axis = True
        if type(self.r_axis) != list:
            flag_axis = False
            self.printWarning("r_axis should be a list. s_axis will not be calculated.", inspect.stack())
        elif type(self.r_axis[0]) != numpy.ndarray or type(self.r_axis[2]) != numpy.ndarray:
            flag_axis = False
            self.printWarning(
                "r_axis[0] or r_axis[2] should be a numpy.ndarray. s_axis will not be calculated.", inspect.stack()
            )

        # undersampling has to be an integer
        # if it is a BOOL, it can be converted to 0 or 1
        if type(self.undersampling) == bool:
            if self.undersampling:
                self.undersampling = 1
            else:
                self.undersampling = 0
            self.printWarning("undersampling is a BOOL, will use " + str(self.undersampling), inspect.stack())
        if type(self.undersampling) != int:
            self.printError("undersampling is NaN, not a valid value. ", inspect.stack())
            return False

        # the phase should not be a numpy.nan
        if numpy.isnan(self.phase_degrees):
            self.printError("phase_degrees is NaN, not a valid value. ", inspect.stack())
            return False

        # ACTUAL FUNCTION

        # do the FFT
        try:
            for i in range(len(self.r)):
                self.f[i] = self.absorptive_helper(
                    array=numpy.copy(self.r[i]), axes=axes, window_function=window_function, window_length=window_length
                )
        except ValueError:
            self.printError("Problem with the Fourier Transforms. Are r[0] and r[1] assigned?", inspect.stack())
            return False

        self.verbose("  done with FFT", flag_verbose)

        # phase the spectrum
        self.s = numpy.real(numpy.exp(1j * self.phase_rad) * self.f[0] + numpy.exp(-1j * self.phase_rad) * self.f[1])

        # select part of the data
        # calculate the axes
        if axes == 0 or axes == [1, 0] or axes == 2 or axes == [1, 1]:
            if self.undersampling % 2 == 0:
                self.f[0] = self.f[0][: (len(self.f[0]) / 2)][:]
                self.f[1] = self.f[1][: (len(self.f[1]) / 2)][:]
                self.s = self.s[: (len(self.s) / 2)][:]
            else:
                self.f[0] = self.f[0][(len(self.f[0]) / 2) :][:]
                self.f[1] = self.f[1][(len(self.f[1]) / 2) :][:]
                self.s = self.s[(len(self.s) / 2) :][:]

            if flag_axis:
                self.s_axis[0] = MATH.make_ft_axis(
                    length=2 * numpy.shape(self.s)[0],
                    dt=self.r_axis[0][1] - self.r_axis[0][0],
                    undersampling=self.undersampling,
                )
                self.s_axis[0] = self.s_axis[0][0 : len(self.s_axis[0]) / 2]

        if axes == 1 or axes == [0, 1] or axes == 2 or axes == [1, 1]:
            if self.undersampling % 2 == 0:
                self.f[0] = self.f[0][:][: (len(self.f[0]) / 2)]
                self.f[1] = self.f[1][:][: (len(self.f[1]) / 2)]
                self.s = self.s[:][: (len(self.s) / 2)]
            else:
                self.f[0] = self.f[0][:][(len(self.f[0]) / 2) :]
                self.f[1] = self.f[1][:][(len(self.f[1]) / 2) :]
                self.s = self.s[:][(len(self.s) / 2) :]

            if flag_axis:
                self.s_axis[2] = MATH.make_ft_axis(
                    length=2 * numpy.shape(self.s)[0],
                    dt=self.r_axis[2][1] - self.r_axis[2][0],
                    undersampling=self.undersampling,
                )
                self.s_axis[2] = self.s_axis[2][0 : len(self.s_axis[0]) / 2]

        if flag_axis:
            if axes == 0 or axes == [1, 0]:
                self.s_axis[2] = self.r_axis[2] + self.r_correction[2]

            if axes == 1 or axes == [0, 1]:
                self.s_axis[0] = self.r_axis[0] + self.r_correction[0]

        # add some stuff to self
        self.s_units = ["cm-1", "fs", "cm-1"]

        if flag_axis:
            self.s_resolution = [(self.s_axis[0][1] - self.s_axis[0][0]), 0, (self.s_axis[2][1] - self.s_axis[2][0])]

        return True