Signal and image processing

This vignette is adapted from the official Armadillo documentation.

One-dimensional convolution

The conv() function performs a one-dimensional convolution of two vectors. The orientation of the result vector is the same as the orientation of the first input vector.

Usage:

vec conv(x, y, shape);

The shape argument is optional and can be one of the following:

  • "full": return the full convolution (default setting), with the size equal to x.n_elem + y.n_elem - 1.
  • "same": return the central part of the convolution, with the same size as vector x.

The convolution operation is also equivalent to finite impulse response (FIR) filtering.

Examples

[[cpp11::register]] list conv1_(const doubles& x, const doubles& y) {
  vec a = as_col(x);
  vec b = as_col(y);

  vec c = conv(a, b);
  vec d = conv(a, b, "same");

  writable::list out(2);
  out[0] = as_doubles(c);
  out[1] = as_doubles(d);

  return out;
}

Two-dimensional convolution

The conv2() function performs a two-dimensional convolution of two matrices. The orientation of the result matrix is the same as the orientation of the first input matrix.

Usage:

mat conv2(A, B, shape);

The shape argument is optional and can be one of the following:

  • "full": return the full convolution (default setting), with the size equal to size(A) + size(B) - 1.
  • "same": return the central part of the convolution, with the same size as matrix A.

Caveats

The implementation of 2D convolution in this version is preliminary.

Examples

[[cpp11::register]] list conv2_(const doubles_matrix<>& x,
  const doubles_matrix<>& y) {
  mat a = as_mat(x);
  mat b = as_mat(y);

  mat c = conv2(a, b);
  mat d = conv2(a, b, "same");

  writable::list out(2);
  out[0] = as_doubles_matrix(c);
  out[1] = as_doubles_matrix(d);

  return out;
}

One-dimensional Fast Fourier Transform

The fft() function computes the fast Fourier transform (FFT) of a vector or matrix. The function returns a complex matrix.

Similarly, ifft() computes the inverse fast Fourier transform (IFFT) of a complex matrix.

The transform is done on each column vector of the input matrix.

Usage:

// real or complex
cx_vec Y = fft(X);
cx_vec Y = fft(X, n);

// complex only
cx_mat Z = ifft(cx_mat Y);
cx_mat Z = ifft(cx_mat Y, n);

The optional n argument specifies the transform length:

  • If n is larger than the length of the input vector, a zero-padded version of the vector is used.
  • If n is smaller than the length of the input vector, only the first n elements of the vector are used.

Caveats

  • The transform is fastest when the transform length is a power of 2 (2kk = 1, 2, 3, …).
  • By default, the function uses an internal FFT algorithm based on KISS FFT. With vendoring, it is possible to use the FFTW3 library for faster execution by modifying the cpp11armadillo header to:
...
#include <Rmath.h>

#define ARMA_USE_FFTW3 // add this line
#include <armadillo.hpp>
...

Examples

[[cpp11::register]] list fft1_(const doubles& x) {
  vec a = as_Col(x);

  cx_vec b = fft(a);
  cx_vec c = ifft(b);

  writable::list out(2);
  writable::list out2(2);
  writable::list out3(2);

  out2[0] = as_doubles(real(b));
  out2[1] = as_doubles(imag(b));

  out3[0] = as_doubles(real(c));
  out3[1] = as_doubles(imag(c));

  out[0] = out2;
  out[1] = out3;

  return out;
}

Two-dimensional Fast Fourier Transform

The fft2() function computes the two-dimensional fast Fourier transform (FFT) of a matrix. The function returns a complex matrix.

Similarly, ifft2() computes the inverse fast Fourier transform (IFFT) of a complex matrix.

Usage:

// real or complex
cx_mat Y = fft2(mat X);
cx_mat Y = fft2(mat X, int n_rows, int n_cols);

// complex only
cx_mat Z = ifft2(cx_mat Y);
cx_mat Z = ifft2(cx_mat Y, int n_rows, int n_cols);

The optional n_rows and n_cols arguments specify the transform size:

  • If n_rows and n_cols are larger than the size of the input matrix, a zero-padded version of the matrix is used.
  • If n_rows and n_cols are smaller than the size of the input matrix, only the first n_rows and n_cols elements of the matrix are used.

Caveats

  • The implementation of the 2D transform in this version is preliminary.
  • The transform is fastest when both n_rows and n_cols are a power of 2 (2kk = 1, 2, 3, …).
  • By default, the function uses an internal FFT algorithm based on KISS FFT. With vendoring, it is possible to use the FFTW3 library for faster execution by modifying the cpp11armadillo header to:
...
#include <Rmath.h>

#define ARMA_USE_FFTW3 // add this line
#include <armadillo.hpp>
...

Examples

[[cpp11::register]] list fft2_(const doubles_matrix<>& x) {
  mat a = as_mat(x);

  cx_mat b = fft2(a);
  cx_mat c = ifft2(b);

  writable::list out(2);
  writable::list out2(2);
  writable::list out3(2);

  out2[0] = as_doubles(real(b));
  out2[1] = as_doubles(imag(b));

  out3[0] = as_doubles(real(c));
  out3[1] = as_doubles(imag(c));

  out[0] = out2;
  out[1] = out3;

  return out;
}

One-dimensional interpolation

The interp1() function performs one-dimensional interpolation of a function specified by vectors X and Y. The function generates a vector YI that contains interpolated values at locations XI.

Usage:

vec interp1(X, Y, XI, YI);
vec interp1(X, Y, XI, YI, method);
vec interp1(X, Y, XI, YI, method, extrapolation_value);

The method argument is optional and can be one of the following:

  • "nearest": interpolate using single nearest neighbour.
  • "linear": linear interpolation between two nearest neighbours (default setting).
  • "*nearest": as per "nearest", but faster by assuming that X and XI are monotonically increasing.
  • "*linear": as per "linear", but faster by assuming that X and XI are monotonically increasing.

If a location in XI is outside the domain of X, the corresponding value in YI is set to extrapolation_value.

The extrapolation_value argument is optional; by default, it is datum::nan (not-a-number).

Examples

[[cpp11::register]] doubles interp1_(const int& n) {
  vec x = linspace<vec>(0, 3, n);
  vec y = square(x);

  vec xx = linspace<vec>(0, 3, 2 * n);
  vec yy;

  interp1(x, y, xx, yy);             // use linear interpolation by default
  interp1(x, y, xx, yy, "*linear");  // faster than "linear"
  interp1(x, y, xx, yy, "nearest");

  return as_doubles(yy);
}

Two-dimensional interpolation

The interp2() function performs two-dimensional interpolation of a function specified by matrix Z with coordinates given by vectors X and Y. The function generates a matrix ZI that contains interpolated values at the coordinates given by vectors XI and YI.

Usage:

mat interp2(X, Y, Z, XI, YI, ZI);
mat interp2(X, Y, Z, XI, YI, ZI, method);
mat interp2(X, Y, Z, XI, YI, ZI, method, extrapolation_value);

The method argument is optional and can be one of the following:

  • "nearest": interpolate using nearest neighbours.
  • "linear": linear interpolation between nearest neighbours (default setting).

If a coordinate in the 2D grid specified by (XI, YI) is outside the domain of the 2D grid specified by (X, Y), the corresponding value in ZI is set to extrapolation_value.

The extrapolation_value argument is optional; by default, it is datum::nan (not-a-number).

Examples

[[cpp11::register]] doubles_matrix<> interp2_(const int& n) {
  mat Z(n, n, fill::randu);

  vec X = regspace(1, Z.n_cols);  // X = horizontal spacing
  vec Y = regspace(1, Z.n_rows);  // Y = vertical spacing

  vec XI = regspace(X.min(), 1.0/2.0, X.max()); // magnify by approx 2
  vec YI = regspace(Y.min(), 1.0/3.0, Y.max()); // magnify by approx 3

  mat ZI;

  interp2(X, Y, Z, XI, YI, ZI); // use linear interpolation by default

  return as_doubles_matrix(ZI);
}

Find polynomial coefficients for data fitting

The polyfit() function finds the polynomial coefficients for data fitting. The function models a 1D function specified by vectors X and Y as a polynomial of order N and stores the polynomial coefficients in a column vector P.

The given function is modelled as:

y = p0xN + p1xN − 1 + p2xN − 2 + … + pN − 1x1 + pN

where pi is the i-th polynomial coefficient. The coefficients are selected to minimise the overall error of the fit (least squares).

The column vector P has N + 1 coefficients.

N must be smaller than the number of elements in X.

Usage:

P = polyfit(X, Y, N);
polyfit(P, X, Y, N);

If the polynomial coefficients cannot be found:

  • P = polyfit(X, Y, N) resets P and returns an error.
  • polyfit(P, X, Y, N) resets P and returns a bool set to false without an error.

Examples

[[cpp11::register]] doubles polyfit1_(const int& n, const int& m) {
  vec x = linspace<vec>(0, 1, n);
  vec y = 2*pow(x,2) + 2*x + ones<vec>(n);

  vec p = polyfit(x, y, m);

  return as_doubles(p);
}

Evaluate polynomial

The polyval() function evaluates a polynomial. Given a vector P of polynomial coefficients and a vector X containing the independent values of a 1D function, the function generates a vector Y that contains the corresponding dependent values.

For each x value in vector X, the corresponding y value in vector Y is generated using:

y = p0xN + p1xN − 1 + p2xN − 2 + … + pN − 1x1 + pN

where pi is the i-th polynomial coefficient in vector P.

P must contain polynomial coefficients in descending powers (e.g., generated by the polyfit() function).

Usage:

Y = polyval(P, X);

Examples

[[cpp11::register]] doubles polyval1_(const int& n, const int& m) {
  vec x = linspace<vec>(0, 1, n);
  vec y = 2*pow(x,2) + 2*x + ones<vec>(n);

  vec p = polyfit(x, y, m);
  vec q = polyval(p, x);

  return as_doubles(q);
}