In this article we will explain the effect of aliasing, why it occurs and what can be done against it. Aliasing can occur whenever a sample rate conversion or sampling of an analog signal is performed. Great care needs to be taken to inhibit aliasing, as otherwise the resulting signal can be severely degraded.
To motivate this, let us listen to the effect of aliasing for three different kinds of signals. We take an original audio signal and perform a downsampling operation, for example to save bandwidth. Naturally, higher frequencies in the signal cannot be represented accurately with a too low sampling rate, so the downsampled audio does not sound as "bright" as the original. Despite, the effect of aliasing even impedes the audio quality. For each signal, first the original signal is presented, followed by a downsampled version that contains aliasing. Finally, the downsampled audio that has been sent through an anti-aliasing filter to prevent aliasing is provided.
A speech signal (taken from LibriVox). Here, aliasing manifests itself as some extra noise, especially around characters like 's' and 'z'.
# to call this function, the code below needs to be executed before
presentAliasingAudio(data_voice, rate_voice, 6)
A piece of classical music. Here, the aliasing occurs as some extra high-frequency tones that do not belong to the original recording.
presentAliasingAudio(data_music, rate_music, 6)
Finally, consider an artificial signal, consisting of a chirp, i.e. a signal whose instantaneous frequency grows with time. Here, the aliasing shows up as a decrease in frequency once a particular frequency has been reached. When aliasing was removed by the anti-aliasing filter, this effect is almost completely removed and the signal just remains silent for higher frequencies.
Fs = 44100
t = np.arange(0, 10, 1/Fs)
f = 200
data_chirp = np.sin(2*np.pi*f*t*t)
rate_chirp = Fs
presentAliasingAudio(data_chirp, rate_chirp, 10)
Let us now try to explain what aliasing actually is and how we can understand it:
The word aliasing arises from the fact, that two different sine waves with frequencies $f_0, f_1$ generate the same samples, when $f_1=f_0+F_s$, where $F_s$ is the sampling frequency. I.e., from a sequence of samples of a sine wave it is impossible to tell, what the frequency of the original sine wave was. The sampling is ambiguous, and two different frequencies $f_0,f_1$ are mapped to the same sampling points.
We can show this in a simple form: Assume we have a function $x_0(t)=\sin(2\pi f_0 t)$ and a function $x_1(t)=\sin(2\pi (f_0+F_s)t)$ and we sample both signals with the sampling frequency $F_s$:
$$ \begin{align} x_1[n] &= \sin\left(2\pi f_0 \frac{n}{F_s}\right)\\ x_2[n] &= \sin\left(2\pi (f_0+F_s)\frac{n}{F_s}\right)\\&=\sin\left(2\pi f_0\frac{n}{F_s}+2\pi n\right)=\sin(2\pi f_0\frac{n}{F_s})=x_1[n] \end{align} $$As we see, both signals would create the same samples. We can also show another property, namely, that two sine waves of frequencies $f_0$ and $f_1=F_s-f_0$ also create the same samples up to a sign change:
$$ \begin{align} x_1[n] &= \sin\left(2\pi f_0 \frac{n}{F_s}\right)\\ x_2[n] &= \sin\left(2\pi (F_s-f_0)\frac{n}{F_s}\right)\\ &=\sin\left(-2\pi f_0\frac{n}{F_s}+2\pi n\right)=-x_1[n] \end{align} $$I.e. also the frequencies $f_0$ and $F_s-f_0$ correspond to the same sampling points.
To summarize, sine waves of frequencies $\pm f_0+nF_s, n\in\mathbb{Z}$ all create the same sampling points when sampled with sampling frequency $F_s$. Hence, when a sampled sequence appears to correspond to a sine wave with frequency $f_0$, it could also have been obtained from a sine wave with frequency $f_0+nF_s$ or $nF_s-f_0$. This effect, i.e. the mapping of different frequencies to the same sampling points, is called aliasing.
Let us look at this effect numerically. In the following, we create a sine wave of a given frequency $f_1$ and sample it with sampling frequency $F_s=5Hz$. Also, we draw one corresponding aliasing frequency to show that both sine waves would create the same sample points. Additionally, we plot the spectrum of the original signal and the aliased version.
Fs = 5 # the sampling frequency
F_plot = 100 # the frequency used for plotting the time-continuous curves
T = 2 # the time-span we'll cover
t = np.arange(0, T, 1/Fs) # the sample times
t_plot = np.arange(0, t.max(), 1/F_plot) # time instants for plotting
def showAlias(f1):
f2 = min(f1, Fs-f1) # determine the alias frequency
xt1 = lambda t: np.cos(2*np.pi*f1*t) # create both sine-functions
xt2 = lambda t: np.cos(2*np.pi*f2*t)
# plot the signals
plt.subplot(121)
plt.plot(t_plot, xt1(t_plot), 'b-', lw=2, label='input signal')
plt.stem(t, xt1(t), label='sampled points')
plt.plot(t_plot, xt2(t_plot), 'g-', label='after sampling')
plt.xlabel('$t$'); plt.ylabel('$x(t), x[n]$')
# plot the spectrum of the signals
t_freq = np.arange(0, 20*T, 1/F_plot)
x1 = xt1(t_freq)
x2 = xt2(t_freq)
X1 = np.fft.fftshift(np.fft.fft(x1, 8*len(x1))) / len(x1)
X2 = np.fft.fftshift(np.fft.fft(x2, 8*len(x1))) / len(x2)
f = np.linspace(-F_plot/2, F_plot/2, len(X1), endpoint=False)
plt.subplot(122)
plt.plot(f, abs(X1), lw=2, label='input')
plt.plot(f, abs(X2), label='after sampling')