Skip to content

Pulse

pyglaze.datamodels.Pulse

Data class for a THz pulse. The pulse is expected to be preprocessed such that times are uniformly spaced.

Parameters:

Name Type Description Default
time FloatArray

The time values recorded by the lock-in amp during the scan.

required
signal FloatArray

The signal values recorded by the lock-in amp during the scan.

required

center_frequency property

The frequency of the pulse with the highest spectral desnity.

delay_at_max property

Time delay at the maximum value of the pulse.

delay_at_min property

Time delay at the minimum value of the pulse.

df property

Frequency spacing.

dt property

Time spacing.

energy property

Energy of the pulse.

Note that the energy is not the same as the physical energy of the pulse, but rather the integral of the square of the pulse.

fft property

Return the Fourier Transform of a signal.

frequency property

Return the Fourier Transform sample frequencies.

maximum_spectral_density property

The maximum spectral density of the pulse.

sampling_freq property

The sampling frequency in Hz of the scan.

time_window property

The scan time window size in seconds.

__eq__(obj)

Check if two pulses are equal.

__hash__()

Return a hash based on the contents of time and signal.

The hash combines shape, dtype and raw bytes of both arrays, ensuring that two :class:Pulse instances that compare equal also have identical hashes.

add_white_noise(noise_std, seed=None)

Adds Gaussian noise to each timedomain measurements with a standard deviation given by noise_std.

Parameters:

Name Type Description Default
noise_std float

noise standard deviation

required
seed int | None

Seed for the random number generator. If none, a random seed is used.

None

Returns:

Type Description
Pulse

Pulse with noise

align(scans, *, wrt_max=True, translate_to_zero=True) classmethod

Aligns a list of pulses with respect to the zerocrossings of their main pulse.

Parameters:

Name Type Description Default
scans list[Pulse]

List of scans

required
wrt_max bool

Whether to perform rough alignment with respect to their maximum (true) or minimum(false). Defaults to True.

True
translate_to_zero bool

Whether to translate all scans to t[0] = 0. Defaults to True.

True

Returns:

Type Description
list[Pulse]

list[Pulse]: Aligned scans.

average(scans) classmethod

Creates a Pulse object containing the average scan from a list of scans along with uncertainties. Errors are calculated as the standard errors on the means.

Parameters:

Name Type Description Default
scans list[Pulse]

List of scans to calculate average from

required

cut(from_time, to_time)

Create a Pulse object by cutting out a specific section of the scan.

Parameters:

Name Type Description Default
from_time float

Time in seconds where cut should be made from

required
to_time float

Time in seconds where cut should be made to

required

derivative()

Calculates the derivative of the pulse.

Returns:

Name Type Description
Pulse Pulse

New Pulse object containing the derivative

downsample(max_frequency)

Downsamples the pulse by inverse Fourier transforming the spectrum cut at the supplied max_frequency.

Parameters:

Name Type Description Default
max_frequency float

Maximum frequency bin after downsampling

required

Returns:

Name Type Description
Pulse Pulse

Downsampled pulse

estimate_SNR(linear_segments=1)

Estimates the signal-to-noise ratio.

Estimates the SNR, assuming white noise. The noisefloor is estimated by modelling the log of the pulse's spectrum above the center frequency as a constant noisefloor and n linear segments of equal size. Noise power is then calculated as the mean of the absolute square of the spectral bins above the frequency at which the noise floor is reached. The signal power is then extrapolated above the bandwidth by fitting a second order polynomial to the spectrum above the noisefloor.

Parameters:

Name Type Description Default
linear_segments int

Number of linear segments to fit to the spectrum. Defaults to 1.

1

Returns:

Name Type Description
float FloatArray

Estimated signal-to-noise ratio.

estimate_avg_noise_power(linear_segments=1)

Estimates the noise power.

The noise power is estimated by modelling the the log of pulse's spectrum above the center frequency as a constant noisefloor and n linear segments of equal size. Noise power is then calculated as the mean of the absolute square of the spectral bins above the frequency at which the noise floor is reached.

Parameters:

Name Type Description Default
linear_segments int

Number of linear segments to fit to the spectrum. Defaults to 1.

1

Returns:

Name Type Description
float float

Estimated noise power.

estimate_bandwidth(linear_segments=1)

Estimates the bandwidth of the pulse.

The bandwidth is estimated by modelling the log of the pulse's spectrum above the center frequency as a constant noisefloor and n linear segments of equal size. The bandwidth is then defined as the frequency at which the noisefloor is reached.

Parameters:

Name Type Description Default
linear_segments int

Number of linear segments to fit to the spectrum. Defaults to 1.

1

Returns:

Name Type Description
float float

Estimated bandwidth in Hz

estimate_dynamic_range(linear_segments=1)

Estimates the dynamic range of the pulse.

The dynamic range is estimated by modelling the log of the pulse's spectrum above the center frequency as a constant noisefloor and n linear segments of equal size. The dynamic range is then calculated as the maximum of the spectrum minus the noisefloor.

Parameters:

Name Type Description Default
linear_segments int

Number of linear segments to fit to the spectrum. Defaults to 1.

1

Returns:

Name Type Description
float float

Estimated dynamic range in dB

estimate_peak_to_peak(delay_tolerance=None, strategy=ws_interpolate)

Estimates the peak-to-peak value of the pulse.

If a delay tolerance is provided, the peak-to-peak value is estimated by interpolating the pulse at the maximum and minimum values such that the minimum and maximum values of the pulse fall within the given delay tolerance. A lower tolerance will give a more accurate estimate.

Parameters:

Name Type Description Default
delay_tolerance float | None

Tolerance for peak detection. Defaults to None.

None
strategy Callable[[FloatArray, FloatArray, FloatArray], FloatArray]

Interpolation strategy. Defaults to Whittaker-Shannon interpolation

ws_interpolate

Returns:

Name Type Description
float float

Estimated peak-to-peak value.

estimate_zero_crossing()

Estimates the zero crossing of the pulse between the maximum and minimum value.

Returns:

Name Type Description
float float

Estimated zero crossing.

fft_at_f(f)

Returns the Fourier Transform at a specific frequency.

Parameters:

Name Type Description Default
f float

Frequency in Hz

required

Returns:

Name Type Description
complex complex

Fourier Transform at the given frequency

filter(filtertype, cutoff, order)

Applies a highpass filter to the signal.

Parameters:

Name Type Description Default
filtertype Literal['highpass', 'lowpass']

Type of filter

required
cutoff float

Frequency, where the filter response has dropped 3 dB

required
order int

Order of the highpass filter

required

Returns:

Type Description
Pulse

Highpassed pulse

from_dict(d) classmethod

Create a Pulse object from a dictionary.

Parameters:

Name Type Description Default
d dict[str, FloatArray | list[float] | None]

A dictionary containing the keys 'time', 'signal'.

required

from_fft(time, fft) classmethod

Creates a Pulse object from an array of times and a Fourier spectrum.

Parameters:

Name Type Description Default
time FloatArray

Time series of pulse related to the Fourier spectrum

required
fft ComplexArray

Fourier spectrum of pulse

required

propagate(time)

Propagates the pulse in time by a given amount.

Parameters:

Name Type Description Default
time float

Time in seconds to propagate the pulse by

required

Returns:

Name Type Description
Pulse Pulse

Propagated pulse

signal_at_t(t)

Returns the signal at a specific time using Whittaker Shannon interpolation.

Parameters:

Name Type Description Default
t float

Time in seconds

required

Returns:

Type Description
float

Signal at the given time

spectrum_dB(reference=None, offset_ratio=None)

Calculates the spectral density in decibel.

Parameters:

Name Type Description Default
reference float | None

Reference spectral amplitude. If none, the maximum of the FFT is used.

None
offset_ratio float | None

Offset in decibel relative to the maximum of the FFT to avoid taking the logarithm of 0. If none, no offset is applied.

None

Returns:

Name Type Description
FloatArray FloatArray

Spectral density in decibel

subtract_mean(fraction=0.99)

Subtracts the mean of the pulse.

Parameters:

Name Type Description Default
fraction float

Fraction of the mean to subtract. Defaults to 0.99.

0.99

Returns:

Type Description
Pulse

Pulse with the mean subtracted

timeshift(scale, offset=0)

Rescales and offsets the time axis as.

new_times = scale*(t + offset)

Parameters:

Name Type Description Default
scale float

Rescaling factor

required
offset float

Offset. Defaults to 0.

0

Returns:

Type Description
Pulse

Timeshifted pulse

to_native_dict()

Converts the Pulse object to a native dictionary.

Returns:

Type Description
dict[str, list[float] | None]

Native dictionary representation of the Pulse object.

tukey(taper_length, from_time=None, to_time=None)

Applies a Tukey window and returns a new Pulse object - see https://en.wikipedia.org/wiki/Window_function.

Parameters:

Name Type Description Default
taper_length float

Length in seconds of the cosine tapering length, i.e. half a cosine cycle

required
from_time float | None

Left edge in seconds at which the window becomes 0

None
to_time float | None

Right edge in seconds at which the window becomes 0

None

zeropadded(n_zeros)

Returns a new, zero-padded pulse.

Parameters:

Name Type Description Default
n_zeros int

number of zeros to add

required

Returns:

Type Description
Pulse

Zero-padded pulse

Notes

The lock-in amp outputs \(\left( r, \theta \right)\) values. To get useful readings, one must convert these readings by

\[ r \operatorname{sgn} (\theta - 180). \]

\(\operatorname{sgn}\), the so-called signum function outputs the signs of a vector in a piecewise fashion, implemented in NumPy using

\[ \operatorname{sgn} = \frac{x}{\sqrt{x^2}}. \]

This is handled by the ScanData class, and is done transparently when using pyglaze.scanning.scanner.Scanner. If you have a previous reading that has been converted, ScanData allows you to create an object from this data in dictionary form; see examples below.

Examples

import json
from pathlib import Path

import numpy as np

from pyglaze.datamodels import Pulse

# Generate a pulse - would typically be done with an actual THz device
new_pulse = Pulse(
    time=np.linspace(0, 1, 100), signal=np.random.default_rng().normal(size=100)
)

# Save the pulse as a JSON file
with Path("my_pulse_data.json").open("w") as f:
    json.dump(new_pulse.to_native_dict(), f)

# Load the pulse from the JSON file again
with Path("my_pulse_data.json").open() as f:
    run_data = json.load(f)

pulse = Pulse.from_dict(d=run_data)