def proc_file(file):
        fobj = hsDat(file)

        vperp = fobj.dat[:, 0]
        elec3 = fobj.dat[:, 1]

        vperp_filt = signal.filtfilt(b1, a1, vperp)
        elec3_filt = signal.filtfilt(b2, a2, elec3)

        vperp_fft = np.fft.rfft(vperp_filt)
        elec3_fft = np.fft.rfft(elec3_filt)

        if plot_raw_dat:
            plt.plot(time_vec[:10000], vperp_filt[:10000])
            plt.figure()
            plt.loglog(freqs, np.abs(np.fft.rfft(vperp)))
            plt.loglog(freqs, np.abs(np.fft.rfft(vperp_filt)))
            plt.figure()
            plt.loglog(freqs, np.abs(np.fft.rfft(elec3)))
            plt.loglog(freqs, np.abs(np.fft.rfft(elec3_filt)))
            plt.show()

        fc = freqs[np.argmax(np.abs(vperp_fft))]
        #print fc

        inds1 = np.abs(freqs - fc) < 0.5 * bandwidth
        inds2 = np.abs(freqs - 0.5 * fc) < 0.25 * bandwidth

        dat_phase = np.angle(np.sum(vperp_fft[inds1]))
        drive_phase = np.angle(np.sum(elec3_fft[inds2]))

        drive_amp = np.abs(np.sum(elec3_fft[inds2])) * bu.fft_norm(
            nsamp, fsamp)

        p01 = [np.std(vperp_filt), fc, dat_phase, 0]
        popt1, pcov1 = opti.curve_fit(sine,
                                      time_vec,
                                      vperp_filt,
                                      p0=p01,
                                      maxfev=10000)
        #print popt1

        p02 = [np.std(elec3_filt), 0.5 * fc, drive_phase, 0]
        popt2, pcov2 = opti.curve_fit(sine,
                                      time_vec,
                                      elec3_filt,
                                      p0=p02,
                                      maxfev=10000)
        #print popt2

        drive_amp2 = np.abs(popt2[0])
        drive_phase2 = popt2[2]
        dat_phase2 = popt1[2]

        print(drive_amp / drive_amp2)

        if plot_raw_dat:
            plot_x = time_vec[:10000]
            plt.plot(plot_x, vperp_filt[:10000])
            plt.figure()
            plt.loglog(freqs, np.abs(np.fft.rfft(vperp)))
            plt.loglog(freqs, np.abs(np.fft.rfft(vperp_filt)))
            plt.figure()
            plt.loglog(freqs, np.abs(np.fft.rfft(elec3)))
            plt.loglog(freqs, np.abs(np.fft.rfft(elec3_filt)))
            plt.show()

        if plot_fit:
            plot_x = time_vec[:10000]
            plt.figure()
            plt.plot(plot_x, vperp_filt[:10000])
            plt.plot(plot_x, sine(plot_x, *p01))
            plt.plot(plot_x, sine(plot_x, *popt1))
            plt.figure()
            plt.plot(plot_x, elec3_filt[:10000])
            plt.plot(plot_x, sine(plot_x, *p02))
            plt.plot(plot_x, sine(plot_x, *popt2))
            plt.show()

        return [
            drive_amp, drive_phase, dat_phase, drive_amp2, drive_phase2,
            dat_phase2
        ]
Esempio n. 2
0
        def proc_file(file):
            fobj = bu.hsDat(file, load=True)

            vperp = fobj.dat[:, 0]
            elec3 = fobj.dat[:, 1]

            elec3_filt = signal.filtfilt(b2, a2, elec3)

            if plot_raw_dat:
                fac = bu.fft_norm(nsamp, fsamp)
                plt.plot(time_vec[:10000], elec3[:10000])
                plt.figure()
                plt.plot(time_vec[:10000], vperp[:10000])
                plt.figure()
                plt.loglog(freqs, fac * np.abs(np.fft.rfft(vperp)))
                plt.figure()
                plt.loglog(freqs, fac * np.abs(np.fft.rfft(elec3)))
                plt.loglog(freqs, fac * np.abs(np.fft.rfft(elec3_filt)))
                plt.show()

                input()

            inds = np.abs(freqs - fspin) < 200.0

            elec3_fft = np.fft.rfft(elec3)
            true_fspin = freqs[np.argmax(np.abs(elec3_fft))]

            amp, phase_mod = bu.demod(vperp, true_fspin, fsamp, plot=plot_demod, \
                                  filt=True, bandwidth=bandwidth, \
                                  notch_freqs=notch_freqs, notch_qs=notch_qs, \
                                  tukey=True, tukey_alpha=5.0e-4, \
                                  detrend=detrend, detrend_order=1, harmind=2.0, \
                                  force_2pi_wrap=force_2pi_wrap)

            phase_mod_filt = signal.filtfilt(b3, a3, phase_mod)
            #phase_mod_filt = phase_mod

            amp_asd = np.abs(np.fft.rfft(amp))
            phase_asd = np.abs(np.fft.rfft(phase_mod))
            phase_asd_filt = np.abs(np.fft.rfft(phase_mod_filt))

            # popt_n, pcov_n = opti.curve_fit(gauss, freqs[notch_fit_inds], \
            #                                     phase_asd_filt[notch_fit_inds], \
            #                                     p0=[10000, notch_init, 2, 0])

            if apply_notch:
                notch = freqs[np.argmax(phase_asd_filt * notch_fit_inds)]
                notch_digital = (2.0 / fsamp) * (notch)

                for i in range(notch_nharm):
                    bn, an = signal.iirnotch(notch_digital * (i + 1), notch_q)
                    phase_mod_filt = signal.lfilter(bn, an, phase_mod_filt)

            phase_asd_filt_2 = np.abs(np.fft.rfft(phase_mod_filt))

            if correct_noise_color:
                phase_asd = phase_asd * freqs**noise_color_power
                phase_asd_filt = phase_asd_filt * freqs**noise_color_power
                phase_asd_filt_2 = phase_asd_filt_2 * freqs**noise_color_power

            if plot_phase:
                plt.plot(freqs, phase_mod)
                plt.xlabel('Frequency [Hz]')
                plt.ylabel('Phase [rad]')
                plt.tight_layout()

                plt.figure()
                plt.loglog(freqs, phase_asd)
                plt.loglog(freqs, phase_asd_filt)
                plt.loglog(freqs, phase_asd_filt_2)
                plt.xlabel('Frequency [Hz]')
                plt.ylabel('Phase ASD [arb]')
                plt.tight_layout()

                plt.show()

                input()

            freq_mask = (freqs > allowed_freqs[0]) * (freqs < allowed_freqs[1])

            max_ind = np.argmax(phase_asd_filt_2 * freq_mask)
            max_freq = freqs[max_ind]

            p0 = [10000, max_freq, 5.0, 0]

            try:
                popt, pcov = opti.curve_fit(lorentzian, freqs[max_ind-30:max_ind+30], \
                                            phase_asd_filt_2[max_ind-30:max_ind+30], p0=p0, \
                                            maxfev=10000)

                fit_max = popt[1]
                fit_std = np.abs(popt[2])
            except:
                print('bad fit...')
                fit_max = max_freq
                fit_std = 5.0 * (freqs[1] - freqs[0])
                popt = p0

            if plot_sideband_fit:
                plot_freqs = np.linspace(freqs[max_ind - 30],
                                         freqs[max_ind + 30], 100)
                plt.loglog(freqs, phase_asd_filt_2)
                plt.loglog(plot_freqs, lorentzian(plot_freqs, *popt))
                print(fit_max, fit_std)
                plt.show()

                input()

            # if fit_max < 10:
            #     return

            # if len(wobble_freq):
            #     if (np.abs(fit_max - wobble_freq[-1]) / wobble_freq[-1]) > 0.1:
            #         # plt.loglog(freqs, phase_asd)
            #         # plt.loglog(freqs, phase_asd_filt)
            #         # plt.loglog(freqs, phase_asd_filt_2)
            #         # plt.show()
            #         return

            elec3_filt_fft = np.fft.rfft(elec3_filt)

            fit_ind = 100000
            short_freqs = np.fft.rfftfreq(fit_ind, d=1.0 / fsamp)
            zeros = np.zeros(fit_ind)
            voltage = np.array([zeros, zeros, zeros, elec3_filt[:fit_ind], \
                       zeros, zeros, zeros, zeros])
            efield = bu.trap_efield(voltage * tabor_mon_fac, only_x=True)

            #efield_mag = np.linalg.norm(efield, axis=0)

            efield_asd = bu.fft_norm(fit_ind, fsamp) * np.abs(
                np.fft.rfft(efield[0]))

            # max_ind = np.argmax(np.abs(elec3_filt_fft))
            short_max_ind = np.argmax(efield_asd)
            # freq_guess = freqs[max_ind]
            # phase_guess = np.mean(np.angle(elec3_filt_fft[max_ind-2:max_ind+2]))
            # amp_guess = np.sqrt(2) * np.std(efield[0])
            # p0 = [amp_guess, freq_guess, phase_guess, 0]

            # popt_l, pcov_l = opti.curve_fit(lorentzian, short_freqs[short_max_ind-100:short_max_ind+100], \
            #                                 efield_asd[short_max_ind-100:short_max_ind+100], \
            #                                 p0=[amp_guess, freq_guess, 100, 0], maxfev=10000)

            # start_sine = time.time()
            # popt, pcov = opti.curve_fit(sine, time_vec[:fit_ind], efield[0], \
            #                                 sigma=0.01*efield[0], p0=p0)

            # print popt[0], popt_l[0] * (fsamp / fit_ind)

            #print popt[0], np.sqrt(pcov[0,0])
            # amp_fit = efield_asd[short_max_ind] * np.sqrt(2.0 * fsamp / fit_ind)
            amp_fit = np.sqrt(2) * np.std(efield[0])
            # plt.plot(efield[0])
            # plt.show()

            err_val = np.mean(np.array([efield_asd[short_max_ind-10:short_max_ind], \
                                efield_asd[short_max_ind+1:short_max_ind+11]]).flatten())
            amp_err = np.sqrt(
                (err_val * fsamp / fit_ind)**2)  # + (0.01*amp_fit)**2)
            # print amp_fit, amp_err
            # stop_sine = time.time()
            # print "Field sampling: ", stop_sine - start_sine

            return [2.0 * amp_fit, np.sqrt(2) * amp_err, fit_max, fit_std]
    avg_asd = []

    for fileind, filname in enumerate(files):
        bu.progress_bar(fileind, nfiles)

        df = bu.DataFile()
        df.load(filname)

        df.diagonalize(plot=False)

        drive = df.electrode_data[elec_ind]
        resp = df.pos_data[pos_ind]
        diag_resp = df.diag_pos_data[pos_ind]

        normfac = bu.fft_norm(df.nsamp, df.fsamp)

        if len(resp) != len(drive):
            continue

        freqs = np.fft.rfftfreq(len(resp), d=1.0 / df.fsamp)
        fft = np.fft.rfft(resp)
        diag_fft = np.fft.rfft(diag_resp)
        dfft = np.fft.rfft(drive)

        #plt.figure()
        #plt.loglog(freqs, np.abs(dfft))
        #plt.loglog(freqs, np.abs(fft))
        #plt.show()

        amp = np.abs(fft)
files, _ = bu.find_all_fnames(dir_name,
                              ext='.h5',
                              sort_time=False,
                              skip_subdirectories=False)
files = files[file_inds[0]:file_inds[1]:file_step]

nfiles = len(files)

Ibead = bu.get_Ibead(date=date)

fobj = bu.hsDat(files[0], load=False, load_attribs=True)

nsamp = fobj.nsamp
fsamp = fobj.fsamp
fac = bu.fft_norm(nsamp, fsamp)

time_vec = np.arange(nsamp) * (1.0 / fsamp)
full_freqs = np.fft.rfftfreq(nsamp, 1.0 / fsamp)

out_inds = (full_freqs > output_band[0]) * (full_freqs < output_band[1])
out_freqs = full_freqs[out_inds]

times = []
for file in files:
    fobj = bu.hsDat(file, load=False, load_attribs=True)
    times.append(fobj.time)
times = np.array(times) * 1e-9
times -= times[0]

def build_uncalibrated_H(fobjs, average_first=True, dpsd_thresh = 8e-1, mfreq = 1., \
                         skip_qpd=False, plot_response=False, drop_bad_bins=True, \
                         new_trap=False, lines_to_remove=[60.0], zero_drive_phase=False):
    '''Generates a transfer function from a list of DataFile objects
           INPUTS: fobjs, list of file objects
                   average_first, boolean specifying whether to average responses
                                  for a given drive before computing H
                   dpsd_thresh, threshold above which to compute H
                   mfreq, minimum frequency to consider
                   fix_HF, boolean to specify whether to try fixing spectral
                           leakage at high frequency due to drift in a timebase

           OUTPUTS: Hout, dictionary with 3x3 complex valued matrices as values
                          and frequencies as keys'''

    print("BUILDING H...")
    sys.stdout.flush()

    Hout = {}
    Hout_noise = {}
    Hout_amp = {}
    Hout_phase = {}
    Hout_fb = {}

    Hout_counts = {}

    avg_drive_fft = {}
    avg_data_fft = {}
    avg_fb_fft = {}

    if not skip_qpd:
        avg_side_fft = {}

        avg_amp_fft = {}
        avg_phase_fft = {}

    counts = {}

    if plot_response:
        fbfig, fb_axarr = plt.subplots(3,3,sharex=True,sharey=True,figsize=(9,8))
        posfig, pos_axarr = plt.subplots(3,3,sharex=True,sharey='row',figsize=(9,8))
        drivefig, drive_axarr = plt.subplots(3,3,sharex=True,sharey=True,figsize=(9,8))
        if not skip_qpd:
            ampfig, amp_axarr = plt.subplots(5,3,sharex=True,sharey=True,figsize=(9,10))
            phasefig, phase_axarr = plt.subplots(5,3,sharex=True,sharey=True,figsize=(9,10))
            sidefig, side_axarr = plt.subplots(4,3,sharex=True,sharey=True,figsize=(9,9))

    filind = 0
    for fobj in fobjs:

        N = np.shape(fobj.pos_data)[1]#number of samples
        fsamp = fobj.fsamp
        
        fft_fac = bu.fft_norm(N, fsamp)

        drive = bu.trap_efield(fobj.electrode_data) #* constants.elementary_charge
        #drive = np.roll(drive, -10, axis=-1)

        # dfft = np.fft.rfft(fobj.electrode_data) #fft of electrode drive in daxis.
        dfft = np.fft.rfft( drive ) * fft_fac
        if new_trap: 
            data_fft = np.fft.rfft(fobj.pos_data_3) * fft_fac
        else:
            data_fft = np.fft.rfft(fobj.pos_data) * fft_fac

        fb_fft = np.fft.rfft(fobj.pos_fb) * fft_fac

        if not skip_qpd:
            amp_fft = np.fft.rfft(fobj.amp) * fft_fac
            phase_fft = np.fft.rfft(fobj.phase) * fft_fac

            left = fobj.amp[2] + fobj.amp[3]
            right = fobj.amp[0] + fobj.amp[1]
            top = fobj.amp[2] + fobj.amp[0]
            bot = fobj.amp[3] + fobj.amp[1]
            side_fft = np.fft.rfft(np.array([right, left, top, bot])) * fft_fac

        fft_freqs = np.fft.rfftfreq(N, d=1.0/fsamp)

        # for i in range(len(dfft)):
        #     plt.loglog(fft_freqs, np.abs(dfft[i]))
        # # plt.loglog(fft_freqs, np.abs(dfft[4]))
        # # plt.loglog(fft_freqs, np.abs(data_fft[0]))
        # plt.show()

        dpsd = np.abs(dfft)**2  #psd for all electrode drives
        dpsd_thresh = 0.1 * np.max(dpsd.flatten())
        inds = np.where(dpsd>dpsd_thresh)#Where the dpsd is over the threshold for being used.
        eind = np.unique(inds[0])[0]
        # print(eind)

        if eind not in avg_drive_fft:
            avg_drive_fft[eind] = np.zeros(dfft.shape, dtype=np.complex128)
            avg_data_fft[eind] = np.zeros(data_fft.shape, dtype=np.complex128)
            avg_fb_fft[eind] = np.zeros(fb_fft.shape, dtype=np.complex128)
            if not skip_qpd:
                avg_amp_fft[eind] = np.zeros(amp_fft.shape, dtype=np.complex128)
                avg_phase_fft[eind] = np.zeros(phase_fft.shape, dtype=np.complex128)
                avg_side_fft[eind] = np.zeros(side_fft.shape, dtype=np.complex128)
            counts[eind] = 0.

        # try:
        avg_drive_fft[eind] += dfft
        avg_data_fft[eind] += data_fft
        avg_fb_fft[eind] += fb_fft
        if not skip_qpd:
            avg_amp_fft[eind] += amp_fft
            avg_phase_fft[eind] += phase_fft
            avg_side_fft[eind] += side_fft

        # except:
        #     traceback.print_exc()
        #     print()
        #     print(fobj.fname)
        #     derpfig, derpax = plt.subplots(1,1)
        #     for i in [0,1,2,3,4]:
        #         derpax.loglog(np.abs(amp_fft[i]) * 10**i, label=str(i))
        #     derpax.legend()
        #     plt.show()
        #     input()

        counts[eind] += 1.

    for eind in list(counts.keys()):
        print(eind, counts[eind])
        avg_drive_fft[eind] = avg_drive_fft[eind] / counts[eind]
        avg_data_fft[eind] = avg_data_fft[eind] / counts[eind]
        avg_fb_fft[eind] = avg_fb_fft[eind] / counts[eind]
        if not skip_qpd:
            avg_amp_fft[eind] = avg_amp_fft[eind] / counts[eind]
            avg_phase_fft[eind] = avg_phase_fft[eind] / counts[eind]
            avg_side_fft[eind] = avg_side_fft[eind] / counts[eind]

    poslabs = {0: 'X', 1: 'Y', 2: 'Z'}
    sidelabs = {0: 'Right', 1: 'Left', 2: 'Top', 3: 'Bottom'}
    quadlabs = {0: 'Top Right', 1: 'Bottom Right', 2: 'Top Left', \
                3: 'Bottom Left', 4: 'Backscatter'}

    for eind in list(avg_drive_fft.keys()):
        # First find drive-frequency bins above a fixed threshold
        dpsd = np.abs(avg_drive_fft[eind])**2 
        inds = np.where(dpsd > dpsd_thresh)

        # Extract the frequency indices
        finds = inds[1]

        # Ignore DC and super low frequencies
        mfreq = 1.0
        b = finds > np.argmin(np.abs(fft_freqs - mfreq))

        tf_inds = finds[b]
        for linefreq in lines_to_remove:
            print('Ignoring response at line frequency: {:0.1f}'.format(linefreq))
            line_freq_ind = np.argmin(np.abs(fft_freqs - linefreq))
            tf_inds = tf_inds[tf_inds != line_freq_ind]

        freqs = fft_freqs[tf_inds]

        xlim = (np.min(fft_freqs[1:]), np.max(fft_freqs))
        # xlim = (45.0, 130.0)

        # plt.plot(freqs, np.angle(avg_drive_fft[eind][eind,tf_inds]) / np.pi)
        # plt.title('Raw Phase From Drive FFT')
        # plt.ylabel('Apparent Phase [$\\pi \\, rad$]')
        # plt.xlabel('Drive Frequency [Hz]')
        # plt.tight_layout()

        # plt.figure()
        # plt.plot(freqs, np.unwrap(np.angle(avg_drive_fft[eind][eind,tf_inds])) / np.pi)
        # plt.title('Unwrapped Phase From Drive FFT')
        # plt.ylabel('Apparent Phase [$\\pi \\, rad$]')
        # plt.xlabel('Drive Frequency [Hz]')
        # plt.tight_layout()
        # plt.show()

        # outind = config.elec_map[eind]
        outind = eind

        if plot_response:
            
            for elec in [0,1,2]: #,3,4,5,6,7]:
                drive_axarr[elec,outind].loglog(fft_freqs, \
                                                np.abs(avg_drive_fft[eind][elec]), alpha=1.0)
                drive_axarr[elec,outind].loglog(fft_freqs[tf_inds], \
                                                np.abs(avg_drive_fft[eind][elec])[tf_inds], alpha=1.0)
                if outind == 0:
                    drive_axarr[elec,outind].set_ylabel('Efield axis ' + str(elec) \
                                                            + '\n[(V/m)/$\\sqrt{\\rm Hz}$]')
                if elec == 2: #7:
                    drive_axarr[elec,outind].set_xlabel('Frequency [Hz]')


            for resp in [0,1,2,3,4]:

                if not skip_qpd:
                    amp_axarr[resp,outind].loglog(fft_freqs[tf_inds], \
                                                  np.abs(avg_amp_fft[eind][resp])[tf_inds], alpha=1.0)
                    phase_axarr[resp,outind].loglog(fft_freqs[tf_inds], \
                                                    np.abs(avg_phase_fft[eind][resp])[tf_inds], alpha=1.0)
                    if outind == 0:
                        amp_axarr[resp,outind].set_ylabel(quadlabs[resp])
                        phase_axarr[resp,outind].set_ylabel(quadlabs[resp])
                    if resp == 4:
                        amp_axarr[resp,outind].set_xlabel('Frequency [Hz]')
                        phase_axarr[resp,outind].set_xlabel('Frequency [Hz]')

                    if resp in [0,1,2,3]:
                        side_axarr[resp,outind].loglog(fft_freqs[tf_inds], \
                                                       np.abs(avg_side_fft[eind][resp])[tf_inds], alpha=1.0)
                        if outind == 0:
                            side_axarr[resp,outind].set_ylabel(sidelabs[resp])
                        if resp == 3:
                            side_axarr[resp,outind].set_xlabel('Frequency [Hz]')


                if resp in [0,1,2]:
                    # if resp == 2:
                    #     fac = 1000.0
                    # else:
                    #     fac = 1.0
                    pos_axarr[resp,outind].loglog(fft_freqs, np.abs(avg_data_fft[eind][resp]), alpha=1.0)
                    pos_axarr[resp,outind].loglog(fft_freqs[tf_inds], \
                                                  np.abs(avg_data_fft[eind][resp])[tf_inds], alpha=1.0)

                    fb_axarr[resp,outind].loglog(fft_freqs, np.abs(avg_fb_fft[eind][resp]), alpha=1.0)
                    fb_axarr[resp,outind].loglog(fft_freqs[tf_inds], \
                                                  np.abs(avg_fb_fft[eind][resp])[tf_inds], alpha=1.0)
                    if outind == 0:
                        pos_axarr[resp,outind].set_ylabel(poslabs[resp] + ' [arb]')
                        fb_axarr[resp,outind].set_ylabel(poslabs[resp] + ' FB\n[bits/$\\sqrt{\\rm Hz}$]')
                    if resp == 2:
                        pos_axarr[resp,outind].set_xlabel('Frequency [Hz]')
                        fb_axarr[resp,outind].set_xlabel('Frequency [Hz]')
            
            drivefig.suptitle('Drive Amplitude vs. Frequency', fontsize=16)
            posfig.suptitle('ASD of XYZ vs. Frequency', fontsize=16)
            fbfig.suptitle('ASD of XYZ Feedback vs. Frequency', fontsize=16)
            if not skip_qpd:
                ampfig.suptitle('ASD of Demod. Carrier Amp vs. Frequency', fontsize=16)
                phasefig.suptitle('ASD of Demod. Carrier Phase vs. Frequency', fontsize=16)
                sidefig.suptitle('ASD of Sum of Neighboring QPD Carrier Amplitudes', fontsize=16)

                figlist = [posfig, fbfig, drivefig, ampfig, phasefig, sidefig]
                axlist = [pos_axarr, fb_axarr, drive_axarr, amp_axarr, phase_axarr, side_axarr]

            else:
                figlist = [posfig, fbfig, drivefig]
                axlist = [pos_axarr, fb_axarr, drive_axarr]


            for axind, axarr in enumerate(axlist):
                # axarr[0,0].set_xlim(*xlim)
                axarr[0,0].set_xlim(34, 107)

                for drive in [0,1,2]:
                    axarr[0,drive].set_title(poslabs[drive] + ' Drive')

                for resp in [0,1,2]:
                    if (axind != 0) and (resp != 0):
                        continue

                    mag_major_locator = LogLocator(base=10.0, numticks=30)
                    mag_minor_locator = LogLocator(base=1.0, numticks=300)

                    axarr[resp,0].yaxis.set_major_locator(mag_major_locator)
                    axarr[resp,0].yaxis.set_minor_locator(mag_minor_locator)
                    axarr[resp,0].yaxis.set_minor_formatter(NullFormatter())

                for d in [0,1,2]:
                    for r in [0,1,2]:
                        axarr[r,d].grid(which='both')



        ### Compute FFT of each response divided by FFT of each drive.
        ### This is way more information than we need for a single drive freq
        ### and electrode pair, but it allows a nice vectorization
        Hmat = np.einsum('ij, kj -> ikj', \
                             avg_data_fft[eind][:,tf_inds], 1. / avg_drive_fft[eind][:,tf_inds])

        Hmat_fb = np.einsum('ij, kj -> ikj', \
                            avg_fb_fft[eind][:,tf_inds], 1. / avg_drive_fft[eind][:,tf_inds])

        if not skip_qpd:
            Hmat_amp = np.einsum('ij, kj -> ikj', \
                                 avg_amp_fft[eind][:,tf_inds], 1. / avg_drive_fft[eind][:,tf_inds])
            Hmat_phase = np.einsum('ij, kj -> ikj', \
                                   avg_phase_fft[eind][:,tf_inds], 1. / avg_drive_fft[eind][:,tf_inds])


        # Generate an integer by which to roll the data_fft to compute the noise
        # limit of the TF measurement
        if len(tf_inds) > 1:
            shift = int(0.5 * (tf_inds[1] - tf_inds[0]))
        else:
            shift = int(0.5 * tf_inds[0])
        randadd = np.random.choice(np.arange(-int(0.1*shift), \
                                             int(0.1*shift)+1, 1))
        shift = shift + randadd
        rolled_data_fft = np.roll(avg_data_fft[eind], shift, axis=-1)

        # Compute the Noise TF
        Hmat_noise = np.einsum('ij, kj -> ikj', \
                                 rolled_data_fft[:,tf_inds], 1. / avg_drive_fft[eind][:,tf_inds])

        # Map the 3x7xNfreq arrays to dictionaries with keys given by the drive
        # frequencies and values given by 3x3 complex-values TF matrices
        #outind = config.elec_map[eind]
        outind = eind
        for i, freq in enumerate(freqs):
            if freq not in Hout:
                if i != 0 and drop_bad_bins:
                    sep = freq - freqs[i-1]
                    # Clause to ignore this particular frequency response if an
                    # above threshold response is found not on a drive bin. Sometimes
                    # random noise components pop up or some power leaks to a 
                    # neighboring bin
                    if sep < 0.8 * (freqs[1] - freqs[0]):
                        continue
                Hout[freq] = np.zeros((3,3), dtype=np.complex128)
                Hout_noise[freq] = np.zeros((3,3), dtype=np.complex128)
                Hout_amp[freq] = np.zeros((5,3), dtype=np.complex128)
                Hout_phase[freq] = np.zeros((5,3), dtype=np.complex128)

            # Add the response from this drive freq/electrode pair to the TF matrix
            Hout[freq][:,outind] += Hmat[:,eind,i]
            Hout_noise[freq][:,outind] += Hmat_noise[:,eind,i]
            if not skip_qpd:
                Hout_amp[freq][:,outind] += Hmat_amp[:,eind,i]
                Hout_phase[freq][:,outind] += Hmat_phase[:,eind,i]

    if plot_response:
        for fig in figlist:
            fig.tight_layout()
            fig.subplots_adjust(top=0.90)
        plt.show()

    # first_mats = []
    freqs = list(Hout.keys())
    freqs.sort()


    if zero_drive_phase:
        # init_phases = np.angle(Hout[freqs[0]])

        first_mats = []
        for freq in freqs[1:3]:
            first_mats.append(Hout[freq])
        first_mats = np.array(first_mats)
        init_phases = np.mean(np.unwrap(np.angle(first_mats), axis=0), axis=0)

        # print(init_phases)
        # input()

        for drive in [0,1,2]:
            if np.abs(init_phases[drive,drive]) > 1.5:
                ### Check the second frequency to make sure the first isn't crazy
                if np.abs(np.angle(Hout[freqs[1]][drive,drive])) > 1.5:
                    print("Correcting phase shift for drive channel", drive)
                    sys.stdout.flush()
                    for freq in freqs:
                        Hout[freq][drive,:] = Hout[freq][drive,:] * (-1)
                        # Hout[freq][:,drive] = Hout[freq][:,drive] * (-1)
                else:
                    Hout[freqs[0]][drive,:] = Hout[freqs[0]][drive,:] * (-1)


    out_dict = {'Hout': Hout, 'Hout_amp': Hout_amp, 'Hout_phase': Hout_phase, \
                'Hout_noise': Hout_noise}

    return out_dict
Esempio n. 6
0
def plot_many_spectra(files, data_axes=[0,1,2], cant_axes=[], elec_axes=[], other_axes=[], \
                      fb_axes=[], plot_power=False, diag=True, colormap='plasma', \
                      sort='time', file_inds=(0,10000)):
    '''Loops over a list of file names, loads each file, diagonalizes,
       then plots the amplitude spectral density of any number of data
       or cantilever/electrode drive signals

       INPUTS: files, list of files names to extract data
               data_axes, list of pos_data axes to plot
               cant_axes, list of cant_data axes to plot
               elec_axes, list of electrode_data axes to plot
               diag, boolean specifying whether to diagonalize

       OUTPUTS: none, plots stuff
    '''

    if diag:
        dfig, daxarr = plt.subplots(len(data_axes),2,sharex=True,sharey=True, \
                                    figsize=figsize)
    else:
        dfig, daxarr = plt.subplots(len(data_axes),1,sharex=True,sharey=True, \
                                    figsize=figsize)
    dfig.suptitle('XYZ Data', fontsize=18)

    if len(cant_axes):
        cfig, caxarr = plt.subplots(len(data_axes),
                                    1,
                                    sharex=True,
                                    sharey=True)
        if len(cant_axes) == 1:
            caxarr = [caxarr]
        cfig.suptitle('Attractor Data', fontsize=18)
    if len(elec_axes):
        efig, eaxarr = plt.subplots(len(elec_axes),
                                    1,
                                    sharex=True,
                                    sharey=True)
        if len(elec_axes) == 1:
            eaxarr = [eaxarr]
        efig.suptitle('Electrode Data', fontsize=18)
    if len(other_axes):
        ofig, oaxarr = plt.subplots(len(other_axes),
                                    1,
                                    sharex=True,
                                    sharey=True)
        if len(other_axes) == 1:
            oaxarr = [oaxarr]
        ofig.suptitle('Other Data', fontsize=18)
    if len(fb_axes):
        fbfig, fbaxarr = plt.subplots(len(fb_axes),1,sharex=True,sharey=True, \
                                    figsize=figsize)
        if len(fb_axes) == 1:
            fbaxarr = [fbaxarr]
        fbfig.suptitle('Feedback Data', fontsize=18)
    if plot_power:
        pfig, paxarr = plt.subplots(2, 1, sharex=True, figsize=(6, 6))
        pfig.suptitle('Power/Power Feedback Data', fontsize=18)

    kludge_fig, kludge_ax = plt.subplots(1, 1)

    files = files[file_inds[0]:file_inds[1]]
    if step10:
        files = files[::10]
    if invert_order:
        files = files[::-1]

    colors = bu.get_color_map(len(files), cmap=colormap)
    #colors = ['C0', 'C1', 'C2']

    old_per = 0
    print("Processing %i files..." % len(files))
    for fil_ind, fil in enumerate(files):
        color = colors[fil_ind]

        # Display percent completion
        bu.progress_bar(fil_ind, len(files))

        # Load data
        df = bu.DataFile()
        if new_trap:
            df.load_new(fil)
        else:
            df.load(fil)

        if len(other_axes):
            df.load_other_data()

        df.calibrate_stage_position()

        #df.high_pass_filter(fc=1)
        #df.detrend_poly()

        #plt.figure()
        #plt.plot(df.pos_data[0])
        #plt.show()

        if cascade:
            cascade_scale = (cascade_fac)**fil_ind
        else:
            cascade_scale = 1.0

        freqs = np.fft.rfftfreq(len(df.pos_data[0]), d=1.0 / df.fsamp)

        if diag:
            df.diagonalize(maxfreq=lpf, date=tfdate, plot=tf_plot)

        if fil_ind == 0 and len(cant_axes):
            drivepsd = np.abs(np.fft.rfft(df.cant_data[drive_ax]))
            driveind = np.argmax(drivepsd[1:]) + 1
            drive_freq = freqs[driveind]

        for axind, ax in enumerate(data_axes):

            try:
                fac = cascade_scale * df.conv_facs[ax]  # * (1.0 / 0.12e-12)
            except:
                fac = cascade_scale

            if fullNFFT:
                NFFT = len(df.pos_data[ax])
            else:
                NFFT = userNFFT

            psd, freqs = mlab.psd(df.pos_data[ax], Fs=df.fsamp, \
                                  NFFT=NFFT, window=window)

            norm = bu.fft_norm(df.nsamp, df.fsamp)
            new_freqs = np.fft.rfftfreq(df.nsamp, d=1.0 / df.fsamp)
            #fac = 1.0

            kludge_fac = 1.0
            #kludge_fac = 1.0 / np.sqrt(10)
            if diag:
                dpsd, dfreqs = mlab.psd(df.diag_pos_data[ax], Fs=df.fsamp, \
                                        NFFT=NFFT, window=window)
                kludge_ax.loglog(freqs, np.sqrt(dpsd) *kludge_fac, color='C'+str(axind), \
                                    label=posdic[axind])
                kludge_ax.set_ylabel(
                    '$\sqrt{\mathrm{PSD}}$ $[\mathrm{N}/\sqrt{\mathrm{Hz}}]$')
                kludge_ax.set_xlabel('Frequency [Hz]')

                # daxarr[axind,0].loglog(new_freqs, fac*norm*np.abs(np.fft.rfft(df.pos_data[ax]))*kludge_fac, color='k', label='np.fft with manual normalization')
                daxarr[axind, 0].loglog(freqs,
                                        np.sqrt(psd) * fac * kludge_fac,
                                        color=color,
                                        label=df.fname)  #'mlab.psd')
                daxarr[axind, 0].grid(alpha=0.5)
                daxarr[axind, 1].loglog(
                    new_freqs,
                    norm * np.abs(np.fft.rfft(df.diag_pos_data[ax])) *
                    kludge_fac,
                    color='k')
                daxarr[axind, 1].loglog(freqs,
                                        np.sqrt(dpsd) * kludge_fac,
                                        color=color)
                daxarr[axind, 1].grid(alpha=0.5)
                daxarr[axind, 0].set_ylabel(
                    '$\sqrt{\mathrm{PSD}}$ $[\mathrm{N}/\sqrt{\mathrm{Hz}}]$')
                if ax == data_axes[-1]:
                    daxarr[axind, 0].set_xlabel('Frequency [Hz]')
                    daxarr[axind, 1].set_xlabel('Frequency [Hz]')
            else:
                # daxarr[axind].loglog(new_freqs, norm*np.abs(np.fft.rfft(df.pos_data[ax])), color='k', label='np.fft with manual normalization')
                daxarr[axind].loglog(freqs,
                                     np.sqrt(psd) * fac,
                                     color=color,
                                     label=df.fname)  #'mlab.psd')
                daxarr[axind].grid(alpha=0.5)
                daxarr[axind].set_ylabel(
                    '$\\sqrt{\mathrm{PSD}}$ $[\\mathrm{Arb}/\\sqrt{\mathrm{Hz}}]$'
                )
                #daxarr[axind].set_ylabel('$\sqrt{\mathrm{PSD}}$ $[\mathrm{N}/\sqrt{\mathrm{Hz}}]$')

                if ax == data_axes[-1]:
                    daxarr[axind].set_xlabel('Frequency [Hz]')

        if len(fb_axes):
            for axind, ax in enumerate(fb_axes):
                fb_psd, freqs = mlab.psd(df.pos_fb[ax], Fs=df.fsamp, \
                                      NFFT=NFFT, window=window)
                fbaxarr[axind].loglog(freqs,
                                      np.sqrt(fb_psd) * fac,
                                      color=color)
                fbaxarr[axind].set_ylabel('$\\sqrt{\\mathrm{PSD}}$')

        if len(cant_axes):
            for axind, ax in enumerate(cant_axes):
                psd, freqs = mlab.psd(df.cant_data[ax], Fs=df.fsamp, \
                                      NFFT=NFFT, window=window)
                caxarr[axind].loglog(freqs, np.sqrt(psd), color=color)
                caxarr[axind].set_ylabel('$\\sqrt{\\mathrm{PSD}}$')

        if len(elec_axes):
            for axind, ax in enumerate(elec_axes):
                psd, freqs = mlab.psd(df.electrode_data[ax], Fs=df.fsamp, \
                                      NFFT=NFFT, window=window)
                eaxarr[axind].loglog(freqs, np.sqrt(psd), color=color)
                eaxarr[axind].set_ylabel('$\\sqrt{\\mathrm{PSD}}$')

        if len(other_axes):
            for axind, ax in enumerate(other_axes):
                #ax = ax - 3
                psd, freqs = mlab.psd(df.other_data[ax], Fs=df.fsamp, \
                                      NFFT=NFFT, window=window)
                oaxarr[axind].loglog(freqs, np.sqrt(psd), color=color)
                oaxarr[axind].set_ylabel('$\\sqrt{\\mathrm{PSD}}$')

        if plot_power:
            psd, freqs = mlab.psd(df.power, Fs=df.fsamp, \
                                        NFFT=NFFT, window=window)
            psd_fb, freqs_fb = mlab.psd(df.power_fb, Fs=df.fsamp, \
                                        NFFT=NFFT, window=window)
            paxarr[0].loglog(freqs, np.sqrt(psd), color=color)
            paxarr[1].loglog(freqs_fb, np.sqrt(psd_fb), color=color)
            for axind in [0, 1]:
                paxarr[axind].set_ylabel('$\\sqrt{\\mathrm{PSD}}$')

    if filename_labels:
        daxarr[0].legend(fontsize=10)
    if len(fb_axes):
        fbaxarr[0].legend(fontsize=10)

    #daxarr[0].set_xlim(0.5, 25000)

    if diag:
        derp_ax = daxarr[0, 0]
    else:
        derp_ax = daxarr[0]

    # derp_ax.legend(fontsize=10)

    if len(ylim):
        derp_ax.set_ylim(*ylim)
        kludge_ax.set_ylim(*ylim)
    if len(xlim):
        derp_ax.set_xlim(*xlim)
        kludge_ax.set_xlim(1, 500)

    dfig.tight_layout()
    dfig.subplots_adjust(top=0.91)

    kludge_ax.grid()
    kludge_ax.legend()
    kludge_fig.tight_layout()

    if plot_power:
        paxarr[-1].set_xlabel('Frequency [Hz]')
        pfig.tight_layout()
        pfig.subplots_adjust(top=0.91)
    if len(cant_axes):
        caxarr[-1].set_xlabel('Frequency [Hz]')
        cfig.tight_layout()
        cfig.subplots_adjust(top=0.91)
    if len(elec_axes):
        eaxarr[-1].set_xlabel('Frequency [Hz]')
        efig.tight_layout()
        efig.subplots_adjust(top=0.91)
    if len(other_axes):
        oaxarr[-1].set_xlabel('Frequency [Hz]')
        ofig.tight_layout()
        ofig.subplots_adjust(top=0.91)
    if len(fb_axes):
        fbaxarr[-1].set_xlabel('Frequency [Hz]')
        fbfig.tight_layout()
        fbfig.subplots_adjust(top=0.91)

    if savefigs:
        plt.savefig(title_pre + '.png')

        daxarr[0].set_xlim(2000, 25000)
        plt.tight_layout()

        plt.savefig(title_pre + '_zoomhf.png')

        daxarr[0].set_xlim(1, 80)
        plt.tight_layout()

        plt.savefig(title_pre + '_zoomlf.png')

        daxarr[0].set_xlim(0.5, 25000)

    if not savefigs:
        plt.show()
Esempio n. 7
0
def weigh_bead(files,
               pcol=0,
               colormap='plasma',
               sort='time',
               file_inds=(0, 10000)):
    '''Loops over a list of file names, loads each file, diagonalizes,
       then plots the amplitude spectral density of any number of data
       or cantilever/electrode drive signals

       INPUTS: files, list of files names to extract data
               data_axes, list of pos_data axes to plot
               cant_axes, list of cant_data axes to plot
               elec_axes, list of electrode_data axes to plot
               diag, boolean specifying whether to diagonalize

       OUTPUTS: none, plots stuff
    '''

    files = [(os.stat(path), path) for path in files]
    files = [(stat.st_ctime, path) for stat, path in files]
    files.sort(key=lambda x: (x[0]))
    files = [obj[1] for obj in files]

    files = files[file_inds[0]:file_inds[1]]
    if step10:
        files = files[::10]
    if invert_order:
        files = files[::-1]

    date = re.search(r"\d{8,}", files[0])[0]
    charge_dat = np.load(
        open('/calibrations/charges/' + date + '.charge', 'rb'))
    q_bead = -1.0 * charge_dat[0] * constants.elementary_charge
    # q_bead = -25.0 * 1.602e-19

    nfiles = len(files)
    colors = bu.get_color_map(nfiles, cmap=colormap)

    avg_fft = []

    print("Processing %i files..." % nfiles)
    for fil_ind, fil in enumerate(files):
        color = colors[fil_ind]

        bu.progress_bar(fil_ind, nfiles)

        # Load data
        df = bu.DataFile()
        df.load(fil)

        df.calibrate_stage_position()

        df.calibrate_phase()

        #plt.hist( df.zcal / df.phase[4] )
        #plt.show()

        #print np.mean(df.zcal / df.phase[4]), np.std(df.zcal / df.phase[4])

        freqs = np.fft.rfftfreq(df.nsamp, d=1.0 / df.fsamp)
        fft = np.fft.rfft(df.zcal) * bu.fft_norm(df.nsamp, df.fsamp) \
              * np.sqrt(freqs[1] - freqs[0])
        fft2 = np.fft.rfft(df.phase[4]) * bu.fft_norm(df.nsamp, df.fsamp) \
              * np.sqrt(freqs[1] - freqs[0])

        fftd = np.fft.rfft(df.zcal - np.pi*df.phase[4]) * bu.fft_norm(df.nsamp, df.fsamp) \
               * np.sqrt(freqs[1] - freqs[0])

        #plt.plot(np.pi * df.phase[4])
        #plt.plot(df.zcal)

        #plt.figure()
        #plt.loglog(freqs, np.abs(fft))
        #plt.loglog(freqs, np.pi * np.abs(fft2))
        #plt.loglog(freqs, np.abs(fftd))
        #plt.show()

        drive_fft = np.fft.rfft(df.electrode_data[1])

        #plt.figure()
        #plt.loglog(freqs, np.abs(drive_fft))
        #plt.show()

        inds = np.abs(drive_fft) > 1e4
        inds *= (freqs > 2.0) * (freqs < 300.0)
        inds = np.arange(len(inds))[inds]

        ninds = inds + 5

        drive_amp = np.abs( drive_fft[inds][0] * bu.fft_norm(df.nsamp, df.fsamp) \
                            * np.sqrt(freqs[1] - freqs[0]) )

        if not len(avg_fft):
            avg_fft = fft
            avg_drive_fft = drive_fft

            ratio = fft[inds] / drive_fft[inds]
        else:
            avg_fft += fft
            avg_drive_fft += drive_fft

            ratio += fft[inds] / drive_fft[inds]

    fac = bu.fft_norm(df.nsamp, df.fsamp) * np.sqrt(freqs[1] - freqs[0])

    avg_fft *= (1.0 / nfiles)
    avg_drive_fft *= (1.0 / nfiles)

    resp = fft[inds] * (1064.0e-9 / 2.0) * (1.0 / (2.0 * np.pi))
    noise = fft[ninds] * (1064.0e-9 / 2.0) * (1.0 / (2.0 * np.pi))

    drive_noise = np.abs(np.median(avg_drive_fft[ninds] * fac))

    #plt.loglog(freqs[inds], np.abs(resp))
    #plt.loglog(freqs[ninds], np.abs(noise))
    #plt.show()

    resp_sc = resp * 1e9  # put resp in units of nm
    noise_sc = noise * 1e9

    def amp_sc(f, d_accel, f0, g):
        return np.abs(harmonic_osc(f, d_accel, f0, g)) * 1e9

    def phase_sc(f, d_accel, f0, g):
        return np.angle(harmonic_osc(f, d_accel, f0, g))

    #plt.loglog(freqs[inds], np.abs(resp_sc))
    #plt.loglog(freqs[inds], np.abs(harmonic_osc(freqs[inds], 1e-3, 160, 75e1))*1e9)
    #plt.show()

    #plt.loglog(freqs[inds], np.abs(resp_sc))
    #plt.loglog(freqs, amp_sc(freqs, 1e-3, 160, 750))
    #plt.show()

    popt, pcov = opti.curve_fit(amp_sc, freqs[inds], np.abs(resp_sc), sigma=np.abs(noise_sc), \
                                absolute_sigma=True, p0=[1e-3, 160, 750], maxfev=10000)
    #popt2, pcov2 = opti.curve_fit(phase_sc, freqs[inds], np.angle(resp_sc), p0=[1e-3, 160, 750])

    print(popt)
    print(pcov)

    plt.figure()
    plt.errorbar(freqs[inds],
                 np.abs(resp),
                 np.abs(noise),
                 fmt='.',
                 ms=10,
                 lw=2)
    #plt.loglog(freqs[inds], np.abs(noise))
    plt.loglog(freqs, np.abs(harmonic_osc(freqs, *popt)))
    plt.xlabel('Frequency [Hz]', fontsize=16)
    plt.ylabel('Z Amplitude [m]', fontsize=16)

    force = (drive_amp / (4.0e-3)) * q_bead

    mass = np.abs(popt[0]**(-1) * force) * 10**12
    fit_err = np.sqrt(pcov[0, 0] / popt[0])
    charge_err = 0.1
    drive_err = drive_noise / drive_amp

    print(drive_err)

    mass_err = np.sqrt((fit_err)**2 + (charge_err)**2 + (drive_err)**2) * mass

    #print "IMPLIED MASS [ng]: ", mass

    print('%0.3f ng,  %0.2f e^-,  %0.1f V' % (mass, q_bead *
                                              (1.602e-19)**(-1), drive_amp))
    print('%0.6f ng' % (mass_err))
    plt.tight_layout()

    plt.show()
    def analyze_background(self, data_axes=[0,1,2], lpf=2500, \
                           diag=False, colormap='jet', \
                           file_inds=(0,10000), unwrap=False, \
                           harms_to_track = [1, 2, 3], \
                           ext_cant_drive=False, ext_cant_ind=0, \
                           plot_first_drive=False, sub_cant_phase=True, \
                           progstr=''):
        '''Loops over a list of file names, loads each file, diagonalizes,
           then plots the amplitude spectral density of any number of data
           or cantilever/electrode drive signals

           INPUTS: files, list of files names to extract data
                   data_axes, list of pos_data axes to plot
                   ax_labs, dict with labels for plotted axes
                   diag, bool specifying whether to diagonalize
                   unwrap, bool to unwrap phase of background
                   harms, harmonics to label in ASD

           OUTPUTS: none, generates class attributes
        '''

        files = bu.sort_files_by_timestamp(self.relevant_files)
        files = files[file_inds[0]:file_inds[1]]

        nfreq = len(harms_to_track)
        nax = len(data_axes)
        nfiles = len(files)

        colors = bu.get_color_map(nfiles, cmap=colormap)

        avg_asd = [[]] * nax
        diag_avg_asd = [[]] * nax
        Nasds = [[]] * nax

        amps = np.zeros((nax, nfreq, nfiles))
        amp_errs = np.zeros((nax, nfreq, nfiles))
        phases = np.zeros((nax, nfreq, nfiles))
        phase_errs = np.zeros((nax, nfreq, nfiles))

        temps = np.zeros((2, nfiles))
        times = np.zeros(nfiles)

        print("Processing %i files..." % nfiles)
        for fil_ind, fil in enumerate(files):
            color = colors[fil_ind]

            # Display percent completion
            bu.progress_bar(fil_ind, nfiles, suffix=progstr)

            # Load data
            df = bu.DataFile()
            df.load(fil)

            try:
                temps[0, fil_ind] = df.temps[0]
                temps[1, fil_ind] = df.temps[1]
            except:
                temps[:, fil_ind] = 0.0

            if fil_ind == 0:
                self.fsamp = df.fsamp
                init_time = df.time
                times[0] = 0.0
            else:
                times[fil_ind] = (df.time - init_time).total_seconds()

            df.calibrate_stage_position()

            #df.high_pass_filter(fc=1)
            #df.detrend_poly()

            df.diagonalize(maxfreq=lpf, interpolate=False)

            Nsamp = len(df.pos_data[0])

            if len(harms_to_track):
                harms = harms_to_track
            else:
                harms = [1]

            ginds, driveind, drive_freq, drive_ax = \
                        df.get_boolean_cantfilt(ext_cant_drive=ext_cant_drive, \
                                                ext_cant_ind=ext_cant_ind, \
                                                nharmonics=10, harms=harms)

            if fil_ind == 0:
                if plot_first_drive:
                    df.plot_cant_asd(drive_ax)
                freqs = np.fft.rfftfreq(Nsamp, d=1.0 / df.fsamp)
                bin_sp = freqs[1] - freqs[0]

            datfft, diagdatfft, daterr, diagdaterr = \
                         df.get_datffts_and_errs(ginds, drive_freq, plot=False)

            harm_freqs = freqs[ginds]
            for axind, ax in enumerate(data_axes):
                print(ax, df.conv_facs[ax])

                asd = np.abs( np.fft.rfft(df.pos_data[ax]) ) * \
                      bu.fft_norm(Nsamp, df.fsamp) * df.conv_facs[ax]
                diag_asd = np.abs( np.fft.rfft(df.diag_pos_data[ax]) ) * \
                          bu.fft_norm(Nsamp, df.fsamp)

                if not len(avg_asd[axind]):
                    avg_asd[axind] = asd
                    diag_avg_asd[axind] = diag_asd
                    Nasds[axind] = 1
                else:
                    avg_asd[axind] += asd
                    diag_avg_asd[axind] += diag_asd
                    Nasds[axind] += 1

                for freqind, freq in enumerate(harm_freqs):
                    phase = np.angle(datfft[axind][freqind])
                    if sub_cant_phase:
                        cantfft = np.fft.rfft(df.cant_data[drive_ax])
                        cantphase = np.angle(cantfft[driveind])
                        phases[axind][freqind][fil_ind] = phase - cantphase
                    else:
                        phases[axind][freqind][fil_ind] = phase

                    sig_re = daterr[axind][freqind] / np.sqrt(2)
                    sig_im = np.copy(sig_re)

                    im = np.imag(datfft[axind][freqind])
                    re = np.real(datfft[axind][freqind])

                    phase_var = np.mean((im**2 * sig_re**2 + re**2 * sig_im**2) / \
                                        (re**2 + im**2)**2)
                    phase_errs[axind][freqind][fil_ind] = np.sqrt(phase_var)

                    amps[axind][freqind][fil_ind] = np.abs(datfft[axind][freqind] * \
                                                           np.sqrt(bin_sp) * \
                                                           bu.fft_norm(Nsamp, df.fsamp))
                    amp_errs[axind][freqind][fil_ind] = daterr[axind][freqind] * \
                                                        np.sqrt(bin_sp) * \
                                                        bu.fft_norm(Nsamp, df.fsamp)

        for axind, ax in enumerate(data_axes):
            avg_asd[axind] *= (1.0 / Nasds[axind])
            diag_avg_asd[axind] *= (1.0 / Nasds[axind])

        self.freqs = freqs
        self.ginds = ginds
        self.avg_asd = avg_asd
        self.diag_avg_asd = diag_avg_asd

        self.amps = amps
        self.phases = phases
        self.amp_errs = amp_errs
        self.phase_errs = phase_errs

        self.temps = temps
        self.times = times
Esempio n. 9
0
def weigh_bead(files, colormap='jet', sort='time', file_inds=(0, 10000)):
    '''Loops over a list of file names, loads each file, diagonalizes,
       then plots the amplitude spectral density of any number of data
       or cantilever/electrode drive signals

       INPUTS: files, list of files names to extract data
               data_axes, list of pos_data axes to plot
               cant_axes, list of cant_data axes to plot
               elec_axes, list of electrode_data axes to plot
               diag, boolean specifying whether to diagonalize

       OUTPUTS: none, plots stuff
    '''

    files = [(os.stat(path), path) for path in files]
    files = [(stat.st_ctime, path) for stat, path in files]
    files.sort(key=lambda x: (x[0]))
    files = [obj[1] for obj in files]

    #files = files[file_inds[0]:file_inds[1]]
    #files = [files[0], files[-1]]
    #files = files[::10]

    date = files[0].split('/')[2]
    charge_dat = np.load(
        open('/calibrations/charges/' + date + '.charge', 'rb'))
    #q_bead = -1.0 * charge_dat[0] * 1.602e-19
    q_bead = 25.0 * 1.602e-19

    nfiles = len(files)
    colors = bu.get_color_map(nfiles, cmap=colormap)

    avg_fft = []

    mass_arr = []
    times = []

    q_arr = []

    print("Processing %i files..." % nfiles)
    for fil_ind, fil in enumerate(files):

        date = fil.split('/')[2]
        charge_dat = np.load(
            open('/calibrations/charges/' + date + '.charge', 'rb'))
        q_bead = -1.0 * charge_dat[0] * 1.602e-19

        color = colors[fil_ind]

        bu.progress_bar(fil_ind, nfiles)

        # Load data
        df = bu.DataFile()
        try:
            df.load(fil)
        except:
            continue

        df.calibrate_stage_position()
        df.calibrate_phase()
        #df.diagonalize()

        if fil_ind == 0:
            init_phi = np.mean(df.zcal)

        #plt.hist( df.zcal / df.phase[4] )
        #plt.show()

        #print np.mean(df.zcal / df.phase[4]), np.std(df.zcal / df.phase[4])

        freqs = np.fft.rfftfreq(df.nsamp, d=1.0 / df.fsamp)
        fac = bu.fft_norm(df.nsamp, df.fsamp) * np.sqrt(freqs[1] - freqs[0])

        fft = np.fft.rfft(df.zcal) * fac
        fft2 = np.fft.rfft(df.phase[4]) * fac

        fftd = np.fft.rfft(df.zcal - np.pi * df.phase[4]) * fac

        #plt.plot(np.pi * df.phase[4])
        #plt.plot((df.zcal-np.mean(df.zcal))*(0.532 / (2*np.pi)))

        #plt.figure()
        #plt.loglog(freqs, np.abs(fft))
        #plt.loglog(freqs, np.pi * np.abs(fft2))
        #plt.loglog(freqs, np.abs(fftd))
        #plt.show()

        drive_fft = np.fft.rfft(df.electrode_data[1])

        #plt.figure()
        #plt.loglog(freqs, np.abs(drive_fft))
        #plt.show()

        inds = np.abs(drive_fft) > 1e4
        inds *= (freqs > 2.0) * (freqs < 300.0)
        inds = np.arange(len(inds))[inds]

        ninds = inds + 5

        drive_amp = np.abs(drive_fft[inds][0] * fac)

        resp = fft[inds] * (1064.0e-9 / 2.0) * (1.0 / (2.0 * np.pi))
        noise = fft[ninds] * (1064.0e-9 / 2.0) * (1.0 / (2.0 * np.pi))

        drive_noise = np.abs(np.median(drive_fft[ninds] * fac))

        #plt.loglog(freqs[inds], np.abs(resp))
        #plt.loglog(freqs[ninds], np.abs(noise))
        #plt.show()

        resp_sc = resp * 1e9  # put resp in units of nm
        noise_sc = noise * 1e9

        def amp_sc(f, d_accel, f0, g):
            return np.abs(harmonic_osc(f, d_accel, f0, g)) * 1e9

        def phase_sc(f, d_accel, f0, g):
            return np.angle(harmonic_osc(f, d_accel, f0, g))

        popt, pcov = opti.curve_fit(amp_sc, freqs[inds], np.abs(resp_sc), \
                                    sigma=np.abs(noise_sc), absolute_sigma=True,
                                    p0=[1e-3, 160, 750], maxfev=10000)

        #plt.figure()
        #plt.errorbar(freqs[inds], np.abs(resp), np.abs(noise), fmt='.', ms=10, lw=2)
        #plt.loglog(freqs[inds], np.abs(noise))
        #plt.loglog(freqs, np.abs(harmonic_osc(freqs, *popt)))
        #plt.xlabel('Frequency [Hz]', fontsize=16)
        #plt.ylabel('Z Amplitude [m]', fontsize=16)
        #plt.show()

        if fil_ind == 0:
            q_bead = 25.0 * 1.602e-19
            resps = [resp]
            N = 1
        elif fil_ind < 100:
            q_bead = 25.0 * 1.602e-19
            resps.append(resp)
        else:
            mean_resp = np.mean(np.array(resps), axis=0)
            inner_prod = np.abs(np.vdot(resp, mean_resp))

            proj = inner_prod / np.abs(np.vdot(mean_resp, mean_resp))

            q_bead = (proj * 25.0) * 1.602e-19

        q_arr.append(q_bead / (1.602e-19))

        force = (drive_amp / (4.0e-3)) * q_bead

        mass = np.abs(popt[0]**(-1) * force) * 10**12  # in ng

        #if mass > 0.2:
        #    continue

        #print mass
        #print df.xy_tf_res_freqs

        if fil_ind == 0:
            delta_phi = [0.0]
        else:
            delta_phi.append(np.mean(df.zcal) - init_phi)

        mass_arr.append(mass)
        times.append(df.time)

        #fit_err = np.sqrt(pcov[0,0] / popt[0])
        #charge_err = 0.1
        #drive_err = drive_noise / drive_amp
        #mass_err = np.sqrt( (fit_err)**2 + (charge_err)**2 + (drive_err)**2  ) * mass

    plt.plot((times - times[0]) * 1e-9, q_arr)
    plt.grid(axis='y')
    plt.xlabel('Time')
    plt.ylabel('Charge [e]')

    err_bars = 0.002 * np.ones(len(delta_phi))

    fig, axarr = plt.subplots(2, 1, sharey=True)
    #plt.plot((times - times[0])*1e-9, mass_arr)
    axarr[0].errorbar((times - times[0]) * 1e-9,
                      mass_arr,
                      err_bars,
                      fmt='-o',
                      markersize=5)
    axarr[0].set_xlabel('Time [s]', fontsize=14)
    axarr[0].set_ylabel('Measured Mass [ng]', fontsize=14)

    plt.tight_layout()

    plt.figure(2)
    n, bin_edge, patch = plt.hist(mass_arr, bins=20, \
                                  color='w', edgecolor='k', linewidth=2)
    real_bins = bin_edge[:-1] + 0.5 * (bin_edge[1] - bin_edge[0])
    popt, pcov = opti.curve_fit(gauss,
                                real_bins,
                                n,
                                p0=[100, 0.08, 0.01],
                                maxfev=10000)
    lab = r'$\mu=%0.3f~\rm{ng}$, $\sigma=%0.3f~\rm{ng}$' % (popt[1], popt[2])

    test_vals = np.linspace(np.min(mass_arr), np.max(mass_arr), 100)
    plt.plot(test_vals, gauss(test_vals, *popt), color='r', linewidth=2, \
             label=lab)
    plt.legend()
    plt.xlabel('Measured Mass [ng]', fontsize=14)
    plt.ylabel('Arb', fontsize=14)

    plt.tight_layout()

    #plt.figure()
    #plt.scatter(np.array(delta_phi) * (1.0 / (2 * np.pi)) * (1064.0e-9 / 2) * 1e6, mass_arr)
    axarr[1].errorbar(np.array(delta_phi) * (1.0 / (2 * np.pi)) *
                      (1064.0e-9 / 2) * 1e6,
                      mass_arr,
                      err_bars,
                      fmt='o',
                      markersize=5)
    axarr[1].set_xlabel('Mean z-position (arb. offset) [um]', fontsize=14)
    axarr[1].set_ylabel('Measured Mass [ng]', fontsize=14)

    plt.tight_layout()

    plt.show()
def proc_mc(i):
    cdir = os.path.join(dirname, 'mc_{:d}'.format(i))

    param_path = os.path.join(cdir, 'params.p')
    params = pickle.load( open(param_path, 'rb') )

    pressure = params['pressure']
    drive_amp = params['drive_amp']
    drive_amp_noise = params['drive_amp_noise']
    drive_phase_noise = params['drive_phase_noise']
    discretized_phase = params['discretized_phase']
    drive_freq = params['drive_freq']
    fsig = params['drive_freq']
    p0 = params['p0']
    Ibead = params['Ibead']
    t_therm = params['t_therm']
    beta_rot = params['beta_rot']
    try:
        init_angle = params['init_angle']
    except Exception:
        init_angle = np.pi / 2.0

    try:
        fsamp = params['fsamp']
    except Exception:
        fsamp = 1.0e6

    beta_rot = pressure * np.sqrt(m0) / kappa
    phieq = -1.0 * np.arcsin(2.0 * np.pi * drive_freq * beta_rot / (drive_amp * p0))

    # print(phieq)

    offset_phi = 2.0 * np.pi * drive_freq * t_therm + init_angle

    # print(pressure, time_constant)


    def Ephi(t, t_therm=0.0):
        return 2.0 * np.pi * drive_freq * (t + t_therm)

    def energy(xi, t, ndim=3):
        omega = xi[ndim:]
        omega_frame = 2.0 * np.pi * drive_freq

        omega[1] -= omega_frame

        kinetic_term = 0.5 * Ibead * np.sum(omega**2, axis=0)
        potential_term = -1.0 * p0 * drive_amp * (np.sin(xi[0]) * np.cos(Ephi(t) - xi[1]))

        return kinetic_term + potential_term


    datfiles, lengths = bu.find_all_fnames(cdir, ext=ext, verbose=False, \
                                            sort_time=True, use_origin_timestamp=True)
    nfiles = lengths[0]

    integrated_energy = []
    all_energy = np.array([])
    all_t_energy = np.array([])
    all_amp = np.array([])
    all_t_amp = np.array([])

    plot = False
    for fileind, file in enumerate(datfiles):

        if fileind >= maxfile:
            break

        if plot_first_file:
            plot = not fileind

        try:
            if hdf5:
                fobj = h5py.File(file, 'r')
                dat = np.copy(fobj['sim_data'])
                fobj.close()
            else:
                dat = np.load(file)

        except Exception:
            print('Bad File!')
            print(file)
            continue

        nsamp = dat.shape[1]
        ndim = int((dat.shape[0] - 1) / 2)

        if plot_raw_dat:
            fig1, axarr1 = plt.subplots(2,1,sharex=True)
            axarr1[0].set_title('$\\theta$ - Azimuthal Coordinate (Locked)')
            axarr1[0].plot(dat[0], dat[1], zorder=2)
            axarr1[0].axhline(np.pi/2, color='k', alpha=0.7, ls='--', zorder=1, \
                                label='Equatorial plane')
            axarr1[0].set_ylabel('$\\theta$ [rad]')
            axarr1[1].plot(dat[0], dat[1+ndim])
            axarr1[1].set_xlabel('Time [s]')
            axarr1[1].set_ylabel('$\\omega_{\\theta}$ [rad/s]')
            if plot_thermalization_window:
                xlims = axarr1[0].get_xlim()
                ylims0 = axarr1[0].get_ylim()
                ylims1 = axarr1[1].get_ylim()
                xvec = np.linspace(xlims[0], t_therm, 10)
                top0 = np.ones_like(xvec) * ylims0[1]
                bot0 = np.ones_like(xvec) * ylims0[0]
                top1 = np.ones_like(xvec) * ylims1[1]
                bot1 = np.ones_like(xvec) * ylims1[0]
                axarr1[0].fill_between(xvec, bot0, top0, color='k', alpha=0.3, \
                                        label='Thermalization time')
                axarr1[1].fill_between(xvec, bot1, top1, color='k', alpha=0.3, \
                                        label='Thermalization time')
                axarr1[0].set_xlim(*xlims)
                axarr1[0].set_ylim(*ylims0)
                axarr1[1].set_ylim(*ylims1)
            axarr1[0].legend(fontsize=10, loc='lower right')
            fig1.tight_layout()

            fig2a, axarr2a = plt.subplots(2,1,sharex=True)
            axarr2a[0].set_title('$\\phi$ - Rotating Coordinate')
            axarr2a[0].plot(dat[0], dat[2])
            axarr2a[0].set_ylabel('$\\phi$ [rad]')
            axarr2a[1].plot(dat[0], dat[2+ndim])
            axarr2a[1].set_xlabel('Time [s]')
            axarr2a[1].set_ylabel('$\\omega_{\\phi}$ [rad/s]')
            if plot_thermalization_window:
                xlims = axarr2a[0].get_xlim()
                ylims0 = axarr2a[0].get_ylim()
                ylims1 = axarr2a[1].get_ylim()
                xvec = np.linspace(xlims[0], t_therm, 10)
                top0 = np.ones_like(xvec) * ylims0[1]
                bot0 = np.ones_like(xvec) * ylims0[0]
                top1 = np.ones_like(xvec) * ylims1[1]
                bot1 = np.ones_like(xvec) * ylims1[0]
                axarr2a[0].fill_between(xvec, bot0, top0, color='k', alpha=0.3, \
                                        label='Thermalization time')
                axarr2a[1].fill_between(xvec, bot1, top1, color='k', alpha=0.3, \
                                        label='Thermalization time')
                axarr2a[0].set_xlim(*xlims)
                axarr2a[0].set_ylim(*ylims0)
                axarr2a[1].set_ylim(*ylims1)
            axarr2a[0].legend(fontsize=10, loc='lower right')
            fig2a.tight_layout()

            fig2b, axarr2b = plt.subplots(2,1,sharex=True)
            axarr2b[0].set_title("$\\phi'$ - In Rotating Frame")
            axarr2b[0].plot(dat[0], dat[2] - 2.0*np.pi*drive_freq*dat[0] - offset_phi, zorder=2)
            axarr2b[0].axhline(phieq, color='k', alpha=0.7, ls='--', zorder=1, \
                                label='Expected Equilibrium value')
            axarr2b[0].set_ylabel('$\\phi$ [rad]')
            axarr2b[1].plot(dat[0], dat[2+ndim]-2.0*np.pi*drive_freq)
            axarr2b[1].set_xlabel('Time [s]')
            axarr2b[1].set_ylabel('$\\omega_{\\phi}$ [rad/s]')
            if plot_thermalization_window:
                xlims = axarr2b[0].get_xlim()
                ylims0 = axarr2b[0].get_ylim()
                ylims1 = axarr2b[1].get_ylim()
                xvec = np.linspace(xlims[0], t_therm, 10)
                top0 = np.ones_like(xvec) * ylims0[1]
                bot0 = np.ones_like(xvec) * ylims0[0]
                top1 = np.ones_like(xvec) * ylims1[1]
                bot1 = np.ones_like(xvec) * ylims1[0]
                axarr2b[0].fill_between(xvec, bot0, top0, color='k', alpha=0.3, \
                                        label='Thermalization time')
                axarr2b[1].fill_between(xvec, bot1, top1, color='k', alpha=0.3, \
                                        label='Thermalization time')
                axarr2b[0].set_xlim(*xlims)
                axarr2b[0].set_ylim(*ylims0)
                axarr2b[1].set_ylim(*ylims1)
            axarr2b[0].legend(fontsize=10, loc='lower right')
            fig2b.tight_layout()

            if ndim == 3:
                fig3, axarr3 = plt.subplots(2,1,sharex=True)
                axarr3[0].set_title('$\\psi$ - Roll About Dipole (Free)')
                axarr3[0].plot(dat[0], dat[3])
                axarr3[0].set_ylabel('$\\psi$ [rad]')
                axarr3[1].plot(dat[0], dat[3+ndim])
                axarr3[1].set_xlabel('Time [s]')
                axarr3[1].set_ylabel('$\\omega_{\\psi}$ [rad/s]')
                if plot_thermalization_window:
                    xlims = axarr3[0].get_xlim()
                    ylims0 = axarr3[0].get_ylim()
                    ylims1 = axarr3[1].get_ylim()
                    xvec = np.linspace(xlims[0], t_therm, 10)
                    top0 = np.ones_like(xvec) * ylims0[1]
                    bot0 = np.ones_like(xvec) * ylims0[0]
                    top1 = np.ones_like(xvec) * ylims1[1]
                    bot1 = np.ones_like(xvec) * ylims1[0]
                    axarr3[0].fill_between(xvec, bot0, top0, color='k', alpha=0.3, \
                                            label='Thermalization time')
                    axarr3[1].fill_between(xvec, bot1, top1, color='k', alpha=0.3, \
                                            label='Thermalization time')
                    axarr3[0].set_xlim(*xlims)
                    axarr3[0].set_ylim(*ylims0)
                    axarr3[1].set_ylim(*ylims1)
                axarr3[0].legend(fontsize=10, loc='lower right')
                fig3.tight_layout()

            plt.show()

            input()

        tvec = dat[0]
        theta = dat[1]
        phi = dat[2]

        energy_vec = energy(dat[1:], tvec, ndim=ndim)
        freqs = np.fft.rfftfreq(nsamp, d=1.0/fsamp)
        energy_psd = np.abs( np.fft.rfft(energy_vec-np.mean(energy_vec)) )**2 * bu.fft_norm(nsamp, fsamp)**2
        energy_asd = np.sqrt(energy_psd)
        # plt.loglog(freqs, energy_asd*freqs)
        # plt.show()

        integrated_energy.append(np.sqrt(np.sum(energy_psd) * (freqs[1] - freqs[0])))

        crossp = np.sin(phi)**2

        carrier_amp, carrier_phase \
                = bu.demod(crossp, fsig, fsamp, harmind=2.0, filt=True, \
                           bandwidth=4000.0, plot=plot, tukey=True, \
                           tukey_alpha=1e-3)

        params, cov = bu.fit_damped_osc_amp(carrier_phase, fsamp, plot=plot)

        libration_amp, libration_phase \
                = bu.demod(carrier_phase, params[1], fsamp, harmind=1.0, \
                           filt=True, filt_band=[100, 2000], plot=plot, \
                           tukey=True, tukey_alpha=1e-3)

        amp_ds, tvec_ds = signal.resample(libration_amp, 500, t=tvec, window=None)
        amp_ds_cut = amp_ds[5:-5]
        tvec_ds_cut = tvec_ds[5:-5]

        energy_ds, tvec_ds_2 = signal.resample(energy_vec, 100, t=tvec, window=None)
        energy_ds_cut = energy_ds[5:-5]
        tvec_ds_cut_2 = tvec_ds_2[5:-5]

        all_amp = np.concatenate( (all_amp, amp_ds_cut) )
        all_t_amp = np.concatenate( (all_t_amp, tvec_ds_cut) )

        all_energy = np.concatenate( (all_energy, energy_ds_cut))
        all_t_energy = np.concatenate( (all_t_energy, tvec_ds_cut_2) )

    return [pressure, all_t_amp, all_amp, all_t_energy, all_energy, integrated_energy, \
            drive_amp, drive_amp_noise, drive_phase_noise, discretized_phase]
Esempio n. 11
0
def plot_spectra_3d(files, ax_to_plot=0, diag=False, colormap='plasma'):
    '''Makes a cool 3d plot since waterfalls/cascaded plots end up kind 
       being f****d up.
    '''

    res_freqs = []
    powers = []

    fig = plt.figure(figsize=(7, 5))
    ax = fig.gca(projection='3d')

    ax.get_proj = lambda: np.dot(Axes3D.get_proj(ax), np.diag([1, 1, 0.6, 1]))

    # fig.suptitle('XYZ Data', fontsize=18)

    files = files

    colors = bu.get_color_map(len(files_to_plot), cmap=colormap)
    i = 0
    #colors = ['C0', 'C1', 'C2']

    print("Processing %i files..." % len(files))
    for fil_ind, fil in enumerate(files):

        # Display percent completion
        bu.progress_bar(fil_ind, len(files))

        # Load data
        df = bu.DataFile()
        if new_trap:
            df.load_new(fil)
        else:
            df.load(fil)

        df.calibrate_stage_position()

        if diag:
            df.diagonalize(maxfreq=lpf, date=tfdate, plot=tf_plot)

        try:
            fac = df.conv_facs[ax_to_plot]  # * (1.0 / 0.12e-12)
        except:
            fac = 1.0

        if fullNFFT:
            NFFT = len(df.pos_data[ax_to_plot])
        else:
            NFFT = userNFFT

        if diag:
            psd, freqs = mlab.psd(df.diag_pos_data[ax_to_plot], Fs=df.fsamp, \
                                    NFFT=NFFT, window=window)
        else:
            psd, freqs = mlab.psd(df.pos_data[ax_to_plot], Fs=df.fsamp, \
                                  NFFT=NFFT, window=window)

        inds = (freqs > ylim[0]) * (freqs < ylim[1]) * (
            np.sqrt(psd) > zlim[0] * fac_for_resfreq)

        freqs = freqs[inds]
        psd = psd[inds]

        norm = bu.fft_norm(df.nsamp, df.fsamp)
        new_freqs = np.fft.rfftfreq(df.nsamp, d=1.0 / df.fsamp)

        xs = np.zeros_like(freqs) + fil_ind

        if fil_ind in files_to_plot:
            popt, pcov = bu.fit_damped_osc_amp(df.pos_data[ax_to_plot], fit_band=[10, 2000], \
                                                fsamp=df.fsamp, plot=False)
            res_freqs.append(popt[1])

            color = colors[i]
            i += 1
            ax.plot(xs, np.log10(freqs), np.log10(np.sqrt(psd)), color=color)

    zlim_actual = (zlim[0] * fac_for_resfreq, zlim[1])

    x = np.arange(len(res_freqs))
    interpfunc = interpolate.UnivariateSpline(x, res_freqs, k=2)

    ax.scatter(x, np.log10(res_freqs), zs=np.log10(zlim_actual[0]), \
                zdir='z', s=25, c=colors, alpha=1)
    ax.plot(x, np.log10(interpfunc(x)), zs=np.log10(zlim_actual[0]), \
            zdir='z', lw=2, color='k', zorder=1)

    # ax.grid()

    if ylim:
        ax.set_ylim(np.log10(ylim[0]), np.log10(ylim[1]))

    if zlim:
        ax.set_zlim(np.log10(zlim_actual[0]), np.log10(zlim_actual[1]))

    ax.set_xticks([])

    ax.set_yticks(np.log10(yticks))
    ax.set_yticklabels(yticks)

    ax.set_zticks(np.log10(zticks))
    ax.set_zticklabels(zticklabels)

    # ax.ticklabel_format(axis='z', style='sci')

    ax.set_xlabel('Closer to Focus $\\rightarrow$', labelpad=0)
    ax.set_ylabel('Frequency [Hz]', labelpad=20)
    ax.set_zlabel('ASD [Arb/$\\sqrt{\\rm Hz}$]', labelpad=15)

    # if xlim:
    #     ax.set_xlim(*xlim)

    # if ylim:
    #     ax.set_ylim(*ylim)

    # if zlim:
    #     ax.set_zlim(*zlim)

    # fig.tight_layout()

    ax.view_init(elev=15, azim=-15)

    fig.tight_layout()

    fig.subplots_adjust(top=1.35, left=-0.07, right=0.95, bottom=-0.05)
    plt.show()
def proc_mc(i):
    ### Build the path name, assuming the monte-carlo's are
    ### zero-indexed
    cdir = os.path.join(dirname, 'mc_{:d}'.format(i))

    ### Load the simulation parameters saved alongside the data
    param_path = os.path.join(cdir, 'params.p')
    params = pickle.load(open(param_path, 'rb'))

    ### Define some values that are necessary for analysis
    pressure = params['pressure']
    drive_amp = params['drive_amp']
    fsig = params['drive_freq']
    drive_freq = params['drive_freq']
    p0 = params['p0']
    Ibead = params['Ibead']
    kappa = params['kappa']
    fsamp = params['fsamp']
    fsamp_ds = fsamp

    try:
        t_therm = params['t_therm']
    except:
        t_therm = 0.0

    try:
        init_angle = params['init_angle']
    except Exception:
        init_angle = np.pi / 2.0

    beta_rot = pressure * np.sqrt(m0) / kappa
    phieq = -1.0 * np.arcsin(2.0 * np.pi * drive_freq * beta_rot /
                             (drive_amp * p0))

    time_constant = Ibead / beta_rot
    gamma_calc = 1.0 / time_constant

    # print(pressure, time_constant, t_therm)

    ### Load the data
    datfiles, lengths = bu.find_all_fnames(cdir, ext=ext, verbose=False, \
                                            sort_time=True, use_origin_timestamp=True)

    ### Invert the data file array so that the last files are processed first
    ### since the last files should be the most thermalized
    datfiles = datfiles[::-1]
    nfiles = lengths[0]

    ### Depeding on the requested behavior, instantiate some arrays
    if concatenate:
        long_t = []
        long_sig = []
        long_sig_2 = []
    if average:
        psd_array = []

    ### Loop over the datafiles
    for fileind, file in enumerate(datfiles):
        # print(file)
        ### Break the loop if we've acquired enough data
        if fileind > nspectra_to_combine - 1:
            break

        ### Load the data, taking into account the file type
        if hdf5:
            fobj = h5py.File(file, 'r')
            dat = np.copy(fobj['sim_data'])
            fobj.close()
        else:
            dat = np.load(file)

        ### Determine the length of the data
        nsamp = dat.shape[1]
        nsamp_ds = int(nsamp / downsample_fac)

        ### Load the angles and construct the x-component of the dipole
        ### based on the integrated angular positions
        tvec = dat[0]
        theta = dat[1]
        phi = dat[2]
        px = p0 * np.cos(phi) * np.sin(theta)

        E_phi = 2.0 * np.pi * drive_freq * (tvec + t_therm) + init_angle

        ones = np.ones(len(tvec))

        dipole = np.array([ones, theta, phi])
        efield = np.array([ones, ones * (np.pi / 2), E_phi])
        lib_angle = bu.angle_between_vectors(dipole, efield, coord='s')

        ### construct an estimate of the cross-polarized light
        crossp = np.sin(phi)**2

        ### Normalize to avoid numerical errors. Try to get the max to sit at 10
        crossp *= (10.0 / np.max(np.abs(crossp)))

        ### Build up the long signal if concatenation is desired
        if concatenate:
            if not len(long_sig):
                long_t = tvec
                long_sig = crossp
                long_phi = phi
                long_lib = lib_angle
            else:
                long_t = np.concatenate((tvec, long_t))
                long_sig = np.concatenate((crossp, long_sig))
                long_phi = np.concatenate((phi, long_phi))
                long_lib = np.concatenate((lib_angle, long_lib))

        ### Using a hilbert transform, demodulate the amplitude and phase of
        ### the carrier signal. Filter things if desired.
        carrier_amp, carrier_phase \
                = bu.demod(crossp, fsig, fsamp, harmind=2.0, filt=True, \
                           bandwidth=4000.0, plot=plot_demod, ncycle_pad=100, \
                           tukey=True, tukey_alpha=5e-4)

        # carrier_phase = phi - E_phi

        if plot_raw_data:
            phi_lab = '$\\phi$'
            theta_lab = '$\\theta - \\pi / 2$'
            lib_lab = '$\\left| \\measuredangle (\\vec{E}) (\\vec{d}) \\right|$'

            # plt.plot(carrier_phase)
            plt.plot(tvec, carrier_phase, alpha=1.0, label=phi_lab)
            plt.plot(tvec, theta - np.pi / 2, alpha=0.7, label=theta_lab)
            plt.plot(tvec, lib_angle, alpha=0.7, label=lib_lab)
            plt.title('In Rotating Frame', fontsize=14)
            plt.xlabel('Time [s]')
            plt.ylabel('Angular Coordinate [rad]')
            plt.legend(loc='lower right', fontsize=12)
            plt.tight_layout()
            # plt.show()

            freqs = np.fft.rfftfreq(nsamp, d=1.0 / fsamp)
            norm = bu.fft_norm(nsamp, fsamp)
            plt.figure()
            plt.loglog(freqs,
                       np.abs(np.fft.rfft(carrier_phase)) * norm,
                       label=phi_lab)
            plt.loglog(freqs,
                       np.abs(np.fft.rfft(theta - np.pi / 2)) * norm,
                       label=theta_lab)
            plt.loglog(freqs,
                       np.abs(np.fft.rfft(lib_angle)) * norm,
                       label=lib_lab)
            plt.xlabel('Frequency [Hz]')
            plt.ylabel('ASD [rad / $\\sqrt{ \\rm Hz}$]')
            plt.legend(loc='lower right', fontsize=12)
            plt.xlim(330, 1730)
            plt.ylim(5e-7, 3e-2)
            plt.tight_layout()
            plt.show()

            input()

        ### Downsample the data if desired
        if downsample:
            ### Use scipy's fourier-based downsampling
            carrier_phase_ds, tvec_ds = signal.resample(carrier_phase,
                                                        nsamp_ds,
                                                        t=tvec,
                                                        window=None)
            carrier_phase = np.copy(carrier_phase_ds)
            tvec = np.copy(tvec_ds)

            dt = tvec_ds[1] - tvec_ds[0]
            fsamp_ds = 1.0 / dt

            ### Compute the frequencies and ASD values of the downsampled signal
            freqs = np.fft.rfftfreq(nsamp_ds, d=dt)
            carrier_phase_asd = bu.fft_norm(nsamp_ds, fsamp_ds) * np.abs(
                np.fft.rfft(carrier_phase_ds))

        else:
            ### Compute the frequencies and ASD values
            freqs = np.fft.rfftfreq(nsamp, d=1.0 / fsamp)
            carrier_phase_asd = bu.fft_norm(nsamp, fsamp) * np.abs(
                np.fft.rfft(carrier_phase))

        ### Add the data from the current file to the array of PSDs
        if average:
            if not len(psd_array):
                psd_array = np.zeros(
                    (nspectra_to_combine, len(carrier_phase_asd)),
                    dtype=np.float64)
            psd_array[fileind, :] += carrier_phase_asd**2

    ### Compute the mean and uncertainty of the PSDs, then compute the ASD
    if average:
        avg_psd = np.mean(psd_array, axis=0)
        fit_asd = np.sqrt(avg_psd)

        ### Use propogation of uncertainty and the standard error on the mean
        asd_errs = 0.5 * fit_asd * (np.std(psd_array, axis=0) \
                    * np.sqrt(1.0 / nspectra_to_combine)) / avg_psd

    ### If concatenation was desired, first demodulate the amplitude and phase of the
    ### carrier signal, and then downsample the carrier phase.
    if concatenate:
        ### Compute the new values of nsamp
        nsamp = len(long_sig)
        if downsample:
            nsamp_ds = int(nsamp / downsample_fac)
        else:
            nsamp_ds = nsamp

        ### Hilbert transform demodulation
        carrier_amp_long, carrier_phase_long \
                = bu.demod(long_sig, fsig, fsamp, harmind=2.0, filt=False, \
                           bandwidth=5000.0, plot=False, ncycle_pad=ncycle_pad, \
                           tukey=True, tukey_alpha=1e-4)

        carrier_phase_long = long_phi - 2.0 * np.pi * drive_freq * (
            long_t + t_therm) - init_angle

        ### Downsampling
        carrier_phase_ds, tvec_ds = signal.resample(carrier_phase_long, nsamp_ds, \
                                                    t=long_t, window=None)
        long_lib_ds, tvec_ds_2 = signal.resample(long_lib, nsamp_ds, \
                                                 t=long_t, window=None)

        ### Compute the ASD of the downsampled signals
        fit_asd = bu.fft_norm(nsamp_ds, fsamp_ds) * np.abs(
            np.fft.rfft(carrier_phase_ds))
        fit_asd_2 = bu.fft_norm(nsamp_ds, fsamp_ds) * np.abs(
            np.fft.rfft(long_lib_ds))
        asd_errs = []

        ### Compute the new frequency arrays
        freqs = np.fft.rfftfreq(nsamp_ds, d=1.0 / fsamp_ds)

    ### Fit either the averaged ASD or the ASD of the concatenated signal
    params, cov = bu.fit_damped_osc_amp(fit_asd, fsamp_ds, plot=False, \
                                        sig_asd=True, linearize=True, \
                                        asd_errs=asd_errs, fit_band=[500.0,600.0], \
                                        gamma_guess=gamma_calc, \
                                        weight_lowf=True, weight_lowf_val=0.5, \
                                        weight_lowf_thresh=200)

    # plt.loglog(freqs, fit_asd_2)
    # plt.show()

    ### Fit either the averaged ASD or the ASD of the concatenated signal
    params_2, cov_2 = bu.fit_damped_osc_amp(fit_asd_2, fsamp_ds, plot=False, \
                                            sig_asd=True, linearize=True, \
                                            asd_errs=[], fit_band=[1050.0,1150.0], \
                                            gamma_guess=gamma_calc, freq_guess=2.0*params[1], \
                                            weight_lowf=True, weight_lowf_val=0.5, \
                                            weight_lowf_thresh=200)

    outdict = {'pressure': pressure, 'freqs': freqs, \
               'fit_asd': fit_asd, 'params': params, 'cov': cov, \
               'fit_asd_2': fit_asd_2, 'params_2': params_2, 'cov_2': cov_2, \
               'gamma_calc': gamma_calc, 'drive_freq': drive_freq}

    return outdict
Esempio n. 13
0
def weigh_bead_efield(files, elec_ind, pow_ind, colormap='plasma', sort='time',\
                      file_inds=(0,10000), plot=True, print_res=False, pos=False, \
                      save_mass=False, new_trap=False, correct_phase_shift=False):
    '''Loops over a list of file names, loads each file, diagonalizes,
       then plots the amplitude spectral density of any number of data
       or cantilever/electrode drive signals

       INPUTS: files, list of files names to extract data
               data_axes, list of pos_data axes to plot
               cant_axes, list of cant_data axes to plot
               elec_axes, list of electrode_data axes to plot
               diag, boolean specifying whether to diagonalize

       OUTPUTS: none, plots stuff
    '''
    date = re.search(r"\d{8,}", files[0])[0]
    suffix = files[0].split('/')[-2]

    if new_trap:
        trap_str = 'new_trap'
    else:
        trap_str = 'old_trap'

    charge_file = '/data/{:s}_processed/calibrations/charges/'.format(
        trap_str) + date
    save_filename = '/data/{:s}_processed/calibrations/masses/'.format(trap_str) \
                            + date + '_' + suffix + '.mass'
    bu.make_all_pardirs(save_filename)

    if pos:
        charge_file += '_recharge.charge'
    else:
        charge_file += '.charge'

    try:
        nq = np.load(charge_file)[0]
        found_charge = True
    except:
        found_charge = False

    if not found_charge or manual_charge:
        user_nq = input('No charge file or manual requested. Guess q: ')
        nq = int(user_nq)

    if correct_phase_shift:
        print('Correcting anomalous phase-shift during analysis.')

    # nq = -16
    print('qbead: {:d} e'.format(int(nq)))
    q_bead = nq * constants.elementary_charge

    run_index = 0

    masses = []

    nfiles = len(files)
    if not print_res:
        print("Processing %i files..." % nfiles)

    all_eforce = []
    all_power = []

    all_param = []

    mass_vec = []

    p_ac = []
    p_dc = []

    e_ac = []
    e_dc = []

    pressure_vec = []

    zamp_avg = 0
    zphase_avg = 0
    zamp_N = 0
    zfb_avg = 0
    zfb_N = 0
    power_avg = 0
    power_N = 0

    Nbad = 0

    powpsd = []

    for fil_ind, fil in enumerate(files):  # 15-65

        # 4
        # if fil_ind == 16 or fil_ind == 4:
        #     continue

        bu.progress_bar(fil_ind, nfiles)

        # Load data
        df = bu.DataFile()
        try:
            if new_trap:
                df.load_new(fil)
            else:
                df.load(fil, load_other=True)
        except Exception:
            traceback.print_exc()
            continue

        try:
            # df.calibrate_stage_position()
            df.calibrate_phase()
        except Exception:
            traceback.print_exc()
            continue

        if ('20181129' in fil) and ('high' in fil):
            pressure_vec.append(1.5)
        else:
            try:
                pressure_vec.append(df.pressures['pirani'])
            except Exception:
                pressure_vec.append(0.0)

        ### Extract electrode data
        if new_trap:
            top_elec = df.electrode_data[1]
            bot_elec = df.electrode_data[2]
        else:
            top_elec = mon_fac * df.other_data[elec_ind]
            bot_elec = mon_fac * df.other_data[elec_ind + 1]

        fac = 1.0
        if np.std(top_elec) < 0.5 * np.std(bot_elec) \
                or np.std(bot_elec) < 0.5 * np.std(top_elec):
            print(
                'Adjusting electric field since only one electrode was digitized.'
            )
            fac = 2.0

        nsamp = len(top_elec)
        zeros = np.zeros(nsamp)

        voltages = [zeros, top_elec, bot_elec, zeros, \
                    zeros, zeros, zeros, zeros]
        efield = bu.trap_efield(voltages, new_trap=new_trap)
        eforce2 = fac * sign * efield[2] * q_bead

        tarr = np.arange(0, df.nsamp / df.fsamp, 1.0 / df.fsamp)

        # fig, axarr = plt.subplots(2,1,sharex=True,figsize=(10,8))

        # axarr[0].plot(tarr, top_elec, label='Top elec.')
        # axarr[0].plot(tarr, bot_elec, label='Bottom elec.')
        # axarr[0].set_ylabel('Apparent Voltages [V]')
        # axarr[0].legend(fontsize=12, loc='upper right')

        # axarr[1].plot(tarr, efield[2])
        # axarr[1].set_xlabel('Time [s]')
        # axarr[1].set_ylabel('Apparent Electric Field [V/m]')

        # fig.tight_layout()

        # plt.show()
        # input()

        freqs = np.fft.rfftfreq(df.nsamp, d=1.0 / df.fsamp)
        drive_ind = np.argmax(np.abs(np.fft.rfft(eforce2)))
        drive_freq = freqs[drive_ind]

        zamp = np.abs( np.fft.rfft(df.zcal) * bu.fft_norm(df.nsamp, df.fsamp) * \
                       np.sqrt(freqs[1] - freqs[0]) )
        zamp *= (1064.0e-9 / 2.0) * (1.0 / (2.9 * np.pi))
        zphase = np.angle(np.fft.rfft(df.zcal))
        zamp_avg += zamp[drive_ind]
        zamp_N += 1

        #plt.loglog(freqs, zamp)
        #plt.scatter(freqs[drive_ind], zamp[drive_ind], s=10, color='r')
        #plt.show()


        zfb = np.abs(np.fft.rfft(df.pos_fb[2]) * bu.fft_norm(df.nsamp, df.fsamp) * \
                      np.sqrt(freqs[1] - freqs[0]) )
        zfb_avg += zfb[drive_ind]
        zfb_N += 1

        #eforce2 = (top_elec * e_top_func(0.0) + bot_elec * e_bot_func(0.0)) * q_bead
        if noise:
            e_dc.append(np.mean(eforce2))
            e_ac_val = np.abs(np.fft.rfft(eforce2))[drive_ind]
            e_ac.append(e_ac_val * bu.fft_norm(df.nsamp, df.fsamp) \
                        * np.sqrt(freqs[1] - freqs[0]) )

        zphase_avg += (zphase[drive_ind] - np.angle(eforce2)[drive_ind])

        if np.sum(df.power) == 0.0:
            current = np.abs(df.other_data[pow_ind]) / trans_gain
        else:
            fac = 1e-6
            current = fac * df.power / trans_gain

        power = current / pd_gain
        power = power / line_filter_trans
        power = power / bs_fac

        power_avg += np.mean(power)
        power_N += 1
        if noise:
            p_dc.append(np.mean(power))
            p_ac_val = np.abs(np.fft.rfft(power))[drive_ind]
            p_ac.append(p_ac_val * bu.fft_norm(df.nsamp, df.fsamp) \
                        * np.sqrt(freqs[1] - freqs[0]) )

        fft1 = np.fft.rfft(power)
        fft2 = np.fft.rfft(df.pos_fb[2])

        if not len(powpsd):
            powpsd = np.abs(fft1)
            Npsd = 1
        else:
            powpsd += np.abs(fft1)
            Npsd += 1

        # freqs = np.fft.rfftfreq(df.nsamp, d=1.0/df.fsamp)
        # plt.loglog(freqs, np.abs(np.fft.rfft(eforce2)))
        # plt.loglog(freqs, np.abs(np.fft.rfft(power)))
        # plt.show()
        # input()

        # fig, axarr = plt.subplots(2,1,sharex=True,figsize=(10,8))

        # axarr[0].plot(tarr, power)
        # axarr[0].set_ylabel('Measured Power [Arb.]')

        # axarr[1].plot(tarr, power)
        # axarr[1].set_xlabel('Time [s]')
        # axarr[1].set_ylabel('Measured Power [Arb.]')

        # bot, top = axarr[1].get_ylim()
        # axarr[1].set_ylim(1.05*bot, 0)

        # fig.tight_layout()

        # plt.show()
        # input()


        bins, dat, errs = bu.spatial_bin(eforce2, power, nbins=200, width=0.0, #width=0.05, \
                                         dt=1.0/df.fsamp, harms=[1], \
                                         add_mean=True, verbose=False, \
                                         correct_phase_shift=correct_phase_shift, \
                                         grad_sign=0)

        dat = dat / np.mean(dat)

        #plt.plot(bins, dat, 'o')
        #plt.show()

        popt, pcov = opti.curve_fit(line, bins*1.0e13, dat, \
                                    absolute_sigma=False, maxfev=10000)
        test_vals = np.linspace(np.min(eforce2 * 1.0e13),
                                np.max(eforce2 * 1.0e13), 100)

        fit = line(test_vals, *popt)

        lev_force = -popt[1] / (popt[0] * 1.0e13)
        mass = lev_force / (9.806)

        #umass = ulev_force / 9.806
        #lmass = llev_force / 9.806

        if mass > upper_outlier or mass < lower_outlier:
            print('Crazy mass: {:0.2f} pg.... ignoring'.format(mass * 1e15))
            # fig, axarr = plt.subplots(3,1,sharex=True)
            # axarr[0].plot(eforce2)
            # axarr[1].plot(power)
            # axarr[2].plot(df.pos_data[2])
            # ylims = axarr[1].get_ylim()
            # axarr[1].set_ylim(ylims[0], 0)
            # plt.show()
            continue

        all_param.append(popt)

        all_eforce.append(bins)
        all_power.append(dat)

        mass_vec.append(mass)

    if noise:
        print('DC power: ', np.mean(p_dc), np.std(p_dc))
        print('AC power: ', np.mean(p_ac), np.std(p_ac))
        print('DC field: ', np.mean(e_dc), np.std(e_dc))
        print('AC field: ', np.mean(e_ac), np.std(e_ac))
        return

    #plt.plot(mass_vec)

    mean_popt = np.mean(all_param, axis=0)

    mean_lev = np.mean(mass_vec) * 9.806
    plot_vec = np.linspace(np.min(all_eforce), mean_lev, 100)

    if plot:
        fig = plt.figure(dpi=200, figsize=(6, 4))
        ax = fig.add_subplot(111)
        ### Plot force (in pN / g = pg) vs power
        plt.plot(np.array(all_eforce).flatten()[::5]*1e15*(1.0/9.806), \
                 np.array(all_power).flatten()[::5], \
                 'o', alpha = 0.5)
        #for params in all_param:
        #    plt.plot(plot_vec, line(plot_vec, params[0]*1e13, params[1]), \
        #             '--', color='r', lw=1, alpha=0.05)
        plt.plot(plot_vec*1e12*(1.0/9.806)*1e3, \
                 line(plot_vec, mean_popt[0]*1e13, mean_popt[1]), \
                 '--', color='k', lw=2, \
                 label='Implied mass: %0.1f pg' % (np.mean(mass_vec)*1e15))
        left, right = ax.get_xlim()
        # ax.set_xlim((left, 500))
        ax.set_xlim(*xlim)

        bot, top = ax.get_ylim()
        ax.set_ylim((0, top))

        plt.legend()
        plt.xlabel('Applied electrostatic force/$g$ (pg)')
        plt.ylabel('Optical power (arb. units)')
        plt.grid()
        plt.tight_layout()
        if save_example:
            fig.savefig(example_filename)
            fig.savefig(example_filename[:-4] + '.pdf')
            fig.savefig(example_filename[:-4] + '.svg')

        x_plotvec = np.array(all_eforce).flatten()
        y_plotvec = np.array(all_power).flatten()

        yresid = (y_plotvec - line(x_plotvec, mean_popt[0] * 1e13,
                                   mean_popt[1])) / y_plotvec

        plt.figure(dpi=200, figsize=(3, 2))
        plt.hist(yresid * 100, bins=30)
        plt.legend()
        plt.xlabel('Resid. Power [%]')
        plt.ylabel('Counts')
        plt.grid()
        plt.tight_layout()

        plt.figure(dpi=200, figsize=(3, 2))
        plt.plot(x_plotvec * 1e15, yresid * 100, 'o')
        plt.legend()
        plt.xlabel('E-Force [pN]')
        plt.ylabel('Resid. Pow. [%]')
        plt.grid()
        plt.tight_layout()

        derpfig = plt.figure(dpi=200, figsize=(3, 2))
        #derpfig.patch.set_alpha(0.0)
        plt.hist(np.array(mass_vec) * 1e15, bins=10)
        plt.xlabel('Mass (pg)')
        plt.ylabel('Count')
        plt.grid()
        #plt.title('Implied Masses, Each from 50s Integration')
        #plt.xlim(0.125, 0.131)
        plt.tight_layout()
        if save_example:
            derpfig.savefig(example_filename[:-4] + '_hist.png')
            derpfig.savefig(example_filename[:-4] + '_hist.pdf')
            derpfig.savefig(example_filename[:-4] + '_hist.svg')

        plt.show()

    final_mass = np.mean(mass_vec)
    final_err_stat = 0.5 * np.std(mass_vec)  #/ np.sqrt(len(mass_vec))
    final_err_sys = np.sqrt((0.015**2 + 0.01**2) * final_mass**2)
    final_pressure = np.mean(pressure_vec)

    if save_mass:
        save_arr = [final_mass, final_err_stat, final_err_sys]
        np.save(open(save_filename, 'wb'), save_arr)

    print('Bad Files: %i / %i' % (Nbad, nfiles))
    if print_res:
        gresid_fac = (2.0 * np.pi * freqs[drive_ind])**2 / 9.8

        print('      mass    [pg]: {:0.1f}'.format(final_mass * 1e15))
        print('      st.err  [pg]: {:0.2f}'.format(final_err_stat * 1e15))
        print('      sys.err [pg]: {:0.2f}'.format(final_err_sys * 1e15))
        print('      qbead    [e]: {:d}'.format(
            int(round(q_bead / constants.elementary_charge))))
        print('      P     [mbar]: {:0.2e}'.format(final_pressure))
        print('      <P>    [arb]: {:0.2e}'.format(power_avg / power_N))
        print('      zresid   [g]: {:0.3e}'.format(
            (zamp_avg / zamp_N) * gresid_fac))
        print('      zphase [rad]: {:0.3e}'.format(zphase_avg / zamp_N))
        print('      zfb    [arb]: {:0.3e}'.format(zfb_avg / zfb_N))
        outarr = [ final_mass*1e15, final_err_stat*1e15, final_err_sys*1e15, \
                   q_bead/constants.elementary_charge, \
                   final_pressure, power_avg / power_N, \
                   (zamp_avg / zamp_N) * gresid_fac, \
                   zphase_avg / zamp_N, zfb_avg / zfb_N ]
        return outarr
    else:
        scaled_params = np.array(all_param)
        scaled_params[:, 0] *= 1e13

        outdic = {'eforce': all_eforce, 'power': all_power, \
                  'linear_fit_params': scaled_params, \
                  'ext_masses': mass_vec}

        return outdic