Basic Mathematical Operations
Addition
#include "arm_math.h"
arm_status arm_add_q7(q7_t *pSrcA, q7_t *pSrcB, q7_t *pDst, uint32_t blockSize) {
for (uint32_t i = 0; i < blockSize; i++) {
pDst[i] = (q7_t)(__SSAT(((__q7_t)pSrcA[i] + (__q7_t)pSrcB[i]), 8));
}
return ARM_MATH_SUCCESS;
}
Subtraction
arm_status arm_sub_q7(q7_t *pSrcA, q7_t *pSrcB, q7_t *pDst, uint32_t blockSize) {
for (uint32_t i = 0; i < blockSize; i++) {
pDst[i] = (q7_t)(__SSAT(((__q7_t)pSrcA[i] - (__q7_t)pSrcB[i]), 8));
}
return ARM_MATH_SUCCESS;
}
Multiplication
arm_status arm_mult_q7(q7_t *pSrcA, q7_t *pSrcB, q7_t *pDst, uint32_t blockSize) {
for (uint32_t i = 0; i < blockSize; i++) {
pDst[i] = (q7_t)(__SSAT(((__q7_t)pSrcA[i] * (__q7_t)pSrcB[i]) >> 7, 8));
}
return ARM_MATH_SUCCESS;
}
Dot Product
arm_status arm_dot_prod_q7(q7_t *pSrcA, q7_t *pSrcB, uint32_t blockSize, q7_t *result) {
q31_t sum = 0;
for (uint32_t i = 0; i < blockSize; i++) {
sum += (q31_t)pSrcA[i] * pSrcB[i];
}
*result = (q7_t)(__SSAT(sum >> 7, 8));
return ARM_MATH_SUCCESS;
}
Fast Mathematical Operations
Fast Addition
q7_t arm_add_q7_fast(q7_t a, q7_t b) {
return (q7_t)(__SSAT(((__q7_t)a + (__q7_t)b), 8));
}
Fast Subtraction
q7_t arm_sub_q7_fast(q7_t a, q7_t b) {
return (q7_t)(__SSAT(((__q7_t)a - (__q7_t)b), 8));
}
Fast Multiplication
q7_t arm_mult_q7_fast(q7_t a, q7_t b) {
return (q7_t)(__SSAT(((__q7_t)a * (__q7_t)b) >> 7, 8));
}
Complex Mathematical Operations
Complex Addition
arm_status arm_cmplx_add_q31(q31_t *pSrcA, q31_t *pSrcB, q31_t *pDst, uint32_t numSamples) {
for (uint32_t i = 0; i < numSamples; i++) {
pDst[2 * i] = pSrcA[2 * i] + pSrcB[2 * i];
pDst[2 * i + 1] = pSrcA[2 * i + 1] + pSrcB[2 * i + 1];
}
return ARM_MATH_SUCCESS;
}
Complex Subtraction
arm_status arm_cmplx_sub_q31(q31_t *pSrcA, q31_t *pSrcB, q31_t *pDst, uint32_t numSamples) {
for (uint32_t i = 0; i < numSamples; i++) {
pDst[2 * i] = pSrcA[2 * i] - pSrcB[2 * i];
pDst[2 * i + 1] = pSrcA[2 * i + 1] - pSrcB[2 * i + 1];
}
return ARM_MATH_SUCCESS;
}
Complex Multiplication
arm_status arm_cmplx_mult_q31(q31_t *pSrcA, q31_t *pSrcB, q31_t *pDst, uint32_t numSamples) {
for (uint32_t i = 0; i < numSamples; i++) {
q31_t real = (pSrcA[2 * i] * pSrcB[2 * i]) - (pSrcA[2 * i + 1] * pSrcB[2 * i + 1]);
q31_t imag = (pSrcA[2 * i] * pSrcB[2 * i + 1]) + (pSrcA[2 * i + 1] * pSrcB[2 * i]);
pDst[2 * i] = real;
pDst[2 * i + 1] = imag;
}
return ARM_MATH_SUCCESS;
}
Complex Magnitude
arm_status arm_cmplx_mag_q31(q31_t *pSrc, q31_t *pDst, uint32_t numSamples) {
for (uint32_t i = 0; i < numSamples; i++) {
q31_t real = pSrc[2 * i];
q31_t imag = pSrc[2 * i + 1];
pDst[i] = (q31_t)sqrt((real * real) + (imag * imag));
}
return ARM_MATH_SUCCESS;
}
Filters
FIR Filter
arm_status arm_fir_q15(
arm_fir_instance_q15 *S,
q15_t *pSrc,
q15_t *pDst,
uint32_t blockSize) {
q15_t *pState = S->pState;
q15_t *pCoeffs = S->pCoeffs;
uint32_t numTaps = S->numTaps;
uint32_t i, j;
for (i = 0; i < blockSize; i++) {
q31_t sum = 0;
q15_t *pStateCurnt = &pState[i];
q15_t *pCoeffsCurnt = pCoeffs;
for (j = 0; j < numTaps; j++) {
sum += (q31_t)(*pStateCurnt++) * (*pCoeffsCurnt++);
}
pDst[i] = (q15_t)(__SSAT(sum >> 15, 16));
}
return ARM_MATH_SUCCESS;
}
IIR Filter
arm_status arm_iir_lattice_q15(
arm_iir_lattice_instance_q15 *S,
q15_t *pSrc,
q15_t *pDst,
uint32_t blockSize) {
q15_t *pState = S->pState;
q15_t *pCoeffs = S->pCoeffs;
uint32_t numStages = S->numStages;
uint32_t i, j;
for (i = 0; i < blockSize; i++) {
q15_t x = pSrc[i];
q15_t *pStateCurnt = pState;
q15_t *pCoeffsCurnt = pCoeffs;
for (j = 0; j < numStages; j++) {
q15_t f = *pStateCurnt;
q15_t g = *(pStateCurnt + 1);
q15_t coeff = *pCoeffsCurnt;
q15_t temp = x - (q15_t)((q31_t)f * coeff >> 15);
x = (q15_t)((q31_t)g * coeff >> 15) + temp;
*pStateCurnt++ = temp;
*(pStateCurnt++) = x;
pCoeffsCurnt++;
}
pDst[i] = x;
}
return ARM_MATH_SUCCESS;
}
Matrix Functions
Matrix Addition
arm_status arm_mat_add_q15(
arm_matrix_instance_q15 *pSrcA,
arm_matrix_instance_q15 *pSrcB,
arm_matrix_instance_q15 *pDst) {
if ((pSrcA->numRows != pSrcB->numRows) || (pSrcA->numCols != pSrcB->numCols)) {
return ARM_MATH_SIZE_MISMATCH;
}
for (uint32_t i = 0; i < pSrcA->numRows * pSrcA->numCols; i++) {
pDst->pData[i] = pSrcA->pData[i] + pSrcB->pData[i];
}
return ARM_MATH_SUCCESS;
}
Matrix Subtraction
arm_status arm_mat_sub_q15(
arm_matrix_instance_q15 *pSrcA,
arm_matrix_instance_q15 *pSrcB,
arm_matrix_instance_q15 *pDst) {
if ((pSrcA->numRows != pSrcB->numRows) || (pSrcA->numCols != pSrcB->numCols)) {
return ARM_MATH_SIZE_MISMATCH;
}
for (uint32_t i = 0; i < pSrcA->numRows * pSrcA->numCols; i++) {
pDst->pData[i] = pSrcA->pData[i] - pSrcB->pData[i];
}
return ARM_MATH_SUCCESS;
}
Matrix Multiplication
arm_status arm_mat_mult_q15(
arm_matrix_instance_q15 *pSrcA,
arm_matrix_instance_q15 *pSrcB,
arm_matrix_instance_q15 *pDst,
q15_t *pBuffer) {
if ((pSrcA->numCols != pSrcB->numRows) || (pSrcA->numRows != pDst->numRows) || (pSrcB->numCols != pDst->numCols)) {
return ARM_MATH_SIZE_MISMATCH;
}
for (uint32_t i = 0; i < pSrcA->numRows; i++) {
for (uint32_t j = 0; j < pSrcB->numCols; j++) {
q31_t sum = 0;
for (uint32_t k = 0; k < pSrcA->numCols; k++) {
sum += (q31_t)pSrcA->pData[i * pSrcA->numCols + k] * pSrcB->pData[k * pSrcB->numCols + j];
}
pDst->pData[i * pDst->numCols + j] = (q15_t)__SSAT(sum >> 15, 16);
}
}
return ARM_MATH_SUCCESS;
}
Matrix Transpose
arm_status arm_mat_trans_q15(
arm_matrix_instance_q15 *pSrc,
arm_matrix_instance_q15 *pDst) {
if (pSrc->numRows != pDst->numCols || pSrc->numCols != pDst->numRows) {
return ARM_MATH_SIZE_MISMATCH;
}
for (uint32_t i = 0; i < pSrc->numRows; i++) {
for (uint32_t j = 0; j < pSrc->numCols; j++) {
pDst->pData[j * pDst->numCols + i] = pSrc->pData[i * pSrc->numCols + j];
}
}
return ARM_MATH_SUCCESS;
}
Transforms
FFT
arm_status arm_cfft_q15(
arm_cfft_instance_q15 *S,
q15_t *pSrc,
uint8_t ifftFlag,
uint8_t bitReverseFlag) {
uint16_t nPoints = S->nPoints;
uint8_t *pBitRevTable = S->pBitRevTable;
uint16_t twiddleCoefModifier = S->twiddleCoefModifier;
q15_t *pTwiddle = S->pTwiddle;
uint16_t i, j, k, l;
uint16_t n, n2, n4;
q15_t *pSrc1, *pSrc2, *pCoef;
q15_t a, b, c, d, e, f, g, h;
q15_t t1, t2, t3, t4;
if (bitReverseFlag) {
arm_bitreversal_q15(pSrc, nPoints, pBitRevTable);
}
n4 = nPoints / 4;
n2 = nPoints / 2;
pSrc1 = pSrc;
pSrc2 = pSrc + n2;
for (i = 0; i < n4; i++) {
a = pSrc1[0];
b = pSrc1[1];
c = pSrc2[0];
d = pSrc2[1];
pSrc1[0] = a + c;
pSrc1[1] = b + d;
pSrc2[0] = a - c;
pSrc2[1] = b - d;
pSrc1 += 2;
pSrc2 += 2;
}
for (k = 2; k <= nPoints; k <<= 1) {
n2 = k >> 1;
pCoef = pTwiddle;
twiddleCoefModifier <<= 1;
for (l = 0; l < nPoints; l += k) {
pSrc1 = pSrc + l;
pSrc2 = pSrc1 + n2;
for (i = 0; i < n2; i += 2) {
a = pSrc1[i];
b = pSrc1[i + 1];
c = pSrc2[i];
d = pSrc2[i + 1];
e = pCoef[0];
f = pCoef[1];
t1 = (q15_t)((q31_t)a * e >> 15);
t2 = (q15_t)((q31_t)a * f >> 15);
t3 = (q15_t)((q31_t)b * e >> 15);
t4 = (q15_t)((q31_t)b * f >> 15);
pSrc2[i] = t1 - t4;
pSrc2[i + 1] = t3 + t2;
pSrc1[i] = a + c;
pSrc1[i + 1] = b + d;
pSrc2[i] = t1 - t4;
pSrc2[i + 1] = t3 + t2;
}
pTwiddle += twiddleCoefModifier;
}
}
return ARM_MATH_SUCCESS;
}
DCT
arm_status arm_dct4_q15(
arm_dct4_instance_q15 *S,
q15_t *pSrc,
q15_t *pDst,
q15_t *pBuffer) {
arm_rfft_q15(&S->rfftInstance, pSrc, pDst, pBuffer);
arm_dct4_compute_q15(S, pDst, pDst, pBuffer);
return ARM_MATH_SUCCESS;
}
Motor Control Functions
Inverter Control
arm_status arm_pmsm_foc_speed_observer_q31(
arm_pmsm_foc_speed_observer_instance_q31 *S,
q31_t speedRef,
q31_t speedEstimate,
q31_t *pSpeedObserverGain,
q31_t *pSpeedObserverPole,
q31_t *pSpeedObserverCurrent,
q31_t *pSpeedObserverVoltage) {
q31_t gain = *pSpeedObserverGain;
q31_t pole = *pSpeedObserverPole;
q31_t current = *pSpeedObserverCurrent;
q31_t voltage = *pSpeedObserverVoltage;
q31_t error = speedRef - speedEstimate;
S->state[0] += (error * gain) >> 15;
S->state[1] = (S->state[0] * pole) >> 15;
return ARM_MATH_SUCCESS;
}
Speed Control
arm_status arm_pid_q31(
arm_pid_instance_q31 *S,
q31_t in,
q31_t *pOut) {
q31_t sum;
q31_t out;
sum = S->state[0] + in;
out = (__SSAT((S->K[0] * sum) >> 15, 31) +
__SSAT((S->K[1] * (sum - S->state[1])) >> 15, 31) +
__SSAT((S->K[2] * S->state[2]) >> 15, 31));
*pOut = __SSAT(out, 31);
S->state[0] = sum;
S->state[1] = in;
S->state[2] = out;
return ARM_MATH_SUCCESS;
}
Statistical Functions
Mean
arm_status arm_mean_q15(q15_t *pSrc, uint32_t blockSize, q15_t *pResult) {
q31_t sum = 0;
for (uint32_t i = 0; i < blockSize; i++) {
sum += pSrc[i];
}
*pResult = (q15_t)(__SSAT(sum / blockSize, 16));
return ARM_MATH_SUCCESS;
}
Standard Deviation
arm_status arm_std_q15(q15_t *pSrc, uint32_t blockSize, q15_t *pResult) {
q31_t mean = 0;
q31_t sum = 0;
q31_t sumOfSquares = 0;
for (uint32_t i = 0; i < blockSize; i++) {
sum += pSrc[i];
}
mean = sum / blockSize;
for (uint32_t i = 0; i < blockSize; i++) {
sumOfSquares += (pSrc[i] - mean) * (pSrc[i] - mean);
}
*pResult = (q15_t)(__SSAT(sqrt(sumOfSquares / blockSize), 16));
return ARM_MATH_SUCCESS;
}
Maximum Value
arm_status arm_max_q15(q15_t *pSrc, uint32_t blockSize, q15_t *pResult) {
q15_t max = pSrc[0];
for (uint32_t i = 1; i < blockSize; i++) {
if (pSrc[i] > max) {
max = pSrc[i];
}
}
*pResult = max;
return ARM_MATH_SUCCESS;
}
Minimum Value
arm_status arm_min_q15(q15_t *pSrc, uint32_t blockSize, q15_t *pResult) {
q15_t min = pSrc[0];
for (uint32_t i = 1; i < blockSize; i++) {
if (pSrc[i] < min) {
min = pSrc[i];
}
}
*pResult = min;
return ARM_MATH_SUCCESS;
}
Support Functions
Saturation
q31_t arm_saturate_q31(q31_t x, uint8_t bits) {
q31_t max = (1 << (bits - 1)) - 1;
q31_t min = -max - 1;
if (x > max) {
return max;
} else if (x < min) {
return min;
} else {
return x;
}
}
Bit Reversal
uint32_t arm_bitreversal(uint32_t value, uint16_t fftLen) {
uint32_t result = 0;
for (uint32_t i = 0; i < fftLen; i++) {
result = (result << 1) | (value & 1);
value >>= 1;
}
return result;
}
Interpolation Functions
Linear Interpolation
q31_t arm_linear_interp_q31(
q31_t x,
q31_t *pX,
q31_t *pY,
uint32_t numOfPoints) {
if (x <= pX[0]) {
return pY[0];
} else if (x >= pX[numOfPoints - 1]) {
return pY[numOfPoints - 1];
} else {
uint32_t index = 0;
while (x > pX[index + 1]) {
index++;
}
q31_t x0 = pX[index];
q31_t x1 = pX[index + 1];
q31_t y0 = pY[index];
q31_t y1 = pY[index + 1];
q31_t fraction = (x - x0) / (x1 - x0);
return y0 + (y1 - y0) * fraction;
}
}
Cubic Interpolation
q31_t arm_cubic_interp_q31(
q31_t x,
q31_t *pX,
q31_t *pY,
uint32_t numOfPoints) {
if (x <= pX[0]) {
return pY[0];
} else if (x >= pX[numOfPoints - 1]) {
return pY[numOfPoints - 1];
} else {
uint32_t index = 0;
while (x > pX[index + 1]) {
index++;
}
q31_t x0 = pX[index - 1];
q31_t x1 = pX[index];
q31_t x2 = pX[index + 1];
q31_t x3 = pX[index + 2];
q31_t y0 = pY[index - 1];
q31_t y1 = pY[index];
q31_t y2 = pY[index + 1];
q31_t y3 = pY[index + 2];
q31_t t = (x - x1) / (x2 - x1);
q31_t t2 = t * t;
q31_t t3 = t * t * t;
q31_t result = (-y0 + 3 * y1 - 3 * y2 + y3) * t3 + (3 * y0 - 6 * y1 + 3 * y2) * t2 + (-3 * y0 + 3 * y2) * t + y1;
return result;
}
}
Little Endian and Big Endian
-
Little Endian: The low-order byte is stored at the lowest address.
-
Big Endian: The high-order byte is stored at the lowest address.
The functions in the CMSIS-DSP library behave consistently in both little-endian and big-endian modes, but the data storage order differs.
Naming Conventions
Function naming follows the <span>arm_OP_DATATYPE</span> format, for example:
-
<span>arm_dot_prod_q7</span>: Dot product operation for 8-bit fixed-point. -
<span>arm_mult_q15</span>: Multiplication operation for 16-bit fixed-point. -
<span>arm_add_q31</span>: Addition operation for 32-bit fixed-point. -
<span>arm_fir_f32</span>: FIR filter operation for 32-bit floating-point.
Data Type Descriptions
-
q7: 8-bit fixed-point.
-
q15: 16-bit fixed-point.
-
q31: 32-bit fixed-point.
-
q32: 32-bit floating-point.