def matchedFilter(template, noiseSpectrum, nTaps=50): ''' Make a matched filter using a template and noise PSD. Rolls off template above 250kHz. (same as 250 roll off Wiener filter but calculated with the covariance matrix) INPUTS: template - array containing pulse template noiseSpectrum - noise PSD nTaps - number of filter coefficients OUTPUTS matchedFilt - matched filter that should be convolved with the data to get the pulse heights ''' #check normalized to 1 template /= np.max(np.abs(template)) #mimic antialiasing filter fft = np.fft.rfft(template) spectrum = 1 / (1 + (np.fft.rfftfreq(len(template), d=1e-6) / 250000.0)**8.0) fft = fft * spectrum template1 = np.fft.irfft(fft) template1 /= np.max(np.abs(template1)) noiseCov = mNS.covFromPsd(noiseSpectrum, nTaps)['covMatrix'] template1 = template1[:nTaps] #shorten template to length nTaps template = template[:nTaps] filterNorm = np.dot(template, np.linalg.solve(noiseCov, template1)) matchedFilt = np.linalg.solve(noiseCov, template1) / filterNorm return -matchedFilt
def makeMatchedFilter(noiseSpectDict, template): """ Calculate Matched Filter coefficients Does not work yet 08/18/2016 INPUTS: noiseSpectDict - Dictionary containing noise spectrum and list of corresponding frequencies template - template of pulse shape OUTPUTS: matchedFilter - list of Matched Filter coefficients """ noiseSpectrum = noiseSpectDict["noiseSpectrum"] noiseCovInv = mNS.covFromPsd(noiseSpectrum)["covMatrixInv"] filterNorm = np.sqrt(np.dot(template, np.dot(noiseCovInv, template))) # filterNorm not working correctly matchedFilt = np.dot(noiseCovInv, template) / filterNorm return matchedFilt
def superMatchedFilter(template, noiseSpectrum, nTaps=50): ''' Make a matched filter that is robust against pulse pileup using prescription from Alpert 2013 Rev. of Sci. Inst. 84. (Untested) INPUTS: template - array containing pulse template noiseSpectrum - noise PSD nTaps - number of filter coefficients OUTPUTS superMatchedFilt - super matched filter that should be convolved with the data to get the pulse heights ''' #get the fall time for the end of the pulse #(only a good idea to use this formula if using a fitted template) fallTime = (template[-1] - template[-2]) / np.log( template[-2] / template[-1]) #determine pulse direction if np.min(template) > np.max(template): pos_neg = -1. else: pos_neg = 1 #check normalized to 1 template /= np.abs(template[np.argmax(np.abs(template))]) #create covariance inverse matrix noiseCovInv = mNS.covFromPsd(noiseSpectrum, nTaps)['covMatrixInv'] #shorten template to length nTaps template = template[:nTaps] #create exponential to be orthogonal to exponential = pos_neg * np.exp(-np.arange(0, len(template)) / fallTime) #create filter orthMat = np.array([template, exponential]) orthMat = orthMat.T e1 = np.array([1, 0]) norm = np.linalg.inv(np.dot(orthMat.T, np.dot(noiseCovInv, orthMat))) superMatchedFilter = np.dot(noiseCovInv, np.dot(orthMat, np.dot(norm, e1))) #flip so that filter works with correlation and not convolution superMatchedFilter = superMatchedFilter[::-1] return superMatchedFilter
def makeSuperMatchedFilter(template, noiseSpectrum, fallTime, nTaps=50, tempOffs=90,sampleRate=1e6): ''' Make a matched filter that is robust against pulse pileup using prescription from Alpert 2013 Rev. of Sci. Inst. 84 INPUTS: template - array containing pulse template noiseSpectrum - noise PSD fallTime - pulse fall time to make fits robust to nTaps - number of filter coefficients tempOffs - offset of template subset to use for filter sampleRate - sample rate of template in Hz OUTPUTS superMatchedFilt - super matched filter that should be convolved with the data to get the pulse heights ''' #determine pulse direction if np.min(template)>np.max(template): pos_neg=-1. else: pos_neg=1 #check normalized to 1 template/=np.abs(template[np.argmax(np.abs(template))]) #create covariance inverse matrix noiseCovInv = noise.covFromPsd(noiseSpectrum, nTaps)['covMatrixInv'] #shorten template to length nTaps template = template[tempOffs:tempOffs+nTaps] #create exponential to be orthogonal to exponential=pos_neg*np.exp(-np.arange(0,len(template))/fallTime/sampleRate) #create filter orthMat=np.array([template,exponential]) orthMat=orthMat.T e1=np.array([1,0]) norm=np.linalg.inv(np.dot(orthMat.T,np.dot(noiseCovInv,orthMat))) superMatchedFilter=np.dot(noiseCovInv,np.dot(orthMat,np.dot(norm,e1))) superMatchedFilter=superMatchedFilter[::-1] return superMatchedFilter
def makeMatchedFilter(template, noiseSpectrum, nTaps=50, tempOffs=90): ''' Make a matched filter using a template and noise PSD INPUTS: template - array containing pulse template noiseSpectrum - noise PSD nTaps - number of filter coefficients tempOffs - offset of template subset to use for filter OUTPUTS matchedFilt - matched filter that should be convolved with the data to get the pulse heights ''' #check normalized to 1 template/=np.abs(template[np.argmax(np.abs(template))]) noiseCovInv = noise.covFromPsd(noiseSpectrum, nTaps)['covMatrixInv'] #print np.dot(noise.covFromPsd(noiseSpectrum, nTaps)['covMatrixInv'] ,noise.covFromPsd(noiseSpectrum, nTaps)['covMatrix'] ) template = template[tempOffs:tempOffs+nTaps] #shorten template to length nTaps filterNorm = np.dot(template, np.dot(noiseCovInv, template)) matchedFilt = np.dot(noiseCovInv, template)/filterNorm matchedFilt=matchedFilt[::-1] return matchedFilt