#from math import * from numpy import zeros, convolve, dot, linalg, size #@UnresolvedImport all = ['calc_coeff','smooth'] def _resub(D, rhs): """ solves D D^T = rhs by resubstituion. D is lower triangle-matrix from cholesky-decomposition """ M = D.shape[0] x1= zeros((M,),float) x2= zeros((M,),float) # resub step 1 for l in range(M): sum = rhs[l] for n in range(l): sum -= D[l,n]*x1[n] x1[l] = sum/D[l,l] # resub step 2 for l in range(M-1,-1,-1): sum = x1[l] for n in range(l+1,M): sum -= D[n,l]*x2[n] x2[l] = sum/D[l,l] return x2 def calc_coeff(num_points, pol_degree, diff_order=0): """ Calculates filter coefficients for symmetric savitzky-golay filter. see: http://www.nrbook.com/a/bookcpdf/c14-8.pdf Parameters ---------- num_points : scalar, integer means that 2*num_points+1 values contribute to the smoother. pol_degree : scalar, integer is degree of fitting polynomial diff_order : scalar, integer is degree of implicit differentiation. 0 means that filter results in smoothing of function 1 means that filter results in smoothing the first derivative of function. and so on ... """ # setup normal matrix A = zeros((2*num_points+1, pol_degree+1), float) for i in range(2*num_points+1): for j in range(pol_degree+1): A[i,j] = pow(i-num_points, j) # calculate diff_order-th row of inv(A^T A) ATA = dot(A.transpose(), A) rhs = zeros((pol_degree+1,), float) rhs[diff_order] = 1 D = linalg.cholesky(ATA) wvec = _resub(D, rhs) # calculate filter-coefficients coeff = zeros((2*num_points+1,), float) for n in range(-num_points, num_points+1): x = 0.0 for m in range(pol_degree+1): x += wvec[m]*pow(n, m) coeff[n+num_points] = x return coeff def smooth(signal, coeff): """ applies coefficients calculated by calc_coeff() to signal """ N = size(coeff-1)/2 res = convolve(signal, coeff) return res[N:-N]