Skip to content

BUG: ShortTimeFFT fails with complex input #20009

@rez10191

Description

@rez10191

Describe your issue.

ShortTimeFFT fails with complex input. The following reproduction uses a lightly modified version of the code from the example found in the documentation. The documentation states that the signal input x can be complex:

x

    The input signal as real or complex valued array.

Thanks for all the team's efforts on this great project!

Reproducing Code Example

import numpy as np

import math # REZ10101 added

import matplotlib.pyplot as plt

from scipy.signal import ShortTimeFFT

from scipy.signal.windows import gaussian


T_x, N = 1 / 20, 1000  # 20 Hz sampling rate for 50 s signal
t_x = np.arange(N) * T_x  # time indexes for signal

f_i = 1 * np.arctan((t_x - t_x[N // 2]) / 2) + 5
sig = 2*np.pi*np.cumsum(f_i)*T_x  #  REZ10101 split out
x = math.e ** (np.sin(sig) + 1j * np.cos(sig)) # REZ10101 made complex



g_std = 8  # standard deviation for Gaussian window in samples
w = gaussian(50, std=g_std, sym=True)  # symmetric Gaussian window
SFT = ShortTimeFFT(w, hop=10, fs=1/T_x, mfft=200, scale_to='magnitude')
Sx = SFT.stft(x)  # perform the STFT


fig1, ax1 = plt.subplots(figsize=(6., 4.))  # enlarge plot a bit

t_lo, t_hi = SFT.extent(N)[:2]  # time range of plot

ax1.set_title(
    rf"STFT ({SFT.m_num*SFT.T:g}$\,s$ Gaussian window, " +
    rf"$\sigma_t={g_std*SFT.T}\,$s)"
)

ax1.set(
    xlabel=(
        f"Time $t$ in seconds ({SFT.p_num(N)} slices, " +
        rf"$\Delta t = {SFT.delta_t:g}\,$s)"
    ),
    ylabel=(
        f"Freq. $f$ in Hz ({SFT.f_pts} bins, " +
        rf"$\Delta f = {SFT.delta_f:g}\,$Hz)"
    ),
    xlim=(t_lo, t_hi)
)


im1 = ax1.imshow(
    abs(Sx),
    origin='lower',
    aspect='auto',
    extent=SFT.extent(N),
    cmap='viridis'
)

ax1.plot(t_x, f_i, 'r--', alpha=.5, label='$f_i(t)$')

fig1.colorbar(im1, label="Magnitude $|S_x(t, f)|$")


# Shade areas where window slices stick out to the side:
for t0_, t1_ in [(t_lo, SFT.lower_border_end[0] * SFT.T),
                 (SFT.upper_border_begin(N)[0] * SFT.T, t_hi)]:
    ax1.axvspan(t0_, t1_, color='w', linewidth=0, alpha=.2)

for t_ in [0, N * SFT.T]:  # mark signal borders with vertical line:
    ax1.axvline(t_, color='y', linestyle='--', alpha=0.5)

ax1.legend()

fig1.tight_layout()

plt.show()

Error message

Traceback (most recent call last):
  File "/home/zuber/git/test/test_shortTimeFFT.py", line 24, in <module>
    Sx = SFT.stft(x)  # perform the STFT
         ^^^^^^^^^^^
  File "/home/zuber/git/venv/lib/python3.12/site-packages/scipy/signal/_short_time_fft.py", line 795, in stft
    return self.stft_detrend(x, None, p0, p1, k_offset=k_offset,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zuber/git/venv/lib/python3.12/site-packages/scipy/signal/_short_time_fft.py", line 844, in stft_detrend
    S[..., :, p_] = self._fft_func(x_ * self.win.conj())
                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zuber/git/venv/lib/python3.12/site-packages/scipy/signal/_short_time_fft.py", line 1583, in _fft_func
    return fft_lib.rfft(x, n=self.mfft, axis=-1)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zuber/git/venv/lib/python3.12/site-packages/scipy/fft/_backend.py", line 28, in __ua_function__
    return fn(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^
  File "/home/zuber/git/venv/lib/python3.12/site-packages/scipy/fft/_basic_backend.py", line 72, in rfft
    return _execute_1D('rfft', _pocketfft.rfft, x, n=n, axis=axis, norm=norm,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zuber/git/venv/lib/python3.12/site-packages/scipy/fft/_basic_backend.py", line 28, in _execute_1D
    return pocketfft_func(x, n=n, axis=axis, norm=norm,
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/zuber/git/venv/lib/python3.12/site-packages/scipy/fft/_pocketfft/basic.py", line 53, in r2c
    raise TypeError("x must be a real sequence")
TypeError: x must be a real sequence

SciPy/NumPy/Python version and system information

Python 3.12.1 (main, Dec 10 2023, 15:16:41) [GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys, scipy, numpy; print(scipy.__version__, numpy.__version__, sys.version_info); scipy.show_config()
1.12.0 1.26.3 sys.version_info(major=3, minor=12, micro=1, releaselevel='final', serial=0)
/home/zuber/git/venv/lib/python3.12/site-packages/scipy/__config__.py:154: UserWarning: Install `pyyaml` for better output
  warnings.warn("Install `pyyaml` for better output", stacklevel=1)
{
  "Compilers": {
    "c": {
      "name": "gcc",
      "linker": "ld.bfd",
      "version": "10.2.1",
      "commands": "cc"
    },
    "cython": {
      "name": "cython",
      "linker": "cython",
      "version": "3.0.8",
      "commands": "cython"
    },
    "c++": {
      "name": "gcc",
      "linker": "ld.bfd",
      "version": "10.2.1",
      "commands": "c++"
    },
    "fortran": {
      "name": "gcc",
      "linker": "ld.bfd",
      "version": "10.2.1",
      "commands": "gfortran"
    },
    "pythran": {
      "version": "0.15.0",
      "include directory": "../../tmp/pip-build-env-tfqmvy7q/overlay/lib/python3.12/site-packages/pythran"
    }
  },
  "Machine Information": {
    "host": {
      "cpu": "x86_64",
      "family": "x86_64",
      "endian": "little",
      "system": "linux"
    },
    "build": {
      "cpu": "x86_64",
      "family": "x86_64",
      "endian": "little",
      "system": "linux"
    },
    "cross-compiled": false
  },
  "Build Dependencies": {
    "blas": {
      "name": "openblas",
      "found": true,
      "version": "0.3.21.dev",
      "detection method": "pkgconfig",
      "include directory": "/usr/local/include",
      "lib directory": "/usr/local/lib",
      "openblas configuration": "USE_64BITINT= DYNAMIC_ARCH=1 DYNAMIC_OLDER= NO_CBLAS= NO_LAPACK= NO_LAPACKE= NO_AFFINITY=1 USE_OPENMP= HASWELL MAX_THREADS=2",
      "pc file directory": "/usr/local/lib/pkgconfig"
    },
    "lapack": {
      "name": "openblas",
      "found": true,
      "version": "0.3.21.dev",
      "detection method": "pkgconfig",
      "include directory": "/usr/local/include",
      "lib directory": "/usr/local/lib",
      "openblas configuration": "USE_64BITINT= DYNAMIC_ARCH=1 DYNAMIC_OLDER= NO_CBLAS= NO_LAPACK= NO_LAPACKE= NO_AFFINITY=1 USE_OPENMP= HASWELL MAX_THREADS=2",
      "pc file directory": "/usr/local/lib/pkgconfig"
    },
    "pybind11": {
      "name": "pybind11",
      "version": "2.11.1",
      "detection method": "config-tool",
      "include directory": "unknown"
    }
  },
  "Python Information": {
    "path": "/opt/python/cp312-cp312/bin/python",
    "version": "3.12"
  }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    defectA clear bug or issue that prevents SciPy from being installed or used as expectedscipy.signal

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions