30个CSV文件绘制直方图、高斯拟合求峰均值标准差及代码问题咨询
多峰高斯拟合与直方图绘制完整解决方案
报错修复
你遇到的np.arange相关报错是因为Python内置min()/max()无法直接处理多维numpy数组,np.all()为逻辑判断函数,仅返回单个布尔值,完全不适合用来取极值。正确写法如下:
import numpy as np # numpy的全局极值函数会自动展平数组,读取所有元素的最大/最小值 Xs = np.arange(np.min(voltages), np.max(voltages), 0.05)
直方图逻辑校验
第三个峰幅度过低可按以下两点排查:
- 调整
np.histogram的bin参数:bin数量过少会合并相邻峰,过多会拆分低幅峰为离散碎点,优先用bins='auto'让numpy自动计算最优bin数 - 调整savgol_filter平滑参数:窗口长度必须为奇数,且远小于峰的宽度,窗口过大会直接抹平低幅峰,常规三峰场景设置窗口长度为5、多项式阶数为2即可:
from scipy import signal counts, bins = np.histogram(voltages, bins='auto') bin_centers = (bins[:-1] + bins[1:]) / 2 smooth_counts = signal.savgol_filter(counts, window_length=5, polyorder=2)
绘图标签不显示修复
设置label后未显示的核心原因是未调用图例渲染函数,完整绘图流程参考:
import matplotlib.pyplot as plt plt.hist(voltages.flatten(), bins='auto', label='原始直方图') plt.plot(bin_centers, smooth_counts, c='orange', label='平滑后直方图') plt.xlabel('电压(V)') plt.ylabel('频数') # 必须添加该行才能渲染所有label plt.legend() plt.show()
三峰高斯拟合实现
直接拼接单高斯函数即可得到多峰拟合函数,用scipy的curve_fit工具完成拟合,参考代码:
from scipy.optimize import curve_fit # 单高斯函数:A为振幅,mu为均值,sigma为标准差 def gauss(x, A, mu, sigma): return A * np.exp(-(x - mu)**2 / (2 * sigma**2)) # 三峰高斯函数为三个单高斯的叠加 def tri_gauss(x, A1, mu1, sigma1, A2, mu2, sigma2, A3, mu3, sigma3): return gauss(x, A1, mu1, sigma1) + gauss(x, A2, mu2, sigma2) + gauss(x, A3, mu3, sigma3) # 设置拟合初值,根据直方图的峰位、峰高、峰宽手动调整,初值越接近真实值拟合成功率越高 # 初值顺序:A1, mu1, sigma1, A2, mu2, sigma2, A3, mu3, sigma3 p0 = [100, 1, 0.2, 80, 2, 0.2, 30, 3, 0.2] # 执行拟合 popt, pcov = curve_fit(tri_gauss, bin_centers, smooth_counts, p0=p0)
拟合输出的popt数组已包含所有目标参数:
- 三个峰的均值依次为
popt[1]、popt[4]、popt[7] - 三个峰的标准差依次为
popt[2]、popt[5]、popt[8]
峰参数获取方案
优先通过高斯拟合结果获取峰均值和标准差,精度远高于直接定位局部最大值,可有效规避噪声干扰。如果需要直接定位峰位,可使用scipy的峰值检测工具:
from scipy.signal import find_peaks # height为最小峰高阈值,distance为相邻峰最小间隔,根据实际数据调整 peaks, _ = find_peaks(smooth_counts, height=20, distance=10) # peaks对应的bin中心坐标即为峰位 peak_centers = bin_centers[peaks]
多峰单独标准差计算
若通过高斯拟合已得到sigma参数可直接使用,无需额外计算。如果需要用原始数据单独计算每个峰的标准差,可按峰位切分对应区间的数据后再调用np.std:
# 以第一个峰在1附近为例,切分0.8~1.2区间内的原始电压数据 peak1_data = voltages[(voltages > 0.8) & (voltages < 1.2)] peak1_std = np.std(peak1_data)
内容的提问来源于stack exchange,提问作者Physics World
相关产品推荐
相关产品推荐

