- iOS 13.0+
- Xcode 11.0+
Accelerate’s vDSP module provides functions to perform discrete and fast Fourier transforms (FFTs) on 1D vectors and 2D matrices containing complex numbers. If you want to perform a similar transform on a vector of real numbers, vDSP includes discrete cosine transforms (DCTs).
FFTs and DCTs decompose a signal into its frequency components (known as the frequency domain representation of the signal), and the inverse transform rebuilds a signal from the frequency components.
By zeroing low-amplitude data, such as noise, from the frequency domain data, you can reconstruct a signal, leaving only its dominant frequencies. Meaningful signals that you’re trying to isolate tend to have their energy packed at a few frequencies. Noise, however, has its energy more uniformly spread across the frequency spectrum (that’s what makes it noise). If you zero out low-amplitude frequency components, you can eliminate much of the noise from the spectrum.
This sample walks you through the steps for extracting a signal from noise:
Creating a signal from composite cosine waves and adding random noise to it
Performing a forward DCT on the signal
Zeroing the frequency domain data where the value is less than a specified threshold
Rebuilding the signal from the frequency domain data using an inverse DCT
Generate the Test Signal
Build the test signal from a series of cosine waves, stored as 1024 samples in an array of single-precision values:
The signal function generates a sample at each data point:
The values generated by this code return a signal like the one in the image below:
Adding noise to the signal makes it unrecognizable, and it’s impossible to hear the original tones:
Prepare the DCT Setups
Create setup objects that contain all the information required to perform the forward and inverse DCT operations. Creating these setup objects can be expensive, so do it only once—for example, when your app is starting—and reuse them.
The forward transform is a type II DCT:
The inverse transform is a type III DCT:
Perform the DCT
transform(_:) function to perform the DCT. This function requires the array containing the source signal and returns the frequency domain data:
The following visualization of the frequency domain data shows the component cosine parts. The
cos(phase * 1) * 1 component is on the left, and
cos(phase * 16) * 1 is on the right:
The frequency domain visualization of the noisy signal shows the dominant frequencies with the noise spread evenly throughout the frequency range. The sample zeroes the low-amplitude data to generate the noise-free signal.
Apply a Threshold to the Amplitude Data
Remove the noise from the signal by zeroing all values in the frequency domain data that are below a specified threshold.
threshold(_: function sets all values in the
forward array that fall below the threshold to 0:
Recreate the Signal
Use an inverse DCT to generate a new signal using the cleaned-up frequency domain data:
Now scale the inverse DCT. The scaling factor for the forward transform is 2, and the scaling factor for the inverse transform is the number of samples (in this case, 1024). Use
divide(_: to divide the inverse DCT result by
count / 2 to return a signal with the correct amplitude.