pycsamt.z.utils#

General utilities for working with impedance tensors (Z) and tippers.

This module provides small, composable helpers that complement the object APIs in pycsamt.z.

Functions

align_frequency_stack(ref_freq, freq, z, *)

Align a Z component/vector to a reference frequency grid.

correct_for_sensor_orientation(z_prime[, ...])

Correct an impedance tensor for sensor misorientation.

enforce_offdiag_antisymmetry(z[, z_err])

Enforce the magnetotelluric property Zxy = -Zyx.

ensure_z3(z)

Normalize an impedance array to shape (n_freq, 2, 2).

finite_mask(a)

Boolean mask where all real and imaginary parts are finite.

freq_from_periods(period, *[, log10])

Convert period (s) to frequency (Hz).

invert_z(z[, z_err])

Invert Z (or each Z slice) with optional error propagation.

periods_from_freq(freq, *[, log10])

Convert frequency (Hz) to period (s).

rho_phi_from_z(z, freq[, z_err])

Compute apparent resistivity and phase from Z.

rotate_z(z, angle_deg[, z_err])

Rotate Z by angle_deg (CW positive), vectorized over freq.

sigma_clip_mask(a, *[, nsigma, axis])

Sigma-clip mask for outlier rejection.

pycsamt.z.utils.correct_for_sensor_orientation(z_prime, bx=0.0, by=90.0, ex=0.0, ey=90.0, z_prime_err=None)[source]#

Correct an impedance tensor for sensor misorientation.

Given measured fields in non-standard sensor frames,

\[\mathbf{E}' = \mathbf{Z}' \, \mathbf{B}',\]

and change-of-basis matrices \(\mathbf{T}\) (for E) and \(\mathbf{U}\) (for B), the tensor in standard coordinates is

\[\mathbf{Z} = \mathbf{T} \, \mathbf{Z}' \, \mathbf{U}^{-1}.\]

This function builds \(\mathbf{T}\) and \(\mathbf{U}\) from the sensor orientations and applies the transform.

Parameters:
  • z_prime (ndarray) – Input impedance tensor(s). Shape (2, 2) or (n_freq, 2, 2). Complex valued.

  • bx (float, default 0, 90) – Orientations (deg) of Bx, By relative to geographic North (0°). Positive clockwise.

  • by (float, default 0, 90) – Orientations (deg) of Bx, By relative to geographic North (0°). Positive clockwise.

  • ex (float, default 0, 90) – Orientations (deg) of Ex, Ey relative to geographic North (0°). Positive clockwise.

  • ey (float, default 0, 90) – Orientations (deg) of Ex, Ey relative to geographic North (0°). Positive clockwise.

  • z_prime_err (ndarray, optional) – Standard deviations for \(\mathbf{Z}'\), same shape as z_prime and real-valued. If provided, a conservative error propagation is applied (see Notes).

Returns:

  • z (ndarray) – Orientation-corrected tensor(s), same shape as z_prime.

  • z_err (ndarray or None) – Propagated standard deviations in the default orientation. None if z_prime_err was not given.

Return type:

tuple[ndarray, ndarray | None]

Notes

  • Matrices \(\mathbf{T}\) and \(\mathbf{U}\) are real and built from unit vectors at angles ex, ey and bx, by respectively:

    T = [[cos(ex), cos(ey)],
         [sin(ex), sin(ey)]],
    U = [[cos(bx), cos(by)],
         [sin(bx), sin(by)]]
    
  • Error propagation uses a simple 1-norm–like bound for \(Z = T Z' U^{-1}\):

    \[\Delta Z \approx |T| \, \Delta Z' \, |U^{-1}|,\]

    applied element-wise by summation. This is conservative and ignores covariances.

Examples

>>> import numpy as np
>>> from pycsamt.z.utils import correct_for_sensor_orientation
>>> Zp = np.array([[0+0j, 1+1j], [-1-1j, 0+0j]])
>>> Z, Zerr = correct_for_sensor_orientation(Zp, bx=5, by=95)
pycsamt.z.utils.periods_from_freq(freq, *, log10=False)[source]#

Convert frequency (Hz) to period (s).

Parameters:
  • freq (array-like of float) – Frequencies in Hz.

  • log10 (bool, default False) – If True, return log10(period).

Returns:

Periods with the same length as freq.

Return type:

ndarray

pycsamt.z.utils.freq_from_periods(period, *, log10=False)[source]#

Convert period (s) to frequency (Hz).

Parameters:
  • period (array-like of float) – Periods in seconds. If log10=True, the input is interpreted as log10(period).

  • log10 (bool, default False) – Whether input is in base-10 log scale.

Returns:

Frequencies in Hz.

Return type:

ndarray

pycsamt.z.utils.ensure_z3(z)[source]#

Normalize an impedance array to shape (n_freq, 2, 2).

Parameters:

z (ndarray) – Array with shape (2, 2) or (n_freq, 2, 2) (real or complex).

Returns:

Complex array of shape (n_freq, 2, 2).

Return type:

ndarray

Raises:

ZError – If the shape is not supported.

pycsamt.z.utils.rho_phi_from_z(z, freq, z_err=None)[source]#

Compute apparent resistivity and phase from Z.

Parameters:
  • z (ndarray) – Impedance tensor(s), shape (2, 2) or (n, 2, 2).

  • freq (array-like of float) – Frequency vector (Hz). Length must be n.

  • z_err (ndarray, optional) – Absolute errors for Z, same shape as z. If given, uncertainties are propagated component-wise.

Returns:

  • rho (ndarray) – Apparent resistivity (Ohm·m), shape (n, 2, 2).

  • phi (ndarray) – Phase (deg), shape (n, 2, 2).

  • rho_err (ndarray or None) – Error on resistivity (Ohm·m) or None if z_err is None.

  • phi_err (ndarray or None) – Error on phase (deg) or None if z_err is None.

Return type:

tuple[ndarray, ndarray, ndarray | None, ndarray | None]

pycsamt.z.utils.enforce_offdiag_antisymmetry(z, z_err=None)[source]#

Enforce the magnetotelluric property Zxy = -Zyx.

Parameters:
  • z (ndarray) – Z tensor(s), shape (2, 2) or (n, 2, 2).

  • z_err (ndarray, optional) – Errors with same shape as z. If provided, off-diagonal errors are combined via RMS.

Returns:

  • z_new (ndarray) – Copy of Z with enforced antisymmetry on off-diagonals.

  • z_err_new (ndarray or None) – Propagated errors (off-diagonals via RMS), or None if z_err was not given.

Return type:

tuple[ndarray, ndarray | None]

Notes

We set

\[m = \tfrac{1}{2}(Z_{xy} - Z_{yx}),\; Z_{xy}=m,\; Z_{yx}=-m,\]

which minimally enforces antisymmetry.

pycsamt.z.utils.rotate_z(z, angle_deg, z_err=None)[source]#

Rotate Z by angle_deg (CW positive), vectorized over freq.

Parameters:
  • z (ndarray) – Z tensor(s), shape (2, 2) or (n, 2, 2).

  • angle_deg (float or sequence of float) – Single angle for all stacks or one per frequency.

  • z_err (ndarray, optional) – Error tensor matching z shape.

Returns:

  • z_rot (ndarray) – Rotated Z with same shape as z.

  • z_err_rot (ndarray or None) – Rotated error, if z_err was provided.

Return type:

tuple[ndarray, ndarray | None]

pycsamt.z.utils.invert_z(z, z_err=None)[source]#

Invert Z (or each Z slice) with optional error propagation.

Parameters:
  • z (ndarray) – Z tensor(s), shape (2, 2) or (n, 2, 2).

  • z_err (ndarray, optional) – Error tensor matching z shape.

Returns:

  • z_inv (ndarray) – Inverse of Z with same shape as z.

  • z_inv_err (ndarray or None) – Propagated error of Z inverse, or None if no input error given.

Raises:

ZError – If any slice is singular.

Return type:

tuple[ndarray, ndarray | None]

pycsamt.z.utils.align_frequency_stack(ref_freq, freq, z, *, fill_value=nan)[source]#

Align a Z component/vector to a reference frequency grid.

This is a generalization of a “fit tensor” operation: values at freq are placed at the matching indices of ref_freq and missing locations are filled with fill_value.

Parameters:
  • ref_freq (array-like of float) – Target frequency grid (Hz), length N.

  • freq (array-like of float) – Source frequency grid (Hz), length M with values contained in ref_freq (within exact match).

  • z (ndarray) – Data to align. Shape must be compatible with the first dimension being M (e.g., (M,) or (M, 2, 2)).

  • fill_value (scalar, default NaN) – Value used to fill missing entries.

Returns:

Aligned array with shape (N, ...).

Return type:

ndarray

Raises:

ZError – If shapes are incompatible.

pycsamt.z.utils.finite_mask(a)[source]#

Boolean mask where all real and imaginary parts are finite.

Parameters:

a (ndarray) – Input array.

Returns:

Mask with True for finite entries.

Return type:

ndarray of bool

pycsamt.z.utils.sigma_clip_mask(a, *, nsigma=3.0, axis=0)[source]#

Sigma-clip mask for outlier rejection.

Parameters:
  • a (ndarray) – Input array.

  • nsigma (float, default 3.0) – Threshold in units of standard deviation.

  • axis (int, default 0) – Axis along which statistics are computed.

Returns:

Mask of inliers (True) and outliers (False).

Return type:

ndarray of bool