def reverbUniformity(self,cs): """ Analysis uniformity of reverb pattern Workflow: 1. Define ROI of reverb (dependend on vertical profile) 2. Average ROI horizontally and calculate COV 3. Normalize profile as deviation wrt mean 4. Find dips in profile """ error = True ## 1. Define ROI of reverb (dependend on vertical profile) yran = [] if self.fastmode: 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] print yran if len(yran) == 0: yran = [self.offsetVER,cs.sens_ylim] if cs.sens_ylim>0 else [self.offsetVER] crop = cropImage(cs.rect_image, [self.offsetHOR], yran) uniformity = np.mean(crop,axis=1) uniformitysmoothed = mymath.movingaverage(uniformity,self.smooth_uniformity) ## line uniformity intemin = np.min(uniformity) intemax = np.max(uniformity) inteavg = np.mean(uniformity) cs.unif_line = np.max([intemax-inteavg,inteavg-intemin])/inteavg # Output of COV meanvalue = np.mean(uniformity) stdvalue = np.std(uniformity) # normalized uniformity if self.modeLocalNorm: frac = .1 print "Uniformity, using Local Normalization",frac normuniformity = mymath.localnormalization(uniformity, sigma=len(uniformity)*frac) else: normuniformity = ((uniformitysmoothed-meanvalue)/meanvalue) if cs.testing: try: import QCUS_testing as mytest mytest._exportProfile(normuniformity,fname='xprofile.tsv') mytest._exportNDArray(cs.rect_image) except: pass return self._uniformityAnalysis(cs, normuniformity)
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 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