Esempio n. 1
0
def calibrateScanMirror(appObj):
    DebugLog.log("calibrateScanMirror")    
    appObj.tabWidget.setCurrentIndex(7)
    appObj.doneFlag = False
    appObj.isCollecting = True
    appObj.JSOsaveDispersion_pushButton.setEnabled(True)
    appObj.JSOloadDispersion_pushButton.setEnabled(False)

    if not appObj.oct_hw.IsOCTTestingMode():     # prepare to get new data            
        from DAQHardware import DAQHardware
        daq = DAQHardware()
    audioHW=appObj.audioHW
    mirrorDriver = appObj.mirrorDriver    
    chanNames = [mirrorDriver.X_daqChan, mirrorDriver.Y_daqChan]
    trigChan = audioHW.daqTrigChanIn   #use the audio trigger to start the scan
    outputRate = mirrorDriver.DAQoutputRate

    while appObj.doneFlag == False:        # keep running until the button is turned off 
        scanParams = appObj.getScanParams()
       #    create scan pattern to drive the mirrors
        mode=appObj.scanShape_comboBox.currentIndex()
        print('mode',mode)
        if mode==0:   # create a spiral scan using fast (resonant) scanning
            Vmaxx=mirrorDriver.voltRange[1] # maximum voltage for MEMS mirror for x-axis
            Vmaxy=mirrorDriver.voltRange[1] # maximum voltage for MEMS mirror for y-axis
            xAdjust = 1    
            yAdjust = scanParams.skewResonant
            phaseShift = scanParams.phaseAdjust
            fr = mirrorDriver.resonantFreq  # angular scan rate (frequency of one rotation - resonant frequency)
            fv = scanParams.volScanFreq     # plotParam scan frequency, which scans in and then out, which is actually two volumes
            DebugLog.log("freq of one rotation (fr)= %d; scan frequency (fv)= %d" % (fr, fv))
            diameter = scanParams.length
            voltsPerMM = mirrorDriver.voltsPerMillimeterResonant
            A1=(Vmaxx/2)/xAdjust
            A2=(Vmaxy/2)/yAdjust
            A3=voltsPerMM*diameter/2 
            A=np.min([A1,A2,A3])           
            fs=mirrorDriver.DAQoutputRate   # galvo output sampling rate
            t=np.arange(0,np.around(fs/fv))*1/fs  # t is the array of times for the DAQ output to the mirrors
            r=1/2*(1-np.cos(2*np.pi*fv*t))            
            x=xAdjust*A*r*np.cos(2*np.pi*fr*t) # x and y are the coordinates of the laser at each point in time
            y=yAdjust*A*r*np.sin(2*np.pi*fr*t+phaseShift*np.pi/180)
            mirrorOut= np.vstack((x,y))
            
        elif mode==1:   # create a square scan using slow parameters
            Vmaxx=mirrorDriver.voltRange[1] # maximum voltage for MEMS mirror for x-axis
            Vmaxy=mirrorDriver.voltRange[1] # maximum voltage for MEMS mirror for y-axis
            xAdjust = 1    
            yAdjust = scanParams.skewNonResonant
            diameter = scanParams.length
            voltsPerMMX = mirrorDriver.voltsPerMillimeter*xAdjust
            voltsPerMMY = mirrorDriver.voltsPerMillimeter*yAdjust
            if ((diameter/2)*voltsPerMMX)>Vmaxx:
                diameter=2*Vmaxx/voltsPerMMX
            if ((diameter/2)*voltsPerMMY)>Vmaxy:
                diameter=2*Vmaxy/voltsPerMMY
            freq = appObj.cal_freq_dblSpinBox.value()
            if freq>mirrorDriver.LPFcutoff:  # can't go faster than the maximum scan rate
                appObj.cal_freq_dblSpinBox.setValue(mirrorDriver.LPFcutoff)
            fs=mirrorDriver.DAQoutputRate   # galvo output sampling rate
            t1=np.arange(0,np.around(fs/freq))*1/fs  
            n=np.around(t1.shape[0]/4)-1   # number of points in each 4th of the cycle (reduce by 1 to make it easy to shorten t1)
            t=t1[0:4*n]  # t is the array of times for the DAQ output to the mirrors
            cornerX=(diameter/2)*voltsPerMMX     # voltage at each corner of the square            
            cornerY=(diameter/2)*voltsPerMMY     # voltage at each corner of the square            
            
            # x and y are the coordinates of the laser at each point in time
            x=np.zeros(t.shape)            
            y=np.zeros(t.shape)            
            x[0:n]=np.linspace(-cornerX,cornerX,n)
            y[0:n]=-cornerY
            x[n:2*n]=cornerX
            y[n:2*n]=np.linspace(-cornerY,cornerY,n)
            x[2*n:3*n]=np.linspace(cornerX,-cornerX,n)
            y[2*n:3*n]=cornerY
            x[3*n:4*n]=-cornerX
            y[3*n:4*n]=np.linspace(cornerY,-cornerY,n)
            mirrorOut1= np.vstack((x,y))
            if mirrorDriver.MEMS==True:
                mirrorOut=scipy.signal.filtfilt(mirrorDriver.b_filt,mirrorDriver.a_filt,mirrorOut1)           
            else:
                mirrorOut=mirrorOut1    

        # plot mirror commands to GUI 
        pl = appObj.JSOmisc_plot1
        npts = mirrorOut.shape[1]
        t = np.linspace(0, npts/outputRate, npts)
        pl.clear()
        pl.plot(t, mirrorOut[0, :], pen='b')  
        pl.plot(t, mirrorOut[1, :], pen='r')  
        labelStyle = appObj.xLblStyle
        pl.setLabel('bottom', 'Time', 's', **labelStyle)
        labelStyle = appObj.yLblStyle
        pl.setLabel('left', 'Output', 'V', **labelStyle)
    
        pl2=appObj.JSOmisc_plot2
        pl2.clear()
        pl2.plot(mirrorOut[0, :],mirrorOut[1, :], pen='b')
        labelStyle = appObj.xLblStyle
        pl2.setLabel('bottom', 'X galvo', 'V', **labelStyle)
        labelStyle = appObj.yLblStyle
        pl2.setLabel('left', 'Y galvo', 'V', **labelStyle)
     
        if not appObj.oct_hw.IsDAQTestingMode():
            # setup the analog output DAQ device
            daq.setupAnalogOutput(chanNames, trigChan, outputRate, mirrorOut.transpose())        
            daq.startAnalogOutput()
            
            #start trigger and wait for output to finish 
            daq.sendDigTrig(audioHW.daqTrigChanOut)
            daq.waitDoneOutput(timeout=3, stopAndClear=True)
            
            QtGui.QApplication.processEvents() # check for GUI events
        else:
            appObj.doneFlag = True      # just run one time through if in test mode
            appObj.CalibrateScanMirror_pushButton.setChecked(False)
                  
    # when testing is over, set the mirror position to (0,0)
    if not appObj.oct_hw.IsDAQTestingMode():
        chanNames = [mirrorDriver.X_daqChan, mirrorDriver.Y_daqChan]
        data = np.zeros(2)
        daq.writeValues(chanNames, data)
    
    appObj.JSOsaveDispersion_pushButton.setEnabled(False)    
    appObj.JSOloadDispersion_pushButton.setEnabled(True)        
    appObj.isCollecting = False
    appObj.finishCollection()
Esempio n. 2
0
def runJSOraw(appObj):
    DebugLog.log("runJSOraw")
    try:
        appObj.tabWidget.setCurrentIndex(7)
        appObj.doneFlag = False
        appObj.isCollecting = True
        appObj.JSOsaveDispersion_pushButton.setEnabled(True)
        appObj.JSOloadDispersion_pushButton.setEnabled(False)
        dispData = appObj.dispData             # this class holds all the dispersion compensation data    
        if dispData is None:
            dispData = Dispersion.DispersionData()
            
        laserSweepFreq=appObj.octSetupInfo.getTriggerRate()
        mirrorDriver = appObj.mirrorDriver
        
        if not appObj.oct_hw.IsOCTTestingMode():     # prepare to get new data            
            # set the mirror position to (0,0)
            chanNames = [mirrorDriver.X_daqChan, mirrorDriver.Y_daqChan]
            data = np.zeros(2)
            from DAQHardware import DAQHardware
            daq = DAQHardware()
            daq.writeValues(chanNames, data)
        else:
            appObj.savedDataBuffer.loadData(appObj)
    
        peakXPos=np.array([0],dtype=int)       
        peakYPos=np.array([0],dtype=float)       
        peakXPos1=np.array([0],dtype=int)       
        peakYPos1=np.array([0],dtype=float)       
                   
        while appObj.doneFlag == False:
            # read data analysis settings from the GUI
            numTrigs=appObj.numTrig.value()
            dispData.requestedSamplesPerTrig=appObj.requestedSamplesPerTrig.value()
            dispData.startSample=appObj.startSample.value()
            dispData.endSample=appObj.endSample.value()
            dispData.numKlinPts=appObj.numKlinPts.value()
            dispData.Klin=np.zeros(dispData.numKlinPts)         
            dispData.numShiftPts=appObj.numShiftPts.value()
            dispData.filterWidth=appObj.filterWidth.value()
            dispData.mziFilter=appObj.mziFilter.value()
            dispData.magWin_LPfilterCutoff=appObj.dispMagWindowFilter.value()
            dispData.PDfilterCutoffs=[0,0]
            dispData.dispCode=appObj.dispersionCompAlgorithm_comboBox.currentIndex() 
            dispData.dispMode=appObj.dispersionCompAlgorithm_comboBox.currentText()
                     
            # Get data using one of several methods
            if appObj.oct_hw.IsOCTTestingMode():
                ch0_data,ch1_data=getSavedRawData(numTrigs,dispData.requestedSamplesPerTrig,appObj.savedDataBuffer)
            else:
                ch0_data,ch1_data=getNewRawData(numTrigs,dispData.requestedSamplesPerTrig,appObj)
            
            if appObj.saveData_checkBox.isChecked()==True:      # save data to disk for later use if desired
                fileName='Mirror_Raw'
                dataToSave = (ch0_data, ch1_data)              
                appObj.savedDataBuffer.saveData(appObj,dataToSave,fileName)                                
                appObj.saveData_checkBox.setChecked(False)                     
                
            # delay the MZI to account for it having a shorter optical path than the sample/reference arm path, then calculate k0 as the MZI phase
            pdData,mziData,actualSamplesPerTrig=channelShift(ch0_data,ch1_data,dispData)    
            textString='Actual samples per trigger: {actualSamplesPerTrig}'.format(actualSamplesPerTrig=actualSamplesPerTrig)            
            appObj.actualSamplesPerTrig_label.setText(textString)         
            
            import time
            t1 = time.time()
            mzi_hilbert, mzi_mag, mzi_ph, k0 = processMZI(mziData, dispData) 
            mzi_proc_time = time.time() - t1
            print("MZI processing time = %0.4f ms" % (mzi_proc_time*1000))
    
            # Adjust the k0 curves so that the unwrapping all starts at the same phase
            appObj.k0_plot_3.clear()
            appObj.k0_plot_4.clear()
            appObj.k0_plot_5.clear()
            t1 = time.time()
            k0Cleaned=cleank0(k0,dispData)              
            k0clean_time = time.time() - t1
            print("k0 cleaning time = %0.4f ms" % (k0clean_time*1000))
            
            for i in range(numTrigs):
                appObj.k0_plot_3.plot(k0[i,:2*dispData.startSample], pen=(i,numTrigs)) 
            startMZIdata1=k0[:,dispData.startSample]
            appObj.k0_plot_4.plot(startMZIdata1, pen='r') 
            startMZIdata2=k0Cleaned[:,dispData.startSample]
            appObj.k0_plot_4.plot(startMZIdata2, pen='b') 
            for i in range(numTrigs):
                appObj.k0_plot_5.plot(k0Cleaned[i,:2*dispData.startSample], pen=(i,numTrigs)) 
            k0=k0Cleaned
            
            # Interpolate the PD data based upon the MZI data and calculate the a-lines before dispersion compensation      
            t1 = time.time()
            pd_interpRaw, klin = processPD(pdData, k0, dispData)
            interpPD_time = time.time() - t1
            print("Interp PD time = %0.4f ms" % (interpPD_time*1000))
            dispData.Klin=klin
            pd_fftNoInterp, alineMagNoInterp, alinePhaseNoInterp = calculateAline(pdData[:,dispData.startSample:dispData.endSample])

            t1 = time.time()
            pd_fftRaw, alineMagRaw, alinePhaseRaw = calculateAline(pd_interpRaw)
            alineCalc_time = time.time() - t1
            print("Aline calc time = %0.4f ms" % (alineCalc_time*1000))
            
            # find the mirror in the a-line to determine the filter settings, and then perform the dispersion compensatsion 
            rangePeak1=[100, 900]
            alineAve1=np.average(alineMagRaw,axis=0) 
            peakXPos1[0]=np.argmax(alineAve1[rangePeak1[0]:rangePeak1[1]])+rangePeak1[0]
            peakYPos1[0]=alineAve1[peakXPos1[0]]     
            width=dispData.filterWidth*(rangePeak1[1]-rangePeak1[0])/2         
            dispData.PDfilterCutoffs[0]=(peakXPos1[0]+width)/2048
            dispData.PDfilterCutoffs[1]=(peakXPos1[0]-width)/2048
        
            dispersionCorrection(pd_interpRaw,dispData)
            appObj.dispData=dispData      #store the local variable in the overall class so that it can be saved when the save button is pressed
            
            # now correct the data using dispersion compensation and then process the a-lines
            pd_interpDispComp = dispData.magWin * pd_interpRaw * (np.cos(-1*dispData.phaseCorr) + 1j * np.sin(-1*dispData.phaseCorr))
            pd_fftDispComp, alineMagDispComp, alinePhaseDispComp = calculateAline(pd_interpDispComp)
                  
            #scale k0 and the MZI to the same range to plot them so they overlap
            k0Ripple= scipy.signal.detrend(k0[0,500:700],axis=-1)
            k0RippleNorm=k0Ripple/k0Ripple.max()
            mziDataRipple= scipy.signal.detrend(mziData[0,500:700],axis=-1)
            mziDataNorm=mziDataRipple/mziDataRipple.max()
           
            # Find the peak of the A-line within a range and calculate the phase noise
            rangePeak=[100, 900]
            alineAve=np.average(alineMagDispComp,axis=0) 
            peakXPos[0]=np.argmax(alineAve[rangePeak[0]:rangePeak[1]])+rangePeak[0]
            peakYPos[0]=alineAve[peakXPos[0]]              
            t=np.arange(numTrigs)/laserSweepFreq
            phaseNoiseTD=np.unwrap(alinePhaseDispComp[:,peakXPos[0]])
            phaseNoiseTD=phaseNoiseTD-np.mean(phaseNoiseTD)
            phaseNoiseTD=phaseNoiseTD*1310e-9/(4*np.pi*1.32)
            phaseNoiseFFT = np.abs(np.fft.rfft(phaseNoiseTD))/(numTrigs/2)
#            phaseNoiseFD = 20*np.log10(np.abs(phaseNoiseFFT))        
            freq = np.fft.rfftfreq(numTrigs)*laserSweepFreq
    
            # Clear all of the plots
            appObj.mzi_plot_2.clear() 
            appObj.pd_plot_2.clear()
            appObj.mzi_mag_plot_2.clear()
            appObj.mzi_phase_plot_2.clear()
            appObj.k0_plot_2.clear()
            appObj.interp_pdRaw_plot.clear()
            appObj.interp_pdDispComp_plot.clear()
            appObj.alineNoInterp_plot.clear()
            appObj.alineRaw_plot.clear()
            appObj.alineDispComp_plot.clear()
            appObj.phaseNoiseTD_plot.clear()
            appObj.phaseNoiseFD_plot.clear()
            appObj.dispWnfcMag_plot.clear()
            appObj.dispWnfcPh_plot.clear()
           
            # Plot all the data
            if appObj.plotFirstOnly_checkBox.isChecked()==True:
                i=0
                appObj.pd_plot_2.plot(pdData[i,:], pen='r')            
                appObj.mzi_plot_2.plot(mziData[i,:], pen='r')            
                appObj.mzi_mag_plot_2.plot(mzi_mag[i,:], pen='r')            
                appObj.k0_plot_2.plot(k0[i,:], pen='r')
                sampleNum=np.linspace(dispData.startSample,dispData.endSample,dispData.numKlinPts)
                appObj.k0_plot_2.plot(sampleNum,klin, pen='b')                      
                appObj.interp_pdRaw_plot.plot(pd_interpRaw[i,:], pen='r')           
                appObj.interp_pdDispComp_plot.plot(np.abs(pd_interpDispComp[i,:]), pen='r')           
                appObj.alineNoInterp_plot.plot(alineMagNoInterp[i,:], pen='r')
                appObj.alineRaw_plot.plot(alineMagRaw[i,:], pen='r')
                appObj.alineDispComp_plot.plot(alineMagDispComp[i,:], pen='r')
            else:
                # limit plotting to first 10 or so triggers, otherwise this will freeze up
                nTrigs = min((numTrigs, 10))
                
                for i in range(nTrigs):
                    pen=(i,nTrigs)
                    appObj.pd_plot_2.plot(pdData[i,:], pen=pen)            
                    appObj.mzi_plot_2.plot(mziData[i,:], pen=pen)            
                    appObj.mzi_mag_plot_2.plot(mzi_mag[i,:], pen=pen)            
                    appObj.mzi_phase_plot_2.plot(mzi_ph[i,:], pen=pen)            
                    appObj.k0_plot_2.plot(k0[i,:], pen=pen)            
                    appObj.interp_pdRaw_plot.plot(pd_interpRaw[i,:], pen=pen)            
                    appObj.interp_pdDispComp_plot.plot(np.abs(pd_interpDispComp[i,:]), pen=pen)            
                    appObj.alineNoInterp_plot.plot(alineMagNoInterp[i,:], pen=pen)            
                    appObj.alineRaw_plot.plot(alineMagRaw[i,:], pen=pen)            
                    appObj.alineDispComp_plot.plot(alineMagDispComp[i,:], pen=pen)            
                
            appObj.alineRaw_plot.plot(peakXPos1,peakYPos1, pen=None, symbolBrush='k', symbolPen='b')
            appObj.alineDispComp_plot.plot(peakXPos,peakYPos, pen=None, symbolBrush='k', symbolPen='b')
            appObj.phaseNoiseTD_plot.plot(t,phaseNoiseTD, pen='r')
            appObj.phaseNoiseFD_plot.plot(freq,phaseNoiseFFT, pen='r')
            appObj.mzi_phase_plot_2.plot(mziDataNorm, pen='b')            
            appObj.mzi_phase_plot_2.plot(k0RippleNorm, pen='r')            
            
           
            # if you want to align the pd and the Mzi data
    #            plotPDPhase.plot(pdData[0,:], pen='r')
    #            plotPDPhase.plot(mziData[0,:], pen='b')
    
            appObj.dispWnfcMag_plot.plot(dispData.magWin, pen='b')
            appObj.dispWnfcPh_plot.plot(dispData.phaseCorr, pen='b')
            
            # plot filter cutoff ranges on the raw Aline plot
            yy=[np.min(alineMagRaw[0,:]),np.max(alineMagRaw[0,:])]
            xx0=[alineMagRaw.shape[1]*dispData.PDfilterCutoffs[0],alineMagRaw.shape[1]*dispData.PDfilterCutoffs[0]]        
            xx1=[alineMagRaw.shape[1]*dispData.PDfilterCutoffs[1],alineMagRaw.shape[1]*dispData.PDfilterCutoffs[1]]    
            appObj.alineRaw_plot.plot(xx0,yy, pen='b')
            appObj.alineRaw_plot.plot(xx1,yy, pen='b')
            
    #            # Now create a bscan image from the 1 aline, but sweep the shift value between the mzi and pd to see what works best
    #            nShift=201        
    #            bscan=np.zeros([nShift, alineMag.shape[0]])        
    #            for i in range(nShift):
    #                shift=i-(nShift-1)/2
    #                if shift<0:
    #                    mzi_data_temp=mzi_data[-1*shift:]
    #                    pd_data_temp=pd_data[0:mzi_data_temp.shape[0]]
    #    #                print(mzi_data_temp.shape,pd_data_temp.shape)
    #                elif shift>0:
    #                    pd_data_temp=pd_data[shift:]
    #                    mzi_data_temp=mzi_data[0:pd_data_temp.shape[0]]
    #    #                print(mzi_data_temp.shape,pd_data_temp.shape)
    #                elif shift==0:
    #                    pd_data_temp=pd_data
    #                    mzi_data_temp=mzi_data
    #                    
    #                mzi_hilbert, mzi_mag, mzi_ph, k0 = processMZI(mzi_data_temp)
    #                pd_interpRaw, pd_interpHanning, pd_fft, alineMag, alinePhase, klin = processPD(pd_data_temp, k0, klin_idx, numklinpts)
    #                bscan[i,:]=alineMag
    #    
    #            pl = self.bscan_plot
    #            pl.setImage(bscan)            
            
    #            print('alineMagDispComp ',alineMagDispComp.shape)
            if ~np.all(np.isnan(alineMagDispComp)):  # only make the bscan plot if there is data to show (this prevents an error from occurring)
                appObj.bscan_plot.setImage(alineMagDispComp)
            QtGui.QApplication.processEvents() # check for GUI events  
    except:
        traceback.print_exc(file=sys.stdout)
        QtGui.QMessageBox.critical (appObj, "Error", "Error during scan. Check command line output for details")
        
    appObj.JSOsaveDispersion_pushButton.setEnabled(False)    
    appObj.JSOloadDispersion_pushButton.setEnabled(True)
    appObj.isCollecting = False
    QtGui.QApplication.processEvents() # check for GUI events
    appObj.finishCollection()
Esempio n. 3
0
def runDispersion(appObj):
    DebugLog.log("runDispersion")
    appObj.tabWidget.setCurrentIndex(5)
    appObj.doneFlag = False
    appObj.isCollecting = True
    # trigRate = octfpga.GetTriggerRate()
    mirrorDriver = appObj.mirrorDriver
    
    # set the mirror position to (0,0)
    chanNames = [mirrorDriver.X_daqChan, mirrorDriver.Y_daqChan]
    data = np.zeros(2)
    if not appObj.oct_hw.IsDAQTestingMode():
        from DAQHardware import DAQHardware
        daq = DAQHardware()
        daq.writeValues(chanNames, data)
    
    pd_background = None
    
    fpgaOpts = appObj.oct_hw.fpgaOpts
    numklinpts = fpgaOpts.numKlinPts
    if fpgaOpts.InterpDownsample > 0:
        numklinpts =  numklinpts // 2
    
    # keep looping until we are signlaed to stop by GUI (flag set in appObj)
    try:
        frameNum = 0
        saveDirInit = False
        testDataDir = os.path.join(appObj.basePath, 'exampledata', 'Dispersion')
        dispData = DispersionData(fpgaOpts)
        klin = None # initialze klin to None so it will be computed first iteration
        savedFPGADisp = False
        
        while not appObj.doneFlag: 
            # setup and grab the OCT data - this will also fire the mirror output
            numTrigs = appObj.disp_numTrigs_spinBox.value()
            processMode = OCTCommon.ProcessMode(appObj.processMode_comboBox.currentIndex())
                
            # get proessing optiosn from GUI        
            PD_LP_fc = appObj.disp_pd_lpfilter_cutoff_dblSpinBox.value()
            PD_HP_fc = appObj.disp_pd_hpfilter_cutoff_dblSpinBox.value()
            PDfiltCutoffs = [PD_LP_fc, PD_HP_fc]
            magWin_LPfilterCutoff = appObj.disp_magwin_lpfilter_cutoff_dblSpinBox.value()
            
            dispData.mziFilter = appObj.mziFilter.value()
            dispData.magWin_LPfilterCutoff = magWin_LPfilterCutoff
            dispData.PDfilterCutoffs = PDfiltCutoffs
            
            collectBG = appObj.disp_collectBG_pushButton.isChecked()
            
            pd_background = dispData.phDiode_background                
    
            if processMode == OCTCommon.ProcessMode.FPGA:
                if appObj.oct_hw.IsOCTTestingMode():
                    pd_data = OCTCommon.loadRawData(testDataDir, frameNum % 19, dataType=1)
                    numklinpts = 1400
                else:
                    err, pd_data = appObj.oct_hw.AcquireOCTDataInterpPD(numTrigs)
                    DebugLog.log("runDispersion(): AcquireOCTDataInterpPD() err = %d" % err)
                    # process the data
                dispData = processData(pd_data, dispData, numklinpts, PDfiltCutoffs, magWin_LPfilterCutoff, pd_background, collectBG)

            elif processMode == OCTCommon.ProcessMode.SOFTWARE:
                if appObj.oct_hw.IsOCTTestingMode():
                    ch0_data,ch1_data=JSOraw.getSavedRawData(numTrigs,appObj.dispData.requestedSamplesPerTrig,appObj.savedDataBuffer)
                else:
                    # def AcquireOCTDataRaw(self, numTriggers, samplesPerTrig=-1, Ch0Shift=-1, startTrigOffset=0):
                    samplesPerTrig = fpgaOpts.SamplesPerTrig*2 + fpgaOpts.Ch0Shift*2
                    err, ch0_data,ch1_data = appObj.oct_hw.AcquireOCTDataRaw(numTrigs, samplesPerTrig)

                pdData,mziData,actualSamplesPerTrig = JSOraw.channelShift(ch0_data,ch1_data,dispData)    # shift the two channels to account for delays in the sample data compared to the MZI data 
                mzi_hilbert, mzi_mag, mzi_ph, k0 = JSOraw.processMZI(mziData, dispData)                # calculate k0 from the phase of the MZI data
                k0Cleaned = JSOraw.cleank0(k0, dispData) # Adjust the k0 curves so that the unwrapping all starts at the same phase    
                pd_data, klin = JSOraw.processPD(pdData, k0Cleaned, dispData, klin)  # Interpolate the PD data based upon the MZI data
                dispData.Klin = klin
                dispData = processUniqueDispersion(pd_data, dispData, pd_background, collectBG)
            else:
                QtGui.QMessageBox.critical (appObj, "Error", "Unsuppoted processing mode for current hardware")
                
            # plot the data
            plotDispData(appObj, dispData, PDfiltCutoffs)
            
            if appObj.getSaveState():
                dispFilePath = saveDispersionData(dispData, appObj.settingsPath)
            
                saveOpts = appObj.getSaveOpts()
                if saveOpts.saveRaw:
                    if not saveDirInit:
                        saveDir = OCTCommon.initSaveDir(saveOpts, 'Dispersion')
                        saveDirInit = True
                    
                    OCTCommon.saveRawData(pd_data, saveDir, frameNum, dataType=1)
                if processMode == OCTCommon.ProcessMode.FPGA:
                    appObj.dispDataFPGA = dispData
                    dispFilePathFPGA = dispFilePath
                    savedFPGADisp = True
                else:
                    appObj.dispData = dispData
                
            frameNum += 1
            QtGui.QApplication.processEvents() # check for GUI events, particularly the "done" flag
            
        if savedFPGADisp:
            DebugLog.log("runDispersion(): loading dispersion file into FPGA")
            appObj.loadDispersionIntoFPGA(dispFilePathFPGA, appObj.oct_hw.fpgaOpts)
            
    except Exception as ex:
        # raise ex
        traceback.print_exc(file=sys.stdout)
        QtGui.QMessageBox.critical (appObj, "Error", "Error during scan. Check command line output for details")
    finally:
        appObj.isCollecting = False
        QtGui.QApplication.processEvents() # check for GUI events
        appObj.finishCollection()