Article

Resampling a Signal with Decimation

Reduce the sample rate of a signal, by specifying a decimation factor and applying a custom antialiasing filter.

Overview

vDSP provides functions for decimating a signal. A decimated signal has a lower sample rate compared to its original. Decimation can be advantageous when, for example, you are transmitting a signal, creating a visual representation of a large dataset, or reducing the memory overhead when processing data.

In the following pair of images, the original signal (at left) contains 1024 samples. After decimation by a factor of two, the result (at right) contains 512 samples.

Diagram showing two signals. The original signal is on the left. The decimated signal, on the right, has the same shape, but is half the width.

This article walks you through the following steps to decimate a signal:

  1. Create a composite sine wave to use as a signal.

  2. Define an antialiasing filter to control how the signal is resampled.

  3. Calculate the length of the destination array that receives the decimation result.

  4. Apply the decimation operation.

Create the Input Signal

For this example, create an array and populate it with a composite sine wave:

let inputLength = vDSP_Length(1024)

let inputSignal = (0 ..< inputLength).map {
    sin(Float($0) * 0.007) + sin(Float($0) * 0.03)
}

The following image shows a visualization of the values in inputSignal:

Diagram showing the original signal as a composite sine wave.

Define the Antialiasing Filter

The vDSP decimation function accepts a filter that controls how adjacent samples combine. Each decimated value is the sum of the combined original values multiplied by the corresponding filter value.

In this example, use the following code to create a filter containing [0.5, 0.5]:

let filterLength: vDSP_Length = 2
let filter = [Float](repeating: 1 / Float(filterLength),
                     count: Int(filterLength))

The resulting filter averages pairs of adjacent values in the original signal.

For the most complete result, set the filter length to the same value as the decimation factor, which indicates how much the original signal is decimated. For example, consider an input signal containing 18 values:

let originalSignal: [Float] = [10, 15, 20, 25, 50, 25, 20, 15, 10,
                               10, 15, 20, 25, 50, 25, 20, 15, 10]

The following images visualize the original and decimated signals, and illustrate the effects of different antialiasing filters. The original signal can be visualized as:

Diagram showing eighteen points, joined by lines. The lines form two peaks.

If you create a filter containing a single value [1.0] and a decimation factor of 2, you will only sample the even values of the original signal and will get a result that misses the second 50 at position 13, as shown below.

Diagram showing nine points, joined by lines. The lines form two peaks, but the peak on the right is truncated.

However, you can create a filter with two values, [0.5, 0.5], and it will consider all values in the original signal, illustrated below.

Diagram showing nine points, joined by lines. The lines form two fully-formed peaks.

Define the Output Length

The decimation result length is a function of the original signal length, the decimation factor, and the length of the filter. Use the following code to create a zero-filled array, suitable to receive the decimation result:

let n = vDSP_Length((inputLength - filterLength) / vDSP_Length(decimationFactor)) + 1

var outputSignal = [Float](repeating: 0,
                           count: Int(n))

Perform the Decimation

The vDSP_desamp(_:_:_:_:_:_:) function (and its double-precision equivalent vDSP_desampD(_:_:_:_:_:_:)) perform the decimation:

vDSP_desamp(inputSignal,
            decimationFactor,
            filter,
            &outputSignal,
            n,
            filterLength)

On return, outputSignal contains the result:

Diagram showing the decimated signal as a composite sine wave that is half the width of the original signal.

See Also

Signal Processing Essentials

Controlling vDSP Operations with Stride

Operate selectively on the elements of a vector at regular intervals.

Use Linear Interpolation to Construct New Data Points

Fill the gaps in arrays of numerical data using linear interpolation.

Using vDSP for Vector-based Arithmetic

Increase the performance of common mathematical tasks with vDSP vector-vector and vector-scalar operations.

vDSP

Perform basic arithmetic operations and common digital signal processing routines on large vectors.