Question: I am working on convolving chunks of a signal with a moving average type smoothing operation but having issues with the padding errors which affects downstream calculations. If plotted this is the issue that is caused on the chunk boundaires.  To fix this I am adding N samples from the previous chunk to the beginning of the array. The question is does the convolve operation below remove samples from the beginning or end of the original array? arr = np.array([0.9, 0.9, 0.9, 0.1, 0.1, 0.1, 1.0, 0.1, 0.1, 0.1, 0.9, 0.9, 0.9, ]) print(f"length input array {len(arr)}") result = np.convolve(arr, [1]*3, 'valid')/3 print(f"length result array {len(result)}") print(result) plt.plot(result)  I setup the above example to try to confirm adding samples to the beging of the array is the correct place but it did not help. The input length is 13, the output length is 11. With overlap the convolve looks like: result = np.convolve(np.concatenate(previous_samples[-2:], arr), [1]*3, 'valid')/3 

Answer: I assume (1) the reader has a basic understanding of what a convolution is and (2) a kernel with an odd number > 1 of elements is used. Short answer:  Use np.convolve(…, mode="valid").  Before convolving, pad your chunks  … at their start with the (len(kernel) - 1) / 2 last elements from the preceding chunk, … at their end with the (len(kernel) - 1) / 2 first elements from the following chunk,  where kernel refers to your sliding kernel ([1]*3 in your question).   Long answer: As convolution can be thought of as an operation with a sliding kernel, the question is, as you realized, what happens at the boundaries. The numpy.convolve() function has 3 modes to handle the boundaries, as explained there:  mode="valid" ensures that the sliding kernel never leaves the signal. This implies, however, that the result will have fewer elements than the signal; namely len(kernel) - 1 fewer elements. So, in case you have a signal of 100 elements and a kernel of 5 elements, your result will hold 100-(5-1)=96 elements. The question of where the operation "removes" the missing elements might be a bit misleading; however, one way to think of the result is having its values been written at the centers of the sliding kernel (which makes sense for a symmetric kernel of an odd number of elements, as is the case in your question), so with this interpretation one would have a symmetric removal of elements: (len(kernel) - 1) / 2 elements at the start, (len(kernel) - 1) / 2 elements at the end of the signal. We will see that this is a meaningful interpretation in the code example below. mode="same" ensures that the resulting signal has the same number of values as the input signal. This implies, however, that we have to "make up" values to counter the effect of having fewer elements that we saw with mode="valid". As a consequence, in this mode, the signal is padded with zeros – (len(kernel) - 1) / 2 both at the beginning and at the end – before the convolution operation. mode="full", finally, ensures that all potential combinations of overlap between the signal and the sliding kernel are produced. This implies that (a) we have to "make up" even more values and (b) that the result will be bigger than the input signal. The "made up" values are again zeros here, and the result will hold len(signal) + len(kernel) - 1 elements, thus 100+5-1=104 elements for the previous example.  If you process your signal in chunks, mode="valid" is the way to go: You can ensure that your resulting convolved chunks have the same lengths as the input chunks without the need to "make up" values (i.e. without the need for zero-padding), by padding with the trailing values from the preceding chunk and the leading values from the following chunk. This is true for all but the first and last chunk, in which cases you have to decide yourself how the boundary situation should be handled. In all other cases, pad with half of one less than the kernel length from the preceding and following chunks' values. The code below demonstrates that the described padding of chunks produces the exact same results as if not chunking the signal at all. Note that I shifted the resulting convolved signals in the plots by (len(kernel) - 1) / 2 values to account for the described missing values with mode="valid" at the very beginning of the signal. import matplotlib.pyplot as plt import numpy as np len_signal, len_kernel = 100, 5 num_chunks = 10 rand = np.random.default_rng(seed=42) signal = np.cumsum(rand.normal(size=len_signal)) kernel = np.ones(len_kernel) / len_kernel # Produce convolution result without chunking for reference signal_convolved = np.convolve(signal, kernel, mode="valid") # Split into chunks, then pad them: (1) start with `(len_kernel - 1) / 2` # last values from preceding chunk (except first chunk), (2) end with # `(len_kernel - 1) / 2` first values from following chunk (except last chunk) len_arm = (len_kernel - 1) // 2 # Length of a "kernel arm" chunks_convolved = [] for i, chunk in enumerate(chunks := np.split(signal, num_chunks)): p1 = [] if i == 0 else chunks[i - 1][-len_arm:] # Start padding p2 = [] if i == len(chunks) - 1 else chunks[i + 1][:len_arm] # End padding chunk_conv = np.convolve(np.r_[p1, chunk, p2], kernel, mode="valid") chunks_convolved = np.r_[chunks_convolved, chunk_conv] # Append assert np.allclose(signal_convolved, chunks_convolved) # Check: same result? # Show: convolved w/o chunking (left) vs chunked, padded, and convolved (right) x_c = np.arange(len(signal_convolved)) + len_arm # Right-shift conv. result plt.subplot(121) plt.plot(signal, "--"); plt.plot(x_c, signal_convolved); plt.title("no chunks") plt.subplot(122) plt.plot(signal, "--"); plt.plot(x_c, chunks_convolved); plt.title("chunks") plt.show()  As you can see (and as we checked with assert), both results are the same:  As a final side note: scipy's convolve1d() provides more options other than zero padding for handling the remaining boundary situation at the start and end of your total signal, and thus might be an alternative, depending on the use case.