"""Waveform types."""
from __future__ import annotations
import logging
from collections.abc import Callable, Mapping
from typing import (
TYPE_CHECKING,
Any,
overload,
)
import array_api_compat as xpc
from .. import utils
from . import _mixins, modes
from . import representations as reps
from .misc import AnyAxis, AnyGrid, Interpolator
from .representations import FrequencyPhasor, FrequencySeries, TimePhasor, TimeSeries
Mode = tuple[int, int] | tuple[int, int, int]
if TYPE_CHECKING:
AnyReps = reps.Representation[AnyGrid]
log = logging.getLogger(__name__)
def _validate_maps_to_pws(mapping: Mapping[Any, ProjectedWaveform[AnyReps]]):
"""Validate that a mapping maps to projected waveforms."""
for key, pw in mapping.items():
try:
_ = _mixins.validate_maps_to_reps(pw)
except ValueError as error:
msg = f"Invalid projected waveform for key {key!r}. "
raise ValueError(msg) from error
@overload
def harmonic_waveform[RepT: "AnyReps"](
modes_to_reps: Mapping[tuple[int, int], RepT],
) -> HarmonicWaveform[modes.Harmonic, RepT]: ...
@overload
def harmonic_waveform[RepT: "AnyReps"](
modes_to_reps: Mapping[tuple[int, int, int], RepT],
) -> HarmonicWaveform[modes.QuasiNormalMode, RepT]: ...
@overload
def harmonic_waveform[ModeT: Mode, RepT: "AnyReps"](
modes_to_reps: Mapping[ModeT, RepT],
) -> HarmonicWaveform[ModeT, RepT]: ...
@overload
def homogeneous_harmonic_waveform[RepT: "AnyReps"](
modes_to_reps: Mapping[tuple[int, int], RepT],
) -> HomogeneousHarmonicWaveform[modes.Harmonic, RepT]: ...
@overload
def homogeneous_harmonic_waveform[RepT: "AnyReps"](
modes_to_reps: Mapping[tuple[int, int, int], RepT],
) -> HomogeneousHarmonicWaveform[modes.QuasiNormalMode, RepT]: ...
@overload
def homogeneous_harmonic_waveform[ModeT: Mode, RepT: "AnyReps"](
modes_to_reps: Mapping[ModeT, RepT],
) -> HomogeneousHarmonicWaveform[ModeT, RepT]: ...
@overload
def harmonic_projected_waveform[RepT: "AnyReps"](
modes_to_pws: Mapping[tuple[int, int], ProjectedWaveform[RepT]],
) -> HarmonicProjectedWaveform[modes.Harmonic, RepT]: ...
@overload
def harmonic_projected_waveform[RepT: "AnyReps"](
modes_to_pws: Mapping[tuple[int, int, int], ProjectedWaveform[RepT]],
) -> HarmonicProjectedWaveform[modes.QuasiNormalMode, RepT]: ...
@overload
def harmonic_projected_waveform[ModeT: Mode, RepT: "AnyReps"](
modes_to_pws: Mapping[ModeT, ProjectedWaveform[RepT]],
) -> HarmonicProjectedWaveform[ModeT, RepT]: ...
@overload
def homogeneous_harmonic_projected_waveform[RepT: "AnyReps"](
modes_to_pws: Mapping[tuple[int, int], ProjectedWaveform[RepT]],
) -> HomogeneousHarmonicProjectedWaveform[modes.Harmonic, RepT]: ...
@overload
def homogeneous_harmonic_projected_waveform[RepT: "AnyReps"](
modes_to_pws: Mapping[tuple[int, int, int], ProjectedWaveform[RepT]],
) -> HomogeneousHarmonicProjectedWaveform[modes.QuasiNormalMode, RepT]: ...
@overload
def homogeneous_harmonic_projected_waveform[ModeT: Mode, RepT: "AnyReps"](
modes_to_pws: Mapping[ModeT, ProjectedWaveform[RepT]],
) -> HomogeneousHarmonicProjectedWaveform[ModeT, RepT]: ...
# Convenience aliases
hw = harmonic_waveform
"""Alias for :func:`~harmonic_waveform`."""
hhw = homogeneous_harmonic_waveform
"""Alias for :func:`~homogeneous_harmonic_waveform`."""
pcw = plus_cross_waveform
"""Alias for :func:`~plus_cross_waveform`."""
pw = projected_waveform
"""Alias for :func:`~projected_waveform`."""
hpw = harmonic_projected_waveform
"""Alias for :func:`~harmonic_projected_waveform`."""
hhpw = homogeneous_harmonic_projected_waveform
"""Alias for :func:`~homogeneous_harmonic_projected_waveform`."""
[docs]
def sum_harmonics[ModeT: Mode, AxisT: "AnyAxis"](
wf: HomogeneousHarmonicProjectedWaveform[ModeT, FrequencySeries[AxisT]],
) -> ProjectedWaveform[FrequencySeries[AxisT]]:
"""Sum over modes."""
entries = wf.get_kernel().sum(axis=2, keepdims=True) # c.f. shape convention
_first = wf._first # pyright: ignore[reportPrivateUsage]
return type(_first)(
_first.grid,
entries,
wf.channel_names,
_rep_type=_first._rep_type, # pyright: ignore[reportPrivateUsage]
)
_PhasorWaveTypes = (
HomogeneousHarmonicWaveform[Mode, FrequencyPhasor[AnyAxis]]
| HarmonicWaveform[Mode, FrequencyPhasor[AnyAxis]]
| HomogeneousHarmonicWaveform[Mode, TimePhasor[AnyAxis]]
| HarmonicWaveform[Mode, TimePhasor[AnyAxis]]
| ProjectedWaveform[FrequencyPhasor[AnyAxis]]
| ProjectedWaveform[TimePhasor[AnyAxis]]
| HomogeneousHarmonicProjectedWaveform[Mode, FrequencyPhasor[AnyAxis]]
| HarmonicProjectedWaveform[Mode, FrequencyPhasor[AnyAxis]]
| HomogeneousHarmonicProjectedWaveform[Mode, TimePhasor[AnyAxis]]
| HarmonicProjectedWaveform[Mode, TimePhasor[AnyAxis]]
)
@overload
def densify_phasor[AT: "AnyAxis"](
wf: TimePhasor[AnyAxis],
/,
interpolator: Interpolator,
axis: AT,
*,
embed: bool = False,
) -> TimePhasor[AT]: ...
@overload
def densify_phasor[AT: "AnyAxis"](
wf: FrequencyPhasor[AnyAxis],
/,
interpolator: Interpolator,
axis: AT,
*,
embed: bool = False,
) -> FrequencyPhasor[AT]: ...
@overload
def densify_phasor[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicWaveform[ModeT, TimePhasor[AnyAxis]],
/,
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> HomogeneousHarmonicWaveform[ModeT, TimePhasor[AxisT]]: ...
@overload
def densify_phasor[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicWaveform[ModeT, FrequencyPhasor[AnyAxis]],
/,
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> HomogeneousHarmonicWaveform[ModeT, FrequencyPhasor[AxisT]]: ...
@overload
def densify_phasor[RepT: TimePhasor["AnyAxis"], AxisT: "AnyAxis"](
wf: ProjectedWaveform[RepT],
/,
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> ProjectedWaveform[TimePhasor[AxisT]]: ...
@overload
def densify_phasor[RepT: FrequencyPhasor["AnyAxis"], AxisT: "AnyAxis"](
wf: ProjectedWaveform[RepT],
/,
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> ProjectedWaveform[FrequencyPhasor[AxisT]]: ...
@overload
def densify_phasor[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[ModeT, TimePhasor[AnyAxis]],
/,
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> HomogeneousHarmonicProjectedWaveform[ModeT, TimePhasor[AxisT]]: ...
@overload
def densify_phasor[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[ModeT, FrequencyPhasor[AnyAxis]],
/,
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> HomogeneousHarmonicProjectedWaveform[ModeT, FrequencyPhasor[AxisT]]: ...
[docs]
def densify_phasor[AT: "AnyAxis"](
wf: FrequencyPhasor[AnyAxis] | TimePhasor[AnyAxis] | _PhasorWaveTypes,
/,
interpolator: Interpolator,
axis: AT,
*,
embed: bool = False,
frequencies: AT | None = None,
):
"""Densify a sparse phasor representation by interpolation.
Parameters
----------
wf :
The phasor representation or waveform to densify.
interpolator :
The interpolator to use for densification.
axis :
The axis at which to evaluate the densified phasor.
embed :
If False, the returned phasor is restricted to the subset of `axis`
that overlaps with the support of `wf`.
Attention
---------
The branch with `embed=False` does not support JIT compilation.
"""
if frequencies is not None:
msg = (
"The `frequencies` argument of `densify_phasor` is deprecated "
"and will be removed in 0.8.0; "
"pass the frequencies as the `axis` argument instead."
)
utils.warn_external(
msg,
DeprecationWarning,
)
axis = frequencies
if isinstance(wf, (TimePhasor, FrequencyPhasor)):
xp = xpc.get_namespace(wf.entries)
_axis = _mixins.to_array(axis, xp=xp)
if not embed:
_slice = utils.get_subset_slice(_axis, wf.axis_onset, wf.axis_end)
freqs = axis[_slice]
return wf.get_interpolated(freqs, interpolator)
mask = utils.get_subset_mask(_axis, wf.axis_onset, wf.axis_end)
nwf = wf.get_interpolated(axis, interpolator)
_amp = xp.where(mask, nwf.amplitudes, 0)
_phase = xp.where(mask, nwf.phases, 0)
if isinstance(wf, TimePhasor):
return reps.time_phasor(times=axis, amplitudes=_amp, phases=_phase)
return reps.frequency_phasor(frequencies=axis, amplitudes=_amp, phases=_phase)
if isinstance(wf, HarmonicWaveform):
return hhw(
{
mode: densify_phasor(
wf[mode],
interpolator,
axis,
embed=embed,
)
for mode in wf
},
)
if isinstance(wf, ProjectedWaveform):
return pw(
{
chnname: densify_phasor(
wf[chnname],
interpolator,
axis,
embed=embed,
)
for chnname in wf.channel_names
},
)
# Must be a HarmonicProjectedWaveform at this point
return hhpw(
{
mode: projected_waveform(
{
chnname: densify_phasor(
wf[mode][chnname],
interpolator,
axis,
embed=embed,
)
for chnname in wf._first.channel_names # pyright: ignore[reportPrivateUsage]
},
)
for mode in wf.harmonics
},
)
# if embed:
# freqs = xp.where(mask, _frequencies, 0)
# nwf = wf.get_interpolated(freqs, interpolator)
# return nwf
# freqs = _frequencies[mask]
# nwf = wf.get_interpolated(freqs, interpolator)
# return nwf
# _slice = utils.get_subset_slice(_frequencies, wf.f_min, wf.f_max)
# freqs = frequencies[_slice]
# nwf = wf.get_interpolated(freqs, interpolator)
# if not embed:
# return nwf
# return nwf.get_embedded((frequencies,), known_slices=(_slice,))
@overload
def densify_phasor_hw[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicWaveform[ModeT, TimePhasor[AnyAxis]],
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> HomogeneousHarmonicWaveform[ModeT, TimePhasor[AxisT]]: ...
@overload
def densify_phasor_hw[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicWaveform[ModeT, FrequencyPhasor[AnyAxis]],
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> HomogeneousHarmonicWaveform[ModeT, FrequencyPhasor[AxisT]]: ...
[docs]
@utils.deprecated(
"densify_phasor_hw", "function", "0.8.0", alternative="densify_phasor"
)
def densify_phasor_hw[ModeT: Mode](
wf: HarmonicWaveform[ModeT, FrequencyPhasor[AnyAxis]]
| HarmonicWaveform[ModeT, TimePhasor[AnyAxis]],
interpolator: Interpolator,
axis: AnyAxis,
*,
embed: bool = False,
):
"""Densify :class:`~types.HarmonicWaveform` with sparse :class:`~types.TimePhasor` or :class:`~types.FrequencyPhasor` by interpolation (*Deprecated*).
Parameters
----------
wf :
The harmonic waveform to densify.
interpolator :
The interpolator to use for densification.
axis :
The axis on which to interpolate.
embed :
Whether to embed the densified phasor on the original frequency grid.
.. deprecated:: 0.6.6
Will be removed in 0.8.0; use :func:`densify_phasor` instead.
""" # noqa: E501
return densify_phasor(wf, interpolator, axis, embed=embed)
@overload
def densify_phasor_pw[RepT: TimePhasor["AnyAxis"], AxisT: "AnyAxis"](
wf: ProjectedWaveform[RepT],
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> ProjectedWaveform[TimePhasor[AxisT]]: ...
@overload
def densify_phasor_pw[RepT: FrequencyPhasor["AnyAxis"], AxisT: "AnyAxis"](
wf: ProjectedWaveform[RepT],
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> ProjectedWaveform[FrequencyPhasor[AxisT]]: ...
[docs]
@utils.deprecated(
"densify_phasor_pw", "function", "0.8.0", alternative="densify_phasor"
)
def densify_phasor_pw[
AxisT: "AnyAxis",
](
wf: ProjectedWaveform[TimePhasor[AnyAxis]]
| ProjectedWaveform[FrequencyPhasor[AnyAxis]],
interpolator: Interpolator,
axis: AnyAxis,
*,
embed: bool = False,
):
"""Densify :class:`~types.ProjectedWaveform` with sparse :class:`~types.TimePhasor` or :class:`~types.FrequencyPhasor` representations by interpolation (*Deprecated*).
Parameters
----------
wf :
The projected waveform to densify.
interpolator :
The interpolator to use for densification.
axis :
The axis on which to interpolate.
embed :
Whether to embed the densified phasor on the original frequency grid.
.. deprecated:: 0.6.6
Will be removed in 0.8.0; use :func:`densify_phasor` instead.
""" # noqa: E501
return densify_phasor(wf, interpolator, axis, embed=embed)
@overload
def densify_phasor_hpw[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[ModeT, TimePhasor[AnyAxis]],
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> HomogeneousHarmonicProjectedWaveform[ModeT, TimePhasor[AxisT]]: ...
@overload
def densify_phasor_hpw[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[ModeT, FrequencyPhasor[AnyAxis]],
interpolator: Interpolator,
axis: AxisT,
*,
embed: bool = False,
) -> HomogeneousHarmonicProjectedWaveform[ModeT, FrequencyPhasor[AxisT]]: ...
[docs]
@utils.deprecated(
"densify_phasor_hpw", "function", "0.8.0", alternative="densify_phasor"
)
def densify_phasor_hpw[ModeT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[ModeT, TimePhasor[AnyAxis]]
| HarmonicProjectedWaveform[ModeT, FrequencyPhasor[AnyAxis]],
interpolator: Interpolator,
axis: AnyAxis,
*,
embed: bool = False,
):
"""Densify :class:`~types.HarmonicProjectedWaveform` with sparse :class:`~types.TimePhasor` or :class:`~types.FrequencyPhasor` representations by interpolation (*Deprecated*).
.. deprecated:: 0.6.6
Will be removed in 0.8.0; use :func:`densify_phasor` instead.
""" # noqa: E501
return densify_phasor(wf, interpolator, axis, embed=embed)
@overload
def phasor_to_series[MT: Mode, AxisT: "AnyAxis"](
wf: HomogeneousHarmonicWaveform[MT, FrequencyPhasor[AxisT]],
/,
) -> HomogeneousHarmonicWaveform[MT, FrequencySeries[AxisT]]: ...
@overload
def phasor_to_series[MT: Mode, AxisT: "AnyAxis"](
wf: HarmonicWaveform[MT, FrequencyPhasor[AxisT]],
/,
) -> HarmonicWaveform[MT, FrequencySeries[AxisT]]: ...
@overload
def phasor_to_series[MT: Mode, AxisT: "AnyAxis"](
wf: HomogeneousHarmonicWaveform[MT, TimePhasor[AxisT]],
/,
) -> HomogeneousHarmonicWaveform[MT, TimeSeries[AxisT]]: ...
@overload
def phasor_to_series[MT: Mode, AxisT: "AnyAxis"](
wf: HarmonicWaveform[MT, TimePhasor[AxisT]],
/,
) -> HarmonicWaveform[MT, TimeSeries[AxisT]]: ...
@overload
def phasor_to_series[AxisT: "AnyAxis"](
wf: ProjectedWaveform[FrequencyPhasor[AxisT]],
/,
) -> ProjectedWaveform[FrequencySeries[AxisT]]: ...
@overload
def phasor_to_series[AxisT: "AnyAxis"](
wf: ProjectedWaveform[TimePhasor[AxisT]],
/,
) -> ProjectedWaveform[TimeSeries[AxisT]]: ...
@overload
def phasor_to_series[MT: Mode, AxisT: "AnyAxis"](
wf: HomogeneousHarmonicProjectedWaveform[MT, FrequencyPhasor[AxisT]],
/,
) -> HomogeneousHarmonicProjectedWaveform[MT, FrequencySeries[AxisT]]: ...
@overload
def phasor_to_series[MT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[MT, FrequencyPhasor[AxisT]],
/,
) -> HarmonicProjectedWaveform[MT, FrequencySeries[AxisT]]: ...
@overload
def phasor_to_series[MT: Mode, AxisT: "AnyAxis"](
wf: HomogeneousHarmonicProjectedWaveform[MT, TimePhasor[AxisT]],
/,
) -> HomogeneousHarmonicProjectedWaveform[MT, TimeSeries[AxisT]]: ...
@overload
def phasor_to_series[MT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[MT, TimePhasor[AxisT]],
/,
) -> HarmonicProjectedWaveform[MT, TimeSeries[AxisT]]: ...
[docs]
def phasor_to_series(
wf: _PhasorWaveTypes,
/,
):
"""Convert phasor-valued waveform to series-valued waveform."""
if isinstance(wf, HarmonicWaveform):
_mapping = {mode: wf[mode].to_series() for mode in wf}
if isinstance(wf, HomogeneousHarmonicWaveform):
return homogeneous_harmonic_waveform(_mapping)
return harmonic_waveform(_mapping)
if isinstance(wf, ProjectedWaveform):
return projected_waveform(
{chnname: wf[chnname].to_series() for chnname in wf.channel_names},
)
_mapping = {
mode: projected_waveform(
{
chnname: wf[mode][chnname].to_series()
for chnname in wf[mode].channel_names
},
)
for mode in wf
}
if isinstance(wf, HomogeneousHarmonicProjectedWaveform):
return homogeneous_harmonic_projected_waveform(_mapping)
return harmonic_projected_waveform(_mapping)
@overload
def phasor_to_fs_hw[MT: Mode, AxisT: "AnyAxis"](
wf: HomogeneousHarmonicWaveform[MT, FrequencyPhasor[AxisT]],
) -> HomogeneousHarmonicWaveform[MT, FrequencySeries[AxisT]]: ...
@overload
def phasor_to_fs_hw[MT: Mode, AxisT: "AnyAxis"](
wf: HarmonicWaveform[MT, FrequencyPhasor[AxisT]],
) -> HarmonicWaveform[MT, FrequencySeries[AxisT]]: ...
[docs]
@utils.deprecated(
"phasor_to_fs_hw", "function", "0.8.0", alternative="phasor_to_series"
)
def phasor_to_fs_hw[MT: Mode, AxisT: "AnyAxis"](
wf: HarmonicWaveform[MT, FrequencyPhasor[AxisT]],
):
"""Convert :class:`~types.FrequencyPhasor`-valued :class:`~types.HarmonicWaveform` to :class:`~types.FrequencySeries` (*Deprecated*).
.. deprecated:: 0.6.6
Will be removed in 0.8.0. Use :func:`phasor_to_series` instead.
""" # noqa: E501
return phasor_to_series(wf)
[docs]
@utils.deprecated(
"phasor_to_fs_pw", "function", "0.8.0", alternative="phasor_to_series"
)
def phasor_to_fs_pw[AxisT: "AnyAxis"](
wf: ProjectedWaveform[FrequencyPhasor[AxisT]],
):
"""Convert :class:`~types.FrequencyPhasor`-valued :class:`~types.ProjectedWaveform` to :class:`~types.FrequencySeries` (*Deprecated*).
.. deprecated:: 0.6.6
Will be removed in 0.8.0. Use :func:`phasor_to_series` instead.
""" # noqa: E501
return phasor_to_series(wf)
@overload
def phasor_to_fs_hpw[MT: Mode, AxisT: "AnyAxis"](
wf: HomogeneousHarmonicProjectedWaveform[MT, FrequencyPhasor[AxisT]],
) -> HomogeneousHarmonicProjectedWaveform[MT, FrequencySeries[AxisT]]: ...
@overload
def phasor_to_fs_hpw[MT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[MT, FrequencyPhasor[AxisT]],
) -> HomogeneousHarmonicProjectedWaveform[MT, FrequencySeries[AxisT]]: ...
[docs]
@utils.deprecated(
"phasor_to_fs_hpw", "function", "0.8.0", alternative="phasor_to_series"
)
def phasor_to_fs_hpw[MT: Mode, AxisT: "AnyAxis"](
wf: HarmonicProjectedWaveform[MT, FrequencyPhasor[AxisT]],
):
"""Convert :class:`~types.FrequencyPhasor`-valued :class:`~types.HarmonicProjectedWaveform` to :class:`~types.FrequencySeries` (*Deprecated*).
.. deprecated:: 0.6.6
Will be removed in 0.8.0. Use :func:`phasor_to_series` instead.
""" # noqa: E501
return phasor_to_series(wf)
[docs]
@utils.deprecated("get_dense_maker", "function", "0.8.0")
def get_dense_maker(
interpolator: Interpolator,
):
"""Return a function to convert a sparse phasor projected waveform to a dense phasor projected waveform (*Deprecated*).
The returned function has the signature:
.. code-block:: python
def make(
frequencies: npt.NDArray[np.floating],
embed: bool = False,
) -> Callable[HarmonicProjectedWaveform[Mode, Phasor], HarmonicProjectedWaveform[Mode, Phasor]]:
...
The function takes a list of frequencies and an optional boolean
`embed` argument. If `embed` is True, the returned function will
return a waveform with the same frequencies as the input. If `embed`
is False, the returned function will return a waveform with the
frequencies truncated to the lowest and highest frequencies of the
input waveform.
.. deprecated:: 0.6.0
Will be removed in 0.8.0. Use :func:`densify_phasor`,
:func:`densify_phasor_hw`, :func:`densify_phasor_pw`,
or :func:`densify_phasor_hpw` instead.
""" # noqa: E501
def make[MT: Mode, AxisT: "AnyAxis"](
frequencies: AxisT,
*,
embed: bool = False,
) -> Callable[
[HarmonicProjectedWaveform[MT, FrequencyPhasor[AnyAxis]]],
HarmonicProjectedWaveform[MT, FrequencyPhasor[AxisT]],
]:
def do_phasor(wf: FrequencyPhasor[AnyAxis]):
_frequencies = frequencies.asarray(xpc.get_namespace(wf.entries))
_slice = utils.get_subset_slice(_frequencies, wf.f_min, wf.f_max)
freqs = frequencies[
utils.get_subset_slice(_frequencies, wf.f_min, wf.f_max)
]
nwf = wf.get_interpolated(freqs, interpolator)
if not embed:
return nwf
return nwf.get_embedded((frequencies,), known_slices=(_slice,))
def do_response(resp: ProjectedWaveform[FrequencyPhasor[AnyAxis]]):
return ProjectedWaveform[FrequencyPhasor[AxisT]].from_dict(
{chnname: do_phasor(resp[chnname]) for chnname in resp.channel_names},
)
def do[ModeT: Mode](
wf: HarmonicProjectedWaveform[ModeT, FrequencyPhasor[AnyAxis]],
):
return HarmonicProjectedWaveform[ModeT, FrequencyPhasor[AxisT]](
{mode: do_response(wf[mode]) for mode in wf.harmonics},
)
return do
return make