| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #ifndef _EIDSP_CMSIS_NUMPY_H_ |
| #define _EIDSP_CMSIS_NUMPY_H_ |
|
|
| #include "edge-impulse-sdk/dsp/numpy_types.h" |
| #include "edge-impulse-sdk/dsp/returntypes.hpp" |
| #include <stdint.h> |
|
|
| |
| #include "edge-impulse-sdk/CMSIS/DSP/Include/dsp/matrix_functions.h" |
| #include "edge-impulse-sdk/CMSIS/DSP/Include/dsp/statistics_functions.h" |
|
|
| #ifndef EI_MAX_UINT16 |
| #define EI_MAX_UINT16 65535 |
| #endif |
|
|
| namespace ei { |
|
|
| static inline float hw_sqrt(float x) |
| { |
| float temp; |
| arm_sqrt_f32(x, &temp); |
| return temp; |
| } |
|
|
| static inline int hw_dot(matrix_t *matrix1, matrix_t *matrix2, matrix_t *out_matrix) |
| { |
| if (matrix1->rows > EI_MAX_UINT16 || matrix1->cols > EI_MAX_UINT16 || |
| matrix2->rows > EI_MAX_UINT16 || matrix2->cols > EI_MAX_UINT16 || |
| out_matrix->rows > EI_MAX_UINT16 || out_matrix->cols > EI_MAX_UINT16) { |
| return EIDSP_NARROWING; |
| } |
|
|
| const arm_matrix_instance_f32 m1 = { static_cast<uint16_t>(matrix1->rows), |
| static_cast<uint16_t>(matrix1->cols), |
| matrix1->buffer }; |
| const arm_matrix_instance_f32 m2 = { static_cast<uint16_t>(matrix2->rows), |
| static_cast<uint16_t>(matrix2->cols), |
| matrix2->buffer }; |
| arm_matrix_instance_f32 mo = { static_cast<uint16_t>(out_matrix->rows), |
| static_cast<uint16_t>(out_matrix->cols), |
| out_matrix->buffer }; |
| int status = arm_mat_mult_f32(&m1, &m2, &mo); |
| if (status != ARM_MATH_SUCCESS) { |
| return status; |
| } |
| return EIDSP_OK; |
| } |
|
|
| static inline int |
| hw_dot_by_row(int i, float *row, uint32_t matrix1_cols, matrix_t *matrix2, matrix_t *out_matrix) |
| { |
| if (matrix1_cols > EI_MAX_UINT16 || matrix2->rows > EI_MAX_UINT16 || |
| matrix2->cols > EI_MAX_UINT16 || out_matrix->cols > EI_MAX_UINT16) { |
| return EIDSP_NARROWING; |
| } |
|
|
| const arm_matrix_instance_f32 m1 = { 1, static_cast<uint16_t>(matrix1_cols), row }; |
| const arm_matrix_instance_f32 m2 = { static_cast<uint16_t>(matrix2->rows), |
| static_cast<uint16_t>(matrix2->cols), |
| matrix2->buffer }; |
| arm_matrix_instance_f32 mo = { 1, |
| static_cast<uint16_t>(out_matrix->cols), |
| out_matrix->buffer + (i * out_matrix->cols) }; |
| int status = arm_mat_mult_f32(&m1, &m2, &mo); |
| if (status != ARM_MATH_SUCCESS) { |
| return status; |
| } |
| return EIDSP_OK; |
| } |
|
|
| static inline int |
| hw_mat_transpose(const float *in_matrix, float *out_matrix, uint16_t in_rows, uint16_t in_cols) |
| { |
| if (in_rows > EI_MAX_UINT16 || in_cols > EI_MAX_UINT16) { |
| return EIDSP_NARROWING; |
| } |
| const arm_matrix_instance_f32 i_m = { in_cols, in_rows, const_cast<float *>(in_matrix) }; |
| arm_matrix_instance_f32 o_m = { in_rows, in_cols, out_matrix }; |
| arm_status status = arm_mat_trans_f32(&i_m, &o_m); |
| if (status != ARM_MATH_SUCCESS) { |
| return status; |
| } |
| return EIDSP_OK; |
| } |
|
|
| static inline int hw_mat_scale_inplace(float *data, uint16_t rows, uint16_t cols, float scale) |
| { |
| if (rows > EI_MAX_UINT16 || cols > EI_MAX_UINT16) { |
| return EIDSP_NARROWING; |
| } |
| const arm_matrix_instance_f32 mi = { rows, cols, data }; |
| arm_matrix_instance_f32 mo = { rows, cols, data }; |
| int status = arm_mat_scale_f32(&mi, scale, &mo); |
| if (status != ARM_MATH_SUCCESS) { |
| return status; |
| } |
| return EIDSP_OK; |
| } |
|
|
| static inline int hw_rms_array(const float *array, uint32_t len, float *out_value) |
| { |
| arm_rms_f32(array, len, out_value); |
| return EIDSP_OK; |
| } |
|
|
| static inline int hw_mean_array(const float *array, uint32_t len, float *out_value) |
| { |
| arm_mean_f32(array, len, out_value); |
| return EIDSP_OK; |
| } |
|
|
| static inline int hw_min_array(const float *array, uint32_t len, float *out_value) |
| { |
| float minv; |
| uint32_t ix; |
| arm_min_f32(array, len, &minv, &ix); |
| *out_value = minv; |
| return EIDSP_OK; |
| } |
|
|
| static inline int hw_max_array(const float *array, uint32_t len, float *out_value) |
| { |
| float maxv; |
| uint32_t ix; |
| arm_max_f32(array, len, &maxv, &ix); |
| *out_value = maxv; |
| return EIDSP_OK; |
| } |
|
|
| |
| static inline void hw_variance_np(const float32_t *pSrc, uint32_t blockSize, float32_t *pResult) |
| { |
| uint32_t blkCnt; |
| float32_t sum = 0.0f; |
| float32_t fSum = 0.0f; |
| float32_t fMean, fValue; |
| const float32_t *pInput = pSrc; |
|
|
| if (blockSize <= 1U) { |
| *pResult = 0; |
| return; |
| } |
| blkCnt = blockSize >> 2U; |
|
|
| while (blkCnt > 0U) { |
| sum += *pInput++; |
| sum += *pInput++; |
| sum += *pInput++; |
| sum += *pInput++; |
| blkCnt--; |
| } |
|
|
| blkCnt = blockSize % 0x4U; |
| while (blkCnt > 0U) { |
| sum += *pInput++; |
| blkCnt--; |
| } |
|
|
| fMean = sum / (float32_t)blockSize; |
| pInput = pSrc; |
| blkCnt = blockSize >> 2U; |
| while (blkCnt > 0U) { |
| fValue = *pInput++ - fMean; |
| fSum += fValue * fValue; |
| fValue = *pInput++ - fMean; |
| fSum += fValue * fValue; |
| fValue = *pInput++ - fMean; |
| fSum += fValue * fValue; |
| fValue = *pInput++ - fMean; |
| fSum += fValue * fValue; |
| blkCnt--; |
| } |
|
|
| blkCnt = blockSize % 0x4U; |
| while (blkCnt > 0U) { |
| fValue = *pInput++ - fMean; |
| fSum += fValue * fValue; |
| blkCnt--; |
| } |
| *pResult = fSum / (float32_t)(blockSize); |
| } |
|
|
| static inline void hw_variance(const float32_t *pSrc, uint32_t blockSize, float32_t *pResult) |
| { |
| arm_var_f32(pSrc, blockSize, pResult); |
| } |
|
|
| static inline void |
| hw_third_moment(const float32_t *pSrc, uint32_t blockSize, float32_t mean, float32_t *pResult) |
| { |
| uint32_t blkCnt; |
| float32_t sum = 0.0f; |
| float32_t in; |
|
|
| blkCnt = blockSize >> 2U; |
| while (blkCnt > 0U) { |
| in = *pSrc++; |
| in = in - mean; |
| sum += in * in * in; |
| in = *pSrc++; |
| in = in - mean; |
| sum += in * in * in; |
| in = *pSrc++; |
| in = in - mean; |
| sum += in * in * in; |
| in = *pSrc++; |
| in = in - mean; |
| sum += in * in * in; |
| blkCnt--; |
| } |
|
|
| blkCnt = blockSize % 0x4U; |
| while (blkCnt > 0U) { |
| in = *pSrc++; |
| in = in - mean; |
| sum += in * in * in; |
| blkCnt--; |
| } |
| sum = sum / blockSize; |
| *pResult = sum; |
| } |
|
|
| static inline void |
| hw_fourth_moment(const float32_t *pSrc, uint32_t blockSize, float32_t mean, float32_t *pResult) |
| { |
| uint32_t blkCnt; |
| float32_t sum = 0.0f; |
| float32_t in; |
|
|
| blkCnt = blockSize >> 2U; |
| while (blkCnt > 0U) { |
| in = *pSrc++; |
| in = in - mean; |
| float square = in * in; |
| sum += square * square; |
| in = *pSrc++; |
| in = in - mean; |
| square = in * in; |
| sum += square * square; |
| in = *pSrc++; |
| in = in - mean; |
| square = in * in; |
| sum += square * square; |
| in = *pSrc++; |
| in = in - mean; |
| square = in * in; |
| sum += square * square; |
| blkCnt--; |
| } |
|
|
| blkCnt = blockSize % 0x4U; |
| while (blkCnt > 0U) { |
| in = *pSrc++; |
| in = in - mean; |
| float square = in * in; |
| sum += square * square; |
| blkCnt--; |
| } |
| sum = sum / blockSize; |
| *pResult = sum; |
| } |
|
|
| static inline int hw_stdev_array(const float *array, uint32_t len, float *out_value) |
| { |
| float var; |
| hw_variance_np(array, len, &var); |
| arm_sqrt_f32(var, out_value); |
| return EIDSP_OK; |
| } |
|
|
| static inline int hw_skew_array(const float *array, uint32_t len, float *out_value) |
| { |
| float mean; |
| arm_mean_f32(array, len, &mean); |
| float m3; |
| hw_third_moment(array, len, mean, &m3); |
| float var; |
| hw_variance_np(array, len, &var); |
| float denom; |
| arm_sqrt_f32(var * var * var, &denom); |
| if (denom == 0.0f) { |
| *out_value = 0.0f; |
| } |
| else { |
| *out_value = m3 / denom; |
| } |
| return EIDSP_OK; |
| } |
|
|
| static inline int hw_kurtosis_array(const float *array, uint32_t len, float *out_value) |
| { |
| float mean; |
| arm_mean_f32(array, len, &mean); |
| float m4; |
| hw_fourth_moment(array, len, mean, &m4); |
| float var; |
| hw_variance_np(array, len, &var); |
| var = var * var; |
| if (var == 0.0f) { |
| *out_value = -3.0f; |
| } |
| else { |
| *out_value = (m4 / var) - 3.0f; |
| } |
| return EIDSP_OK; |
| } |
|
|
| static inline int hw_std_axis0(matrix_t *input_matrix, matrix_t *output_matrix) |
| { |
| arm_matrix_instance_f32 arm_in_matrix, arm_transposed_matrix; |
|
|
| if (input_matrix->cols != output_matrix->rows) { |
| return EIDSP_MATRIX_SIZE_MISMATCH; |
| } |
| if (output_matrix->cols != 1) { |
| return EIDSP_MATRIX_SIZE_MISMATCH; |
| } |
|
|
| arm_in_matrix.numRows = input_matrix->rows; |
| arm_in_matrix.numCols = input_matrix->cols; |
| arm_in_matrix.pData = &input_matrix->buffer[0]; |
|
|
| arm_transposed_matrix.numRows = input_matrix->cols; |
| arm_transposed_matrix.numCols = input_matrix->rows; |
| auto alloc = EI_MAKE_TRACKED_POINTER( |
| arm_transposed_matrix.pData, |
| input_matrix->cols * input_matrix->rows); |
| if (arm_transposed_matrix.pData == NULL) { |
| return EIDSP_OUT_OF_MEM; |
| } |
|
|
| int ret = arm_mat_trans_f32(&arm_in_matrix, &arm_transposed_matrix); |
| if (ret != EIDSP_OK) { |
| return ret; |
| } |
|
|
| for (size_t row = 0; row < arm_transposed_matrix.numRows; row++) { |
| float std; |
| float var; |
| hw_variance_np( |
| arm_transposed_matrix.pData + (row * arm_transposed_matrix.numCols), |
| arm_transposed_matrix.numCols, |
| &var); |
| arm_sqrt_f32(var, &std); |
| output_matrix->buffer[row] = std; |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| #define EI_RETURN_IF_ERROR(status) \ |
| if (status != EIDSP_OK) { \ |
| EI_LOGE("ARM CMSIS Error: %d", status); \ |
| return status; \ |
| } |
|
|
| } |
|
|
| #endif |
|
|