Cortex Authority Manual – CMSIS-DSP Library

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.

Leave a Comment