且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

python scipy.signal.peak_widths -->绝对高度?(fft -3dB 阻尼)

更新时间:2023-02-26 18:35:13

In case this is still relevant to you, you can use scipy.signal.peak_widths "as is" to achieve what you want by passing in modified prominence_data. Based on your own answer:

import numpy as np
from scipy.signal import find_peaks, peak_prominences, peak_widths

# Create sample data
x = np.linspace(0, 6 * np.pi, 1000)
x = np.sin(x) + 0.6 * np.sin(2.6 * x)

# Find peaks
peaks, _ = find_peaks(x)
prominences, left_bases, right_bases = peak_prominences(x, peaks)

As stated in peak_widths's documentation the height at which the width is measured is calculated as h_eval = h_peak - prominence * relative_height

We can control the latter two variables through the parameters prominence_data and rel_height. So instead of passing in the calculated prominence which differs for each peak we can create an array where all values are the same and use that to create an absolute height:

# Create constant offset as a replacement for prominences
offset = np.ones_like(prominences)

# Calculate widths at x[peaks] - offset * rel_height
widths, h_eval, left_ips, right_ips = peak_widths(
    x, peaks, 
    rel_height=1,
    prominence_data=(offset, left_bases, right_bases)
)

# Check that h_eval is 1 everywhere
np.testing.assert_equal(x[peaks] - h_eval, 1)

# Visualize result
import matplotlib.pyplot as plt
plt.plot(x)
plt.plot(peaks, x[peaks], "x")
plt.hlines(h_eval, left_ips, right_ips, color="C2")
plt.show()

As you can see the width is evaluated for each peak at the same constant offset of 1. By using the original left_bases and right_bases as provided by peak_prominences we are limiting the maximal measured width (e.g. see peaks at 299 and 533). If you want to remove that limitation you must create these arrays yourself.