Drive Constructor is initially selected in the
Advanced pull-down menu. The Python scripting interface allows you configure the Multifrequency Lockin Analyzer MLA™. You can use the Drive Constructor to create a frequency comb of drive tones, and to select the frequencies at which you want to perform lockin measurement. Before attempting to use the Drive Constructor, you should read the section on Intermodulation Measurement.
Configuring the MLA™¶
The Python scripting interface has several pre-defined variables and and built-in functions to help in the construction of drive frequency combs. Using the interface requires knowledge of the Python programming language. A pull-down menu lists the name of various Python scripts, stored in IMP Sessions and Settings/settings/drive_setups/user_drive_scripts.py. These scripts are well commented to help you understand how they work. You create a new script by changing the name of an old script, and pressing
Delete will kill the currently selected script.
The scripting interface has some useful functionality:
Change font size with ctrl+Plus / ctrl+Minus or ctrl+Mouse wheel.
Hit ctrl+Space for a list of reserved keywords
The following variables are defined in all scripts. For some of these variables you will want to change their values, or re-define them, but do not change their shape or data-type. Other variables should not be changed, but you will want to use their values.
f0 [real, Hz] and Q [real] are the measured resonant frequency and quality factor stored in the Current calibration. If you have not run a calibration, these will be zero and your drive script may give an error if you do not set them to a reasonable value in your script.
nfreq_out [integer] and nfreq_in [integer] are the number of drive frequencies and response frequencies respectively. These numbers will depend on the MLA™ firmware that you are running. In the most common configurations, nfreq_out = freq_in, and in any case, nfreq_out < nfreq_in. Do not re-define these values.
f_sample [samples per second] is the sampling frequency of the MLA™. Do not re-define this value.
df [real, Hz], T [real, sec], or samples_per_pixel [integer]. The measurement bandwidth is set by assigning a value to one (and only one) of these variables. (df = 1/T = samples_per_pixel/f_sample).
n [integer array] or f [real array, Hz]. The frequencies are set by assigning values to either of these arrays (f=n*df). The length of these arrays is nfreq_in and should not be changed. The first nfreq_out entries are the frequencies at which it is possible to drive.
a [real array, arbitrary units]. The drive amplitudes are set by assigning values to this array. The length of a is set to be nfreq_out and should not be changed. Amplitudes are set relative to each other, in arbitrary units. The maximum or peak amplitude is then set with the amplitude scaling factor (see below).
p [real array, Radians]. The drive phases are set by assigning values to this array. The length of p is set to nfreq_out and should not be changed. Phases are given in radians.
asf [real] is the amplitude scaling factor, a real number between zero and one. asf = 1 gives maximum output voltage of the MLA™ at peak amplitude of the waveform. The default value that you get if you do not specify this variable is asf = 0.1. An error will appear in the debug window if asf is out of the range [0,1]. ( Advanced users only: asf = -1 overrides the scaling of amplitudes, in which case the amplitude values must be given in ADU and care must be taken not to exceed the max output. )
out1_mask [Boolean array] with nfreq_out elements. When the element is True (False) it will (will not) send the corresponding tone to port OUT 1 of the MLA™. The default value of this array is all True.
out2_mask [Boolean array] same as out1_mask, but for port OUT 2 of the MLA™. Note that it is possible to send the same signal to both output ports. The default value of this array is all False.
input_multiplex [integer array] with nfreq_in elements. Each element can take on the values 1,2,3 or 4. When an element is 1, the corresponding tone will be measured at port IN 1; when the element is 2, the corresponding tone will be measured at port IN 2… etc. Note that each tone can be measured at only one input port. The default value is all elements = 1.
The frequency array (n or f) does not have to be ordered in ascending frequency values. The frequency values can have any order, but there is a correspondence between the first nfreq_out elements of the frequency array and the elements of the amplitude array (a), phase array (p), and the output mask arrays. There is also a correspondence between all elements of the frequency array and input_multiplex array. We access each element of these arrays with the tone index. In summary:
MLA™ tones are specified by the indexed element of an array
n drive tones [0,1,2,…n]
m measurement tones [0,1,2,…n,…m]
first n elements correspond. n<m and usually n=m.
The following built-in functions are provided in all scripts:
tune_integer(df) takes the target value of df and returns a re-defined value of df that is commensurate with divisions of the MLA™ clock frequency, such that Fourier coefficients will be calculated for perfect integer multiples of df. This function is equivalent to the
integerbutton in the frequency-tuning controls of Advanced Setup. You should use this tuning if you are synchronizing the MLA™ with other instruments.
tune_round(df, f0) takes two arguments, the target value of df and a desired frequency commensurate with df (e.g. the resonant frequency of the cantilever) . It returns a re-defined value of df such that Fourier coefficients will be calculated for near-integer multiples of df. This function is equivalent to the
roundbutton in the frequency-tuning controls of Advanced Setup.
Synthesize and Configure¶
Synthesize Comb runs the script and plots the comb as an amplitude-phase plot in the frequency domain, and the waveform in the time domain. The MLA™ can be configured with this comb in one of two ways:
Configure Drive causes a voltage signal described by the synthesized frequency comb to be put at the output port of the MLA™.
Configure Response adjusts the comb at the output port, such that the synthesized comb appears at the input port. The algorithm that makes this adjustment assumes that a chain of linear systems (e.g. actuator -> cantilever -> detector) is connected between the output and input ports of the MLA™ and it will not work properly when nonlinearity is present in the chain. If the drive voltage to the piezo shaker is not very high and the detector signal is not close to saturation, the AFM is very close to a linear chain. In this case, after pressing Configure Response, the actual cantilever motion have the frequency content given by the comb synthesized from your script.
Setting the feedback¶
Setup Feedback performs the necessary routines to make the free response at the tone index zero, correspond to 100% set-point value. By convention, the MLA™ calculates the feedback error signal from the amplitude of the response at the tone with index zero (frequency specified in the zeroth position of the n array or f array). You should make sure that your script puts the frequency at which you would like to run feedback in the zero position (see useful code block below). It is probably best to chose the frequency where you get the largest free response for feedback. More information on feedback can be found in the section on Intermodulation Measurement (Feedback) and in the section on Advanced Setup (Setup Feedback).
Debugging a script¶
Debug window allows you to test what is happening with your script. Error messages will appear in this window and you can print any variable here using the dprint(var_name) statement in your script. The script automatically prints relevant data for your comb in the Debug window.
Useful Python code blocks¶
Some useful blocks of code for making frequency combs are described below. These code blocks are used in the example scripts. You can copy and paste these in to your scripts.
Tune df close to 500 Hz and set the frequencies to consecutive integer multiples of df, centered as close as possible to the resonant frequency f0:
df = tune_integer(500) f1 =f0 - (nfreq_out / 2) * df #start freq of comb n1 = round(f1/df) # integer closest f1 n = np.int_(arange(nfreq_out) + n1) # integer array of frequencies
Tune df closer to 500 Hz and set the frequencies to consecutive integer multiples of df, centered as close as possible to the resonant frequency f0:
df = tune_round(500,f0) f1 =f0 - (nfreq_out / 2) * df #start freq of comb n1 = round(f1/df) # integer closest f1 n = np.int_(arange(nfreq_out) + n1) # integer array of frequencies
Exchange the frequency with the index mi, with the feedback frequency at position n:
#put frequency near resonance as first frequency for feedback mi=nfreq_out/2 #index of center of comb n[mi], n, a[mi], a, p[mi], p = n, n[mi], a, a[mi], p, p[mi]
Create an signal in the time domain, consisting of a rapidly oscillating component at the frequency f_bar and a slowly modulated amplitude mod. Fourier transform and pick out the nfreq_out components close to f_bar and set the amplitudes a and phases p:
N=2*int(2.*f_bar/df) #number of time samples, so f_max = 2*f_bar t = arange(0.,1,1./N)/df #construct signal x(t) in the time domain and FFT to get comb mod = 0.1*sin(2.*pi*arange(N)/N) # the modulation function x =(1.+ mod)*cos(2.*pi*f_bar*t) # x(t) x_hat = fft.rfft(x) # take components of comb, at frequencies given by n array a = abs(x_hat[n]) asf = 0.1 # adjust peak amplitude p = angle(x_hat[n])
Create an signal in the time domain, consisting of a rapidly oscillating component with a slowly modulated frequency f_bar*mod(t) . Fourier transform and pick out the nfreq_out components close to the center frequency f_bar and set the amplitudes a and phases p:
N=2*int(2.*n_bar) #number of time samples, so f_max = 2*f_bar t = (1./df)*arange(0.,1,1./N) #construct signal x(t) in the time domains x = cos(2. * pi * ( f_bar * t - delta_f /(4*pi*df)*sin(2*pi*df*t))) # FFT to get frequency comb x_hat = fft.rfft(x)/(N/2.) a = abs(x_hat[n]) asf = 0.1 # adjust peak amplitude p = angle(x_hat[n])