Matrix math

The matrix math software module provides an easy way to use matrices. It uses an opaque data type uz_matrix_t that boxes important information about the matrix (e.g., number of rows and column) together with the data. The module provides common functions, e.g., matrix multiplication, which are called with matrices of the data type uz_matrix_t, allowing error checking regarding dimensions. The module does not hold the data of the matrix internally but uses an pointer to the data instead to allow variable length of arrays with one data type without using flexible array member. The variable holding the data as well as the struct uz_matrix_t has to be initialized outside of the module since this module is not configured by the Global configuration.

Listing 93 initialization of uz_matrix
float data[5]={0};
struct uz_matrix_t input_matrix = {0};
uz_matrix_t *input = uz_matrix_init(&input_matrix, data, UZ_MATRIX_SIZE(data), 1, 5);

Warning

Take the storage duration of variables into account for the array as well as the uz_matrix_t struct! Most of the time, use static storage duration.

Warning

The data can be accessed directly in the array. Do not do this after a uz_matrix_t instance is coupled with the array by initialization.

Note

The matrix software module has similarities to the Array module but features math functions instead of a box for arrays including their length for different data types.

Matrix definition

The following matrix definition with the number of columns \(n\) and number of rows \(m\) is used:

\[\begin{split}\begin{array}{cc} & \text{Columns $n$ } \\ \text{Rows $m$ } & \begin{bmatrix} a_{11} & a_{12} & \cdots & a_{1n} \\ a_{21} & a_{22} & \cdots & a_{2n} \\ \vdots & \vdots & \ddots & \vdots \\ a_{m1} & a_{m2} & \cdots & a_{mn} \end{bmatrix} \end{array}\end{split}\]

Note

Keep in mind that in C everything is 0-indexed while the matrix definitions still use 1-based indexing to be consistent with common math conventions! Thus, \(a_{11}\) is the element with index \([0,0]\) in c-code!

Dimensions

A pointer to the actual data array has to be supplied uz_matrix_init. The array has to be of length \(m \times n\). The dimension \(n\) (columns) can be one to generate a column vector \(m \times 1\).

\[\begin{split}x= \begin{bmatrix} x_{11} \\ x_{21} \\ \vdots \\ x_{m1} \end{bmatrix}\end{split}\]

The dimension \(n\) can be one to generate a row vector \(1 \times n\).

\[x= \begin{bmatrix} x_{11} & x_{12} & \cdots & x_{1n} \end{bmatrix}\]

The provided array is always an vector with \(m \times n\) elements. The array is split up according to the provided dimensions. It is treated as an matrix in the following way (zero indexing internally):

\[\begin{split}\begin{bmatrix} \color{red} x_{11} & \color{red} x_{12} & \color{red} x_{13}\\ \color{blue} x_{21} & \color{blue} x_{22} & \color{blue} x_{23}\\ \color{green} x_{31} & \color{green} x_{32} & \color{green} x_{33} \end{bmatrix} &= \begin{bmatrix} \color{red} x_{11} & \color{red} x_{12} & \color{red} x_{13} & \color{blue} x_{21} & \color{blue} x_{22} & \color{blue} x_{23} & \color{green} x_{31} & \color{green} x_{32} & \color{green} x_{33} \end{bmatrix} \\ &= \begin{bmatrix} x_{0} & x_{1} & x_{2} & x_{3} & x_{4} & x_{5} & x_{6} & x_{7} & x_{8} \end{bmatrix}\end{split}\]

Note

Keep this in mind when initializing the data array or initialize all elements of the array to zero and use the set functions.

Example

Each matrix has to be initialized with uz_matrix_init. To initialize the following \(3 \times 3\) matrix:

\[\begin{split}\begin{bmatrix} \color{red} 1 & \color{red} 2 & \color{red} 3\\ \color{blue} 4 & \color{blue} 5 & \color{blue} 6\\ \color{green} 7 & \color{green} 8 & \color{green} 9 \end{bmatrix} = \begin{bmatrix} \color{red} 1 & \color{red} 2 & \color{red} 3 & \color{blue} 4 & \color{blue} 5 & \color{blue} 6 & \color{green} 7 & \color{green} 8 & \color{green} 9 \end{bmatrix} \\\end{split}\]
Listing 94 Initialize a \(3 \times 3\) matrix:
// declare data array static outside of a function to ensure static storage duration and file scope.
static float mat[9]={1,2,3,4,5,6,7,8,9};
struct uz_matrix_t input_matrix = {0};

void uz_matrix_init_3_times_3_matrix(void){
    int rows=3; // Row and columns can be automatic storage duration since they are not required after initialization (stored in the module)
    int columns=3;
    uz_matrix_t* my_matrix=uz_matrix_init(input_matrix,mat,UZ_MATRIX_SIZE(mat),rows,columns);
}

Reference

typedef struct uz_matrix_t uz_matrix_t

Typedef for uz_matrix_t struct.

uz_matrix_t *uz_matrix_init(uz_matrix_t *self, float *data, uint32_t length_of_data, uint32_t rows, uint32_t columns)

Initialize an uz_matrix.

Parameters
  • self – Pointer to the instance

  • data – Pointer to the data

  • length_of_data – Number of data elements calculated by UZ_MATRIX_SIZE makro

  • rows – Number of rows

  • columns – Number of columns

Returns

uz_matrix_t* Returns an pointer to the instance that was passed

uint32_t uz_matrix_get_number_of_rows(uz_matrix_t const *const self)

Returns the number of rows of the given uz_matrix.

Parameters
  • self – Pointer to a uz_matrix_t instance

Returns

uint32_t

uint32_t uz_matrix_get_number_of_columns(uz_matrix_t const *const self)

Returns the number of columns of the given uz_matrix.

Parameters
  • self – Pointer to a uz_matrix_t instance

Returns

uint32_t

float uz_matrix_get_element_zero_based(uz_matrix_t const *const A, uint32_t row, uint32_t column)

Get the element row x column of matrix A with zero based indexing.

Parameters
  • A – Matrix object, hast to be ready.

  • row – Row of element

  • column – Column of element

Returns

float

void uz_matrix_set_element_zero_based(uz_matrix_t *const A, float x, uint32_t row, uint32_t column)

Set the element row x column of matrix A with zero based indexing.

Parameters
  • A – Matrix object

  • x – Value that the element is set to

  • row – Row of element to set

  • column – Column of element to set

void uz_matrix_add_scalar(uz_matrix_t *const A, float scalar)

Adds a scalar to all elements of the matrix A.

Parameters
  • A

  • scalar

void uz_matrix_multiply_by_scalar(uz_matrix_t *const A, float scalar)

Multiplies all elements of the matrix A by a scalar.

Parameters
  • A – Pointer to a uz_matrix_t instance

  • scalar – Scalar value with which each element of A is multiplied

void uz_matrix_apply_function_to_each_element(uz_matrix_t *const A, float (*f)(float))

Applies a function f, that is passed as a function pointer, to each of the elements.

Parameters
  • A – Pointer to a uz_matrix_t instance

  • f – Function pointer, function has to accept one float as argument and return one float

float uz_matrix_get_max_value(uz_matrix_t const *const A)

Retruns the value of the biggest element of the matrix.

Parameters
  • A – Pointer to a uz_matrix_t instance

Returns

float

uint32_t uz_matrix_get_max_index(uz_matrix_t const *const A)

Returns the index at which position the biggest value is located in the matrix A.

Parameters
  • A – Pointer to a uz_matrix_t instance

Returns

uint32_t

void uz_matrix_transpose(uz_matrix_t *A)

Transposes the matrix A.

Parameters
  • A – Pointer to a uz_matrix_t instance

Warning

uz_matrix_transpose uses a variable length array (VLA), which does not comply to the coding rules.

Performance estimation

The following performance is measured when the functions are called in the, expect for the test code and uz_SystemTime_ISR_Tic() functions, empty ISR of the R5.

Listing 95 Test code for performance estimation
void ISR_Control(void *data)
{
    uz_SystemTime_ISR_Tic();
    for(uint32_t i=0U;i<10;i++){
            function_under_test(A,B,C ); //
    }
    uz_SystemTime_ISR_Toc();
}

Testing is conducted with compiler optimization set to -O2.

  • Empty ISR: 2.7 us

  • Add a 3x3 matrix, code executed 10 times: 5.5 us

  • elementwise_product of two 10x10 matrix, code executed 10 times: 18 us

  • matrix_multiply 10x10 matrix, code executed 1 time: 23 us

  • matrix_multiply 3x3 matrix, code executed 10 times: 14 us

  • matrix_multiply 10x10 matrix with double data type (not implemented in the software module!), code executed 1 time: 52.8 us

Rough estimation:

  • Adding a 3x3 matrix takes 0.3 us

  • Multiplication of a 3x3 matrix takes 1us, of a 10x10 matrix 12 us.

  • Multiplication of a 10x10 matrix takes 12 us.