Delay, gain, and mix
Contents
3.1. Delay, gain, and mix#
The term convolution gets thrown around quite a bit in signal processing, and it can sound more complicated than it really is. In the simplest terms, convolution consists of three basic operations:
delaying a signal by some fixed number of samples,
applying a gain to the delayed signal (changing its amplitude),
mixing (adding) the delayed and gained signal with the original signal.
Before we get into the equations in full generality, let’s work through a couple of simple examples.
3.1.1. Example 1: delay and mix#
As a first example, let’s consider the case where there is no gain applied to either the delayed or original signal, so we only have to worry about delay and mixing.
If our input signal is
That is, the
Fig. 3.1 demonstrates this process for an input
Fig. 3.1 Top: a signal
Before we move on, there are already a couple of observations we can make.
First, the output
Second, the first few samples of
This period of time corresponding to
Having defined the behavior for the warm-up phase, we can now translate the equation for
# Make an output buffer the same size as the input
N = len(x)
y = np.zeros(N)
# Set our delay
k = 3
for n in range(N):
if n >= k:
y[n] = x[n] + x[n-k]
else:
y[n] = x[n]
A complete code example is given below.
import numpy as np
import scipy.signal
from IPython.display import Audio
# Our input will be a 100Hz square wave for one second, sampled at 8 KHz.
fs = 8000
duration = 1
f0 = 100
times = np.arange(duration * fs) / fs
x = scipy.signal.square(2 * np.pi * f0 * times)
# The delay will be 8 samples for this example
k = 8
# Try changing k to see how it affects the sound of the output.
# Can you find a setting of k that makes the output silent?
# Initialize the output buffer to match the shape of x
N = len(x)
y = np.zeros(N)
# Compute y
for n in range(N):
if n >= k:
y[n] = x[n] + x[n-k]
else:
# At the start of the signal, x[n-k] doesn't exist yet
# so pretend that x[n-k] = 0
y[n] = x[n]
display('Input x[n]')
display(Audio(data=x, rate=fs))
display('Output y[n] = x[n] + x[n-{}]'.format(k))
display(Audio(data=y, rate=fs))
'Input x[n]'
'Output y[n] = x[n] + x[n-8]'
3.1.2. Example 2: delay + gain#
In this example, we’ll mix two different delays, each with a different gain coefficient:
Here, the delay-0 signal (
Fig. 3.2 Top: an input signal
Note that in this example, the gain coefficients can be both positive or negative.
The code below implements filter on the same square wave as the previous example. Try modifying the gain coefficients below. How does the sound change if you make both coefficients positive? Or both negative?
import numpy as np
import scipy.signal
from IPython.display import Audio
# Our input will be a 100Hz square wave for one second, sampled at 8 KHz.
fs = 8000
duration = 1
f0 = 100
times = np.arange(duration * fs) / fs
x = scipy.signal.square(2 * np.pi * f0 * times)
# Initialize the output buffer to match the shape of x
N = len(x)
y = np.zeros(N)
# Compute y
for n in range(N):
if n >= 1:
y[n] = 0.5 * x[n] - 0.5 * x[n-1]
else:
# At the start of the signal, x[n-1] doesn't exist yet
# so pretend that x[n-k] = 0
y[n] = 0.5 * x[n]
display('Input x[n]')
display(Audio(data=x, rate=fs))
display('Output y[n] = 1/2 * x[n] - 1/2 * x[n-1]')
display(Audio(data=y, rate=fs))
'Input x[n]'
'Output y[n] = 1/2 * x[n] - 1/2 * x[n-1]'