Stream Recorder

_images/streamrecorder.png

When scanning a sample, the MLA™ process end-of-line (EOL) and end-of-file (EOF) triggers and lockin data is stored at pixel locations in a scan file. The stream recorder operates in a different manner: it ignores all triggers and stores data as one continuous, uninterrupted stream. This mode is quite useful for taking data when the AFM probe slowly approachs and retracts from a surface. The data stream can be stored in either Time mode or Frequency mode (see Intermodulation Measurement).

  • Start will start the stream record. Click again to Stop. If the Autosave box is checked in the Status Banner, each run of the stream recorder will result in a file being saved in the session folder. The file name has the form record01234 where the number is automatically incremented. In Time mode the files will have the .std extension, and in Frequency mode the files will have the .imp extension (see the File Management section for more information on file types). Unchecking the Autosave box will result in no data being saved.

  • Mode selects weather the data is stored in Time mode or Frequency mode. In either mode all data is saved as a continuous stream without any breaks or gaps in the data.

  • Plot controls only which data is being plotted and does not effect the saving of data. You can adjust the number of points to be plotted in the past number of seconds. The check boxes enable plotting of the amplitudes (or amplitude and phase in the polar plot) at the different frequencies listed.

Note that in the Time mode the response at all frequencies in the comb can be examined by analyzing stream data with the Fast Fourier Transform. A script called PlotTimeMode (see Scripting Interface) is provided which gives a simple GUI inteface for plotting and extracting time-mode data taken with the stream recorder. Below we give an example which can be a useful starting point for your own analysis scripts. The script can be copied to a new filename.py, modified and run, for example in the iPython shell.

Example script

This script reads a time-mode stream data file (.std file) and parses it in to time windows or ‘beats’, on which the signal is periodic. Each time window is assigned an index (the beat index) and the terminal asks for the beat index on which you want to perform analysis. The script extracts that beat from the data file, and simply plots both time data and the frequency data. Note that you must input the path to the AFM Suite on your computer, and the path to the .std file that you want to analyze:

import matplotlib.pyplot as plt
import numpy as np
import sys

# Path to AFM Suite
suitepath = '/Users/david_haviland/IntermodulatorSuite'
sys.path.append(suitepath)
from StreamRecorder import stdfile

# Path to stream recorder file in time-mode
recorder_path = 'path_to_file.std' # full path to recorder file in .std format
print "loading file", recorder_path
sf   = stdfile.stdfile(recorder_path,b_raw=False,do_scale=False)

# Read metadata from file
fs = sf.freq_samples # Sampling frequency, Hz
f1 = sf.f1 # First drive frequency, Hz
f2 = sf.f2 # Second drive frequency, Hz

# Calculate number of samples to avoid Fourier leakage
n_samples_beat = int(np.round(fs/abs(f2-f1))) # Number of samples in one beat
t = 1./fs*np.arange(n_samples_beat) # Time axis for plotting
df = fs/n_samples_beat # Frequency resolution
freqs = df*np.arange(n_samples_beat/2+1) # Frequency axis for plotting

# Index each beat in the stream
ii_s = np.arange(0,sf.n_samples,n_samples_beat)[:-1] # remove last since it might not be complete

# Loop through all beats and read max value
beats_to_plot = 1000
if len(ii_s)<=beats_to_plot:
    ii_plot = ii_s
else:
    skip = float(len(ii_s))/beats_to_plot
    ii_plot = np.int_(skip*np.arange(beats_to_plot))

peak = np.zeros(len(ii_plot))
for i,beat_i in enumerate(ii_plot):
    if i%100==0:
        print "Beat %i / %i"%(beat_i, len(ii_s))
    # Read data
    i_start = ii_s[beat_i]
    data = sf.get_samples(i_start,n_samples_beat)
    peak[i] = max(data)

# Plot
plt.figure(1)
plt.clf()
plt.plot(ii_plot,peak)
plt.xlabel("Beat index")
plt.ylabel("Peak value [ADU]")
plt.show()

# Ask terminal for beat number, then data from that beat
n = -1
while n == -1:
    s = raw_input("Enter beat index to plot: ")
    try:
        n = int(s)
    except ValueError:
        print "Input must be an interger"

data = sf.get_samples(ii_s[n],n_samples_beat)
data_fft = np.fft.rfft(data)/len(data)

# Plot
plt.figure(2)
plt.subplot(211)
plt.plot(t,data)
plt.xlabel("Time [s]")
plt.ylabel("In [ADU]")
plt.subplot(212)
plt.semilogy(freqs*1e-3,2*abs(data_fft))
plt.xlabel("Frequency [kHz]")
plt.ylabel("Amplitude [ADU]")
plt.show()