Scipy 1.9.3中sosfilt报错ValueError:ndarray非C连续
问题:Scipy sosfilt 报错 ValueError: ndarray is not C-contiguous
使用scipy=1.9.3的sosfilt函数处理numpy=1.23.4数组时,触发ValueError: ndarray is not C-contiguous异常,最小复现代码如下:
import numpy as np from scipy.signal import sosfilt fs=48000 rng = np.random.default_rng() signal = rng.normal(size=(fs)) b_0k = [1.01589602025559, 0.958943219304445, 0.961371976333197, 2.22580350360974, 0.471735128494163, 0.115267139824401, 0.988029297230954, 1.95223768730136] b_1k = [-1.92529887777608, -1.80608801184949, -1.76363215433825, -1.43465048479216, -0.366091796830044, 0.0, -1.91243380293387, 0.162319983017519] b_2k = [0.922118060364679, 0.876438777856084, 0.821787991845146, -0.498204282194628, 0.244144703885020, -0.115267139824401, 0.926131550180785, -0.667994113035186] a_0k = np.ones(len(b_0k)) a_1k = [-1.92529887777608, -1.80608801184949, -1.76363215433825, -1.43465048479216, -0.366091796830044, -1.79600256669201, -1.91243380293387, 0.162319983017519] a_2k = [0.938014080620272, 0.835381997160530, 0.783159968178343, 0.727599221415107, -0.284120167620817, 0.805837815618546, 0.914160847411739, 0.284243574266175] sos = np.array([b_0k, b_1k, b_2k, a_0k, a_1k, a_2k]).T signalFiltered = sosfilt(sos, signal, axis=0)
执行后报错信息:
signalFiltered = sosfilt(sos, signal, axis=0) Traceback (most recent call last): Cell In[102], line 1 signalFiltered = sosfilt(sos, signal, axis=0) File C:\ProgramData\Miniconda3\envs\devenv\lib\site-packages\scipy\signal\_signaltools.py:4247 in sosfilt _sosfilt(sos, x, zi) File _sosfilt.pyx:81 in scipy.signal._sosfilt._sosfilt File stringsource:660 in View.MemoryView.memoryview_cwrapper File stringsource:350 in View.MemoryView.memoryview.__cinit__ ValueError: ndarray is not C-contiguous
但检查signal的flags显示其是C连续的:
C_CONTIGUOUS : True F_CONTIGUOUS : True OWNDATA : True WRITEABLE : True ALIGNED : True WRITEBACKIFCOPY : False
导入WAV文件的信号也出现相同错误,未找到该函数的已知问题。
原因分析与解决方法
核心原因
报错的根源不在signal数组,而是**sos数组的内存连续性问题**:
- 创建
sos时使用了.T转置,转置后的numpy数组默认是**Fortran连续(F-contiguous)**而非C连续(C-contiguous)。 sosfilt的底层Cython实现要求输入的sos数组必须是C连续的,否则会触发内存视图初始化失败的异常,且报错信息指向不够准确,容易误导开发者认为是signal的问题。
验证方法
打印sos的flags即可确认:
print(sos.flags)
输出会显示C_CONTIGUOUS : False,F_CONTIGUOUS : True。
解决方法
方法1:将sos转换为C连续数组
使用np.ascontiguousarray()强制转换sos的内存布局:
sos = np.ascontiguousarray(np.array([b_0k, b_1k, b_2k, a_0k, a_1k, a_2k]).T)
方法2:直接按C连续方式构建sos
调整数组创建顺序,避免转置操作,直接按每个二阶节的[b0, b1, b2, a0, a1, a2]顺序组合:
# 逐个构建二阶节 sos_list = [] for b0, b1, b2, a0, a1, a2 in zip(b_0k, b_1k, b_2k, a_0k, a_1k, a_2k): sos_list.append([b0, b1, b2, a0, a1, a2]) sos = np.array(sos_list)
这样构建的sos天然是C连续的,不会触发异常。
内容的提问来源于stack exchange,提问作者Mike
相关产品推荐
相关产品推荐

