n维数组开窗函数的一般化

时间:2018-11-27 10:14:18

标签: python python-3.x multidimensional-array windowing

我有a个n维数组,我想对其应用开窗函数。简而言之,我需要为每个维度构造一个window函数并将其乘以a数组。例如,我首先为第一个维度构造window函数,将其堆叠为其余维度,然后将其点对乘以数组a。我依次对所有数组维执行此操作。

我能够通过在条件结构(例如if a.ndim == 1: ... elif a.ndim == 2: ...等)中考虑数组的尺寸来做到这一点。这是具有非通用版本的MCVE可以做到的(例如1D和3D阵列):

import numpy as np
import scipy.signal as signal

def window_ndim(a, wfunction):
    """
    Performs an in-place windowing on N-dimensional data.
    This is done to mitigate boundary effects in the FFT.
    :param a: Input data to be windowed, modified in place.
    :param wfunction: 1D window generation function. Example: scipy.signal.hamming
    :return: windowed a
    """
    if a.ndim == 1:
        return a * wfunction(len(a))
    elif a.ndim == 2:
        window0 = wfunction(a.shape[0])
        window1 = wfunction(a.shape[1])
        window0 = np.stack([window0] * a.shape[1], axis=1)
        window1 = np.stack([window1] * a.shape[0], axis=0)
        a *= window0*window1
        return a
    elif a.ndim == 3:
        window0 = wfunction(a.shape[0])
        window1 = wfunction(a.shape[1])
        window2 = wfunction(a.shape[2])
        window0 = np.stack([window0] * a.shape[1], axis=1)
        window0 = np.stack([window0] * a.shape[2], axis=2)
        window1 = np.stack([window1] * a.shape[0], axis=0)
        window1 = np.stack([window1] * a.shape[2], axis=2)
        window2 = np.stack([window2] * a.shape[0], axis=0)
        window2 = np.stack([window2] * a.shape[1], axis=1)
        a *= window0*window1*window2
        return a
    else: raise ValueError('Wrong dimensions')

np.random.seed(0)
np.set_printoptions(precision=2)
a = np.random.rand(2,3,4)
# [[[0.55 0.72 0.6  0.54]
#   [0.42 0.65 0.44 0.89]
#   [0.96 0.38 0.79 0.53]]

#  [[0.57 0.93 0.07 0.09]
#   [0.02 0.83 0.78 0.87]
#   [0.98 0.8  0.46 0.78]]]
a_windowed = window_ndim(a, signal.hamming)
# [[[2.81e-04 3.52e-03 2.97e-03 2.79e-04]
#   [2.71e-03 3.98e-02 2.70e-02 5.71e-03]
#   [4.93e-04 1.89e-03 3.90e-03 2.71e-04]]

#  [[2.91e-04 4.56e-03 3.50e-04 4.46e-05]
#   [1.29e-04 5.13e-02 4.79e-02 5.57e-03]
#   [5.01e-04 3.94e-03 2.27e-03 4.00e-04]]]

a = np.random.rand(10) # [0.12 0.64 0.14 0.94 0.52 0.41 0.26 0.77 0.46 0.57]
a_windowed = window_ndim(a, signal.hamming) # [0.01 0.12 0.07 0.73 0.51 0.4  0.2  0.36 0.09 0.05]

我的目标是为了概括此条件结构,因此我无需检查数组的维大小写。像for axis, axis_size in enumerate(a.shape):...之类的东西会更优雅,并说明一个n维数组,而不只是1、2或3维。我的尝试涉及到itertools.cycleitertools.islice包含

axis_idxs = np.arange(len(a.shape))
the_cycle = cycle(axis_idxs)
for axis, axis_size in enumerate(a.shape):
    axis_cycle = islice(the_cycle, axis, None)
    next_axis = next(axis_cycle)
    window = wfunction(axis_size)
    window = np.stack([window]*a.shape[next_axis], axis=next_axis)
    ...
    a *= window
return a

但是从来没有走太远,因为a.ndim == 3很难从第二个轴构造窗口函数,因为与其他窗口函数相反,我首先需要先堆叠第一个轴,然后堆叠最后一个轴和最后一个轴),通过循环axis_cycle在下一个轴上依次堆叠。

1 个答案:

答案 0 :(得分:0)

通过总是在第一维上开始堆叠$A [1] 1 2 3 $B [1] 4 5 6 数组并跳过自身轴上的堆叠操作,找到了一种将其概括为n维数组的方法。

window

对于问题1,2D或3D数组,这将返回与问题MCVE测试用例相同的结果。