John A. Marohn (jam99@cornell.edu)
Department of Chemistry and Chemical Biology
Cornell University
Ithaca, NY USA; 14853-1301
2014/06/28 created
2014/11/23 revised
Here we apply freqdemod
to a noiseless sine-wave oscillation, obtaining phase vs time data from oscillation amplitude vs time data. We fit the phase vs time data to a line and obtain a slope that agrees exactly with the known frequency of the sine wave.
In [1]:
import os, sys
module_path = os.path.abspath(os.path.join(os.getcwd(), '..'))
sys.path.append(module_path)
Now we are ready to load the module:
In [2]:
from freqdemod import Signal
In [3]:
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
f0 = 7.457E3
fd = 50.0E3
dt = 1/fd
nt = 300
t = dt*np.arange(nt)
s = np.sin(2*np.pi*f0*t)
s_name = "x"
s_unit = "nm"
plt.plot(t*1E6,s)
plt.xlabel("t [us]")
plt.ylabel(s_name + " [" + s_unit + "]")
plt.show()
In [4]:
S = Signal(s,s_name,s_unit,dt)
print(S)
In [5]:
S.binarate("middle")
print(S)
Window the data so that is starts and ends at zero. Look at two possible windowing functions. Use the second one. Below we plot, versus time in microseconds, the unwindowed signal (green), the windowed signal (red), and the windowing function (blue).
In [6]:
S.window(128*dt)
plt.plot(S.signal['t']*1E6,S.signal['w'])
plt.plot(S.signal['t']*1E6,S.signal['s'])
plt.plot(S.signal['t']*1E6,S.signal['sw'])
plt.show()
In [7]:
S.window(32*dt)
plt.plot(S.signal['t']*1E6,S.signal['w'])
plt.plot(S.signal['t']*1E6,S.signal['s'])
plt.plot(S.signal['t']*1E6,S.signal['sw'])
plt.show()
In [8]:
S.fft()
plt.plot(S.signal['f'],S.signal['swFT'].real)
plt.plot(S.signal['f'],S.signal['swFT'].imag)
plt.show()
plt.plot(S.signal['f'],abs(S.signal['swFT']))
plt.show()
Apply the right-hand and bandpass filters. In the plot below we see plotted versus frequency on a semi-log scale the FT'ed signal (green), the right handed filter function (red), the bandpass filter function (purple), and the filtered FT'ed signal (blue). The filter order is the default -- 50. Note how sharp the edges of the filter window are; this is a "brick wall" filter.
In [9]:
S.filter(bw=2000.0)
yf = abs(S.signal['swFTfilt'])
y = abs(S.signal['swFT'])
plt.plot(S.signal['f'],yf/max(yf))
plt.plot(S.signal['f'],y/max(y))
plt.plot(S.signal['f'],S.signal['rh'])
plt.plot(S.signal['f'],S.signal['bp'])
plt.plot(S.signal['f'],S.signal['rh']*S.signal['bp'])
plt.yscale('log')
plt.ylim([1E-7,3.0])
plt.show()
IFFT the data to obtain a plot of phase in-phase and out-of-phase amplitude versis time (see the greed and blue curves in the below).
In [10]:
S.ifft()
In [11]:
t = 1E6*S.signal['t'][0:50]
y1 = S.signal['z'].real[0:50]
y2 = S.signal['z'].imag[0:50]
plt.plot(t,y1)
plt.plot(t,y2)
plt.xlabel("t [us]")
plt.show()
Trim the complex signal, phase, and amplitude data to remove the initial and final ripple.
In [12]:
S.trim()
In [13]:
plt.plot(S.signal['t']*1E6,S.signal['theta'])
plt.xlim(0,S.signal['t_original'][-1]*1E6)
plt.ylabel("phase [cycles/sec]")
plt.xlabel("t [us]")
plt.show()
plt.plot(S.signal['t']*1E6,S.signal['a'])
plt.xlim(0,S.signal['t_original'][-1]*1E6)
plt.ylabel("amplitude")
plt.xlabel("t [us]")
plt.show()
In [14]:
zf = np.polyfit(S.signal['t'], S.signal['theta'], 1)
print "Best-fit frequency = {0:.3f} Hz".format(zf[0])
print " Known frequency = {0:.3f} Hz".format(f0)
The frequency inferred from the slope of the phsse vs frequency line agrees with the known frequency to six decminal places.
In [15]:
# Load the neccessary packages
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# Generate a signal
#
# f0 = signal frequency
# fd = digitization frequency
# nt = number of signal points
f0 = 4.457E3
fd = 50.0E3
nt = 512
dt = 1/fd
t = dt*np.arange(nt)
s = np.sin(2*np.pi*f0*t)
R = Signal(s,"x","nm",1/fd)
# Analyze the signal
R.binarate("middle")
R.window(201E-6)
R.fft()
R.filter(bw=4E3)
R.ifft()
R.trim()
# Print the signal
print(R)
In [16]:
# Plot the signal
plt.plot(1E6*R.signal['t'][0:100],R.signal['z'].real[0:100])
plt.plot(1E6*R.signal['t'][0:100],R.signal['z'].imag[0:100])
# plt.xlim(0,R.signal['t_original'][-1]*1E6)
plt.ylabel(s_name + " [" + s_unit + "]")
plt.xlabel("t [us]")
plt.show()
plt.plot(R.signal['t']*1E6,R.signal['theta'])
plt.xlim(0,R.signal['t_original'][-1]*1E6)
plt.ylabel("phase [cycles]")
plt.xlabel("t [us]")
plt.show()
plt.plot(R.signal['t']*1E6,R.signal['a'])
plt.xlim(0,R.signal['t_original'][-1]*1E6)
plt.ylabel("amplitude")
plt.xlabel("t [us]")
plt.show()