def test_real_to_complex(verbose): fft = fftpack.real_to_complex(6) vd = flex.double(fft.m_real()) vc = flex.complex_double(fft.n_complex()) for i in xrange(fft.n_real()): vd[i] = 1.*i for i in xrange(fft.n_complex()): vc[i] = complex(vd[2*i], vd[2*i+1]) vdt = fft.forward(vd) vct = fft.forward(vc) for t in (vdt, vct): assert t.origin() == (0,) assert t.all()[0] == fft.n_complex() assert t.focus()[0] == fft.n_complex() if (verbose): show_rseq(vd, fft.m_real()) assert_complex_eq_real(vc, vd) vdt = fft.backward(vd) vct = fft.backward(vc) for t in (vdt, vct): assert t.origin() == (0,) assert t.all()[0] == fft.m_real() assert t.focus()[0] == fft.n_real() if (verbose): show_rseq(vd, fft.n_real()) assert_complex_eq_real(vc, vd) """ The backward fft computes y_k = sum_{n=0}^15 x_n e^{i 2pi n/16 k} = sum_{n=0}^7 2 Re( x_n e^{i 2pi n/16 k} ) + x_8 cos{i k pi} because of the assumed Hermitian condition x_{16-i} = x_i^* (=> x_8 real). Only x_0, ..., x_8 need to be stored. """ fft = fftpack.real_to_complex(16) assert fft.n_complex() == 9 x = flex.complex_double(fft.n_complex(), 0) x[4] = 1 + 1.j y = fft.backward(x) for i in xrange(0, fft.n_real(), 4): assert tuple(y[i:i+4]) == (2, -2, -2, 2) x = flex.complex_double(fft.n_complex(), 0) x[2] = 1 + 1.j y = fft.backward(x) for i in xrange(0, fft.n_real(), 8): assert tuple(y[i:i+3]) == (2, 0, -2) assert approx_equal(y[i+3], -2*math.sqrt(2)) assert tuple(y[i+4:i+7]) == (-2, 0, 2) assert approx_equal(y[i+7], 2*math.sqrt(2)) x = flex.complex_double(fft.n_complex(), 0) x[8] = 1. y = fft.backward(x) for i in xrange(0, fft.n_real(), 2): assert tuple(y[i:i+2]) == (1, -1)
def test_real_to_complex(verbose): fft = fftpack.real_to_complex(6) vd = flex.double(fft.m_real()) vc = flex.complex_double(fft.n_complex()) for i in range(fft.n_real()): vd[i] = 1. * i for i in range(fft.n_complex()): vc[i] = complex(vd[2 * i], vd[2 * i + 1]) vdt = fft.forward(vd) vct = fft.forward(vc) for t in (vdt, vct): assert t.origin() == (0, ) assert t.all()[0] == fft.n_complex() assert t.focus()[0] == fft.n_complex() if (verbose): show_rseq(vd, fft.m_real()) assert_complex_eq_real(vc, vd) vdt = fft.backward(vd) vct = fft.backward(vc) for t in (vdt, vct): assert t.origin() == (0, ) assert t.all()[0] == fft.m_real() assert t.focus()[0] == fft.n_real() if (verbose): show_rseq(vd, fft.n_real()) assert_complex_eq_real(vc, vd) """ The backward fft computes y_k = sum_{n=0}^15 x_n e^{i 2pi n/16 k} = sum_{n=0}^7 2 Re( x_n e^{i 2pi n/16 k} ) + x_8 cos{i k pi} because of the assumed Hermitian condition x_{16-i} = x_i^* (=> x_8 real). Only x_0, ..., x_8 need to be stored. """ fft = fftpack.real_to_complex(16) assert fft.n_complex() == 9 x = flex.complex_double(fft.n_complex(), 0) x[4] = 1 + 1.j y = fft.backward(x) for i in range(0, fft.n_real(), 4): assert tuple(y[i:i + 4]) == (2, -2, -2, 2) x = flex.complex_double(fft.n_complex(), 0) x[2] = 1 + 1.j y = fft.backward(x) for i in range(0, fft.n_real(), 8): assert tuple(y[i:i + 3]) == (2, 0, -2) assert approx_equal(y[i + 3], -2 * math.sqrt(2)) assert tuple(y[i + 4:i + 7]) == (-2, 0, 2) assert approx_equal(y[i + 7], 2 * math.sqrt(2)) x = flex.complex_double(fft.n_complex(), 0) x[8] = 1. y = fft.backward(x) for i in range(0, fft.n_real(), 2): assert tuple(y[i:i + 2]) == (1, -1)
def kernapply(x, k, circular=False): """Convolve a sequence x with a Kernel k""" x = flex.double(x).deep_copy() lenx = len(x) w = flex.double(lenx, 0.0) w.set_selected(flex.size_t_range(k.m + 1), k.coef) sel = lenx -1 - flex.size_t_range(k.m) w.set_selected(sel, k.coef[1:]) # do convolution in the Fourier domain fft = fftpack.real_to_complex(lenx) n = fft.n_real() m = fft.m_real() x.extend(flex.double(m-n, 0.)) w.extend(flex.double(m-n, 0.)) conv = fft.forward(x) * fft.forward(w) # extend result by the reverse conjugate, omitting the DC offset and Nyquist # frequencies. If fft.n_real() is odd there is no Nyquist term. end = fft.n_complex() - (fft.n_real() + 1) % 2 conv.extend(flex.conj(conv[1:end]).reversed()) # transform back, take real part and scale fft = fftpack.complex_to_complex(len(conv)) result = fft.backward(conv).parts()[0] / n if circular: return result else: return result[(k.m):(lenx-k.m)]
def exercise_real_to_complex_padding_area(): mt = flex.mersenne_twister(seed=1) for n_real in range(1, 101): fft = fftpack.real_to_complex(n_real) assert fft.n_real() == n_real assert fft.n_complex() == n_real // 2 + 1 assert fft.m_real() == fft.n_complex() * 2 m_real = fft.m_real() z = mt.random_double( size=m_real) * 2 - 1 # non-zero values in padded area c = z.deep_copy() fft.forward(c) if (n_real % 2 == 0): assert approx_equal(c[-1], 0) # imaginary part of last complex value r = c.deep_copy() fft.backward(r) r *= (1 / n_real) assert approx_equal(r[:n_real], z[:n_real]) if (n_real % 2 == 0): assert approx_equal(r[n_real:], [0, 0]) q = c.deep_copy() q[-1] = 123 # random imaginary part (which should be zero) fft.backward(q) q *= (1 / n_real) assert approx_equal(q, r) # obtain zeros in padded area anyway
def exercise_real_to_complex(): print "real_to_complex" for n in xrange(1,256+1): fft = fftpack.real_to_complex(n) dp = flex.random_double(size=n)*2-1 dp.resize(flex.grid(fft.m_real()).set_focus(n)) dw = dp.deep_copy() cw = fftw3tbx.real_to_complex_in_place(dw) cp = fft.forward(dp) assert flex.max(flex.abs(cw-cp)) < 1.e-6 rw = fftw3tbx.complex_to_real_in_place(cw, n) rp = fft.backward(cp) assert flex.max(flex.abs(rw[:n]-rp[:n])) < 1.e-6 for n,n_repeats in [(2400,500), (19200,250)]: fft = fftpack.real_to_complex(n) print " factors of %d:" % n, list(fft.factors()) print " repeats:", n_repeats d0 = flex.random_double(size=n)*2-1 d0.resize(flex.grid(fft.m_real()).set_focus(n)) # t0 = time.time() for i_trial in xrange(n_repeats): d = d0.deep_copy() overhead = time.time()-t0 print " overhead: %.2f seconds" % overhead # t0 = time.time() for i_trial in xrange(n_repeats): d = d0.deep_copy() c = fftw3tbx.real_to_complex_in_place(data=d) fftw3tbx.complex_to_real_in_place(data=c, n=n) print " fftw: %.2f seconds" % (time.time()-t0-overhead) # t0 = time.time() for i_trial in xrange(n_repeats): d = d0.deep_copy() c = fftpack.real_to_complex(n).forward(d) fftpack.real_to_complex(n).backward(c) print " fftpack: %.2f seconds" % (time.time()-t0-overhead) sys.stdout.flush()
def fft(d): from scitbx import fftpack f = fftpack.real_to_complex(d.size()) _d = flex.double(f.m_real(), 0.0) for j in range(d.size()): _d[j] = d[j] t = f.forward(_d) p = flex.abs(t) ** 2 # remove the DC component p[0] = 0.0 return p
def fourier_filter(x, y, cutoff_frequency): assert cutoff_frequency < len(y) from scitbx import fftpack fft = fftpack.real_to_complex(len(y)) n = fft.n_real() m = fft.m_real() y_tr = y.deep_copy() y_tr.extend(flex.double(m-n, 0)) fft.forward(y_tr) for i in range(cutoff_frequency, m): y_tr[i] = 0 fft.backward(y_tr) y_tr = y_tr[:n] scale = 1 / fft.n_real() y_tr *= scale return x, y_tr[:n]
def test_comprehensive_rc_1d(max_transform_size): for n in range(1, max_transform_size + 1): fft = fftpack.real_to_complex(n) m = fft.m_real() v_in = flex.double() for i in range(n): v_in.append(random.random()) for i in range(n, m): v_in.append(999) v_tr = v_in.deep_copy() fft.forward(v_tr) fft.backward(v_tr) compare_vectors(n, n, v_in, v_tr) v_in[n] = v_in[1] v_in[1] = 0 if (n % 2 == 0): v_in[n + 1] = 0 v_tr = v_in.deep_copy() fft.backward(v_tr) fft.forward(v_tr) compare_vectors(n, m, v_in, v_tr)
def test_comprehensive_rc_1d(max_transform_size): for n in xrange(1,max_transform_size+1): fft = fftpack.real_to_complex(n) m = fft.m_real() v_in = flex.double() for i in xrange(n): v_in.append(random.random()) for i in xrange(n, m): v_in.append(999) v_tr = v_in.deep_copy() fft.forward(v_tr) fft.backward(v_tr) compare_vectors(n, n, v_in, v_tr) v_in[n] = v_in[1] v_in[1] = 0 if (n % 2 == 0): v_in[n+1] = 0 v_tr = v_in.deep_copy() fft.backward(v_tr) fft.forward(v_tr) compare_vectors(n, m, v_in, v_tr)
def exercise_real_to_complex_padding_area(): mt = flex.mersenne_twister(seed=1) for n_real in xrange(1,101): fft = fftpack.real_to_complex(n_real) assert fft.n_real() == n_real assert fft.n_complex() == n_real // 2 + 1 assert fft.m_real() == fft.n_complex() * 2 m_real = fft.m_real() z = mt.random_double(size=m_real)*2-1 # non-zero values in padded area c = z.deep_copy() fft.forward(c) if (n_real % 2 == 0): assert approx_equal(c[-1], 0) # imaginary part of last complex value r = c.deep_copy() fft.backward(r) r *= (1/n_real) assert approx_equal(r[:n_real], z[:n_real]) if (n_real % 2 == 0): assert approx_equal(r[n_real:], [0,0]) q = c.deep_copy() q[-1] = 123 # random imaginary part (which should be zero) fft.backward(q) q *= (1/n_real) assert approx_equal(q, r) # obtain zeros in padded area anyway
def __init__(self, x, spans=None, demean=True, detrend=True): # Ensure x is copied as it will be changed in-place x = flex.double(x).deep_copy() n = len(x) if detrend: t = flex.size_t_range(n).as_double() + 1 - (n + 1)/2 inv_sumt2 = 1./t.dot(t) x = x - flex.mean(x) - x.dot(t) * t * inv_sumt2 elif demean: x -= flex.mean(x) # determine frequencies stop = ((n - (n % 2)) // 2) + 1 self.freq = flex.double([i / n for i in range(1, stop)]) fft = fftpack.real_to_complex(n) n = fft.n_real() m = fft.m_real() x.extend(flex.double(m-n, 0.)) xf = fft.forward(x) # get abs length of complex and normalise by n to get the raw periodogram spec = flex.norm(xf) / n if spans is None: # if not doing smoothing, the spectrum is just the raw periodogram with # the uninteresting DC offset removed self.spec = spec[1:] return # for smoothing replace the DC offset term and extend the rest of the # sequence by its reverse conjugate, omitting the Nyquist term if it is # present spec[0] = spec[1] end = fft.n_complex() - (fft.n_real() + 1) % 2 spec.extend(spec[1:end].reversed()) try: # multiple integer spans nspans = len(spans) m = int(spans[0]) // 2 multiple = True except TypeError: # single integer span m = int(spans) // 2 multiple = False # construct smoothing kernel k = Kernel('modified.daniell', m) if multiple: for i in range(1, nspans): # construct kernel for convolution m1 = int(spans[i]) // 2 k1 = Kernel('modified.daniell', m1) # expand coefficients of k to full kernel and zero pad for smoothing x1 = flex.double(k1.m, 0.0) x1.extend(k.coef.reversed()) x1.extend(k.coef[1:]) x1.extend(flex.double(k1.m, 0.0)) # convolve kernels coef = kernapply(x1, k1, circular=True) m = len(coef)//2 coef = coef[m:(len(coef))] k = Kernel(coef=coef) # apply smoothing kernel spec = kernapply(spec, k, circular=True) self.spec = spec[1:fft.n_complex()] return