# P372-PS14-FFT-shift.py """ A wavepacket is made to move. Based on P372-PS14-FFT.py """ import numpy as np import pylab as pl import numpy.fft as fft # Some basic numbers, first. These are all design decisions you can change! numPoints = 1000 # number of points in x-waveform, how much resolution numFreqs = numPoints / 2 + 1 # (numPoints/2 -1) complex & 2 real k-amplitudes # This is still same numPoints of bits of information! # The wavenumber k's are also called "spatial frequencies" # We are going to look at the region between 0 and 2 in x-space, # but suppose we don't want anything to repeat within twice this, so windowLength = 4.0 # effective window length dx = windowLength / numPoints # Step size in x-space x = np.arange(0.0, windowLength, dx) # All the x-positions # Now prepare the spectrum and k wavenumbers dk = 2 * np.pi / windowLength # Step size in k-space ks = np.arange(numFreqs) * dk # All the k's, highest k found at ks[-1] # HERE IS WHERE THE REAL WORK GETS DONE, the above is all just setting up # Choose the k0 = 0.1 * ks[-1] # 25% of highest k value <-- PICK THIS! alpha = 0.1 # smaller alpha means wider phi_k, narrower psi_x <-- AND THIS! # Now define the k-spectrum amplitudes phi_k = np.exp(-0.5 * alpha * (ks - k0) ** 2) # the spectral amplitudes (complex) # And generate the wavefunction from phi(k) using Inverse Real FFT psi_x = fft.irfft(phi_k) # inverse real FFT gets the real wavefunction # Now we want the wavepacket to move! Let's define a velocity: v = 0.5 # First let's have it move just 1/4 cycle to the right # Thus k0 v dt = pi/2 dt = 0.5 * np.pi / v / k0 # Calculate the phase shifts phaseShift = np.exp(-1j * ks * v * dt) # And apply them before doing the F.T. psi_x_shift = fft.irfft(phi_k * phaseShift) # And now let's get them to shift all the way to x=1.0, which means vt = 1.0 t1 = 1.0 / v # Calculate the phase shifts phaseShift1 = np.exp(-1j * ks * v * t1) # And apply them before doing the F.T. psi_x_shift1 = fft.irfft(phi_k * phaseShift1) pl.figure(1) pl.plot(ks, phi_k) # phi_k could be complex, which would throw a warning here # if so, could use: pl.plot(ks, np.abs(phi_k) ) pl.title(r"Spectrum $\phi(k)$") pl.xlabel("wavenumber k") pl.ylabel("spectral amplitude") pl.figure(2) pl.plot(x[:numPoints // 2], psi_x[:numPoints // 2]) # only plot half of the points pl.plot(x[:numPoints // 2], psi_x_shift[:numPoints // 2]) # These are the shifted wavepacket pl.plot(x[:numPoints // 2], psi_x_shift1[:numPoints // 2]) # These are the shifted wavepacket pl.title(r"Wavefunction $\psi(x)$ shifted") pl.xlabel("position x") pl.ylabel(r"wavefunction $\psi(x)$") pl.show() # show the graph windows and loop here until they are closed print("Done.")