简体   繁体   中英

matlab convolution “same” to numpy.convolve

I noticed that when I use conv(a, b, 'same') in matlab, it would return say M of length 200, but when I use numpy.convolve(a, b, 'same') it would return N of length 200, but shifted by one element compared to M (N[1:] would be the same as M[0:-1] and M[-1] would not be in N, N[0] not in M), how can I fix this?

I can cut off the first element of N, but is there a way I can get the last element of M without going through some hassles?

My guess is that the length of the shorter input array is even. In this case, there is an ambiguity in how it should be handled when the method is "same". Apparently Matlab and numpy adopted different conventions.

There is an example of the use of the 'same' method on the Matlab documentation web page ( http://www.mathworks.com/help/matlab/ref/conv.html ):

> u = [-1 2 3 -2 0 1 2];
> v = [2 4 -1 1];
> w = conv(u,v,'same')

w =

    15     5    -9     7     6     7    -1

The first term, 15, is (1)*(0) + (-1)*(-1) + (4)*(2) + (2)*(3) , and the last term, -1, is (1)*(1) + (-1)*(2) + (4)*(0) + (2)*(0) . You can interpret that as padding u to be [0 -1 2 3 -2 0 1 2 0 0], and then using the 'valid' method.

With numpy:

In [24]: u
Out[24]: array([-1,  2,  3, -2,  0,  1,  2])

In [25]: v
Out[25]: array([ 2,  4, -1,  1])

In [26]: np.convolve(u, v, 'same')
Out[26]: array([ 0, 15,  5, -9,  7,  6,  7])

The first term, 0, is (1)*(0) + (-1)*(0) + (4)*(-1) + (2)*(2) , and the last term, 7, is (1)*(0) + (-1)*(1) + (4)*(2) + (2)*(0) . That result can be interpreted as padding u to be [0, 0, -1, 2, 3, -2, 0, 1, 2, 0] and then using the 'valid' method.

By thinking about the 'same' method as being equivalent to padding the longer argument with p zeros (where p is one less than the length of the shorter input) and then applying the 'valid' method, you can see that when p is odd (ie the shorter length is even), a choice is required for which end gets the extra 0. Matlab and numpy use different choices.

To implement the Matlab version of the 'same' method, you could do the padding yourself and use the 'valid' method with np.convolve . For example,

In [45]: npad = len(v) - 1

In [46]: u_padded = np.pad(u, (npad//2, npad - npad//2), mode='constant')

In [47]: np.convolve(u_padded, v, 'valid')
Out[47]: array([15,  5, -9,  7,  6,  7, -1])

Or you could apply the 'full' method, and then slice out the part that is equivalent to Matlab's 'same' method:

In [62]: npad = len(v) - 1

In [63]: full = np.convolve(u, v, 'full')

In [64]: first = npad - npad//2

In [65]: full[first:first+len(u)]
Out[65]: array([15,  5, -9,  7,  6,  7, -1])

Other implementations are possible. Which one to use depends on how much you want to avoid extra copying, extra memory use and extra computation.

If the shorter input array has an odd length, the results in Matlab and numpy should be the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM