Apply a frequency response function#
Objects from thztools: apply_frf, timebase, wave.
[1]:
from matplotlib import pyplot as plt
import numpy as np
import thztools as thz
Set the simulation parameters#
[2]:
n = 256  # Number of samples
dt = 0.05  # Sampling time [ps]
a = 0.5 # Scale factor
eta = 1.0 # Delay [ps]
Simulate an input waveform#
[3]:
t = thz.timebase(n, dt=dt)
mu = thz.wave(n, dt=dt)
Define the frequency response function#
The frequency response function frfun rescales the input waveform by a and delays it by eta.
[4]:
def frfun(omega, _a, _eta):
    return _a * np.exp(-1j * omega * _eta)
Apply the frequency response function#
Generate the time-domain output waveform psi by applying frfun to mu with the apply_frf function.
[5]:
psi = thz.apply_frf(frfun, mu, dt=dt, args=(a, eta))
Show the input and output waveforms#
[6]:
_, ax = plt.subplots()
ax.plot(t, mu, label=r'$\mu$')
ax.plot(t, psi, label=r'$\psi$')
ax.legend()
ax.set_xlabel('Time (ps)')
ax.set_ylabel(r'Amplitude (units of $\mu_{p})$')
ax.set_xticks(np.arange(0, 11, 5))
ax.set_xlim(0, 10)
plt.show()
 
Change sign convention#
The above example uses the \(+i\omega t\) sign convention for representing harmonic waves with complex exponentials. NumPy also uses this convention in its definition of the FFT. Physicists commonly use the \(-i\omega t\) sign convention, which can cause confusion when translating between analytic expressions and computational expressions. The apply_frf function supports both sign conventions through the boolean parameter numpy_sign_convention.
[7]:
def frfun_phys(omega, _a, _eta):
    return _a * np.exp(1j * omega * _eta)
[8]:
psi_phys = thz.apply_frf(frfun_phys, mu, dt=dt, args=(a, eta), numpy_sign_convention=False)
[9]:
_, ax = plt.subplots()
ax.plot(t, mu, label=r'$\mu$')
ax.plot(t, psi_phys, label=r'$\psi$')
ax.legend()
ax.set_xlabel('Time (ps)')
ax.set_ylabel(r'Amplitude (units of $\mu_{p})$')
ax.set_xticks(np.arange(0, 11, 5))
ax.set_xlim(0, 10)
plt.show()
