`output="complex"` for Welch method should only allow `average=None`

Đang mở Phù hợp với người mới
#14,495 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

@iis-MarkKuang đang làm issue này rồi.

Từ ngày 5/11/2026.

  • #14498 của @iis-MarkKuang — đang mở

Đánh giá

Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức phù hợp với người mới
74/100
Loại issue
Lỗi
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
python
Lĩnh vực
data

Hướng nghiên cứu

Bắt đầu bằng cách lần theo cách xử lý Welch của output="complex" và average trong epochs.compute_psd(), sau đó kiểm tra cách Spectrum.plot() chuyển đổi các hệ số thành công suất. Thêm kiểm tra để từ chối các giá trị average khác None khi đầu ra là số phức, đồng thời tìm các kiểm thử hiện có bao quát các chế độ đầu ra Welch và việc vẽ biểu đồ. Hoàn tất khi tổ hợp không hợp lệ phát sinh lỗi rõ ràng, còn average=None và đầu ra công suất vẫn giữ hành vi như mong đợi.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

BUG
Description of the problem

For Welch method, if average is requested with output="complex", segments are aggregated for complex coefficients, which can mess up the phase information in the resulting coefficients. Subsequently computing power from these coefficients gives very different results to if output="power" was used directly. This also affects the conversion to power from coefficients in Spectrum.plot().

Steps to reproduce
import numpy as np

import mne
from mne.time_frequency.psd import _median_biases

data_path = mne.datasets.sample.data_path()
raw = mne.io.read_raw_fif(
    data_path / "MEG" / "sample" / "sample_audvis_filt-0-40_raw.fif", verbose=False
)
raw.pick("eeg", exclude="bads").crop(tmax=60).load_data(verbose=False)
epochs = mne.make_fixed_length_epochs(raw, duration=4.0, preload=True, verbose=False)
kwargs = dict(method="welch", n_fft=128, verbose=False)  # 4 segments per epoch


def coefs_to_power(spectrum):
    """Convert complex Welch coefficients to one-sided power."""
    coefs = spectrum.get_data()
    freqs, sfreq = spectrum.freqs, spectrum.info["sfreq"]
    # double all bins except DC and Nyquist (scipy.signal.spectrogram does this for
    # mode="psd", but not for mode="complex")
    scale = np.where((freqs == 0) | np.isclose(freqs, sfreq / 2), 1.0, 2.0)
    if coefs.ndim == 4:  # unaggregated: (epoch, channel, freq, segment)
        scale = scale[:, np.newaxis]
    return (coefs * coefs.conj()).real * scale


for average in ("mean", "median"):
    power = epochs.compute_psd(output="power", average=average, **kwargs).get_data()

    # output="complex" with average!=None aggregates the complex coefficients across
    # segments, so power computed afterwards is wrong
    spec = epochs.compute_psd(output="complex", average=average, **kwargs)
    power_agg_first = coefs_to_power(spec)

    # correct: average=None, compute power per segment, then aggregate
    spec = epochs.compute_psd(output="complex", average=None, **kwargs)
    power_seg = coefs_to_power(spec)
    if average == "mean":
        power_agg_last = power_seg.mean(axis=-1)
    else:
        n_segments = power_seg.shape[-1]
        power_agg_last = (
            np.median(power_seg, axis=-1) / _median_biases(n_segments)[n_segments]
        )

    print(f"average={average!r}")
    for name, psd in (
        ("complex -> aggregate -> power", power_agg_first),
        ("complex -> power -> aggregate", power_agg_last),
    ):
        ratio = psd / power
        print(
            f"  {name}: ratio to output='power' median={np.median(ratio):.3f} "
            f"min={ratio.min():.3g} max={ratio.max():.3g} "
            f"allclose={np.allclose(psd, power, rtol=1e-6, atol=0)}"
        )
Link to data

No response

Expected results

average!=None with output="complex" is not allowed, as it gives invalid coefficients.

Actual results

Computing output="complex" with average!=None is allowed, and gives very different results when trying to compute power from these coefficients, compared to the proper approach of unaggregated coefficients → unaggregated power → aggregated power (which is what happens with output="power").

average='mean'
  complex -> aggregate -> power: ratio to output='power' median=0.131 min=2.06e-08 max=0.992 allclose=False
  complex -> power -> aggregate: ratio to output='power' median=1.000 min=1 max=1 allclose=True
average='median'
  complex -> aggregate -> power: ratio to output='power' median=0.326 min=9.42e-08 max=36.2 allclose=False
  complex -> power -> aggregate: ratio to output='power' median=1.000 min=1 max=1 allclose=True
Additional information

AI disclosure: Claude Opus 5.5 initially identified the problem, which I further investigated.

Ngôn ngữ chính
Python
Star
3.6k
Fork
1.6k
Merge trung bình
1 ngày 18 giờ
Pull request đã merge (30 ngày)
74

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của mne-tools/mne-python

Tất cả issue của mne-tools/mne-python

Issue tương tự

Thêm issue về Python

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.