symop.modes.envelopes

Envelope implementations.

This subpackage defines time- and frequency-domain mode envelopes, including analytic envelopes (e.g., Gaussian, GaussianMixture) and numerically constructed envelopes (e.g., filtered envelopes).

Envelopes provide evaluation, overlap computation, and plotting utilities.

class FilteredEnvelope(base: TimeFrequencyEnvelope, transfer: TransferFunction, n_fft: int = 32768, w_span_sigma: float = 12.0) None

Bases: BaseEnvelope

Envelope defined by spectral multiplication.

Given an input spectrum \(Z_\mathrm{in}(\omega)\) and a transfer function \(H(\omega)\), the output spectrum is

\[Z_\mathrm{out}(\omega) = H(\omega)\,Z_\mathrm{in}(\omega).\]

The time-domain field \(\zeta_\mathrm{out}(t)\) is obtained numerically using an FFT-based inverse transform on a fixed grid, followed by complex interpolation.

Notes

  • This class is intended to make basis changes “real”: generic overlaps may call time_eval() via numeric fallback, so time_eval() should be coherent with freq_eval().

  • The absolute Fourier convention is not critical as long as internal operations (overlap, plotting) are consistent. If you later care about absolute scaling, unify the convention across all envelopes.

  • Instances are treated as mode descriptors and are numerically normalized:

freq_eval() applies a cached real scale factor chosen so that

\[\frac{1}{2\pi}\int |Z(\omega)|^2\,d\omega \approx 1\]

where the integral is approximated by trapezoidal quadrature on an automatically chosen finite frequency window. The normalization is therefore subject to window truncation and discretization error.

Parameters:
  • base (TimeFrequencyEnvelope)

  • transfer (TransferFunction)

  • n_fft (int)

  • w_span_sigma (float)

_abc_impl = <_abc._abc_data object>
_freq_eval_raw(w: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the unnormalized filtered spectrum.

Given a base spectrum \(Z_{\mathrm{in}}(\omega)\) and transfer \(H(\omega)\), this returns

\[Z_{\mathrm{raw}}(\omega) = H(\omega)\,Z_{\mathrm{in}}(\omega).\]

This method intentionally does not apply the mode-normalization factor. Use freq_eval() for the normalized spectrum.

Parameters:

w (ndarray[tuple[Any, ...], dtype[double]]) – Angular-frequency grid.

Returns:

Complex samples of \(Z_{\mathrm{raw}}(\omega)\).

Return type:

RCArray

property _norm2: float

Return the squared mode norm of the unnormalized filtered spectrum.

We treat envelopes as mode descriptors, so they are expected to be normalized such that

\[\langle \zeta, \zeta \rangle = 1.\]

Using the package Fourier convention, the overlap can be evaluated in the frequency domain as

\[\langle \zeta, \zeta \rangle = \frac{1}{2\pi}\int_{-\infty}^{\infty} |Z(\omega)|^2\,d\omega.\]

This method computes that quantity for the raw filtered spectrum

\[Z_{\mathrm{raw}}(\omega) = H(\omega)\,Z_{\mathrm{in}}(\omega),\]

on a finite window and returns a positive finite scalar.

Notes

  • The window is chosen from spectral hints of the base envelope.

  • The returned value is cached, so the normalization cost is paid once.

property _norm_scale: float

Return the scalar that normalizes the filtered envelope.

If

\[N^2 = \frac{1}{2\pi}\int |Z_{\mathrm{raw}}(\omega)|^2\,d\omega,\]

then the normalized spectrum is

\[Z(\omega) = \frac{1}{N}\,Z_{\mathrm{raw}}(\omega).\]

This method returns \(1/N\).

approx_signature(*, decimals: int = 12, ignore_global_phase: bool = False) tuple[object, ...]

Approximate signature with rounded base-envelope parameters.

Parameters:
  • decimals (int) – Number of decimals for rounding in the base envelope’s approx signature.

  • ignore_global_phase (bool) – If True, request that the base envelope ignore its global phase (if supported).

Returns:

Approximate signature tuple.

Return type:

Signature

base: TimeFrequencyEnvelope
center_and_scale() tuple[float, float]

Estimate a time-domain center and scale from the filtered spectrum.

The estimate is invariant under global real rescaling of the spectrum, so it uses the raw spectrum \(Z_{\mathrm{raw}}(\omega)\).

This computes a temporary time-domain signal via an FFT-based inverse transform, then estimates the mean and standard deviation of \(|\zeta(t)|^2\).

Returns:

  • center – Center time.

  • scale – Characteristic scale.

Return type:

tuple[float, float]

delayed(dt: float) Self

Return a delayed copy of this filtered envelope.

Parameters:

dt (float) – Delay applied to the base envelope.

Returns:

Delayed filtered envelope.

Return type:

FilteredEnvelope

property eta: float

Power transmissivity of the raw filtered mode.

Defined as the squared norm of the unnormalized filtered spectrum:

\[\eta = \frac{1}{2\pi}\int |H(\omega)|^2 |Z_{\mathrm{in}}(\omega)|^2 d\omega.\]

This is computed numerically on the same finite window used for normalization.

freq_eval(w: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the normalized filtered spectrum \(Z(\omega)\).

The filtered (raw) spectrum is

\[Z_{\mathrm{raw}}(\omega) = H(\omega)\,Z_{\mathrm{in}}(\omega).\]

We then normalize to enforce the mode condition

\[\frac{1}{2\pi}\int_{-\infty}^{\infty} |Z(\omega)|^2\,d\omega = 1,\]

by applying a global real scale factor

\[Z(\omega) = \alpha\,Z_{\mathrm{raw}}(\omega), \qquad \alpha = \frac{1}{\sqrt{\frac{1}{2\pi}\int |Z_{\mathrm{raw}}(\omega)|^2\,d\omega}}.\]
Parameters:

w (ndarray[tuple[Any, ...], dtype[double]]) – Angular-frequency grid.

Returns:

Complex samples of the normalized spectrum.

Return type:

RCArray

n_fft: int = 32768
overlap_with_generic(other: TimeFrequencyEnvelope) complex

Compute overlap using a frequency-domain quadrature.

This approximates

\[\langle \zeta_1, \zeta_2 \rangle \;\approx\; \frac{1}{2\pi}\int \overline{Z_1(\omega)}\,Z_2(\omega)\,d\omega,\]

using a finite window and trapezoidal quadrature.

Parameters:

other (TimeFrequencyEnvelope) – Envelope to overlap with.

Returns:

Approximate overlap.

Return type:

complex

phased(dphi: float) Self

Return a phased copy of this filtered envelope.

Parameters:

dphi (float) – Phase increment applied to the base envelope.

Returns:

Phased filtered envelope.

Return type:

FilteredEnvelope

property signature: tuple[object, ...]

Stable signature for caching/comparison.

time_eval(t: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the filtered time-domain field \(\zeta_\mathrm{out}(t)\).

The output spectrum is constructed as

\[Z(\omega) = \alpha\,H(\omega)\,Z_{\mathrm{in}}(\omega),\]

where \(\alpha\) is a global real normalization chosen such that \(\langle \zeta, \zeta \rangle = 1\).

The method: 1. Builds a centered frequency grid around \(\omega_0\). 2. Samples \(Z(\omega)\) on that grid. 3. Applies an FFT-based inverse transform to obtain a centered time grid. 4. Re-applies the carrier \(e^{i\omega_0 t}\) and interpolates onto t.

Parameters:

t (ndarray[tuple[Any, ...], dtype[double]]) – Time grid.

Returns:

Complex samples of \(\zeta_\mathrm{out}(t)\).

Return type:

RCArray

transfer: TransferFunction
w_span_sigma: float = 12.0
class GaussianEnvelope(omega0: float, sigma: float, tau: float, phi0: float = 0.0) None

Bases: BaseEnvelope

Canonical Gaussian time-domain envelope.

Parameters:
  • omega0 (float) – Carrier (angular) frequency \(\omega_0\).

  • sigma (float) – Temporal width \(\sigma_t\) (standard deviation in time).

  • tau (float) – Time shift (center) \(\tau\).

  • phi0 (float) – Global phase \(\phi_0\).

Definition

We define the complex field (not a rotating-frame envelope) as

\[\zeta(t) = \left(\frac{1}{2\pi\sigma_t^{2}}\right)^{1/4} \exp\!\left[-\frac{(t-\tau)^2}{4\sigma_t^{2}}\right] \exp\!\bigl(i(\omega_0(t-\tau)+\phi_0)\bigr).\]

Frequency domain

With the Fourier convention used in this package:

\[Z(\omega) = \int_{-\infty}^{\infty} \zeta(t)\,e^{+i\omega t}\,dt,\]

so that

\[\zeta(t)=\frac{1}{2\pi}\int_{-\infty}^{\infty} Z(\omega)\,e^{-i\omega t}\,d\omega.\]

Under this convention, the spectrum is also Gaussian:

\[Z(\omega) = \mathcal{A}\, \exp\!\left[-\sigma_t^2(\omega-\omega_0)^2\right]\, \exp\!\bigl(-i\omega\tau + i\phi_0\bigr),\]

where \(\mathcal{A}\) is a real constant (depends on normalization and Fourier convention). For overlaps and CCR-consistent mode construction, the absolute constant does not matter as long as it is used consistently.

Notes

This implementation chooses a consistent normalization constant for freq_eval, but the exact overall scale is not intended to be relied on unless you have explicitly standardized a Fourier convention across the codebase.

_abc_impl = <_abc._abc_data object>
approx_signature(*, decimals: int = 12, ignore_global_phase: bool = False) tuple[object, ...]

Approximate signature with rounded floating parameters.

Parameters:
  • decimals (int) – Number of decimals to round to.

  • ignore_global_phase (bool) – If True, treat \(\phi_0\) as zero for grouping.

Returns:

Rounded/approximate signature tuple.

Return type:

Signature

center_and_scale() tuple[float, float]

Return plotting/overlap heuristics.

Returns:

  • center – Center time (\(\tau\)).

  • scale – Characteristic scale (\(\sigma_t\)).

Return type:

tuple[float, float]

delayed(dt: float) GaussianEnvelope

Return a copy delayed by dt.

Parameters:

dt (float) – Time shift to add to \(\tau\).

Returns:

Delayed envelope.

Return type:

GaussianEnvelope

formalism: ClassVar[Literal['generic', 'gaussian_closed']] = 'gaussian_closed'
freq_eval(w: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the frequency-domain spectrum \(Z(\omega)\).

This returns a Gaussian spectrum consistent with the time-domain definition used in time_eval(), up to an overall real scale factor.

Parameters:

w (ndarray[tuple[Any, ...], dtype[double]]) – Frequency grid (angular frequency \(\omega\)).

Returns:

Complex samples of the spectrum.

Return type:

RCArray

omega0: float
property omega_sigma: float

Heuristic spectral width hint (rad/s).

For the envelope definition used here, a reasonable scaling for the intensity spectral standard deviation is approximately \(1/\sigma_t\).

overlap_gaussian_closed(other: SupportsGaussianClosedOverlap) complex

Closed-form overlap with another closed-form Gaussian envelope.

This computes the inner product

\[\langle \zeta_1, \zeta_2 \rangle = \int_{-\infty}^{\infty} \overline{\zeta_1(t)}\,\zeta_2(t)\,dt,\]

specialized to the normalized Gaussian family defined by time_eval().

Let \(\sigma_1,\tau_1,\omega_1,\phi_1\) be the parameters of self and \(\sigma_2,\tau_2,\omega_2,\phi_2\) those of other. Define

\[\begin{split}S &= \sigma_1^2 + \sigma_2^2, \\ \Delta\tau &= \tau_2 - \tau_1, \\ \Delta\omega &= \omega_2 - \omega_1, \\ \omega_w &= \frac{\omega_1\sigma_1^2 + \omega_2\sigma_2^2}{S}.\end{split}\]

Then the overlap is

\[\langle \zeta_1, \zeta_2 \rangle = \sqrt{\frac{2\sigma_1\sigma_2}{S}} \exp\!\left(-\frac{\Delta\tau^2}{4S}\right) \exp\!\left(-\frac{\sigma_1^2\sigma_2^2}{S}\,\Delta\omega^2\right) \exp\!\left(i(\phi_2-\phi_1-\omega_w\Delta\tau)\right).\]

Notes

  • This formula assumes both envelopes are normalized such that

\(\langle \zeta, \zeta \rangle = 1\). The normalization used in time_eval() satisfies this. - The result is consistent with conjugate symmetry: \(\langle \zeta_1,\zeta_2\rangle = \overline{\langle \zeta_2,\zeta_1\rangle}\).

Parameters:

other (SupportsGaussianClosedOverlap) – Another envelope in the same closed-form Gaussian family.

Returns:

The overlap \(\langle \zeta_1, \zeta_2 \rangle\).

Return type:

complex

Raises:
phased(dphi: float) GaussianEnvelope

Return a copy with an added global phase.

Parameters:

dphi (float) – Phase increment to add to \(\phi_0\).

Returns:

Phased envelope.

Return type:

GaussianEnvelope

phi0: float = 0.0
sigma: float
property signature: tuple[object, ...]

Stable signature for caching/comparison.

tau: float
time_eval(t: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the time-domain complex field \(\zeta(t)\).

Parameters:

t (ndarray[tuple[Any, ...], dtype[double]]) – Time grid.

Returns:

Complex samples of the field.

Return type:

RCArray

class GaussianMixtureEnvelope(components: tuple[GaussianEnvelope, ...], weights: ndarray[tuple[Any, ...], dtype[complexfloating[Any, Any]]], report: FitReport | None = None) None

Bases: BaseEnvelope

Linear combination of normalized closed-form Gaussian envelopes.

A Gaussian mixture envelope is defined as a finite superposition

\[\zeta(t) = \sum_{k=1}^{K} c_k\,g_k(t),\]

where each \(g_k(t)\) is a normalized GaussianEnvelope (same closed-form Gaussian family), and the complex weights \(c_k\) are stored in weights.

Normalization

This class enforces that the mixture is a mode descriptor:

\[\langle \zeta, \zeta \rangle = 1.\]

Since \(\zeta\) is a superposition, its norm depends on pairwise overlaps:

\[\|\zeta\|^2 = \sum_{i=1}^{K}\sum_{j=1}^{K} \overline{c_i}\,c_j\,\langle g_i, g_j\rangle.\]

In __post_init__(), the provided weights are rescaled by

\[c_k \leftarrow \frac{c_k}{\sqrt{\|\zeta\|^2}}\]

using closed-form overlaps \(\langle g_i, g_j\rangle\).

Overlaps

If the other envelope is in the same closed-form Gaussian family, overlaps are computed without numerical quadrature.

  1. Mixture vs single Gaussian:

\[\langle \zeta, h\rangle = \sum_{i=1}^{K} \overline{c_i}\,\langle g_i, h\rangle.\]
  1. Mixture vs mixture:

\[\left\langle \sum_i c_i g_i,\ \sum_j d_j h_j \right\rangle = \sum_{i=1}^{K}\sum_{j=1}^{L} \overline{c_i}\,d_j\,\langle g_i, h_j\rangle.\]

Here \(\langle g_i, h_j\rangle\) is evaluated by GaussianEnvelope.overlap_gaussian_closed().

Time and frequency evaluation

Evaluation is performed by linear superposition:

\[\zeta(t) = \sum_k c_k g_k(t), \qquad Z(\omega) = \sum_k c_k G_k(\omega).\]

Heuristics

center_and_scale() returns a plotting/overlap heuristic. The center is a power-weighted average of component centers (\(|c_k|^2\) weights) and the scale is the maximum component \(\sigma_t\) (conservative window choice).

type components:

tuple[GaussianEnvelope, ...]

param components:

Tuple of component GaussianEnvelope objects. Must be non-empty.

type weights:

ndarray[tuple[Any, ...], dtype[complexfloating[Any, Any]]]

param weights:

Complex 1D numpy array of shape (K,). Length must match len(components). The array is copied/coerced to complex and then rescaled in __post_init__() to enforce unit norm.

type report:

FitReport | None

param report:

Optional FitReport describing how the mixture was obtained (for example from a fit of a target function on a chosen time interval).

raises ValueError:

If weights is not 1D, if lengths mismatch, if components are empty, or if the computed norm is non-positive / non-finite.

_abc_impl = <_abc._abc_data object>
static _norm2_closed(weights: ndarray[tuple[Any, ...], dtype[complexfloating[Any, Any]]], comps: tuple[GaussianEnvelope, ...]) float

Compute the squared norm of a Gaussian mixture in closed form.

For a mixture

\[\zeta(t) = \sum_{k=1}^{K} c_k g_k(t),\]

the squared norm is

\[\|\zeta\|^2 = \sum_{i=1}^{K}\sum_{j=1}^{K} \overline{c_i}\,c_j\,\langle g_i, g_j\rangle.\]

This helper evaluates that quantity using analytic pairwise overlaps between the component GaussianEnvelope objects.

Parameters:
Returns:

Real-valued squared norm of the mixture.

Return type:

float

Notes

The return value is the real part of the accumulated overlap sum. For physically consistent inputs this should be non-negative, up to small numerical error.

approx_signature(*, decimals: int = 12, ignore_global_phase: bool = False) tuple[object, ...]

Approximate signature with rounded floating parameters.

Parameters:
  • decimals (int) – Number of decimals to round to.

  • ignore_global_phase (bool) – If True, treat \(\phi_0\) as zero for grouping.

Returns:

Rounded/approximate signature tuple.

Return type:

Signature

center_and_scale() tuple[float, float]

Return plotting/overlap heuristics.

Returns:

  • center – Center time (\(\tau\)).

  • scale – Characteristic scale (\(\sigma_t\)).

Return type:

tuple[float, float]

components: tuple[GaussianEnvelope, ...]
delayed(dt: float) GaussianMixtureEnvelope

Return a copy delayed by dt.

Parameters:

dt (float) – Time shift to add to \(\tau\).

Returns:

Delayed envelope.

Return type:

GaussianMixtureEnvelope

formalism: ClassVar[Literal['generic', 'gaussian_closed']] = 'gaussian_closed'
freq_eval(w: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the frequency-domain spectrum \(Z(\omega)\).

This returns a GaussianMixture spectrum consistent with the time-domain definition used in time_eval(), up to an overall real scale factor.

Parameters:

w (ndarray[tuple[Any, ...], dtype[double]]) – Frequency grid (angular frequency \(\omega\)).

Returns:

Complex samples of the spectrum.

Return type:

RCArray

classmethod from_callable(func: Callable[[ndarray[tuple[Any, ...], dtype[float64]]], ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]], *, tmin: float, tmax: float, k: int, omega0: float = 0.0, n_samples: int = 2000, sigma: float | None = None) GaussianMixtureEnvelope

Fit a Gaussian-mixture envelope to a time-domain target field.

This constructor fits a complex-valued time-domain amplitude \(f(t)\) on a uniform grid over [tmin, tmax] using a linear combination of GaussianEnvelope basis functions:

\[f(t) \approx \sum_{j=1}^{K} c_j g_j(t).\]

The component centers are chosen uniformly across the fit interval, all components share the same carrier frequency omega0, and a common width sigma is used. If sigma is not provided, a simple window-based heuristic is used.

Parameters:
Returns:

Normalized Gaussian mixture with an attached fit report.

Return type:

GaussianMixtureEnvelope

Raises:

ValueError – If the fit configuration is invalid.

classmethod from_lorentzian(*, gamma: float, tau: float = 0.0, omega0: float = 0.0, phi0: float = 0.0, k: int = 8, n_samples: int = 2000, window_multiple: float = 8.0) GaussianMixtureEnvelope

Construct a Gaussian mixture approximation to a Lorentzian pulse.

This convenience constructor fits a Gaussian mixture to the time-domain target field

\[f(t) = e^{i\phi_0} \frac{1}{1 + \left(\frac{t-\tau}{\gamma}\right)^2} e^{i\omega_0 (t-\tau)}.\]

The fit is performed on a symmetric time window around \(\tau\):

\[[\,\tau - m\gamma,\ \tau + m\gamma\,],\]

where \(m\) is window_multiple.

Parameters:
  • gamma (float) – Lorentzian width parameter. Must be positive.

  • tau (float) – Center time of the pulse.

  • omega0 (float) – Carrier angular frequency.

  • phi0 (float) – Global phase offset.

  • k (int) – Number of Gaussian basis components used in the fit.

  • n_samples (int) – Number of time samples used for the fitting procedure.

  • window_multiple (float) – Half-window size expressed in multiples of gamma.

Returns:

Normalized Gaussian mixture approximating the Lorentzian target, with an attached fit report.

Return type:

GaussianMixtureEnvelope

Raises:

ValueError – If gamma is not positive.

Notes

This is a numerical approximation utility built on top of from_callable(). The resulting mixture is normalized as a mode descriptor after fitting.

overlap_gaussian_closed(other: SupportsGaussianClosedOverlap) complex

Compute the closed-form overlap with another Gaussian-closed envelope.

Supported cases are:

  1. Mixture vs single Gaussian:

\[\langle \zeta, h\rangle = \sum_i \overline{c_i}\,\langle g_i, h\rangle.\]
  1. Mixture vs mixture:

\[\left\langle \sum_i c_i g_i,\ \sum_j d_j h_j \right\rangle = \sum_i \sum_j \overline{c_i}\,d_j\,\langle g_i, h_j\rangle.\]

In both cases, pairwise overlaps are evaluated analytically using GaussianEnvelope.overlap_gaussian_closed().

Parameters:

other (SupportsGaussianClosedOverlap) – Another envelope in the same closed Gaussian formalism.

Returns:

Complex overlap \(\langle \text{self}, \text{other} \rangle\).

Return type:

complex

Raises:

TypeError – If other is not a supported Gaussian-closed envelope type.

Notes

This method supports overlaps with GaussianEnvelope and GaussianMixtureEnvelope.

phased(dphi: float) GaussianMixtureEnvelope

Return a copy with an added global phase.

Parameters:

dphi (float) – Phase increment to add to \(\phi_0\).

Returns:

Phased envelope.

Return type:

GaussianMixtureEnvelope

report: FitReport | None = None
property signature: tuple[object, ...]

Stable signature for caching/comparison.

time_eval(t: ndarray[tuple[Any, ...], dtype[float64]]) ndarray[tuple[Any, ...], dtype[complex128]] | ndarray[tuple[Any, ...], dtype[float64]]

Evaluate the time-domain complex field \(\zeta(t)\).

Parameters:

t (ndarray[tuple[Any, ...], dtype[double]]) – Time grid.

Returns:

Complex samples of the field.

Return type:

RCArray

weights: ndarray[tuple[Any, ...], dtype[complexfloating[Any, Any]]]
Parameters:

Modules

base

Base envelope abstraction.

filtered

Spectrally filtered envelopes.

gaussian

Closed-form Gaussian time-domain envelopes.

gaussian_mixture

Gaussian mixtures of closed-form Gaussian time-domain envelopes.