def writeValues(self, chanNames, data): DebugLog.log("DAQhardware.writeValue(): chanNames= %s val= %s" % (repr(chanNames), repr(data))) self.analog_output = None # ensure the output task is closed samplesWritten = daqmx.int32() analog_output = daqmx.Task() data = np.vstack((data, data)) data = data.transpose() data = np.require(data, np.double, ['C', 'W']) numSamples = 2 outputRate = 1000 for chanName in chanNames: analog_output.CreateAOVoltageChan(chanName,"",-10.0,10.0, daqmx.DAQmx_Val_Volts, None) analog_output.CfgSampClkTiming("",outputRate, daqmx.DAQmx_Val_Rising, daqmx.DAQmx_Val_FiniteSamps, numSamples) analog_output.WriteAnalogF64(numSampsPerChan=numSamples, autoStart=True,timeout=1.0, dataLayout=daqmx.DAQmx_Val_GroupByChannel, writeArray=data, reserved=None, sampsPerChanWritten=byref(samplesWritten)) DebugLog.log("DAQhardware.setupAnalogOutput(): Wrote %d samples" % samplesWritten.value) # wait until write is completeled isDone = False isDoneP = daqmx.c_ulong() while not isDone: err = analog_output.IsTaskDone(byref(isDoneP)) isDone = isDoneP.value != 0 analog_output = None
def loadDispersion_onStartup(appObj): # infile=os.path.join(appObj.configPath, 'Dispersion','dispComp-initial.pickle') infile = appObj.octSetupInfo.dispFilename dispData = Dispersion.loadDispData(appObj, infile) appObj.dispData=dispData DebugLog.log('JSORaw.loadDispersion_onStartup: set appObj.dispData') appObj.dispCompFilename_label.setText(infile) updateDispersionGUI(appObj, appObj.dispData)
def processSpkCalData(mic_data, freq, freq_idx, audioParams, inputRate, speakerCalIn, spkNum): # print("SpeakerCalProtocol: processData: mic_data=" + repr(mic_data)) # ensure data is 1D if len(mic_data.shape) > 1: mic_data = mic_data[:, 0] numpts = len(mic_data) DebugLog.log("SpeakerCalProtocol: processData: numpts= %d" % (numpts)) t = np.linspace(0, numpts/inputRate, numpts) zero_pad_factor = 2 numfftpts = numpts*zero_pad_factor winfcn = np.hanning(numpts) mic_fft = np.fft.fft(winfcn*mic_data, numfftpts) endIdx = np.ceil(numfftpts/2) mic_fft = mic_fft[0:endIdx] mic_fft_mag = 2*np.abs(mic_fft) # convert to dB, correctting for RMS and FFT length fftrms_corr = 2/(numpts*np.sqrt(2)) mic_fft_mag = fftrms_corr*mic_fft_mag mic_fft_mag_log = 20*np.log10(mic_fft_mag/20e-6 ) # 20e-6 pa mic_fft_phase = np.angle(mic_fft) mic_freq = np.linspace(0, inputRate/2, endIdx) fIdx = int(np.floor(freq*numfftpts/inputRate)) DebugLog.log("SpeakerCalibration: processData: freq= %f fIdx= %d" % (freq, fIdx)) stim_freq_mag = np.NAN stim_freq_phase = np.NAN try: npts = zero_pad_factor mag_rgn = mic_fft_mag_log[fIdx-npts:fIdx+npts] phase_rgn = mic_fft_phase[fIdx-npts:fIdx+npts] fIdx = int(np.floor(freq*numfftpts/inputRate)) DebugLog.log("SpeakerCalibration: processData: freq= %f fIdx= %d" % (freq, fIdx)) maxIdx = np.argmax(mag_rgn) stim_freq_mag = mag_rgn[maxIdx] stim_freq_phase = phase_rgn[maxIdx] except Exception as ex: DebugLog.log(ex) DebugLog.log("SpeakerCalibration: processData: stim_freq_mag= %f stim_freq_phase= %f" % (stim_freq_mag, stim_freq_phase)) micData = MicData() micData.raw = mic_data micData.t = t micData.fft_mag = mic_fft_mag_log micData.fft_phase = mic_fft_phase micData.fft_freq = mic_freq micData.stim_freq_mag = stim_freq_mag micData.stim_freq_phase = stim_freq_phase speakerCalIn.magResp[spkNum, freq_idx] = stim_freq_mag speakerCalIn.phaseResp[spkNum, freq_idx] = stim_freq_phase return micData, speakerCalIn
def readAnalogInput(self, timeout=3.0): ## DAQmx Read Code read = daqmx.int32() numSamplesIn = len(self.dataIn) self.analog_input.ReadAnalogF64(numSamplesIn, timeout, daqmx.DAQmx_Val_GroupByChannel, self.dataIn, numSamplesIn, byref(read), None) DebugLog.log("DAQhardware.sendDigTrig(): Read %s samples" % repr(read)) data = self.dataIn return data
def __init__(self, freqArray): self.voltsOut = 0.1 self.freq = freqArray numFreq = freqArray.shape[1] DebugLog.log("SpeakerCalData: numFreq= %d" % numFreq) self.magResp = np.zeros((2, numFreq)) self.magResp[:, :] = np.NaN self.phaseResp = np.zeros((2, numFreq)) self.phaseResp[:, :] = np.NaN
def sendDigTrig(self, trigOutLine): # setup the digital trigger DebugLog.log("DAQhardware.sendDigTrig(): trigOutLine= %s " % trigOutLine) dig_out = daqmx.Task() dig_out.CreateDOChan(trigOutLine, "", daqmx.DAQmx_Val_ChanForAllLines) doSamplesWritten = daqmx.int32() doData = self.doTrigData numpts = len(doData) dig_out.WriteDigitalU32(numSampsPerChan=numpts, autoStart=True, timeout=1.0, dataLayout=daqmx.DAQmx_Val_GroupByChannel, writeArray=doData, reserved=None, sampsPerChanWritten=byref(doSamplesWritten)) DebugLog.log("DAQhardware.sendDigTrig(): Wrote %d samples" % doSamplesWritten.value) dig_out.ClearTask()
def softwareProcessing(ch0_data,ch1_data,zROI,appObj, returnPhase=False, unwrapPhase=False): # This routine can be called from any other routine to do software processing of the raw data. # It needs appObj.dispData so you must have loaded a dispersion file already for this to work. dispData=appObj.dispData pdData,mziData,actualSamplesPerTrig=channelShift(ch0_data,ch1_data,dispData) # shift the two channels to account for delays in the sample data compared to the MZI data t1 = time.time() mzi_hilbert, mzi_mag, mzi_ph, k0 = processMZI(mziData, dispData) # calculate k0 from the phase of the MZI data DebugLog.log("JSOraw.softwareProcessing(): process MZI time= %0.4f" % (time.time() - t1)) DebugLog.log("JSOraw.softwareProcessing(): numTriggers collected= %d" % (k0.shape[0])) k0Cleaned=cleank0Run(k0,dispData) # Adjust the k0 curves so that the unwrapping all starts at the same phase Klin=dispData.Klin t1 = time.time() pd_interpRaw, klin = processPD(pdData, k0Cleaned, dispData, Klin) # Interpolate the PD data based upon the MZI data DebugLog.log("JSOraw.softwareProcessing(): process PD time= %0.4f" % (time.time() - t1)) t1 = time.time() pd_interpDispComp = dispData.magWin * pd_interpRaw * (np.cos(-1*dispData.phaseCorr) + 1j * np.sin(-1*dispData.phaseCorr)) # perform dispersion compensation pd_fftDispComp, alineMagDispComp, alinePhaseDispComp = calculateAline(pd_interpDispComp, returnPhase, unwrapPhase) # calculate the a-line DebugLog.log("JSOraw.softwareProcessing(): calc Aline time= %0.4f" % (time.time() - t1)) oct_data = pd_fftDispComp[:, zROI[0]:zROI[1]] return oct_data, klin
def cleank0Run(k0,dispData): # for Runtime: use the cleaned k0Reference data and adjust all new k0 data by 2pi rads to overlap it k0Cleaned=np.copy(k0) k0Init=k0Cleaned[:,dispData.startSample] DebugLog.log('JSOraw.cleank0Run: len(k0reference)= %d startSample= %d' % (len(dispData.k0Reference), dispData.startSample)) k0RefInit=np.tile(dispData.k0Reference[dispData.startSample],len(k0Init)) # If there are phase jumps going on in the data, find the bad k0 curves and shift them appropriately by 2pi diff=k0Init-k0RefInit while np.max(np.abs(diff))>(1.5*np.pi): indexGrp1=np.argwhere(diff>(1.5*np.pi)) indexGrp2=np.argwhere(diff<(-1.5*np.pi)) k0Cleaned[indexGrp1,:]=k0Cleaned[indexGrp1,:]-2*np.pi k0Cleaned[indexGrp2,:]=k0Cleaned[indexGrp2,:]+2*np.pi k0Init=k0Cleaned[:,dispData.startSample] diff=k0Init-k0RefInit return k0Cleaned
def getSavedRawData(numTrigs,requestedSamplesPerTrig,JSOrawSavedData): # oct_data is a 2D arary of complex numbers # When used to carry raw data: # Photodiode data (interferogram from the sample) is encoded as imaginary part # MZI data (interferogram from MZI) is encoded as imaginary part print(self.count,self.oct_data_all.shape[0]) # print('size/numTrigs',self.oct_data_file.shape[0],numTrigs) DebugLog.log("JSOraw.getSavedRawData(): data file count= %d " % (JSOrawSavedData.count)) ch0_data=np.zeros([numTrigs,JSOrawSavedData.ch1_data_file.shape[1]]) ch1_data=np.zeros([numTrigs,JSOrawSavedData.ch1_data_file.shape[1]]) for i in range(numTrigs): if JSOrawSavedData.count==JSOrawSavedData.ch0_data_file.shape[0]: JSOrawSavedData.count=0 ch0_data[i,:]=JSOrawSavedData.ch0_data_file[JSOrawSavedData.count,:] ch1_data[i,:]=JSOrawSavedData.ch1_data_file[JSOrawSavedData.count,:] JSOrawSavedData.count=JSOrawSavedData.count+1 return ch0_data, ch1_data
def setupAnalogOutput(self, chanNames, digTrigChan, outputRate, data): numSamples = data.shape[0] DebugLog.log("DAQhardware.setupAnalogOutput(): chanNames= %s digTrigChan= %s outputRate= %f numSamples= %f" % (chanNames, digTrigChan, outputRate, numSamples)) self.clearAnalogOutput() # ensure the output task is closed samplesWritten = daqmx.int32() analog_output = daqmx.Task() data = np.require(data, np.float, ['C', 'W']) for chanName in chanNames: analog_output.CreateAOVoltageChan(chanName,"",-10.0,10.0, daqmx.DAQmx_Val_Volts, None) analog_output.CfgSampClkTiming("",outputRate, daqmx.DAQmx_Val_Rising, daqmx.DAQmx_Val_FiniteSamps, numSamples) analog_output.CfgDigEdgeStartTrig(digTrigChan, daqmx.DAQmx_Val_Rising) #analog_output.WriteAnalogF64(numSampsPerChan=numSamples, autoStart=False,timeout=3.0, dataLayout=daqmx.DAQmx_Val_GroupByChannel, writeArray=data, reserved=None, sampsPerChanWritten=byref(samplesWritten)) analog_output.WriteAnalogF64(numSampsPerChan=numSamples, autoStart=False,timeout=3.0, dataLayout=daqmx.DAQmx_Val_GroupByScanNumber, writeArray=data, reserved=None, sampsPerChanWritten=byref(samplesWritten)) DebugLog.log("DAQhardware.setupAnalogOutput(): Wrote %d samples" % samplesWritten.value) self.analog_output = analog_output
def setupAnalogInput(self, chanNames, digTrigChan, inputRate, numInputSamples): # ensure old task has been cosed self.clearAnalogInput() DebugLog.log("DAQhardware.setupAnalogOutput(): chanNames= %s digTrigChan= %s inputRate= %f numInputSamples= %f" % (chanNames, digTrigChan, inputRate, numInputSamples)) ## DAQmx Configure Code # analog_input.CreateAIVoltageChan("Dev1/ai0","",DAQmx_Val_Cfg_Default,-10.0,10.0,DAQmx_Val_Volts,None) analog_input = daqmx.Task() for chanName in chanNames: analog_input.CreateAIVoltageChan(chanName,"", daqmx.DAQmx_Val_Cfg_Default,-10.0,10.0, daqmx.DAQmx_Val_Volts,None) analog_input.CfgSampClkTiming("", inputRate, daqmx.DAQmx_Val_Rising, daqmx.DAQmx_Val_FiniteSamps, numInputSamples) analog_input.CfgDigEdgeStartTrig(digTrigChan, daqmx.DAQmx_Val_Rising) numCh = len(chanNames) self.dataIn = np.zeros((numInputSamples*numCh,)) # ## DAQmx Start Code self.analog_input = analog_input
def getCalibratedOutputVoltageAndAttenLevel(self, freq, ampdB, speakerNum): freqArray = self.speakerCalFreq[speakerNum, :] calArray = self.speakerCal[speakerNum, :] DebugLog.log("AudioHardware.getCalibratedOutputVoltageAndAttenLevel freq= %f freqArray= %s calArray= %s" % (freq, repr(freqArray), repr(calArray))) caldBarr = np.interp([freq], freqArray, calArray) caldB = caldBarr[0] dBdiff = ampdB - caldB DebugLog.log("AudioHardware.getCalibratedOutputVoltageAndAttenLevel ampdB= %f caldB= %f dBdiff= %f" % (ampdB, caldB, dBdiff)) outV = self.speakerCalVolts*(10 ** (dBdiff/20)) minV = self.speakerOutputRng[0] maxV = self.speakerOutputRng[1] attenLevel = 0 if outV > maxV: outV = 0 elif outV < minV: attenLevel = np.ceil(20 * np.log10(minV/outV)) attenLevel = int(attenLevel) outV = minV if attenLevel > self.maxAtten: outV = 0 return (outV, attenLevel)
def processPD(pd_data, k0, dispData, klin=None): numklinpts = dispData.numKlinPts # this section is only run during the dispersion compensation algorithm. Then, klin is saved with the dispersion file and used from there on if klin is None or (len(klin) != numklinpts): klin = np.linspace(k0[0,dispData.startSample], k0[0,dispData.endSample], numklinpts) # if num klinpts is > 2048, need to use downsampling to get interp points below 2048 if numklinpts > 2048: dsf = numklinpts // 2048 + 1 num_klin_ds = numklinpts // dsf DebugLog.log("JSOraw.processPD numklinpts= %d dsf= %d len(klin)= %d pd_data.shape= %s" % (numklinpts, dsf, len(klin), repr(pd_data.shape))) pd_interp = np.zeros((pd_data.shape[0], numklinpts // dsf)) for i in range(pd_data.shape[0]): interp_pd = np.interp(klin, k0[i,:], pd_data[i,:]) interp_pd = np.reshape(interp_pd, (num_klin_ds, dsf)) interp_pd = np.mean(interp_pd, 1) pd_interp[i,:] = interp_pd else: pd_interp=np.zeros((pd_data.shape[0], numklinpts)) for i in range(pd_data.shape[0]): pd_interp[i,:] = np.interp(klin, k0[i,:], pd_data[i,:]) return pd_interp, klin
def calculateAline(pd, returnPhase=True, unwrapPhase=True): numPts=pd.shape[1] t1 = time.time() pd_fft = (np.fft.fft(pd, n=2048,axis=-1)/numPts)/100 DebugLog.log("JSOraw.calculateAline() FFT time= %0.4f" % (time.time() - t1)) t1 = time.time() alineMag = np.abs(pd_fft) DebugLog.log("JSOraw.calculateAline() abs time= %0.4f" % (time.time() - t1)) t1 = time.time() alineMag = 20*np.log10(alineMag + 1) DebugLog.log("JSOraw.calculateAline() log10 time= %0.4f" % (time.time() - t1)) alinePhase = None if returnPhase: alinePhase= np.angle(pd_fft) if unwrapPhase: alinePhase= np.unwrap(alinePhase,axis=-1) return pd_fft, alineMag, alinePhase
def processMZI(mzi_data, dispData, FIRcoeff=[0+0j]): t1 = time.time() complex_FIR = 1 if complex_FIR == 0: #normal way using fft/ifft approach to do the hilbert transform # filtering seems to reduce sidebands created during the interpolation process (b, a) = scipy.signal.butter(2, dispData.mziFilter, 'highpass') mzi_data=scipy.signal.lfilter(b, a, mzi_data,axis=-1) # mean subtraction is much faster, and we only need to eliminate the zero-frequency componment # mzi_data = mzi_data - np.mean(mzi_data, keepdims=True) mzi_complex = scipy.signal.hilbert(mzi_data, axis=-1) elif complex_FIR==1: # Approximate Hilbert Transform using FIR filter """ # code to design the filter coefficients (This is not needed since they are pasted in below, but the code included for reference) filter_order = 35 stop_freq=0.25 pass_freq=0.15 prt_lpf=scipy.signal.remez(filter_order, [0, pass_freq, stop_freq, 0.5], [1, 0]) exp_len=np.arange(-filter_order/2,filter_order/2,1) FIRcoeff=prt_lpf*np.exp(np.complex(0,1)*2*np.pi*0.25*exp_len) for i in range(filter_order): print(FIRcoeff[i],',') """ # these filter coefficients come from the above code FIRcoeff=np.array([ (-0.00030351655287-0.00030351655287j) , (0.00113140195234-0.00113140195234j) , (-9.35755583151e-05-9.35755583151e-05j) , (0.00252252948249-0.00252252948249j) , (0.00218108432482+0.00218108432482j) , (0.0032263770108-0.0032263770108j) , (0.00690123992871+0.00690123992871j) , (0.0001322186872-0.0001322186872j) , (0.0122523152659+0.0122523152659j) , (-0.00969906300727+0.00969906300727j) , (0.0128955480118+0.0128955480118j) , (-0.0267326545724+0.0267326545724j) , (0.000205842190372+0.000205842190372j) , (-0.0472714248792+0.0472714248792j) , (-0.0409251974438-0.0409251974438j) , (-0.0643104412456+0.0643104412456j) , (-0.212334405586-0.212334405586j) , (0.282605062261-0.282605062261j) , (0.212334405586+0.212334405586j) , (-0.0643104412456+0.0643104412456j) , (0.0409251974438+0.0409251974438j) , (-0.0472714248792+0.0472714248792j) , (-0.000205842190372-0.000205842190372j) , (-0.0267326545724+0.0267326545724j) , (-0.0128955480118-0.0128955480118j) , (-0.00969906300727+0.00969906300727j) , (-0.0122523152659-0.0122523152659j) , (0.0001322186872-0.0001322186872j) , (-0.00690123992871-0.00690123992871j) , (0.0032263770108-0.0032263770108j) , (-0.00218108432482-0.00218108432482j) , (0.00252252948249-0.00252252948249j) , (9.35755583151e-05+9.35755583151e-05j) , (0.00113140195234-0.00113140195234j) , (0.00030351655287+0.00030351655287j) ]) # mzi_complex=np.zeros(mzi_data.shape, dtype=complex) # for i_th in range(0, mzi_data.shape[0]): # mzi_complex[i_th,:]=np.convolve(mzi_data[i_th,:],FIRcoeff, mode='same') # this works but is slow # mzi_complex=scipy.ndimage.filters.convolve1d(mzi_data,FIRcoeff) # This gives errors - doesn't work with complex numbers correctly mzi_complex=np.apply_along_axis(lambda m: np.convolve(m, FIRcoeff, mode='same'), axis=1, arr=mzi_data) # this works and is the fastest way to do it that I could figure out # mzi_complex=scipy.signal.lfilter(FIRcoeff,[1],mzi_data,axis=1) # this works, but is also very slow DebugLog.log("JSOraw.processMZI() hilbert trasnform time= %0.4f" % (time.time() - t1)) mzi_mag = np.abs(mzi_complex) t1 = time.time() mzi_ph = np.angle(mzi_complex) DebugLog.log("JSOraw.processMZI() angle calc time= %0.4f" % (time.time() - t1)) mzi_hilbert = np.imag(mzi_complex) t1 = time.time() k0 = np.unwrap(mzi_ph,axis=-1) DebugLog.log("JSOraw.processMZI() unwraptime= %0.4f" % (time.time() - t1)) return mzi_hilbert, mzi_mag, mzi_ph, k0
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()
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()
def processData(interpPD, dispData, numklinpts, PDfilterCutoffs, magWin_LPfilterCutoff, pd_background=None, bg_collect=False): # scanP = self.scanParams numTrigs = interpPD.shape[0] numPts = interpPD.shape[1] DebugLog.log("Dispersion.processData numTrigs= %d numPts= %d" % (numTrigs, numPts)) pd = np.mean(interpPD, 0) dispData.phDiode = pd winFcn = np.hanning(numklinpts) k = np.linspace(0, 1000, numklinpts) if bg_collect: pd = np.real(interpPD[:, 0:numklinpts]) pd_background = np.mean(pd, 0) magWin = np.zeros((numTrigs, numklinpts)) phaseCorr = np.zeros((numTrigs, numklinpts)) # HP filter to get rid of LF components # filterCutoff = procOpts.dispersion_PD_HPfilterCutoff # (b, a) = scipy.signal.butter(2, filterCutoff, 'highpass') lpfc = PDfilterCutoffs[0] hpfc = PDfilterCutoffs[1] Wn = [hpfc, lpfc] (b, a) = scipy.signal.butter(2, Wn=Wn, btype='bandpass') (b2, a2) = scipy.signal.butter(2, 0.4, 'lowpass') # subtract background sigdata = np.real(interpPD[:, 0:numklinpts]) if pd_background is not None: bg = np.tile(pd_background, (numTrigs, 1)) sigdata = sigdata - bg for n in range(0, numTrigs): sig = sigdata[n, :] #sig = scipy.signal.lfilter(b, a, sig) # filter signal perfectly by using FFT-IFFT method fftsig = np.fft.rfft(sig) ln = len(sig) # calculate indices in array by multipling by filter cuoffs idx0 = np.round(hpfc*ln) idx1 = np.round(lpfc*ln) if n == 0: DebugLog.log("DispersonProtocol.processData() len(sig)= %d len(fftsig)= %d idx0= %d idx1= %d" % (len(sig), len(fftsig), idx0, idx1)) fftsig[0:idx0] = 0 fftsig[idx1:] = 0 sig = np.fft.irfft(fftsig, len(sig)) # HP filter to get rid of LF components sig_ht = scipy.signal.hilbert(sig) #mag = np.complex(sig, np.imag(sig_ht)) mag = np.abs(sig_ht) mag0 = mag[0] mag = mag - mag0 mag = scipy.signal.lfilter(b2, a2, mag) mag = mag + mag0 # mag = mag # print("mag.shape= %s winFcn.shape= %s" % (repr(mag.shape), repr(winFcn.shape))) magWin[n, :] = winFcn / mag # magWin[n, :] = mag ph = np.angle(sig_ht) ph_unwr = np.unwrap(ph) pcof = np.polyfit(k, ph_unwr, 1) fity = np.polyval(pcof, k) phaseCorr[n, :] = ph_unwr - fity magWin = np.mean(magWin, 0) # low pass filter to get rid of ripple filterCutoff = magWin_LPfilterCutoff (b, a) = scipy.signal.butter(2, filterCutoff, 'lowpass') magWin = scipy.signal.filtfilt(b, a, magWin) # renomalze to 0...1 minWin = np.min(magWin) maxWin = np.max(magWin) magWin = (magWin - minWin)/(maxWin - minWin) #magWin = magWin[0, :] phaseCorr = np.mean(phaseCorr, 0) dispData.magWin = magWin dispData.phaseCorr = phaseCorr winFcnTile = np.tile(winFcn, numTrigs).reshape(numTrigs, numklinpts) # make uncorrected aline fft_sig_u = np.fft.fft(winFcnTile * sigdata, 2048, 1) dispData.uncorrAline = 20*np.log10(np.mean(np.abs(fft_sig_u) + 1, 0)) # make orrected aline magWinTile = np.tile(magWin, numTrigs).reshape(numTrigs, numklinpts) phaseCorrTile = np.tile(phaseCorr, numTrigs).reshape(numTrigs, numklinpts) sigDataComplex = magWinTile * sigdata * (np.cos(-phaseCorrTile) + 1j * np.sin(-phaseCorrTile)) fft_sig_c = np.fft.fft(sigDataComplex, 2048, 1) dispData.corrAline = 20*np.log10(np.mean(np.abs(fft_sig_c) + 1, 0)) dispData.numTrigs = numTrigs dispData.numklinpts = numklinpts dispData.magWin_LPfilterCutoff = magWin_LPfilterCutoff dispData.PDfilterCutoffs = PDfilterCutoffs dispData.phDiode_background = pd_background return dispData
def mousePressEvent(self, mouseEvent): # call super to ensure that mouse events are correctly propogated to items QtGui.QGraphicsView.mousePressEvent(self, mouseEvent) if self._ROIdragMode != ROIImgViewdDragMode.NONE: return # mouse press event already handled by items pt = (mouseEvent.x(), mouseEvent.y()) qpt = QtCore.QPoint(pt[0], pt[1]) ptf = self.mapToScene(qpt) img_ptf = self.pixMapItem.mapFromScene(ptf) img_pt = (int(round(img_ptf.x())), int(round(img_ptf.y()))) pt = (ptf.x(), ptf.y()) print("ROIImageGraphicsView.mousePressEvent x= %d y= %d img_pt=%s button= %s" % (pt[0], pt[1], repr(img_pt), repr(mouseEvent.button()))) self.buttonPressed = mouseEvent.button() if mouseEvent.button() == QtCore.Qt.LeftButton: print(" left button"); # hit test on circusors self._ROIdragMode = ROIImgViewdDragMode.DRAWROI elif mouseEvent.button() == QtCore.Qt.RightButton: print(" right button"); self._ROIdragMode = ROIImgViewdDragMode.MOVE self.dragLastPt = pt self.dragLastPtF = ptf self.isMouseDrag = True return DebugLog.log("ROIImageGraphicsView.mouseMoveEvent: drawtype = %s" % self._ROIdrawType.name) if self._ROIdrawType == ROIImgViewROIDrawType.BOX: self.isMouseDrag = True self.ROIBox_pt1 = pt elif self._ROIdrawType == ROIImgViewROIDrawType.SINGLE_PT: d = self.xhair_d x1 = pt[0] - d x2 = pt[0] + d y1 = pt[1] - d y2 = pt[1] + d self.xhairItem1.setLine(x1, y1, x2, y2) self.xhairItem2.setLine(x1, y2, x2, y1) self.singlePt = img_pt if self.mainOCTObj is not None: self.mainOCTObj.mscanSinglePtSet(self.singlePt) elif self._ROIdrawType == ROIImgViewROIDrawType.MULTI_PT: d = self.xhair_d x1 = pt[0] - d x2 = pt[0] + d y1 = pt[1] - d y2 = pt[1] + d txtX = pt[0] + 2*d txtY = pt[1] scene = self.scene() pen = self.ptPen if self.multPtMode == ROIImgViewMultPtMode.NEW: xhairItem1 = scene.addLine(x1, y1, x2, y2, pen) xhairItem2 = scene.addLine(x1, y2, x2, y1, pen) ptNum = len(self.ptsList) # #textItem.textCursor().charFormat().setBackground(brush) #textItem.textCursor().blockCharFormat().setForeground(brush) #textItem.textCursor().blockCharFormat().setBackground(brush) #textItem.setZValue(-2) #textItem.setDefaultTextColor(clr) txtItem = scene.addSimpleText(repr(ptNum + 1), self.ptFont) txtItem.setPos(txtX, txtY) #txtItem.textCursor().charFormat().setForeground(self.txtBrush) #txtItem.textCursor().blockCharFormat().setForeground(self.txtBrush) #txtItem.textCursor().charFormat().setBackground(self.txtBrush) #txtItem.textCursor().blockCharFormat().setBackground(self.txtBrush) txtItem.setBrush(self.txtBrush) # txtItem.setDefaultColor(self.txtClr) self.ptsList.append(img_pt) self.multiPt_grItems.append((xhairItem1, xhairItem2, txtItem)) elif self.multPtMode == ROIImgViewMultPtMode.MOVE: ptNum = len(self.ptsList) - 1 (xhairItem1, xhairItem2, txtItem) = self.multiPt_grItems[ptNum] self.ptsList[ptNum] = img_pt xhairItem1.setLine(x1, y1, x2, y2) xhairItem2.setLine(x1, y2, x2, y1) txtItem.setPos(txtX, txtY) self.ptsList[ptNum] = img_pt elif self._ROIdrawType == ROIImgViewROIDrawType.POLYGON: qptf = QtCore.QPointF(pt[0], pt[1]) if qptf != self.ROI_poly.last(): scene = self.scene() self.ROI_poly.append(qptf) scene.removeItem(self.ROI_poly_item) self.ROI_poly_item = scene.addPolygon(self.ROI_poly, pen=self.linePen) elif self._ROIdrawType == ROIImgViewROIDrawType.FREE: self.isMouseDrag = True
def runSpeakerCal(appObj, testMode=False): DebugLog.log("runSpeakerCal") appObj.tabWidget.setCurrentIndex(1) appObj.doneFlag = False appObj.isCollecting = True # trigRate = octfpga.GetTriggerRate() audioHW = appObj.audioHW outputRate = audioHW.DAQOutputRate inputRate = audioHW.DAQInputRate if testMode: testDataDir = os.path.join(appObj.basePath, 'exampledata', 'Speaker Calibration') filePath = os.path.join(testDataDir, 'AudioParams.pickle') f = open(filePath, 'rb') audioParams = pickle.load(f) f.close() else: audioParams = appObj.getAudioParams() numSpk = audioParams.getNumSpeakers() if not testMode: from DAQHardware import DAQHardware daq = DAQHardware() chanNamesIn= [ audioHW.mic_daqChan] micVoltsPerPascal = audioHW.micVoltsPerPascal spCal = None freq_array2 = audioParams.freq[1, :] try: frameNum = 0 isSaveDirInit = False saveOpts = appObj.getSaveOpts() for spkNum in range(0, numSpk): chanNameOut = audioHW.speakerL_daqChan attenLines = audioHW.attenL_daqChan spkIdx = 0 if (numSpk == 1 and audioParams.speakerSel == Speaker.RIGHT) or spkNum == 2: chanNameOut = audioHW.speakerR_daqChan attenLines = audioHW.attenR_daqChan spkIdx = 1 freq_array = audioParams.freq[spkIdx, :] if (audioParams.stimType == AudioStimType.TWO_TONE_DP) and (numSpk == 1): freq_array = np.concatenate((freq_array, freq_array2)) freq_array = np.sort(freq_array) freq_array2 = freq_array if spCal is None: spCal = SpeakerCalData(np.vstack((freq_array, freq_array2))) DebugLog.log("runSpeakerCal freq_array=" + repr(freq_array)) freq_idx = 0 attenSig = AudioHardware.makeLM1972AttenSig(0) if not testMode: # daq.sendDigOutCmd(attenLines, attenSig) appObj.oct_hw.SetAttenLevel(0, attenLines) for freq in freq_array: DebugLog.log("runSpeakerCal freq=" + repr(freq)) spkOut = makeSpeakerCalibrationOutput(freq, audioHW, audioParams) npts = len(spkOut) t = np.linspace(0, npts/outputRate, npts) pl = appObj.plot_spkOut pl.clear() endIdx = int(5e-3 * outputRate) # only plot first 5 ms pl.plot(t[0:endIdx], spkOut[0:endIdx], pen='b') numInputSamples = int(inputRate*len(spkOut)/outputRate) if testMode: mic_data = OCTCommon.loadRawData(testDataDir, frameNum, dataType=3) else: # setup the output task daq.setupAnalogOutput([chanNameOut], audioHW.daqTrigChanIn, int(outputRate), spkOut) daq.startAnalogOutput() # setup the input task daq.setupAnalogInput(chanNamesIn, audioHW.daqTrigChanIn, int(inputRate), numInputSamples) daq.startAnalogInput() # trigger the acquiisiton by sending ditital pulse daq.sendDigTrig(audioHW.daqTrigChanOut) mic_data = daq.readAnalogInput() mic_data = mic_data/micVoltsPerPascal if not testMode: daq.stopAnalogInput() daq.stopAnalogOutput() daq.clearAnalogInput() daq.clearAnalogOutput() npts = len(mic_data) t = np.linspace(0, npts/inputRate, npts) pl = appObj.plot_micRaw pl.clear() pl.plot(t, mic_data, pen='b') labelStyle = appObj.xLblStyle pl.setLabel('bottom', 'Time', 's', **labelStyle) labelStyle = appObj.yLblStyle pl.setLabel('left', 'Response', 'Pa', **labelStyle) micData, spCal = processSpkCalData(mic_data, freq*1000, freq_idx, audioParams, inputRate, spCal, spkIdx) pl = appObj.plot_micFFT pl.clear() df = micData.fft_freq[1] - micData.fft_freq[0] nf = len(micData.fft_freq) i1 = int(1000*freq_array[0]*0.9/df) i2 = int(1000*freq_array[-1]*1.1/df) DebugLog.log("SpeakerCalibration: df= %0.3f i1= %d i2= %d nf= %d" % (df, i1, i2, nf)) pl.plot(micData.fft_freq[i1:i2], micData.fft_mag[i1:i2], pen='b') labelStyle = appObj.xLblStyle pl.setLabel('bottom', 'Frequency', 'Hz', **labelStyle) labelStyle = appObj.yLblStyle pl.setLabel('left', 'Magnitude', 'db SPL', **labelStyle) pl = appObj.plot_micMagResp pl.clear() # pl.plot(1000*spCal.freq[spkIdx, :], spCal.magResp[spkIdx, :], pen="b", symbol='o') pl.plot(freq_array, spCal.magResp[spkIdx, :], pen="b", symbol='o') labelStyle = appObj.xLblStyle pl.setLabel('bottom', 'Frequency', 'Hz', **labelStyle) labelStyle = appObj.yLblStyle pl.setLabel('left', 'Magnitude', 'db SPL', **labelStyle) freq_idx += 1 if appObj.getSaveState(): if not isSaveDirInit: saveDir = OCTCommon.initSaveDir(saveOpts, 'Speaker Calibration', audioParams=audioParams) isSaveDirInit = True if saveOpts.saveRaw: OCTCommon.saveRawData(mic_data, saveDir, frameNum, dataType=3) QtGui.QApplication.processEvents() # check for GUI events, such as button presses # if done flag, break out of loop if appObj.doneFlag: break frameNum += 1 # if done flag, break out of loop if appObj.doneFlag: break if not appObj.doneFlag: saveDir = appObj.settingsPath saveSpeakerCal(spCal, saveDir) appObj.audioHW.loadSpeakerCalFromProcData(spCal) appObj.spCal = spCal except Exception as ex: traceback.print_exc(file=sys.stdout) QtGui.QMessageBox.critical (appObj, "Error", "Error during scan. Check command line output for details") 8# update the audio hardware speaker calibration appObj.isCollecting = False QtGui.QApplication.processEvents() # check for GUI events, such as button presses appObj.finishCollection()
Created on Wed Oct 7 16:27:38 2015 @author: OHNS """ import numpy as np from DebugLog import DebugLog from ctypes import byref import time # Patrick, please make this conditional... it won't work on my Mac try: import PyDAQmx as daqmx except ImportError: DebugLog.log("DAQHardware.py: could not import PyDAQmx module - DAQ hardware I/O will not work!!!") class DAQHardware: def __init__(self): highSamples = 1000 numpts = 3 * highSamples #dn = 100000 doData = np.zeros((numpts,), dtype=np.uint32) doData[highSamples:2*highSamples] = 2**32 - 1 self.doTrigData = doData # write single value to maultiple channels def writeValues(self, chanNames, data): DebugLog.log("DAQhardware.writeValue(): chanNames= %s val= %s" % (repr(chanNames), repr(data)))
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()
def runSpeakerCalTest(appObj): DebugLog.log("runSpeakerCal") appObj.tabWidget.setCurrentIndex(1) appObj.doneFlag = False appObj.isCollecting = True # trigRate = octfpga.GetTriggerRate() audioHW = appObj.audioHW outputRate = audioHW.DAQOutputRate inputRate = audioHW.DAQInputRate audioParams = appObj.getAudioParams() numSpk = audioParams.getNumSpeakers() daq = DAQHardware() chanNamesIn = [audioHW.mic_daqChan] micVoltsPerPascal = audioHW.micVoltsPerPascal # spCal = SpeakerCalData(audioParams) try: testMode = appObj.oct_hw.IsDAQTestingMode() frameNum = 0 isSaveDirInit = False saveOpts = appObj.getSaveOpts() if audioParams.speakerSel == Speaker.LEFT: chanNameOut = audioHW.speakerL_daqChan attenLines = audioHW.attenL_daqChan spkIdx = 0 else: chanNameOut = audioHW.speakerR_daqChan attenLines = audioHW.attenR_daqChan spkIdx = 1 freq_array = audioParams.freq[spkIdx, :] if (audioParams.stimType == AudioStimType.TWO_TONE_DP) and (numSpk == 1): freq2 = audioParams.freq[1, :] freq_array = np.concatenate((freq_array, freq2)) freq_array = np.sort(freq_array) DebugLog.log("freq_array=" + repr(freq_array)) amp_array = audioParams.amp numAmp = len(amp_array) numFreq = len(freq_array) magResp = np.zeros((numFreq, numAmp)) magResp[:, :] = np.nan phaseResp = np.zeros((numFreq, numAmp)) phaseResp[:, :] = np.nan THD = np.zeros((numFreq, numAmp)) THD[:, :] = np.nan for freq_idx in range(0, numFreq): for amp_idx in range(0, numAmp): freq = freq_array[freq_idx] amp = amp_array[amp_idx] spkOut, attenLvl = makeSpkCalTestOutput(freq, amp, audioHW, audioParams, spkIdx) DebugLog.log("runSpeakerCalTest freq= %0.3f kHz amp= %d attenLvl= %d" % (freq, amp, attenLvl)) if spkOut is None: DebugLog.log("runSpeakerCalTest freq= %0.3f kHz cannot output %d dB" % (freq, amp)) frameNum = frameNum + 1 continue npts = len(spkOut) t = np.linspace(0, npts / outputRate, npts) pl = appObj.plot_spkOut pl.clear() endIdx = int(5e-3 * outputRate) # only plot first 5 ms pl.plot(t[0:endIdx], spkOut[0:endIdx], pen="b") attenSig = AudioHardware.makeLM1972AttenSig(attenLvl) numInputSamples = int(inputRate * len(spkOut) / outputRate) if not testMode: # daq.sendDigOutCmd(attenLines, attenSig) appObj.oct_hw.SetAttenLevel(attenLvl, attenLines) # setup the output task daq.setupAnalogOutput([chanNameOut], audioHW.daqTrigChanIn, int(outputRate), spkOut) daq.startAnalogOutput() # setup the input task daq.setupAnalogInput(chanNamesIn, audioHW.daqTrigChanIn, int(inputRate), numInputSamples) daq.startAnalogInput() # trigger the acquiisiton by sending ditital pulse daq.sendDigTrig(audioHW.daqTrigChanOut) mic_data = daq.readAnalogInput() mic_data = mic_data / micVoltsPerPascal daq.waitDoneInput() daq.waitDoneOutput() daq.stopAnalogInput() daq.stopAnalogOutput() daq.clearAnalogInput() daq.clearAnalogOutput() else: mic_data = GetTestData(frameNum) npts = len(mic_data) t = np.linspace(0, npts / inputRate, npts) pl = appObj.plot_micRaw pl.clear() pl.plot(t, mic_data, pen="b") labelStyle = appObj.xLblStyle pl.setLabel("bottom", "Time", "s", **labelStyle) labelStyle = appObj.yLblStyle pl.setLabel("left", "Response", "Pa", **labelStyle) micData, magResp, phaseResp, THD = processSpkCalTestData( mic_data, freq * 1000, freq_idx, amp_idx, audioParams, inputRate, magResp, phaseResp, THD ) pl = appObj.plot_micFFT pl.clear() df = micData.fft_freq[1] - micData.fft_freq[0] nf = len(micData.fft_freq) i1 = int(1000 * freq_array[0] * 0.9 / df) i2 = int(1000 * freq_array[-1] * 1.1 / df) DebugLog.log("SpeakerCalibration: df= %0.3f i1= %d i2= %d nf= %d" % (df, i1, i2, nf)) pl.plot(micData.fft_freq[i1:i2], micData.fft_mag[i1:i2], pen="b") labelStyle = appObj.xLblStyle pl.setLabel("bottom", "Frequency", "Hz", **labelStyle) labelStyle = appObj.yLblStyle pl.setLabel("left", "Magnitude", "db SPL", **labelStyle) pl = appObj.plot_micMagResp pl.clear() for a_idx in range(0, numAmp): pen = (a_idx, numAmp) pl.plot(1000 * freq_array, magResp[:, a_idx], pen=pen, symbol="o") labelStyle = appObj.xLblStyle pl.setLabel("bottom", "Frequency", "Hz", **labelStyle) labelStyle = appObj.yLblStyle pl.setLabel("left", "Magnitude", "db SPL", **labelStyle) pl = appObj.plot_speakerDistortion pl.clear() for a_idx in range(0, numAmp): pen = (a_idx, numAmp) pl.plot(1000 * freq_array, THD[:, a_idx], pen=pen, symbol="o") labelStyle = appObj.xLblStyle pl.setLabel("bottom", "Frequency", "Hz", **labelStyle) labelStyle = appObj.yLblStyle pl.setLabel("left", "Magnitude", "db SPL", **labelStyle) if appObj.getSaveState(): if not isSaveDirInit: saveDir = OCTCommon.initSaveDir(saveOpts, "Speaker Cal Test", audioParams=audioParams) isSaveDirInit = True if saveOpts.saveRaw: OCTCommon.saveRawData(mic_data, saveDir, frameNum, dataType=3) frameNum = frameNum + 1 QtGui.QApplication.processEvents() # check for GUI events, such as button presses # if done flag, break out of loop if appObj.doneFlag: break # if done flag, break out of loop if appObj.doneFlag: break except Exception as ex: traceback.print_exc(file=sys.stdout) QtGui.QMessageBox.critical(appObj, "Error", "Error during scan. Check command line output for details") 8 # update the audio hardware speaker calibration appObj.isCollecting = False QtGui.QApplication.processEvents() # check for GUI events, such as button presses appObj.finishCollection()
def runAOTest(daqHW,): chanNames = ['Dev1/ao0', 'Dev1/ao3'] chanNames = ['PXI1Slot2/ao0', 'PXI1Slot2/ao1'] data = np.zeros(2) daqHW.writeValues(chanNames, data) outputRate = 200000 amp=1 amp2 = amp/2 outT = 100e-3 npts = int(outputRate*outT) t = np.linspace(0, outT, npts) freq = 2000 freq2 = freq*2 cmd_x = amp*np.sin(2*np.pi*freq*t) cmd_y = amp2*np.sin(2*np.pi*freq2*t) # plt.figure(1); # plt.clf() # plt.plot(cmd_x, '-r') # plt.plot(cmd_y, '-b') # plt.show() # plt.draw() outData = np.vstack((cmd_x, cmd_y)) #outData = cmd_x trigChan = '/Dev1/PFI0' trigOutLine = 'Dev1/port0/line0' chanName = chanNames[1] # numSamples = npts # samplesWritten = daqmx.int32() # analog_output = daqmx.Task() # outData = np.require(outData, np.float, ['C', 'W']) # analog_output.CreateAOVoltageChan(chanName,"",-10.0,10.0, daqmx.DAQmx_Val_Volts, None) #for chanName in chanNames: # analog_output.CreateAOVoltageChan(chanName,"",-10.0,10.0, daqmx.DAQmx_Val_Volts, None) # analog_output.CfgSampClkTiming("",outputRate, daqmx.DAQmx_Val_Rising, daqmx.DAQmx_Val_FiniteSamps, numSamples) # analog_output.CfgDigEdgeStartTrig(trigChan, daqmx.DAQmx_Val_Rising) # analog_output.WriteAnalogF64(numSampsPerChan=numSamples, autoStart=False,timeout=3.0, dataLayout=daqmx.DAQmx_Val_GroupByChannel, writeArray=outData, reserved=None, sampsPerChanWritten=byref(samplesWritten)) dataOut = copy.copy(outData) daqHW.setupAnalogOutput(chanNames, trigChan, outputRate, dataOut.transpose()) for n in range(0, 20): daqHW.startAnalogOutput() print("n= ", n) #nalog_output.StartTask() daqHW.sendDigTrig(trigOutLine) # wait unti output is finsihed and clean up tasks err = daqHW.waitDoneOutput(3) if err < 0: DebugLog.log("waitDoneOutput() err = %s" % repr(err)) daqHW.stopAnalogOutput() # isDone = False # isDoneP = daqmx.c_ulong() # while not isDone: # err = analog_output.IsTaskDone(byref(isDoneP)) # isDone = isDoneP.value != 0 # # analog_output.StopTask() time.sleep(0.1) # analog_output.ClearTask() daqHW.clearAnalogOutput()
def processSpkCalTestData(mic_data, freq, freq_idx, amp_idx, audioParams, inputRate, magRespIn, phaseRespIn, THDIn): # print("SpeakerCalProtocol: processData: mic_data=" + repr(mic_data)) # ensure data is 1D if len(mic_data.shape) > 1: mic_data = mic_data[:, 0] numpts = len(mic_data) DebugLog.log("SpeakerCalProtocol: processData: numpts= %d" % (numpts)) t = np.linspace(0, numpts / inputRate, numpts) zero_pad_factor = 2 numfftpts = numpts * zero_pad_factor winfcn = np.hanning(numpts) mic_fft = np.fft.fft(winfcn * mic_data, numfftpts) endIdx = np.ceil(numfftpts / 2) mic_fft = mic_fft[0:endIdx] mic_fft_mag = 2 * np.abs(mic_fft) # convert to dB, correctting for RMS and FFT length fftrms_corr = 2 / (numpts * np.sqrt(2)) mic_fft_mag = fftrms_corr * mic_fft_mag # 20e-6 pa mic_fft_mag_log = 20 * np.log10(mic_fft_mag / 20e-6) mic_fft_phase = np.angle(mic_fft) mic_freq = np.linspace(0, inputRate / 2, endIdx) fIdx = int(np.floor(freq * numfftpts / inputRate)) DebugLog.log("SpeakerCalibration: processData: freq= %f fIdx= %d" % (freq, fIdx)) stim_freq_mag = np.NAN stim_freq_phase = np.NAN try: npts = zero_pad_factor mag_rgn = mic_fft_mag_log[fIdx - npts : fIdx + npts] phase_rgn = mic_fft_phase[fIdx - npts : fIdx + npts] maxIdx = np.argmax(mag_rgn) stim_freq_mag = mag_rgn[maxIdx] stim_freq_phase = phase_rgn[maxIdx] mag_rgn = mic_fft_mag[fIdx - npts : fIdx + npts] stim_freq_mag_pa = mag_rgn[maxIdx] except Exception as ex: # DebugLog.log(ex) traceback.print_exc(file=sys.stdout) thd = 0 try: nmax = int(np.floor((inputRate / 2) / freq)) npts = zero_pad_factor # for n in range(2, nmax+1): # fIdx = int(np.floor(freq*n*numfftpts/inputRate)) # # mag_rgn = mic_fft_mag[fIdx-npts:fIdx+npts] # maxIdx = np.argmax(mag_rgn) # resp = mag_rgn[maxIdx] # # idx1= fIdx+npts+2 # idx2 = fIdx+npts+82 # noise_rgn = mic_fft_mag[fIdx-npts:fIdx+npts] # noise_mean = np.mean(noise_rgn) # noise_std = np.std(noise_rgn) # noise_lvl = noise_mean + 2*noise_std # print("n= ", n, " resp= ", resp, " noise_lvl= ", noise_lvl) # if resp > noise_lvl: # thd += (resp**2) # print("sum distortions= ", thd, " stim_freq_mag_pa= ", stim_freq_mag_pa) # thd = (thd ** 0.5)/stim_freq_mag fIdx1 = int(np.floor(freq * 2 * numfftpts / inputRate)) fIdx2 = int(np.floor((freq / 2) * numfftpts / inputRate)) mag_rgn1 = mic_fft_mag_log[fIdx1 - npts : fIdx1 + npts] mag_rgn2 = mic_fft_mag_log[fIdx2 - npts : fIdx2 + npts] maxIdx1 = np.argmax(mag_rgn1) maxIdx2 = np.argmax(mag_rgn2) resp1 = mag_rgn1[maxIdx1] resp2 = mag_rgn2[maxIdx2] # thd = max((resp1, resp2)) thd = resp2 print("thd= ", thd) # if thd > 0: # thd = 20*np.log10(thd) # convert to dB # else: # thd = np.nan # print("20*log10(thd/20e-6)= ", thd) except Exception as ex: # DebugLog.log(ex) traceback.print_exc(file=sys.stdout) DebugLog.log( "SpeakerCalibration: processData: stim_freq_mag= %f stim_freq_phase= %f" % (stim_freq_mag, stim_freq_phase) ) micData = SpeakerCalibration.MicData() micData.raw = mic_data micData.t = t micData.fft_mag = mic_fft_mag_log micData.fft_phase = mic_fft_phase micData.fft_freq = mic_freq micData.stim_freq_mag = stim_freq_mag micData.stim_freq_phase = stim_freq_phase micData.thd = thd magRespIn[freq_idx, amp_idx] = stim_freq_mag phaseRespIn[freq_idx, amp_idx] = stim_freq_phase THDIn[freq_idx, amp_idx] = thd return micData, magRespIn, phaseRespIn, THDIn
def processUniqueDispersion(pd_data, dispData, pd_background=None, bg_collect=False): numTrigs = pd_data.shape[0] numklinpts = pd_data.shape[1] DebugLog.log("Dispersion.processUniqueDispersion: numklinpts= %d" % numklinpts) winFcn = np.hanning(numklinpts) pd = np.mean(pd_data, 0) dispData.phDiode = pd if bg_collect: pd = np.real(pd_data[:, 0:numklinpts]) pd_background = np.mean(pd, 0) magWin = np.zeros((numTrigs, numklinpts)) phaseCorr = np.zeros((numTrigs, numklinpts)) # set up filter coefficients idx0 = np.round(dispData.PDfilterCutoffs[1]*numklinpts) idx1 = np.round(dispData.PDfilterCutoffs[0]*numklinpts) (b, a) = scipy.signal.butter(2, dispData.magWin_LPfilterCutoff, 'lowpass') # subtract background sigdata = np.real(pd_data[:, 0:numklinpts]) if pd_background is not None: bg = np.tile(pd_background, (numTrigs, 1)) sigdata = sigdata - bg for n in range(0, numTrigs): sig = sigdata[n, :] # first filter the interferograph using an ideal filter with the FFT-IFFT method fftsig = np.fft.rfft(sig) fftsig[0:idx0] = 0 fftsig[idx1:] = 0 sig = np.fft.irfft(fftsig, len(sig)) """ Hilbert Transform A perfect reflector like a mirror should make the interferogram like a sine wave. The phase of the Hilbert Transform of a sine wave should be a linear ramp. Any deviation from this must therefore be from dispersion. """ sig_ht = scipy.signal.hilbert(sig) mag = np.abs(sig_ht) magWin[n, :] = winFcn / mag ph = np.angle(sig_ht) ph_unwr = np.unwrap(ph) phaseCorr[n, :] = scipy.signal.detrend(ph_unwr) magWin = np.mean(magWin, 0) magWin = scipy.signal.lfilter(b, a, magWin) minWin = np.min(magWin) maxWin = np.max(magWin) dispData.magWin = (magWin - minWin)/(maxWin - minWin) phaseCorr = np.mean(phaseCorr, 0) dispData.phaseCorr = phaseCorr dispData.phDiode_background = pd_background winFcnTile = np.tile(winFcn, numTrigs).reshape(numTrigs, numklinpts) # make uncorrected aline fft_sig_u = np.fft.fft(winFcnTile * sigdata, 2048, 1) dispData.uncorrAline = 20*np.log10(np.mean(np.abs(fft_sig_u) + 1, 0)) DebugLog.log("Dispersion.processUniqueDispersion: len(ph_unwr)= %d phaseCorr.shape= %s" % (len(ph_unwr), repr(phaseCorr.shape))) DebugLog.log("Dispersion.processUniqueDispersion: magWin.shape= %s" % repr(magWin.shape)) # make orrected aline magWinTile = np.tile(magWin, numTrigs).reshape(numTrigs, numklinpts) phaseCorrTile = np.tile(phaseCorr, numTrigs).reshape(numTrigs, numklinpts) sigDataComplex = magWinTile * sigdata * (np.cos(-phaseCorrTile) + 1j * np.sin(-phaseCorrTile)) fft_sig_c = np.fft.fft(sigDataComplex, 2048, 1) dispData.corrAline = 20*np.log10(np.mean(np.abs(fft_sig_c) + 1, 0)) return dispData