ThinkDSP
This notebook contains code examples from Chapter 6: Discrete Cosine Transform
Copyright 2015 Allen Downey
Synthesis
The simplest way to synthesize a mixture of sinusoids is to add up sinusoid signals and evaluate the sum.
Here's an example that's a mixture of 4 components.
We can express the same process using matrix multiplication.
And it should sound the same.
And we can confirm that the differences are small.
Analysis
The simplest way to analyze a signal---that is, find the amplitude for each component---is to create the same matrix we used for synthesis and then solve the system of linear equations.
Using the first 4 values from the wave array, we can recover the amplitudes.
What we have so far is a simple version of a discrete cosine tranform (DCT), but it is not an efficient implementation because the matrix we get is not orthogonal.
To check whether a matrix is orthogonal, we can compute , which should be the identity matrix:
But it's not, which means that this choice of M is not orthogonal.
Solving a linear system with a general matrix (that is, one that does not have nice properties like orthogonality) takes time proportional to . With an orthogonal matrix, we can get that down to . Here's how:
Now is (approximately), so M is orthogonal except for a factor of two.
And that means we can solve the analysis problem using matrix multiplication.
It works:
DCT
What we've implemented is DCT-IV, which is one of several versions of DCT using orthogonal matrices.
We can check that it works:
DCT and inverse DCT are the same thing except for a factor of 2.
And it works:
Dct
thinkdsp
provides a Dct
class that encapsulates the DCT in the same way the Spectrum class encapsulates the FFT.
To make a Dct object, you can invoke make_dct
on a Wave.
Dct provides make_wave
, which performs the inverse DCT.
The result is very close to the wave we started with.
Negating the signal changes the sign of the DCT.
Adding phase offset has the same effect.