You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

fftconvolve输出异常:卷积结果负区间出现非零概率密度问题

卷积概率分布后负区间出现非零值的解决方法

问题场景

我定义了两个概率分布:

  • 在区间[-0.05, 0)上概率密度为0
  • 在区间[0,1]上通过插值生成,实现代码如下:
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal

step = 1e-3
x = np.arange(-0.05, 1, step)

x_0minus = x[x<0]
x_0plus = x[x>0]

pdf1 = np.concatenate([np.repeat(0, len(x_0minus)), np.interp(x_0plus, [0, 0.08, 0.28], [0, 80, 0])])
pdf2 = np.concatenate([np.repeat(0, len(x_0minus)), np.interp(x_0plus, [0, 0.1, 0.3, 0.31], [60, 60, 60, 0])])

已通过以下代码绘制两个分布的参考图:

  • plt.scatter(x = x, y = pdf1)(对应Pdf1图像)
  • plt.scatter(x = x, y = pdf2)(对应Pdf2图像)

遇到的问题

使用fftconvolve对两个归一化后的分布做卷积时,结果在0以下的区间出现了非零概率密度,卷积代码如下:

res = signal.fftconvolve(pdf1 / pdf1.sum(), pdf2 / pdf2.sum(), 'same')
plt.scatter(x = x, y = res)

我希望**不将计算范围扩展到[-1,1]**的前提下解决这个问题,避免浪费计算资源。

原因分析

  1. FFT卷积的循环特性:fftconvolve基于FFT实现,FFT本质是循环卷积。当输入信号长度不足以覆盖线性卷积的有效范围时,循环卷积会产生混叠效应——原本应出现在正区间边缘的信号被“卷绕”到负区间,导致负区间出现非零值。
  2. 'same'模式的边界问题:使用'same'参数时,输出长度和输入一致,但FFT的循环特性会把输入的末尾与开头连接,相当于把负区间的0和正区间尾部错误地做了卷积计算。

解决方案

方法1:计算全长度卷积后截取有效范围

两个原始分布的最小值都是0,卷积结果的有效区间应为[0,2]。先计算全长度线性卷积,再截取原输入x对应的范围,同时将负区间值置0:

# 计算全长度线性卷积
full_conv = signal.fftconvolve(pdf1 / pdf1.sum(), pdf2 / pdf2.sum(), 'full')
# 生成卷积结果对应的x轴范围
x_full = np.arange(2*x[0], 2*x[-1]+step, step)
# 匹配原x的范围
mask = (x_full >= x[0]) & (x_full <= x[-1])
# 截取并修正负区间
res = full_conv[mask]
res[x_full[mask] < 0] = 0
# 绘图
plt.scatter(x = x, y = res)

方法2:最小化补零避免混叠

不需要扩展到[-1,1],只需给输入补足够的零,让FFT循环卷积长度等于线性卷积长度(len(pdf1) + len(pdf2) - 1),这样循环卷积等价于线性卷积,不会混叠。之后截取原x对应的范围:

# 计算需要补零的长度
pad_len = len(pdf1) + len(pdf2) - 1 - len(pdf1)
# 仅在尾部补零(负区间已为0)
pdf1_padded = np.pad(pdf1, (0, pad_len), mode='constant')
pdf2_padded = np.pad(pdf2, (0, pad_len), mode='constant')
# 计算卷积
full_conv = signal.fftconvolve(pdf1_padded / pdf1_padded.sum(), pdf2_padded / pdf2_padded.sum(), 'full')
# 生成对应x轴
x_full = np.arange(x[0], x[-1] + (len(pdf1_padded)-1)*step, step)
# 截取并修正负区间
mask = (x_full >= x[0]) & (x_full <= x[-1])
res = full_conv[mask]
res[x_full[mask] < 0] = 0
plt.scatter(x = x, y = res)

方法3:直接修正负区间值(简洁但精度有限)

如果只需要消除负区间的非零值,可直接将结果中x<0部分置0,再重新归一化:

res = signal.fftconvolve(pdf1 / pdf1.sum(), pdf2 / pdf2.sum(), 'same')
# 负区间置0
res[x < 0] = 0
# 重新归一化保证概率和为1
res = res / res.sum()
plt.scatter(x = x, y = res)

注意:这种方法只能修正表面问题,若混叠导致正区间结果偏差,无法解决卷积本身的计算误差,适合精度要求不高的场景。


内容的提问来源于stack exchange,提问作者matsuo_basho

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:12:59