def fftAnalysis(self,cs,profile,mode='sensitivity'): """ Fourier analysis: find main frequencies and power therein """ if cs.verbose: try: import QCUS_testing as mytest if mode == 'sensitivity': mytest._exportProfile( profile,fname='y2profile.tsv' ) else: mytest._exportProfile( profile,fname='x2profile.tsv' ) except: pass fdelta = .1 # peak should differ by more than this fraction of max ps if mode == 'sensitivity': cs.sens_basewavelength = 0. cs.sens_ylim2 = -1 # remove average component ywork = profile-np.average(profile) nx = len(ywork) x = np.array(range(nx)) ffty = np.fft.rfft(ywork) ps = np.abs(ffty)**2 integral = np.sum(ps[self.fft_skip:]) # calculate total content, but ignore zero component freqs = rfftfreq(nx) # find peaks xy_max,xy_min = wadwrapper_lib.peakdet(ps, delta=fdelta*np.max(ps[self.fft_skip:])) # returns indices for freqs # sort peaks from large to small xy_max = sorted(xy_max,key=operator.itemgetter(1)) xy_max = xy_max[::-1] # find max component which is not zero-component and represents larger than given fraction of power base_ix = 0 # index of base-frequency start_ix = 0 # index of zero-peak for i,(xi,yi) in enumerate(xy_max): if xi<=self.fft_skip: # zero-peak must be located in skip start_ix = xi if xi>self.fft_skip and base_ix<1: base_ix = xi if mode == 'sensitivity': cs.sens_basewavelength = self.pixels2mm(cs, 1./freqs[xi]) break # filter-out all non-background trend components to find extend of signal for i in range(len(ffty)): if i>(base_ix+start_ix)/2: ffty[i] = 0. # locate minimum (after zero-peak) of trend fy = np.fft.irfft(ffty) ix_max = np.argmax(fy) ix_min = ix_max+np.argmin(fy[ix_max:]) if cs.verbose: print 'max @',ix_max print 'min @',ix_min if mode == 'sensitivity': cs.sens_ylim2 = ix_min if cs.verbose: plt.figure() plt.plot(ywork) plt.plot(fy) if mode == 'sensitivity': plt.title('sensitivity,filtered') else: plt.title('uniformity,filtered') plt.figure() plt.plot(ps) if mode == 'sensitivity': plt.title('sensitivity,powerspectrum') else: plt.title('uniformity,powerspectrum') cs.hasmadeplots = True
def sensitivityAnalysis(self,cs): """ Workflow: 1. Calculate profile (vertically) 2. Determine noise level 3. Exponential fit to peaks in profile 4. total sensitivity = penetration depth (intercept fit and noise) 5. Repeat for subsets """ error = True ## 1. Calculate profile (vertically) wid,hei = np.shape(cs.rect_image) offsetHOR= wid/4 #10 ; adjusted to remove influence of annotations through reverb data (enhancement line) if offsetHOR == 0: offsetHOR = self.offsetHOR crop = cropImage(cs.rect_image, [offsetHOR], [self.offsetVER]) wid,hei = np.shape(crop) sensitivity = np.mean(crop,axis=0) time0 = time.time() self.fftAnalysis(cs,sensitivity,mode='sensitivity') cs.report.append(('sens_fft',time.time()-time0)) nx = len(sensitivity) sensitivitysmoothed = mymath.movingaverage(sensitivity,self.smooth_sensitivity) if cs.testing: try: import QCUS_testing as mytest mytest._exportProfile( [ (s,ss) for s,ss in zip(sensitivity,sensitivitysmoothed) ],fname='yprofile.tsv' ) except: pass ##2. Determine noise level (mean of last n values of sensitivity) cs.sens_noiseM = -1 noiseRange = 2 noise_av = np.mean(sensitivitysmoothed[-noiseRange:]) noise_sd = np.std(sensitivitysmoothed[-noiseRange:]) noise_snr = noise_av/noise_sd if noise_sd >0. else 0. noise_inc = False # sometimes snr starts with a local max for nr in range(noiseRange+2,nx/3): av = np.mean(sensitivitysmoothed[-nr:]) sd = np.std(sensitivitysmoothed[-nr:]) snr = av/sd if sd >0. else 0. if snr>noise_snr or not noise_inc: if snr>noise_snr: noise_inc = True noise_av = av noise_sd = sd noise_snr = snr else: cs.sens_noiserange = nr break cs.sens_noiseM = noise_av top_val = np.max(sensitivitysmoothed) cut_val = cs.sens_noiseM+.1*(top_val-cs.sens_noiseM) for kk in reversed(range(nx)): if sensitivitysmoothed[kk]>cut_val: cs.sens_ylim = kk break # peak detection pmax = np.max(sensitivitysmoothed) pmin = np.min(sensitivitysmoothed) delta = (pmax-max(cs.sens_noiseM,pmin))*self.fdelta_sensitivity xy_max,xy_min = wadwrapper_lib.peakdet(sensitivitysmoothed, delta=delta,x=range(nx)) # select only those peaks where max>noise; alternatively, select those peaks with min<noise if self.sens_hicut: xy_swap = [] for xy in xy_max: if xy[1]>cs.sens_noiseM: xy_swap.append(xy) else: break xy_max = xy_swap if len(xy_max)>0: cs.sens_ylim = max(cs.sens_ylim,max(xy_max,key=operator.itemgetter(0))[0]) xy_swap = [] for xy in xy_min: if xy[0]<cs.sens_ylim: xy_swap.append(xy) else: xy_swap.append(xy) # last point break xy_min = xy_swap else: xy_swap = [] for xy in xy_min: if xy[1]<cs.sens_noiseM or len(xy_swap)<3: xy_swap.append(xy) else: break xy_min = xy_swap if len(xy_min)>1: cs.sens_ylim = max(xy_min,key=operator.itemgetter(0))[0] xy_swap = [] for xy in xy_max: if xy[0]<cs.sens_ylim: xy_swap.append(xy) else: xy_swap.append(xy) # last point break xy_max = xy_swap cs.sens_numtops = len(xy_max) cs.sens_numbots = len(xy_min) if cs.testing: try: import QCUS_testing as mytest mytest._exportProfile( xy_max, fname='xy_max.tsv' ) mytest._exportProfile( xy_min, fname='xy_min.tsv' ) except: pass if cs.verbose: x_max = np.array([xy[0] for xy in xy_max]) y_max = np.array([xy[1] for xy in xy_max]) x_min = np.array([xy[0] for xy in xy_min]) y_min = np.array([xy[1] for xy in xy_min]) x = np.array(range(nx)) plt.figure() plt.plot(x,sensitivitysmoothed,'k-') plt.plot(x_min,y_min,'ro') plt.plot(x_max,y_max,'bo') cs.hasmadeplots = True error = False return error
def _uniformityAnalysis(self,cs,normuniformity): # Helper function for analysis of normalized uniformity profile: error = True nx = len(normuniformity) time0 = time.time() self.fftAnalysis(cs,normuniformity,mode='uniformity') cs.report.append(('unif_fft',time.time()-time0)) # peak detection with ugly hack to also allow peaks at index 0 and last #xy_max,xy_min = wadwrapper_lib.peakdet(normuniformity, delta=self.delta_uniformity,x=range(nx)) p0 = normuniformity[::-1] p2 = np.append(np.append(p0[:-1],normuniformity),p0[1:]) x2 = np.array(range(-(nx-1),2*nx-1)) xy_max,xy_min = wadwrapper_lib.peakdet(p2, delta=self.delta_uniformity,x=x2) xy_max = [xy for xy in xy_max if xy[0]>-1 and xy[0]<nx] xy_min = [xy for xy in xy_min if xy[0]>-1 and xy[0]<nx] ## peak analysis # sorted list of extrema positions: minmax_pos = [da[0] for da in xy_min] minmax_pos.extend( [da[0] for da in xy_max] ) minmax_pos = sorted(minmax_pos) # generate an image of non-uniformity x_max = np.array([xy[0] for xy in xy_max]) y_max = np.array([xy[1] for xy in xy_max]) x_min = np.array([xy[0] for xy in xy_min]) y_min = np.array([xy[1] for xy in xy_min]) yran = [] if self.fastmode: # use only first ring print 'Uniformity: FASTMODE',cs.sens_basewavelength if cs.sens_basewavelength >0: ylim = int(cs.sens_basewavelength/self.pixels2mm(cs,1.)+.5) yran = [self.offsetVER,ylim] if len(yran) == 0: yran = [self.offsetVER,cs.sens_ylim] if cs.sens_ylim>0 else [self.offsetVER] plt.figure() crop = cropImage(cs.rect_image, [self.offsetHOR], yran) plt.imshow(crop.transpose(),cmap=plt.gray()) x = np.array(range(nx)) plt.plot(x,-100*normuniformity,'y-',label='100*normalized') plt.plot(x_min,-100*y_min,'ro',label='accepted dips') plt.plot(x_max,-100*y_max,'bo',label='accepted peaks') plt.xlim([0,nx]) if not self.guimode: fname = 'uniformity_'+self.imageID(cs,probeonly=True)+'.jpg' plt.savefig(fname) cs.image_fnames.append(fname) else: cs.hasmadeplots = True if cs.verbose: plt.figure() plt.plot(x,normuniformity,'k-') plt.plot(x_min,y_min,'ro') plt.plot(x_max,y_max,'bo') cs.hasmadeplots = True # possible clean-up of peaks detected cs.unif_bots = [] for damin in xy_min: # find range around each dip and remove strongly asymetric dips if self.check_asym: peak_pos = damin[0] peak_val = damin[1] asym = True delta = self.delta_uniformity while asym: pos_left = peak_pos for ix in reversed(range(0,peak_pos)): if normuniformity[ix]>peak_val+delta: pos_left= ix break pos_right = peak_pos for ix in range(peak_pos,nx): if normuniformity[ix]>peak_val+delta: pos_right= ix break if pos_left == peak_pos: print 'ERROR! Could not find left point of peak',peak_ix,peak_pos,peak_val return error if pos_right == peak_pos: print 'ERROR! Could not find left point of peak',peak_ix,peak_pos,peak_val return error # check if we are looking at a strongly symmetric peak if (pos_right-pos_left)>4*min(peak_pos-pos_left,pos_right-peak_pos): delta -= .1*self.delta_uniformity if delta < .2*self.delta_uniformity: break else: asym = False if asym: print 'ERROR! Very asymmetric peak',peak_ix,peak_pos,peak_val,peak_pos-pos_left,pos_right-peak_pos continue # acceptable cs.unif_bots.append(damin) # some figures of merit to store: non-unif in deepest dip and overal cs.unif_lowest = 1. if len(cs.unif_bots)==0 else min(cs.unif_bots,key=operator.itemgetter(1))[1] cs.unif_low = min(normuniformity[1:-1]) # exclude bounds error = False return error