#!/usr/bin/env python # -*- coding: utf-8 -*- # ================ HXR signal deconvolution algorithm 0.1 ============================================ # algorithm based on the naive implementation of the blind deconvolution algorithm to increase response time of the HXR detector. # in the first step the peak positions are estimated by function peaksCounter # in the second step a "back deconvolution" is done by function back_deconvolution top find the system response function # in the third step a really sophisticate algorithm is used for signal deconvolution. # in final step a function peaksCounter is used to identify peaks and prepare data for hystorogram. # function: back_deconvolution; data - signal from HXR detector,events_pos - some of the identified peaks,events_area - and their surface, # peak_width - estimated width of the response function support,lam - regularization parameter,upsample - upsampling parameter to increase resulution and precision, # description - this function calculate inversion problem to the deconvolution. Therefore it is quite well conditioned. It also supports corrupted data in signal (nans), #function: deconvolution; data - signal from HXR detector,response - response function of the system , # win - width od the windows used for calculations,lam - regularization parameter , upsample- upsampling parameter to increase resulution and precision, #description - deconvolution algorithm based on minimum tikhonov information. It is nonlinear, weighted by size of the deconvoltioned signal. This way also a positiovity constrain is enforced. # this algorithm can deal with data currupted by nans (for example if DAS overcame its maximal range), moreover the constant offset over the window is threated. And finally an upsampling is supported. #Autor: Tomas Odstrcil 2012 tomasodstrcil at gmail.com from numpy import * from numpy import linalg import time from scipy import sparse from numpy import linalg import matplotlib matplotlib.rcParams['backend'] = 'Qt4Agg' from matplotlib.pyplot import * from scipy.interpolate import interp1d from scikits.sparse.cholmod import cholesky, analyze, cholesky_AAt from numpy.matlib import repmat from numpy import * from matplotlib.pyplot import * from scipy.sparse import * import time MAD = lambda x: median(abs(x-median(x, axis = 0)), axis = 0)*1.48 def peaksCounter(signal, threshold_min,threshold_max ): """ identifikuje to peak jeden po druhém od největšího po nejmeší """ signal = copy(signal) x0 = argmax(signal) peaks = list() std = MAD(signal) signal-= median(signal) while(signal[x0] > threshold_min): a = signal[x0] xl= x0 xr= x0 while xl > 0 and signal[xl]>=signal[xl-1]: xl-=1 while xr+1 < len(signal) and signal[xr]>=signal[xr+1]: xr+=1 interv = arange(xl,xr+1) x0 -= (signal[x0+1]-signal[x0-1])/(signal[x0+1]-2*a+signal[x0-1])/2 area = sum(signal[interv]) #plot(signal[interv]) #show() signal[interv] = 0 x0 = argmax(signal) if a < threshold_max: peaks.append((x0, area)) return array(peaks, copy = False) #z odhalých poloh to zkusí typnout konvoluční funkci def back_deconvolution( data,events_pos,events_area,peak_width,lam,upsample): #Vyřešit to nějak vážení? data = copy(data) i_nan = isnan(data) data-= median(data[~i_nan]) n = len(data) n_peaks = len(events_pos) lam = lam*upsample#*n_peaks**2 npix = upsample*peak_width Events_matrix = sparse.lil_matrix(( n,npix)) for i in range(n_peaks): l = max(int(events_pos[i]-20),0) r = min(int(events_pos[i]+80),n) s = int((events_pos[i]-floor(events_pos[i]))*upsample) for j in range(r-l): Events_matrix[l+j,j*upsample+upsample-s-1] = events_area[i] nogaps = spdiags(int_(1-i_nan),0, n, n,format='csr') Events_matrix = nogaps*csc_matrix(Events_matrix) diag_data = ones((2,npix)) diag_data[1,:]*=-1 D = spdiags(diag_data, (0,1), npix, npix,format='csr') DD = D.T*D EE = Events_matrix.T*Events_matrix normEE = linalg.norm(EE.todense()) #print lam, upsample, n_peaks, normEE/1e4 factor = cholesky(Events_matrix.T*Events_matrix+lam*normEE/1e4*DD) g = squeeze(factor( Events_matrix.T*data)) #plot(g) #show() #plot(data) #plot(Events_matrix*g) #show() return copy(g) def deconvolution(data,response, win,lam,upsample): t_start = time.time() win = 2*(win/2) n = len(data) n_resp = len(response)#*upsample #fun = interp1d(arange(0,n_resp,upsample),response,kind='cubic',bounds_error = False,fill_value = 0) #response = fun(arange(n_resp)) data-=median(data) response/= abs(sum(response)) response*= upsample n_ext = (n/win+1)*win ext_signal = empty(n_ext) ext_signal[(n_ext-n)/2:-(n_ext-n)/2] = data ext_signal[:(n_ext-n)/2+1] = median(data[~isnan(data)][:win/2]) ext_signal[-(n_ext-n)/2-1:] = median(data[~isnan(data)][win/2:]) intervals = arange(0,n_ext+win/2, win/2) i_nan = isnan(ext_signal) ext_signal[i_nan] = 0 deconv = zeros(n_ext*upsample) retrofit = zeros_like(ext_signal) npix = upsample*win diags = arange(argmax(response)-n_resp+1, argmax(response)+1) diag_data = repmat(response[::-1], npix,1).T ConvMatrix = spdiags(diag_data, diags, npix, npix,format='csc') ReductMatrix = kron(eye(win,win),eye(1,upsample),format='csr') ConvMatrix = ReductMatrix*ConvMatrix #příprava dat do hlavného algoritmu na dekonvoluci, řeší se soustava Tg = f pomocí tichonovovy regularizace s nelineárním vážením bez shlazování (minimalizuje se norma g) T = ConvMatrix f = ext_signal # tohle to upravuje signál tak aby se od něj automaticky odečítal konstantní offset a = hstack([sparse.csc_matrix(ones([win,1])), sparse.csc_matrix((win, npix-1))],format='csr') #T=T+a TT_ = T.T*T #TT = (T+a).T*(T+a) #factor = analyze(TT) g = zeros(npix) g = exp(-linspace(-1,1,npix )**2) #print sum(ConvMatrix*g), sum(g) #plot(g) #plot(ConvMatrix*g) #show() #exit() for i in range(len(intervals)-2): t0 = time.time() W = ones(npix) #váhová matice i_nan_win = i_nan[intervals[i]:intervals[i+2]] gaps = spdiags(int_(i_nan_win),0, win, win,format='csr') t = time.time() #T0 = gaps*T #T0T = T0.T*T #dTT = T0T+T0T.T-T0.T*T0 #TT_ = TT-dTT #i_nan_g = hstack((i_nan_win,i_nan_win)) #i_nan_g = reshape(i_nan_g, (1,-1)) i_nan_g = repeat(i_nan_win, 2) #exit() factor = analyze(TT_+identity(npix,format='csc')) t = time.time() #print i for j in range(5): #print shape(W), shape(i_nan[intervals[i]:intervals[i+2]]) #W[i_nan_g] = 0.001*mean(W) W = sparse.spdiags(W,0, npix,npix) factor.cholesky_inplace(TT_ +lam*W) g = squeeze(factor(T.T*f[intervals[i]:intervals[i+2]])) g_tmp = copy(g) g_tmp[g_tmp < 0.01] = 0.01 # ořezání záporných bodů (výsledek požadujeme jenom kladný) #g_tmp[i_nan[intervals[i]:intervals[i+2]]] = 1000 W = mean(g_tmp)/(g_tmp) # nová váhová matice do další iterace #print "time", time.time() - t, t-t0 f_i = T*g if any(f_i > 0.2): print sum(f_i-median(f_i))/sum(abs(f_i-median(f_i)))*2, sum(g), sum(abs(f_i-median(f_i))) #plot(linspace(0,win,win),cumsum( f_i-median(f_i))) #plot(linspace(0,win,win*upsample), cumsum(g*upsample)) #show() deconv[(intervals[i]+intervals[i+1])/2*upsample:(intervals[i+1]+intervals[i+2])/2*upsample] = g[len(g)/4:-len(g)/4] retrofit[(intervals[i]+intervals[i+1])/2:(intervals[i+1]+intervals[i+2])/2] = f_i[len(f_i)/4:-len(f_i)/4] print time.time()-t_start deconv = deconv[(n_ext-n)/2*upsample:-(n_ext-n)/2*upsample] retrofit = (retrofit)[(n_ext-n)/2:-(n_ext-n)/2] i_nan = (i_nan)[(n_ext-n)/2:-(n_ext-n)/2] plot(linspace(0,n,n*upsample),deconv*upsample, label = 'deconv') plot(linspace(0,n,n),data, label = 'raw') plot(linspace(0,n,n),retrofit, label = 'retrofit') plot(i_nan) legend() #savefig('retrofit.svgz', linewidth=0.3) #savefig('retrofit.png', linewidth=0.3) show() return deconv,retrofit #TODO zabudovat plasma start, plasma end #TODO vážení peaků při jejich hledání, ignorování přepálených??? # spuštění algoritmu for shot_num in range(0,1): #data = loadtxt('HXR_') print 'shot_num', shot_num #data = loadtxt('HXR_Co.txt') try: data = loadtxt('./data/'+str(shot_num)+'/HXR_') except: continue try: plasma_start = loadtxt('./data/'+str(shot_num)+'/PlasmaStart')/1000 plasma_end = loadtxt('./data/'+str(shot_num)+'/PlasmaEnd' )/1000 except: plasma_start = 0 plasma_end = 4e-2 plasma_start_adv = max(plasma_start-1e-3,0) plasma_end_adv = min(plasma_end+1e-3,4e-2) dt = 0.04/len(data) Bt_trigger = 5e-3 data[int(Bt_trigger/dt)-100:int(Bt_trigger/dt)+200 ] = median(data[int(Bt_trigger/dt)-100:int(Bt_trigger/dt)+200 ])#remove trigger peak plot(arange(len(data))*dt, data) axvline(x = plasma_start) axvline(x = plasma_end) ylim(-1,10) data = data[int(plasma_start_adv/dt):int(plasma_end_adv/dt) ] plot(arange(int(plasma_start_adv/dt), int(plasma_end_adv/dt))*dt,data) savefig('./graphs/'+str(shot_num)+'_data.png') close() win = 600 upsample = 1 peakwidth = 100 DAS_limit = 10 #[V] regularization = 0.1 peaks = peaksCounter(data,0.1,10) if len(peaks) == 0: print 'any radiation' continue hist(peaks[:,1],sqrt(len(peaks))) ylabel('counts [-]') xlabel('energy [keV]') xlim([0,amax(peaks[:,1])] ) savefig('./graphs/'+str(shot_num)+'historogram_.png') #show() close() data[data > DAS_limit] = nan #ořezané peaky response_fun = back_deconvolution(data,peaks[:,0],peaks[:,1],peakwidth,1e3,upsample) savetxt('response_fun', response_fun) plot(response_fun) savefig('./graphs/'+str(shot_num)+'response_fun.png') #show() close() savefig deconv,retrofit = deconvolution(data,response_fun, win,regularization,upsample) deconv/= upsample peaks = peaksCounter(deconv,0.2,10) hist(peaks[:,1],sqrt(len(peaks))) xlim([0,amax(peaks[:,1])] ) savefig('./graphs/'+str(shot_num)+'historogram.png') close() #TODO vrátit číslo celkové plochy/ délkou plazmatu = průměrný vyzářený výkon