Untitled

Housekeeping

close all force; clear; clc; s = tf('s');

Convolution is a key mathematical concept both in dynamics and signal analysis, but it's rarely explained from an intuitive perspective. It's easy to look up the definition as

but what does this MEAN?

Before we answer that question, I would like to start with a familiar concept, the moving average. Consider the below signal, its moving average, and the convolution of the original signal with the "kernal" for a moving average.

n = 50;
kernal = ones(1,n);
 
signal = [zeros(1,200) ones(1,200) 2*ones(1,200) 0.5*ones(1,200) zeros(1,100)];
moving_average = movmean(signal, n);
convolution = (1/n)*conv(signal, kernal, 'same'); % the 1/n term is necessary to approximate a continous convolution
 
f = figure(); f.Position = [0,0,1800,500];
 
subplot(1,3,1)
stairs(signal);
title('original signal');
xlim([0, length(signal)]); ylim([min(signal), 1.2*max(signal)]);
 
subplot(1,3,2)
stairs(moving_average);
title('moving average');
xlim([0, length(signal)]); ylim([min(signal), 1.2*max(signal)]);
 
subplot(1,3,3)
stairs(convolution);
title('kernal convolution');
xlim([0, length(signal)]); ylim([min(signal), 1.2*max(signal)]);

Purely from observation it appears that the moving average, and the convolution of the signal with the moving average kernal are precisely the same thing (although slightly shifted in time)! In fact, convolution can be considered a generalizaton of the moving average!

This, I have found, is the most intuitive way of understanding what a convolution is really doing. In convoling two signals, we simply consider one of them to be a kernal and compute the generalized "moving average". The convolution in this understanding is essentially a "weighted moving average" of two signals.

To drive the point home, let us consider a more general example using the above signal convolved with a ramp function.

t = 1:1:length(signal);
l = 200;
ramp = [zeros(1,l) (2/l)*t(1,1:(l)) zeros(1,l)];
 
convolution2 = (1/l).*conv(signal, ramp, 'same'); % the 1/l term is necessary to approximate a continous convolution
 
f = figure(); f.Position = [0,0,1800,500];
 
subplot(1,3,1)
stairs(signal);
title('original signal');
xlim([0, length(signal)]); ylim([min(signal), 1.2*max(signal)]);
 
subplot(1,3,2)
stairs(ramp)
title('ramp signal');
xlim([0, length(signal)]); ylim([min(signal), 1.2*max(signal)]);
 
subplot(1,3,3)
stairs(convolution2);
title('kernal convolution');
xlim([0, length(signal)]); ylim([min(signal), 1.2*max(signal)]);

Understanding convolution this way seems to make a lot of sense when you consider that the dynamics of systems and signals is not clean, and the full response of their interactions will be the sum of all possible overlaps between the two responses/signals. Some responses may be shifted forward or backward [relatively] in time, or be returned backwards (such as a signal hitting the end of a wire and returning backwards).

Thus the convolution, which represents the cumulative time-domain interaction between two system responses or signals, is nothing more than a weighted-moving-average between the two signals!!!