### Script to take thermal tuning data and calculate the spring constant using the Sader Method¶

#### Import required modules¶

In [1]:

    import numpy as np
    from NSFopen.read import read
    import matplotlib
    import matplotlib.pyplot as plt

    from scipy.optimize import curve_fit

    from sader import sader

    font = {'size': 10}
    matplotlib.rc('font', **font)

#### SHO oscillator function with White Noise¶

In [2]:

    def SHO(x, *args):
        f0, Q, A0, WN = args
        qterm = 1 / Q**2
        wnterm = WN**2
        return WN + A0*f0**4/((x**2-f0**2)**2 + (x*f0/Q)**2)

#### Open thermal tune file¶

In [3]:

    file = 'thermal.nid'

    # cantilever dimensions in um
    L = 225e-6
    W = 40e-6

    # open file and read Sweep data
    afm = read(file)
    amp = afm.data.Sweep.FFT['Amplitude Spectral Density'][0]

    # define the frequencies (X-axis)
    f_min = afm.param.X['min'][0]
    f_range = afm.param.X.range[0]

    freq = np.linspace(f_min, f_min + f_range, len(amp))

    amp = amp[freq > 1000]
    freq = freq[freq > 1000]

    # find the resonance frequency at the peak amplitude
    f0 = freq[np.where(amp == np.max(amp))[0][0]]
    df = 15e3  # defines the bandwidth

    #
    x = freq[(freq>f0-df) & (freq<f0+df)]
    y = amp[(freq>f0-df) & (freq<f0+df)]

#### Setup fitting of SHO equation to thermal¶

In [4]:

    p0 = [f0, 500, 1e-13, 1e-13]
    # bounds = ((100,0,-np.inf,-np.inf),(np.inf))
    coeff, _ = curve_fit(SHO, x, y, p0=p0)

#### Plot results and print spring constant from Sader¶

In [5]:

    fig = plt.figure(figsize=(6,4), dpi=300)
    plt.plot(x/1e3, y*1e12, linewidth=3)
    plt.plot(x/1e3, SHO(x, *coeff)*1e12, linewidth = 1, color = 'r', linestyle = '--')
    plt.title(f'Spring Constant (Sader Method): %5.1f N/m' % sader(L, W, *coeff), fontsize=10)
    plt.xlabel('Frequency (kHz)')
    plt.ylabel('Amp. Spec. Density (pm/$\sqrt{Hz}$)')
    plt.legend(['Data', 'Fit'])

Out[5]:

    <matplotlib.legend.Legend at 0x23801383ac0>