Matlab中的matlab filtfilt()函数实现

时间:2014-12-01 01:56:01

标签: java c++ matlab signal-processing

是否有人尝试在Java (或至少在C ++中)实现matlab的filtfilt()函数?如果你们有一个算法,这将是非常有帮助的。

2 个答案:

答案 0 :(得分:5)

Here是我在MATLAB中实现的filtfilt算法的C ++实现。希望这会对你有所帮助。

答案 1 :(得分:3)

好的,我知道这个问题很古老,但是也许我会对想问 (jQuery('#loginModal') as ModalElement).modal('show'); 实际工作的其他人有所帮助。

尽管从文档中可以明显看出filtfilt进行了正向(即零相位)过滤,但是对我来说,它不是如何处理 padding 初始条件

由于我在此处(其他地方)找不到其他答案,没有关于filtfilt的这些实现细节的足够信息,因此我实现了filtfilt'的简化版本s Python,基于其来源和文档(因此,不是scipy.signal.filtfilt也不是Java,而是C++)。我相信Python版本works the same的方式与scipy一样。

为简单起见,以下代码专门针对第二阶IIR filter编写,并且假定系数矢量Matlaba已知(例如,从{{1 }}或calculated by hand)。

它使用b长度scipy.signal.butter的填充来匹配filtfilt的默认行为,该填充在正向传递之前应用。可以使用odddocs)中的方法找到初始状态。

免责声明:此代码仅用于提供对3 * max(len(a), len(b))某些实现细节的深入了解,因此目标是清晰而不是计算效率/性能。 scipy.signal.lfilter_zi的实现要快得多(例如,根据我的系统上进行的快速而肮脏的filtfilt测试,速度提高了100倍。

scipy.signal.filtfilt

请注意,此实现不需要不需要timeit。此外,通过写出import numpy def custom_filter(b, a, x): """ Filter implemented using state-space representation. Assume a filter with second order difference equation (assuming a[0]=1): y[n] = b[0]*x[n] + b[1]*x[n-1] + b[2]*x[n-2] + ... - a[1]*y[n-1] - a[2]*y[n-2] """ # State space representation (transposed direct form II) A = numpy.array([[-a[1], 1], [-a[2], 0]]) B = numpy.array([b[1] - b[0] * a[1], b[2] - b[0] * a[2]]) C = numpy.array([1.0, 0.0]) D = b[0] # Determine initial state (solve zi = A*zi + B, see scipy.signal.lfilter_zi) zi = numpy.linalg.solve(numpy.eye(2) - A, B) # Scale the initial state vector zi by the first input value z = zi * x[0] # Apply filter y = numpy.zeros(numpy.shape(x)) for n in range(len(x)): # Determine n-th output value (note this simplifies to y[n] = z[0] + b[0]*x[n]) y[n] = numpy.dot(C, z) + D * x[n] # Determine next state (i.e. z[n+1]) z = numpy.dot(A, z) + B * x[n] return y def custom_filtfilt(b, a, x): # Apply 'odd' padding to input signal padding_length = 3 * max(len(a), len(b)) # the scipy.signal.filtfilt default x_forward = numpy.concatenate(( [2 * x[0] - xi for xi in x[padding_length:0:-1]], x, [2 * x[-1] - xi for xi in x[-2:-padding_length-2:-1]])) # Filter forward y_forward = custom_filter(b, a, x_forward) # Filter backward x_backward = y_forward[::-1] # reverse y_backward = custom_filter(b, a, x_backward) # Remove padding and reverse return y_backward[-padding_length-1:padding_length-1:-1] 的解决方案并使用列表而不是numpy数组,可以轻松地使其适应于纯Python,甚至没有scipy。这甚至带来巨大的性能优势,因为在python循环中访问单个numpy数组元素比访问列表元素要慢得多。

此处的过滤器本身是通过简单的numpy循环实现的。它使用状态空间表示形式,因为无论如何它都用于确定初始条件(请参见zi)。我相信线性滤波器的实际Python实现(即scipy.signal.lfilter_zi)在scipy中会执行类似的操作,如here所示(感谢this answer )。

以下代码提供了(非常基本的)检查scipy.signal.sigtools._linear_filter输出和C输出是否相等的代码:

scipy

此基本比较得出的数字如下所示,对于这种特定情况(机器精度,我想是吗?),建议等于至少14位小数:

filtfilt scipy vs custom implementation