| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| #ifndef _EIDSP_NUMPY_H_ |
| #define _EIDSP_NUMPY_H_ |
|
|
| |
| |
| |
| |
| #ifndef __has_include |
| #define __has_include 1 |
| #endif |
|
|
| |
| |
| #ifdef abs |
| #undef abs |
| #endif |
|
|
| #include <stdint.h> |
| #include <string.h> |
| #include <stddef.h> |
| #include <cfloat> |
| #include "ei_vector.h" |
| #include <algorithm> |
| #include "numpy_types.h" |
| #include "config.hpp" |
| #include "returntypes.hpp" |
| #include "memory.hpp" |
| #include "ei_utils.h" |
| #include "kissfft/kiss_fftr.h" |
| #include "edge-impulse-sdk/porting/ei_logging.h" |
|
|
| |
| #if EIDSP_USE_CEVA_DSP |
| |
|
|
| #if EIDSP_USE_CEVA_DSP_FIXED |
| #include "edge-impulse-sdk/dsp/dsp_engines/ei_ceva_dsp_fixed.h" |
| #else |
| #include "edge-impulse-sdk/dsp/dsp_engines/ei_ceva_dsp.h" |
| #endif |
|
|
| #elif EIDSP_USE_CMSIS_DSP |
| #include "edge-impulse-sdk/dsp/dsp_engines/ei_arm_cmsis_dsp.h" |
| #include "edge-impulse-sdk/dsp/dsp_engines/ei_cmsis_numpy.hpp" |
|
|
| #elif EIDSP_USE_ESP_DSP |
| #include "edge-impulse-sdk/dsp/dsp_engines/ei_esp_dsp.h" |
|
|
| #else |
| #define EIDSP_INCLUDE_KISSFFT 1 |
| #include "edge-impulse-sdk/dsp/dsp_engines/ei_no_hw_dsp.h" |
|
|
| #endif |
|
|
|
|
| |
| #ifndef EIDSP_INCLUDE_KISSFFT |
|
|
| #if defined(EI_CLASSIFIER_NON_STANDARD_FFT_SIZES) && !EI_CLASSIFIER_NON_STANDARD_FFT_SIZES |
| #define EIDSP_INCLUDE_KISSFFT 0 |
| #else |
| #define EIDSP_INCLUDE_KISSFFT 1 |
| #endif |
|
|
| #endif |
|
|
| |
| #include "edge-impulse-sdk/CMSIS/DSP/Include/dsp/statistics_functions.h" |
|
|
| |
| #if EIDSP_USE_CMSIS_DSP |
| #define EIDSP_USE_HW_MATH 1 |
| #else |
| #define EIDSP_USE_HW_MATH 0 |
| #endif |
|
|
| #ifdef __MBED__ |
| #include "mbed.h" |
| #else |
| #include <functional> |
| #endif |
|
|
| #if EIDSP_USE_NEON |
| #include <arm_neon.h> |
| #endif |
|
|
| #define EI_MAX_UINT16 65535 |
|
|
| #ifndef M_PI |
| #define M_PI 3.1415926 |
| #endif |
|
|
| namespace ei { |
|
|
| using fvec = ei_vector<float>; |
| using ivec = ei_vector<int>; |
|
|
| |
| |
| static constexpr float quantized_values_one_zero[] = { (0.0f / 1.0f), (1.0f / 100.0f), (2.0f / 100.0f), (3.0f / 100.0f), (4.0f / 100.0f), (1.0f / 22.0f), (1.0f / 21.0f), (1.0f / 20.0f), (1.0f / 19.0f), (1.0f / 18.0f), (1.0f / 17.0f), (6.0f / 100.0f), (1.0f / 16.0f), (1.0f / 15.0f), (7.0f / 100.0f), (1.0f / 14.0f), (1.0f / 13.0f), (8.0f / 100.0f), (1.0f / 12.0f), (9.0f / 100.0f), (1.0f / 11.0f), (2.0f / 21.0f), (1.0f / 10.0f), (2.0f / 19.0f), (11.0f / 100.0f), (1.0f / 9.0f), (2.0f / 17.0f), (12.0f / 100.0f), (1.0f / 8.0f), (13.0f / 100.0f), (2.0f / 15.0f), (3.0f / 22.0f), (14.0f / 100.0f), (1.0f / 7.0f), (3.0f / 20.0f), (2.0f / 13.0f), (3.0f / 19.0f), (16.0f / 100.0f), (1.0f / 6.0f), (17.0f / 100.0f), (3.0f / 17.0f), (18.0f / 100.0f), (2.0f / 11.0f), (3.0f / 16.0f), (19.0f / 100.0f), (4.0f / 21.0f), (1.0f / 5.0f), (21.0f / 100.0f), (4.0f / 19.0f), (3.0f / 14.0f), (22.0f / 100.0f), (2.0f / 9.0f), (5.0f / 22.0f), (23.0f / 100.0f), (3.0f / 13.0f), (4.0f / 17.0f), (5.0f / 21.0f), (24.0f / 100.0f), (1.0f / 4.0f), (26.0f / 100.0f), (5.0f / 19.0f), (4.0f / 15.0f), (27.0f / 100.0f), (3.0f / 11.0f), (5.0f / 18.0f), (28.0f / 100.0f), (2.0f / 7.0f), (29.0f / 100.0f), (5.0f / 17.0f), (3.0f / 10.0f), (4.0f / 13.0f), (31.0f / 100.0f), (5.0f / 16.0f), (6.0f / 19.0f), (7.0f / 22.0f), (32.0f / 100.0f), (33.0f / 100.0f), (1.0f / 3.0f), (34.0f / 100.0f), (7.0f / 20.0f), (6.0f / 17.0f), (5.0f / 14.0f), (36.0f / 100.0f), (4.0f / 11.0f), (7.0f / 19.0f), (37.0f / 100.0f), (3.0f / 8.0f), (38.0f / 100.0f), (8.0f / 21.0f), (5.0f / 13.0f), (7.0f / 18.0f), (39.0f / 100.0f), (2.0f / 5.0f), (9.0f / 22.0f), (41.0f / 100.0f), (7.0f / 17.0f), (5.0f / 12.0f), (42.0f / 100.0f), (8.0f / 19.0f), (3.0f / 7.0f), (43.0f / 100.0f), (7.0f / 16.0f), (44.0f / 100.0f), (4.0f / 9.0f), (9.0f / 20.0f), (5.0f / 11.0f), (46.0f / 100.0f), (6.0f / 13.0f), (7.0f / 15.0f), (47.0f / 100.0f), (8.0f / 17.0f), (9.0f / 19.0f), (10.0f / 21.0f), (48.0f / 100.0f), (49.0f / 100.0f), (1.0f / 2.0f), (51.0f / 100.0f), (52.0f / 100.0f), (11.0f / 21.0f), (10.0f / 19.0f), (9.0f / 17.0f), (53.0f / 100.0f), (8.0f / 15.0f), (7.0f / 13.0f), (54.0f / 100.0f), (6.0f / 11.0f), (11.0f / 20.0f), (5.0f / 9.0f), (56.0f / 100.0f), (9.0f / 16.0f), (57.0f / 100.0f), (4.0f / 7.0f), (11.0f / 19.0f), (58.0f / 100.0f), (7.0f / 12.0f), (10.0f / 17.0f), (59.0f / 100.0f), (13.0f / 22.0f), (3.0f / 5.0f), (61.0f / 100.0f), (11.0f / 18.0f), (8.0f / 13.0f), (13.0f / 21.0f), (62.0f / 100.0f), (5.0f / 8.0f), (63.0f / 100.0f), (12.0f / 19.0f), (7.0f / 11.0f), (64.0f / 100.0f), (9.0f / 14.0f), (11.0f / 17.0f), (13.0f / 20.0f), (66.0f / 100.0f), (2.0f / 3.0f), (67.0f / 100.0f), (68.0f / 100.0f), (15.0f / 22.0f), (13.0f / 19.0f), (11.0f / 16.0f), (69.0f / 100.0f), (9.0f / 13.0f), (7.0f / 10.0f), (12.0f / 17.0f), (71.0f / 100.0f), (5.0f / 7.0f), (72.0f / 100.0f), (13.0f / 18.0f), (8.0f / 11.0f), (73.0f / 100.0f), (11.0f / 15.0f), (14.0f / 19.0f), (74.0f / 100.0f), (3.0f / 4.0f), (76.0f / 100.0f), (16.0f / 21.0f), (13.0f / 17.0f), (10.0f / 13.0f), (77.0f / 100.0f), (17.0f / 22.0f), (7.0f / 9.0f), (78.0f / 100.0f), (11.0f / 14.0f), (15.0f / 19.0f), (79.0f / 100.0f), (4.0f / 5.0f), (17.0f / 21.0f), (81.0f / 100.0f), (13.0f / 16.0f), (9.0f / 11.0f), (82.0f / 100.0f), (14.0f / 17.0f), (83.0f / 100.0f), (5.0f / 6.0f), (84.0f / 100.0f), (16.0f / 19.0f), (11.0f / 13.0f), (17.0f / 20.0f), (6.0f / 7.0f), (86.0f / 100.0f), (19.0f / 22.0f), (13.0f / 15.0f), (87.0f / 100.0f), (7.0f / 8.0f), (88.0f / 100.0f), (15.0f / 17.0f), (8.0f / 9.0f), (89.0f / 100.0f), (17.0f / 19.0f), (9.0f / 10.0f), (19.0f / 21.0f), (10.0f / 11.0f), (91.0f / 100.0f), (11.0f / 12.0f), (92.0f / 100.0f), (12.0f / 13.0f), (13.0f / 14.0f), (93.0f / 100.0f), (14.0f / 15.0f), (15.0f / 16.0f), (94.0f / 100.0f), (16.0f / 17.0f), (17.0f / 18.0f), (18.0f / 19.0f), (19.0f / 20.0f), (20.0f / 21.0f), (21.0f / 22.0f), (96.0f / 100.0f), (97.0f / 100.0f), (98.0f / 100.0f), (99.0f / 100.0f), (1.0f / 1.0f) , |
| 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; |
| |
|
|
| class numpy { |
| public: |
|
|
| static float sqrt(float x) { |
| #if EIDSP_USE_HW_MATH |
| return hw_sqrt(x); |
| #else |
| return sqrtf(x); |
| #endif |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static int roll(float *input_array, size_t input_array_size, int shift) { |
| if (shift < 0) { |
| shift = input_array_size + shift; |
| } |
|
|
| if (shift == 0) { |
| return EIDSP_OK; |
| } |
|
|
| |
| EI_DSP_MATRIX(shift_matrix, 1, shift); |
|
|
| |
| memcpy(shift_matrix.buffer, input_array + input_array_size - shift, shift * sizeof(float)); |
|
|
| |
| memmove(input_array + shift, input_array, (input_array_size - shift) * sizeof(float)); |
|
|
| |
| memcpy(input_array, shift_matrix.buffer, shift * sizeof(float)); |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static int roll(int *input_array, size_t input_array_size, int shift) { |
| if (shift < 0) { |
| shift = input_array_size + shift; |
| } |
|
|
| if (shift == 0) { |
| return EIDSP_OK; |
| } |
|
|
| |
| EI_DSP_MATRIX(shift_matrix, 1, shift); |
|
|
| |
| memcpy(shift_matrix.buffer, input_array + input_array_size - shift, shift * sizeof(int)); |
|
|
| |
| memmove(input_array + shift, input_array, (input_array_size - shift) * sizeof(int)); |
|
|
| |
| memcpy(input_array, shift_matrix.buffer, shift * sizeof(int)); |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static int roll(int16_t *input_array, size_t input_array_size, int shift) { |
| if (shift < 0) { |
| shift = input_array_size + shift; |
| } |
|
|
| if (shift == 0) { |
| return EIDSP_OK; |
| } |
|
|
| |
| EI_DSP_MATRIX(shift_matrix, 1, shift); |
|
|
| |
| memcpy(shift_matrix.buffer, input_array + input_array_size - shift, shift * sizeof(int16_t)); |
|
|
| |
| memmove(input_array + shift, input_array, (input_array_size - shift) * sizeof(int16_t)); |
|
|
| |
| memcpy(input_array, shift_matrix.buffer, shift * sizeof(int16_t)); |
|
|
| return EIDSP_OK; |
| } |
|
|
| static float sum(float *input_array, size_t input_array_size) { |
| float res = 0.0f; |
| for (size_t ix = 0; ix < input_array_size; ix++) { |
| res += input_array[ix]; |
| } |
| return res; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static int dot(matrix_t *matrix1, matrix_t *matrix2, matrix_t *out_matrix) { |
| if (matrix1->cols != matrix2->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| |
| if (matrix1->rows != out_matrix->rows || matrix2->cols != out_matrix->cols) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| #if EIDSP_USE_HW_MATH |
| { |
| EI_RETURN_IF_ERROR(hw_dot(matrix1, matrix2, out_matrix)); |
| } |
| #else |
| memset(out_matrix->buffer, 0, out_matrix->rows * out_matrix->cols * sizeof(float)); |
|
|
| for (size_t i = 0; i < matrix1->rows; i++) { |
| dot_by_row(i, |
| matrix1->buffer + (i * matrix1->cols), |
| matrix1->cols, |
| matrix2, |
| out_matrix); |
| } |
| #endif |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static int dot(matrix_t *matrix1, |
| quantized_matrix_t *matrix2, |
| matrix_t *out_matrix) |
| { |
| if (matrix1->cols != matrix2->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| |
| if (matrix1->rows != out_matrix->rows || matrix2->cols != out_matrix->cols) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| memset(out_matrix->buffer, 0, out_matrix->rows * out_matrix->cols * sizeof(float)); |
|
|
| for (size_t i = 0; i < matrix1->rows; i++) { |
| dot_by_row(i, |
| matrix1->buffer + (i * matrix1->cols), |
| matrix1->cols, |
| matrix2, |
| out_matrix); |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int dot_by_row(int i, float *row, uint32_t matrix1_cols, matrix_t *matrix2, matrix_t *out_matrix) { |
| if (matrix1_cols != matrix2->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| #if EIDSP_USE_HW_MATH |
| EI_RETURN_IF_ERROR(hw_dot_by_row(i, row, matrix1_cols, matrix2, out_matrix)); |
| #else |
| for (size_t j = 0; j < matrix2->cols; j++) { |
| float tmp = 0.0f; |
| for (size_t k = 0; k < matrix1_cols; k++) { |
| tmp += row[k] * matrix2->buffer[k * matrix2->cols + j]; |
| } |
| out_matrix->buffer[i * matrix2->cols + j] += tmp; |
| } |
| #endif |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int dot_by_row(int i, float *row, size_t matrix1_cols, |
| quantized_matrix_t *matrix2, matrix_t *out_matrix) |
| { |
| if (matrix1_cols != matrix2->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (uint16_t j = 0; j < matrix2->cols; j++) { |
| float tmp = 0.0; |
| for (uint16_t k = 0; k < matrix1_cols; k++) { |
| uint8_t u8 = matrix2->buffer[k * matrix2->cols + j]; |
| if (u8) { |
| tmp += row[k] * quantized_values_one_zero[u8]; |
| } |
| } |
| out_matrix->buffer[i * matrix2->cols + j] = tmp; |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| static void transpose_in_place(matrix_t *matrix) { |
| |
| if( matrix->rows != 1 && matrix->cols != 1) { |
| size_t size = matrix->cols * matrix->rows - 1; |
| float temp; |
| size_t next; |
| size_t cycleBegin; |
| size_t i; |
| size_t all_done_mark = 1; |
| ei_vector<bool> done(size+1,false); |
|
|
| i = 1; |
| while (1) |
| { |
| cycleBegin = i; |
| temp = matrix->buffer[i]; |
| do |
| { |
| size_t col = i % matrix->cols; |
| size_t row = i / matrix->cols; |
| |
| next = col*matrix->rows + row; |
| float temp2 = matrix->buffer[next]; |
| matrix->buffer[next] = temp; |
| temp = temp2; |
| done[next] = true; |
| i = next; |
| } |
| while (i != cycleBegin); |
|
|
| |
| for (i = all_done_mark; done[i]; i++) { |
| all_done_mark++; |
| if(i>=size) { goto LOOP_END; } |
| } |
| } |
| } |
| LOOP_END: |
| |
| std::swap(matrix->rows, matrix->cols); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int transpose(matrix_t *matrix) { |
| int r = transpose(matrix->buffer, matrix->cols, matrix->rows); |
| if (r != 0) { |
| return r; |
| } |
|
|
| uint16_t old_rows = matrix->rows; |
| uint16_t old_cols = matrix->cols; |
|
|
| matrix->rows = old_cols; |
| matrix->cols = old_rows; |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static int transpose(float *matrix, int rows, int columns) { |
| EI_DSP_MATRIX(temp_matrix, rows, columns); |
| if (!temp_matrix.buffer) { |
| EIDSP_ERR(EIDSP_OUT_OF_MEM); |
| } |
|
|
| #if EIDSP_USE_HW_MATH |
| EI_RETURN_IF_ERROR(hw_mat_transpose(matrix, temp_matrix.buffer, |
| static_cast<uint16_t>(rows), static_cast<uint16_t>(columns))); |
| #else |
| for (int j = 0; j < rows; j++){ |
| for (int i = 0; i < columns; i++){ |
| temp_matrix.buffer[j * columns + i] = matrix[i * rows + j]; |
| } |
| } |
| #endif |
|
|
| memcpy(matrix, temp_matrix.buffer, rows * columns * sizeof(float)); |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static int transpose(quantized_matrix_t *matrix) { |
| int r = transpose(matrix->buffer, matrix->cols, matrix->rows); |
| if (r != 0) { |
| return r; |
| } |
|
|
| uint16_t old_rows = matrix->rows; |
| uint16_t old_cols = matrix->cols; |
|
|
| matrix->rows = old_cols; |
| matrix->cols = old_rows; |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static int transpose(uint8_t *matrix, int rows, int columns) { |
| |
| EI_DSP_QUANTIZED_MATRIX(temp_matrix, rows, columns, &dequantize_zero_one); |
| if (!temp_matrix.buffer) { |
| EIDSP_ERR(EIDSP_OUT_OF_MEM); |
| } |
|
|
| for (int j = 0; j < rows; j++){ |
| for (int i = 0; i < columns; i++){ |
| temp_matrix.buffer[j * columns + i] = matrix[i * rows + j]; |
| } |
| } |
|
|
| memcpy(matrix, temp_matrix.buffer, rows * columns * sizeof(uint8_t)); |
|
|
| return EIDSP_OK; |
| } |
|
|
| static int dct_transform(float vector[], size_t len) |
| { |
| const size_t fft_data_out_size = (len / 2 + 1) * sizeof(ei::fft_complex_t); |
| const size_t fft_data_in_size = len * sizeof(float); |
|
|
| |
| fft_complex_t *fft_data_out = |
| (ei::fft_complex_t*)ei_dsp_calloc(fft_data_out_size, 1); |
| if (!fft_data_out) { |
| return ei::EIDSP_OUT_OF_MEM; |
| } |
|
|
| float *fft_data_in = (float*)ei_dsp_calloc(fft_data_in_size, 1); |
| if (!fft_data_in) { |
| ei_dsp_free(fft_data_out, fft_data_out_size); |
| return ei::EIDSP_OUT_OF_MEM; |
| } |
|
|
| |
| size_t halfLen = len / 2; |
| for (size_t i = 0; i < halfLen; i++) { |
| fft_data_in[i] = vector[i * 2]; |
| fft_data_in[len - 1 - i] = vector[i * 2 + 1]; |
| } |
| if (len % 2 == 1) { |
| fft_data_in[halfLen] = vector[len - 1]; |
| } |
|
|
| int r = ei::numpy::rfft(fft_data_in, len, fft_data_out, (len / 2 + 1), len); |
| if (r != 0) { |
| ei_dsp_free(fft_data_in, fft_data_in_size); |
| ei_dsp_free(fft_data_out, fft_data_out_size); |
| return r; |
| } |
|
|
| size_t i = 0; |
| for (; i < len / 2 + 1; i++) { |
| float temp = i * M_PI / (len * 2); |
| vector[i] = fft_data_out[i].r * cos(temp) + fft_data_out[i].i * sin(temp); |
| } |
| |
| for (; i < len; i++) { |
| float temp = i * M_PI / (len * 2); |
| int conj_idx = len-i; |
| |
| vector[i] = fft_data_out[conj_idx].r * cos(temp) - fft_data_out[conj_idx].i * sin(temp); |
| } |
| ei_dsp_free(fft_data_in, fft_data_in_size); |
| ei_dsp_free(fft_data_out, fft_data_out_size); |
|
|
| return 0; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int dct2(float *input, size_t N, DCT_NORMALIZATION_MODE normalization = DCT_NORMALIZATION_NONE) { |
| if (N == 0) { |
| return EIDSP_OK; |
| } |
|
|
| int ret = dct_transform(input, N); |
| if (ret != EIDSP_OK) { |
| EIDSP_ERR(ret); |
| } |
|
|
| |
| for (size_t ix = 0; ix < N; ix++) { |
| input[ix] *= 2; |
| } |
|
|
| if (normalization == DCT_NORMALIZATION_ORTHO) { |
| input[0] = input[0] * sqrt(1.0f / static_cast<float>(4 * N)); |
| for (size_t ix = 1; ix < N; ix++) { |
| input[ix] = input[ix] * sqrt(1.0f / static_cast<float>(2 * N)); |
| } |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| static int dct2(matrix_t *matrix, DCT_NORMALIZATION_MODE normalization = DCT_NORMALIZATION_NONE) { |
| for (size_t row = 0; row < matrix->rows; row++) { |
| int r = dct2(matrix->buffer + (row * matrix->cols), matrix->cols, normalization); |
| if (r != EIDSP_OK) { |
| return r; |
| } |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| static uint8_t quantize_zero_one(float value) { |
| const size_t length = sizeof(quantized_values_one_zero) / sizeof(float); |
|
|
| |
| for (size_t ix = 0; ix < length; ix++) { |
| if (quantized_values_one_zero[ix] == value) return ix; |
| } |
|
|
| |
|
|
| if (value < quantized_values_one_zero[0]) { |
| return quantized_values_one_zero[0]; |
| } |
| if (value > quantized_values_one_zero[length - 1]) { |
| return quantized_values_one_zero[length - 1]; |
| } |
|
|
| int lo = 0; |
| int hi = length - 1; |
|
|
| while (lo <= hi) { |
| int mid = (hi + lo) / 2; |
|
|
| if (value < quantized_values_one_zero[mid]) { |
| hi = mid - 1; |
| } else if (value > quantized_values_one_zero[mid]) { |
| lo = mid + 1; |
| } else { |
| return quantized_values_one_zero[mid]; |
| } |
| } |
|
|
| |
| return (quantized_values_one_zero[lo] - value) < (value - quantized_values_one_zero[hi]) ? |
| lo : |
| hi; |
| } |
|
|
| |
| |
| |
| |
| static float dequantize_zero_one(uint8_t value) { |
| return quantized_values_one_zero[value]; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int pad_1d_symmetric(matrix_t *input, matrix_t *output, uint16_t pad_before, uint16_t pad_after) { |
| if (output->cols != input->cols) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| if (output->rows != input->rows + pad_before + pad_after) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| if (input->rows == 0) { |
| EIDSP_ERR(EIDSP_INPUT_MATRIX_EMPTY); |
| } |
|
|
| uint32_t pad_before_index = 0; |
| bool pad_before_direction_up = true; |
|
|
| for (int32_t ix = pad_before - 1; ix >= 0; ix--) { |
| memcpy(output->buffer + (input->cols * ix), |
| input->buffer + (pad_before_index * input->cols), |
| input->cols * sizeof(float)); |
|
|
| if (pad_before_index == 0 && !pad_before_direction_up) { |
| pad_before_direction_up = true; |
| } |
| else if (pad_before_index == input->rows - 1 && pad_before_direction_up) { |
| pad_before_direction_up = false; |
| } |
| else if (pad_before_direction_up) { |
| pad_before_index++; |
| } |
| else { |
| pad_before_index--; |
| } |
| } |
|
|
| memcpy(output->buffer + (input->cols * pad_before), |
| input->buffer, |
| input->rows * input->cols * sizeof(float)); |
|
|
| int32_t pad_after_index = input->rows - 1; |
| bool pad_after_direction_up = false; |
|
|
| for (int32_t ix = 0; ix < pad_after; ix++) { |
| memcpy(output->buffer + (input->cols * (ix + pad_before + input->rows)), |
| input->buffer + (pad_after_index * input->cols), |
| input->cols * sizeof(float)); |
|
|
| if (pad_after_index == 0 && !pad_after_direction_up) { |
| pad_after_direction_up = true; |
| } |
| else if (pad_after_index == static_cast<int32_t>(input->rows) - 1 && pad_after_direction_up) { |
| pad_after_direction_up = false; |
| } |
| else if (pad_after_direction_up) { |
| pad_after_index++; |
| } |
| else { |
| pad_after_index--; |
| } |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int scale(matrix_t *matrix, float scale) { |
| if (scale == 1.0f) { return EIDSP_OK; } |
|
|
| #if EIDSP_USE_HW_MATH |
| EI_RETURN_IF_ERROR(hw_mat_scale_inplace(matrix->buffer, |
| static_cast<uint16_t>(matrix->rows), static_cast<uint16_t>(matrix->cols), scale)); |
| #else |
| return scale_and_add(matrix, scale, 0.0f); |
| #endif |
| return EIDSP_OK; |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| static int scale(matrix_t *matrix, matrix_t *scale_matrix) { |
| if (matrix->rows != scale_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| if (scale_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < matrix->rows; row++) { |
| EI_DSP_MATRIX_B(temp, 1, matrix->cols, matrix->buffer + (row * matrix->cols)); |
| int ret = scale(&temp, scale_matrix->buffer[row]); |
| if (ret != EIDSP_OK) { |
| EIDSP_ERR(ret); |
| } |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int add(matrix_t *matrix, float addition) { |
| return scale_and_add(matrix, 1.0f, addition); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int add(matrix_t *matrix, matrix_t *add_matrix) { |
| if (matrix->rows != add_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| if (add_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < matrix->rows; row++) { |
| EI_DSP_MATRIX_B(temp, 1, matrix->cols, matrix->buffer + (row * matrix->cols)); |
| int ret = add(&temp, add_matrix->buffer[row]); |
| if (ret != EIDSP_OK) { |
| EIDSP_ERR(ret); |
| } |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int subtract(matrix_t *matrix, float subtraction) { |
| return scale_and_add(matrix, 1.0f, -subtraction); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int subtract(matrix_t *matrix, matrix_t *subtract_matrix) { |
| if (matrix->rows != subtract_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| if (subtract_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < matrix->rows; row++) { |
| EI_DSP_MATRIX_B(temp, 1, matrix->cols, matrix->buffer + (row * matrix->cols)); |
| int ret = subtract(&temp, subtract_matrix->buffer[row]); |
| if (ret != EIDSP_OK) { |
| EIDSP_ERR(ret); |
| } |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| static int scale_and_add(matrix_t *matrix, float scale, float add) { |
| if (scale == 1.0f && add == 0.0f) { |
| return EIDSP_OK; |
| } |
|
|
| #if EIDSP_USE_CMSIS_DSP |
| if (matrix->rows > EI_MAX_UINT16 || matrix->cols > EI_MAX_UINT16) { |
| |
| for (uint32_t ix = 0; ix < matrix->rows * matrix->cols; ix++) { |
| matrix->buffer[ix] = (matrix->buffer[ix] * scale) + add; |
| } |
| return EIDSP_OK; |
| } |
|
|
| |
| if (scale != 1.0f) { |
| const arm_matrix_instance_f32 mi = { static_cast<uint16_t>(matrix->rows), static_cast<uint16_t>(matrix->cols), matrix->buffer }; |
| arm_matrix_instance_f32 mo = { static_cast<uint16_t>(matrix->rows), static_cast<uint16_t>(matrix->cols), matrix->buffer }; |
| int status = arm_mat_scale_f32(&mi, scale, &mo); |
| if (status != ARM_MATH_SUCCESS) { |
| return status; |
| } |
| } |
|
|
| if (add != 0.0f) { |
| |
| arm_offset_f32(matrix->buffer, add, matrix->buffer, matrix->rows * matrix->cols); |
| } |
|
|
| #elif EIDSP_USE_NEON |
|
|
| float bias = add; |
| float* ptr = matrix->buffer; |
| size_t remaining = matrix->rows * matrix->cols; |
|
|
| |
| const float32x4_t vbias = vdupq_n_f32(bias); |
|
|
| |
| const float scale_val = scale; |
|
|
| |
| while (remaining >= 16) { |
| float32x4_t v0 = vld1q_f32(ptr + 0); |
| float32x4_t v1 = vld1q_f32(ptr + 4); |
| float32x4_t v2 = vld1q_f32(ptr + 8); |
| float32x4_t v3 = vld1q_f32(ptr + 12); |
|
|
| v0 = vmlaq_n_f32(vbias, v0, scale_val); |
| v1 = vmlaq_n_f32(vbias, v1, scale_val); |
| v2 = vmlaq_n_f32(vbias, v2, scale_val); |
| v3 = vmlaq_n_f32(vbias, v3, scale_val); |
|
|
| vst1q_f32(ptr + 0, v0); |
| vst1q_f32(ptr + 4, v1); |
| vst1q_f32(ptr + 8, v2); |
| vst1q_f32(ptr + 12, v3); |
|
|
| ptr += 16; |
| remaining -= 16; |
| } |
|
|
| |
| while (remaining >= 4) { |
| float32x4_t v = vld1q_f32(ptr); |
| v = vmlaq_n_f32(vbias, v, scale_val); |
| vst1q_f32(ptr, v); |
|
|
| ptr += 4; |
| remaining -= 4; |
| } |
|
|
| |
| while (remaining > 0) { |
| *ptr = scale * (*ptr) + bias; |
| ++ptr; |
| --remaining; |
| } |
| #else |
| for (uint32_t ix = 0; ix < matrix->rows * matrix->cols; ix++) { |
| matrix->buffer[ix] = (matrix->buffer[ix] * scale) + add; |
| } |
| #endif |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int rms(matrix_t *matrix, matrix_t *output_matrix) { |
| if (matrix->rows != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < matrix->rows; row++) { |
| #if EIDSP_USE_HW_MATH |
| float rms_result; |
| hw_rms_array(matrix->buffer + (row * matrix->cols), matrix->cols, &rms_result); |
| output_matrix->buffer[row] = rms_result; |
| #else |
| float sum = 0.0; |
| for(size_t ix = 0; ix < matrix->cols; ix++) { |
| float v = matrix->buffer[(row * matrix->cols) + ix]; |
| sum += v * v; |
| } |
| output_matrix->buffer[row] = sqrt(sum / static_cast<float>(matrix->cols)); |
| #endif |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| static int mean(matrix_t *input_matrix, matrix_t *output_matrix) { |
| if (input_matrix->rows != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| #if EIDSP_USE_HW_MATH |
| float mean; |
| hw_mean_array(input_matrix->buffer + (row * input_matrix->cols), input_matrix->cols, &mean); |
| output_matrix->buffer[row] = mean; |
| #else |
| float sum = 0.0f; |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| sum += input_matrix->buffer[( row * input_matrix->cols ) + col]; |
| } |
|
|
| output_matrix->buffer[row] = sum / input_matrix->cols; |
| #endif |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int mean_axis0(matrix_t *input_matrix, matrix_t *output_matrix) { |
| if (input_matrix->cols != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| |
| |
| |
| |
| |
|
|
| float sum = 0.0f; |
|
|
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| sum += input_matrix->buffer[( row * input_matrix->cols ) + col]; |
| } |
|
|
| output_matrix->buffer[col] = sum / input_matrix->rows; |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static int std_axis0(matrix_t *input_matrix, matrix_t *output_matrix) { |
| if (input_matrix->cols != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| #if EIDSP_USE_HW_MATH |
| return hw_std_axis0(input_matrix, output_matrix); |
| #else |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| float sum = 0.0f; |
|
|
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| sum += input_matrix->buffer[(row * input_matrix->cols) + col]; |
| } |
|
|
| float mean = sum / input_matrix->rows; |
|
|
| float std = 0.0f; |
| float tmp; |
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| tmp = input_matrix->buffer[(row * input_matrix->cols) + col] - mean; |
| std += tmp * tmp; |
| } |
|
|
| output_matrix->buffer[col] = sqrt(std / input_matrix->rows); |
| } |
|
|
| return EIDSP_OK; |
| #endif |
| } |
|
|
| |
| |
| |
| |
| |
| static int min(matrix_t *input_matrix, matrix_t *output_matrix) { |
| if (input_matrix->rows != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| #if EIDSP_USE_HW_MATH |
| float minv; |
| hw_min_array(input_matrix->buffer + (row * input_matrix->cols), input_matrix->cols, &minv); |
| output_matrix->buffer[row] = minv; |
| #else |
| float min = FLT_MAX; |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| float v = input_matrix->buffer[( row * input_matrix->cols ) + col]; |
| if (v < min) { |
| min = v; |
| } |
| } |
|
|
| output_matrix->buffer[row] = min; |
| #endif |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| static int max(matrix_t *input_matrix, matrix_t *output_matrix) { |
| if (input_matrix->rows != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| #if EIDSP_USE_HW_MATH |
| float maxv; |
| hw_max_array(input_matrix->buffer + (row * input_matrix->cols), input_matrix->cols, &maxv); |
| output_matrix->buffer[row] = maxv; |
| #else |
| float max = -FLT_MAX; |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| float v = input_matrix->buffer[( row * input_matrix->cols ) + col]; |
| if (v > max) { |
| max = v; |
| } |
| } |
|
|
| output_matrix->buffer[row] = max; |
| #endif |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| static int stdev(matrix_t *input_matrix, matrix_t *output_matrix) { |
| if (input_matrix->rows != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| #if EIDSP_USE_HW_MATH |
| float stdv; |
| hw_stdev_array(&input_matrix->buffer[(row * input_matrix->cols)], input_matrix->cols, &stdv); |
| output_matrix->buffer[row] = stdv; |
| #else |
| float sum = 0.0f; |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| sum += input_matrix->buffer[(row * input_matrix->cols) + col]; |
| } |
|
|
| float mean = sum / input_matrix->cols; |
|
|
| float std = 0.0f; |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| float diff; |
| diff = input_matrix->buffer[(row * input_matrix->cols) + col] - mean; |
| std += diff * diff; |
| } |
|
|
| output_matrix->buffer[row] = sqrt(std / input_matrix->cols); |
| #endif |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| static int skew(matrix_t *input_matrix, matrix_t *output_matrix) { |
| if (input_matrix->rows != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| #if EIDSP_USE_HW_MATH |
| float skewv; |
| hw_skew_array(&input_matrix->buffer[(row * input_matrix->cols)], input_matrix->cols, &skewv); |
| output_matrix->buffer[row] = skewv; |
| #else |
| float sum = 0.0f; |
| float mean; |
|
|
| |
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| sum += input_matrix->buffer[( row * input_matrix->cols ) + col]; |
| } |
| mean = sum / input_matrix->cols; |
|
|
| |
| float m_3 = 0.0f; |
| float m_2 = 0.0f; |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| float diff; |
| diff = input_matrix->buffer[( row * input_matrix->cols ) + col] - mean; |
| m_3 += diff * diff * diff; |
| m_2 += diff * diff; |
| } |
| m_3 = m_3 / input_matrix->cols; |
| m_2 = m_2 / input_matrix->cols; |
|
|
| |
| m_2 = sqrt(m_2 * m_2 * m_2); |
|
|
| |
| if (m_2 == 0.0f) { |
| output_matrix->buffer[row] = 0.0f; |
| } else { |
| output_matrix->buffer[row] = m_3 / m_2; |
| } |
| #endif |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| static int kurtosis(matrix_t *input_matrix, matrix_t *output_matrix) { |
| if (input_matrix->rows != output_matrix->rows) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
| if (output_matrix->cols != 1) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| for (size_t row = 0; row < input_matrix->rows; row++) { |
| #if EIDSP_USE_HW_MATH |
| float kurtv; |
| hw_kurtosis_array(&input_matrix->buffer[(row * input_matrix->cols)], input_matrix->cols, &kurtv); |
| output_matrix->buffer[row] = kurtv; |
| #else |
| |
| float mean = 0.0f; |
| float sum = 0.0f; |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| sum += input_matrix->buffer[( row * input_matrix->cols ) + col]; |
| } |
| mean = sum / input_matrix->cols; |
|
|
| |
| float m_4 = 0.0f; |
| float variance = 0.0f; |
|
|
| for (size_t col = 0; col < input_matrix->cols; col++) { |
| float diff; |
| diff = input_matrix->buffer[(row * input_matrix->cols) + col] - mean; |
| float square_diff = diff * diff; |
| variance += square_diff; |
| m_4 += square_diff * square_diff; |
| } |
| m_4 = m_4 / input_matrix->cols; |
| variance = variance / input_matrix->cols; |
|
|
| |
| variance = variance * variance; |
| |
| if (variance == 0.0f) { |
| output_matrix->buffer[row] = -3.0f; |
| } else { |
| output_matrix->buffer[row] = (m_4 / variance) - 3.0f; |
| } |
| #endif |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int rfft(const float *src, size_t src_size, float *output, size_t output_size, size_t n_fft) { |
| size_t n_fft_out_features = (n_fft / 2) + 1; |
| if (output_size != n_fft_out_features) { |
| EIDSP_ERR(EIDSP_BUFFER_SIZE_MISMATCH); |
| } |
|
|
| fft_complex_t *fft_output = NULL; |
| auto ptr = EI_MAKE_TRACKED_POINTER(fft_output, n_fft_out_features); |
| EI_ERR_AND_RETURN_ON_NULL(fft_output, EIDSP_OUT_OF_MEM); |
|
|
| int ret = rfft(src, src_size, fft_output, n_fft_out_features, n_fft); |
| if (ret != EIDSP_OK) { |
| return ret; |
| } |
|
|
| |
| for (size_t ix = 0; ix < n_fft_out_features; ix++) { |
| output[ix] = sqrt(fft_output[ix].r * fft_output[ix].r + fft_output[ix].i * fft_output[ix].i); |
| } |
| return EIDSP_OK; |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int rfft(const float *src, size_t src_size, fft_complex_t *output, size_t output_size, size_t n_fft) { |
| size_t n_fft_out_features = (n_fft / 2) + 1; |
| if (output_size != n_fft_out_features) { |
| EIDSP_ERR(EIDSP_BUFFER_SIZE_MISMATCH); |
| } |
|
|
| |
| if (src_size > n_fft) { |
| src_size = n_fft; |
| } |
|
|
| |
| |
| EI_DSP_MATRIX(fft_input, 1, n_fft); |
| if (!fft_input.buffer) { |
| EIDSP_ERR(EIDSP_OUT_OF_MEM); |
| } |
|
|
| |
| |
| memcpy(fft_input.buffer, src, src_size * sizeof(float)); |
| |
| memset(fft_input.buffer + src_size, 0, (n_fft - src_size) * sizeof(float)); |
|
|
| auto res = ei::fft::hw_r2c_fft(fft_input.buffer, output, n_fft); |
| if (handle_fft_hw_failure(res, n_fft)) { |
| |
| return software_rfft(fft_input.buffer, output, n_fft, n_fft_out_features); |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int linspace(float start, float stop, uint32_t number, float *out) |
| { |
| if (number < 1 || !out) { |
| EIDSP_ERR(EIDSP_PARAMETER_INVALID); |
| } |
|
|
| if (number == 1) { |
| out[0] = start; |
| return EIDSP_OK; |
| } |
|
|
| |
| float step = (stop - start) / (number - 1); |
|
|
| |
| for (uint32_t ix = 0; ix < number - 1; ix++) { |
| out[ix] = start + ix * step; |
| } |
|
|
| |
| out[number - 1] = stop; |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int linspace(EIDSP_i32 start, EIDSP_i32 stop, uint32_t number, EIDSP_i32 *out) |
| { |
| if (number < 1 || !out) { |
| EIDSP_ERR(EIDSP_PARAMETER_INVALID); |
| } |
|
|
| if (number == 1) { |
| out[0] = start; |
| return EIDSP_OK; |
| } |
|
|
| |
| EIDSP_i32 step = (stop - start) / (number - 1); |
|
|
| |
| for (uint32_t ix = 0; ix < number - 1; ix++) { |
| out[ix] = start + ix * step; |
| } |
|
|
| |
| out[number - 1] = stop; |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static int int16_to_float(const EIDSP_i16 *input, float *output, size_t length) { |
| for (size_t ix = 0; ix < length; ix++) { |
| output[ix] = static_cast<float>((input[ix])); |
| } |
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static int int8_to_float(const EIDSP_i8 *input, float *output, size_t length) { |
| for (size_t ix = 0; ix < length; ix++) { |
| output[ix] = static_cast<float>((input[ix])); |
| } |
| return EIDSP_OK; |
| } |
|
|
| #if EIDSP_SIGNAL_C_FN_POINTER == 0 |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int signal_from_buffer(const float *data, size_t data_size, signal_t *signal) |
| { |
| signal->total_length = data_size; |
| #ifdef __MBED__ |
| signal->get_data = mbed::callback(&numpy::signal_get_data, data); |
| #else |
| signal->get_data = [data](size_t offset, size_t length, float *out_ptr) { |
| return numpy::signal_get_data(data, offset, length, out_ptr); |
| }; |
| #endif |
| return EIDSP_OK; |
| } |
|
|
| #endif |
|
|
| #if defined ( __GNUC__ ) |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic ignored "-Wstrict-aliasing" |
| #endif |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| __attribute__((always_inline)) static inline float log(float a) |
| { |
| int32_t g = (int32_t) * ((int32_t *)&a); |
| int32_t e = (g - 0x3f2aaaab) & 0xff800000; |
| g = g - e; |
| float m = (float) * ((float *)&g); |
| float i = (float)e * 1.19209290e-7f; |
| |
| float f = m - 1.0f; |
| float s = f * f; |
| |
| #if (EIDSP_USE_CMSIS_DSP) && ((defined (__FPU_PRESENT) && (__FPU_PRESENT == 1U)) && \ |
| (defined (__FPU_USED ) && (__FPU_USED == 1U))) |
| float r; |
| __ASM volatile ( |
| "vfma.f32 %0, %1, %2\n" |
| : "=t"(r) |
| : "t"(0.230836749f), "t"(f), "0"(-0.279208571f) |
| ); |
| float t; |
| __ASM volatile ( |
| "vfma.f32 %0, %1, %2\n" |
| : "=t"(t) |
| : "t"(0.331826031f), "t"(f), "0"(-0.498910338f) |
| ); |
| __ASM volatile ( |
| "vfma.f32 %0, %1, %2\n" |
| : "=t"(r) |
| : "t"(r), "t"(s), "0"(t) |
| ); |
| __ASM volatile ( |
| "vfma.f32 %0, %1, %2\n" |
| : "=t"(r) |
| : "t"(r), "t"(s), "0"(f) |
| ); |
| __ASM volatile ( |
| "vfma.f32 %0, %1, %2\n" |
| : "=t"(r) |
| : "t"(i), "t"(0.693147182f), "0"(r) |
| ); |
| #else |
| float r = fmaf(0.230836749f, f, -0.279208571f); |
| float t = fmaf(0.331826031f, f, -0.498910338f); |
| r = fmaf(r, s, t); |
| r = fmaf(r, s, f); |
| r = fmaf(i, 0.693147182f, r); |
| #endif |
| return r; |
| } |
| |
|
|
| |
| |
| |
| |
| |
| |
| __attribute__((always_inline)) static inline float log2(float a) |
| { |
| int e; |
| float f = frexpf(fabsf(a), &e); |
| float y = 1.23149591368684f; |
| y *= f; |
| y += -4.11852516267426f; |
| y *= f; |
| y += 6.02197014179219f; |
| y *= f; |
| y += -3.13396450166353f; |
| y += e; |
| return y; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| __attribute__((always_inline)) static inline float log10(float a) |
| { |
| return numpy::log2(a) * 0.3010299956639812f; |
| } |
| #if defined ( __GNUC__ ) |
| #pragma GCC diagnostic pop |
| #endif |
|
|
| |
| |
| |
| |
| |
| static int log(matrix_t *matrix) |
| { |
| for (uint32_t ix = 0; ix < matrix->rows * matrix->cols; ix++) { |
| matrix->buffer[ix] = numpy::log(matrix->buffer[ix]); |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| static int log10(matrix_t *matrix) |
| { |
| for (uint32_t ix = 0; ix < matrix->rows * matrix->cols; ix++) { |
| matrix->buffer[ix] = numpy::log10(matrix->buffer[ix]); |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static int32_t saturate(int64_t val, uint32_t sat) |
| { |
| if ((sat >= 1U) && (sat <= 32U)) { |
| int64_t max = (int64_t)((1U << (sat - 1U)) - 1U); |
| int64_t min = -1 - max; |
| if (val > max) { |
| return (int32_t)max; |
| } else if (val < min) { |
| return (int32_t)min; |
| } |
| } |
| return (int32_t)val; |
| } |
|
|
| |
| |
| |
| |
| |
| static int normalize(matrix_t *matrix) { |
| |
| |
| int r; |
|
|
| matrix_t temp_matrix(1, matrix->rows * matrix->cols, matrix->buffer); |
|
|
| matrix_t min_matrix(1, 1); |
| if (!min_matrix.buffer) { |
| EIDSP_ERR(EIDSP_OUT_OF_MEM); |
| } |
| r = min(&temp_matrix, &min_matrix); |
| if (r != EIDSP_OK) { |
| EIDSP_ERR(r); |
| } |
|
|
| matrix_t max_matrix(1, 1); |
| if (!max_matrix.buffer) { |
| EIDSP_ERR(EIDSP_OUT_OF_MEM); |
| } |
| r = max(&temp_matrix, &max_matrix); |
| if (r != EIDSP_OK) { |
| EIDSP_ERR(r); |
| } |
|
|
| float min_max_diff = (max_matrix.buffer[0] - min_matrix.buffer[0]); |
| |
| float row_scale = min_max_diff < 0.001 ? 1.0f : 1.0f / min_max_diff; |
|
|
| r = subtract(&temp_matrix, min_matrix.buffer[0]); |
| if (r != EIDSP_OK) { |
| EIDSP_ERR(r); |
| } |
|
|
| r = scale(&temp_matrix, row_scale); |
| if (r != EIDSP_OK) { |
| EIDSP_ERR(r); |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int clip(matrix_t *matrix, float min, float max) { |
| if (max < min) { |
| EIDSP_ERR(EIDSP_PARAMETER_INVALID); |
| } |
|
|
| for (size_t ix = 0; ix < matrix->rows * matrix->cols; ix++) { |
| if (matrix->buffer[ix] < min) { |
| matrix->buffer[ix] = min; |
| } |
| else if (matrix->buffer[ix] > max) { |
| matrix->buffer[ix] = max; |
| } |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| |
| |
| |
| |
| |
| static int round(matrix_t *matrix) { |
| for (size_t ix = 0; ix < matrix->rows * matrix->cols; ix++) { |
| matrix->buffer[ix] = ::round(matrix->buffer[ix]); |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| static int software_rfft(float *fft_input, fft_complex_t *output, size_t n_fft, size_t n_fft_out_features) |
| { |
| #if EIDSP_INCLUDE_KISSFFT || !defined(EIDSP_INCLUDE_KISSFFT) |
| |
| size_t kiss_fftr_mem_length; |
|
|
| kiss_fftr_cfg cfg = kiss_fftr_alloc(n_fft, 0, NULL, NULL, &kiss_fftr_mem_length); |
| if (!cfg) { |
| EIDSP_ERR(EIDSP_OUT_OF_MEM); |
| } |
|
|
| ei_dsp_register_alloc(kiss_fftr_mem_length, cfg); |
|
|
| |
| kiss_fftr(cfg, fft_input, (kiss_fft_cpx*)output); |
|
|
| ei_dsp_free(cfg, kiss_fftr_mem_length); |
|
|
| return EIDSP_OK; |
| #else |
| return EIDSP_NOT_SUPPORTED; |
| #endif |
| } |
|
|
| static int signal_get_data(const float *in_buffer, size_t offset, size_t length, float *out_ptr) |
| { |
| memcpy(out_ptr, in_buffer + offset, length * sizeof(float)); |
| return 0; |
| } |
|
|
| static uint8_t count_leading_zeros(uint32_t data) |
| { |
| if (data == 0U) { return 32U; } |
|
|
| uint32_t count = 0U; |
| uint32_t mask = 0x80000000U; |
|
|
| while ((data & mask) == 0U) |
| { |
| count += 1U; |
| mask = mask >> 1U; |
| } |
| return count; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| static int power_spectrum( |
| float *frame, |
| size_t frame_size, |
| float *out_buffer, |
| size_t out_buffer_size, |
| uint16_t fft_points) |
| { |
| if (out_buffer_size != static_cast<size_t>(fft_points / 2 + 1)) { |
| EIDSP_ERR(EIDSP_MATRIX_SIZE_MISMATCH); |
| } |
|
|
| int r = numpy::rfft(frame, frame_size, out_buffer, out_buffer_size, fft_points); |
| if (r != EIDSP_OK) { |
| return r; |
| } |
|
|
| for (size_t ix = 0; ix < out_buffer_size; ix++) { |
| out_buffer[ix] = (1.0 / static_cast<float>(fft_points)) * |
| (out_buffer[ix] * out_buffer[ix]); |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| static int welch_max_hold( |
| float *input, |
| size_t input_size, |
| float *output, |
| size_t start_bin, |
| size_t stop_bin, |
| size_t fft_points, |
| bool do_overlap) |
| { |
| |
| float saved_point = 0; |
| bool do_saved_point = false; |
| size_t fft_out_size = fft_points / 2 + 1; |
| float *fft_out; |
| const size_t size = fft_out_size * sizeof(float); |
| ei_unique_ptr_t p_fft_out(nullptr, [size](void* ptr){ei::ei_dsp_free_func(ptr, size);}); |
| if (input_size < fft_points) { |
| fft_out = (float *)ei_dsp_calloc(fft_out_size, sizeof(float)); |
| p_fft_out.reset(fft_out); |
| } |
| else { |
| |
| fft_out = input; |
| |
| saved_point = input[fft_points / 2]; |
| do_saved_point = true; |
| } |
|
|
| |
| memset(output, 0, sizeof(float) * (stop_bin - start_bin)); |
| int input_ix = 0; |
| while (input_ix < (int)input_size) { |
| |
| size_t n_input_points = input_ix + fft_points <= input_size ? fft_points |
| : input_size - input_ix; |
| EI_TRY(power_spectrum( |
| input + input_ix, |
| n_input_points, |
| fft_out, |
| fft_points / 2 + 1, |
| fft_points)); |
| int j = 0; |
| |
| for (size_t i = start_bin; i < stop_bin; i++) { |
| output[j] = std::max(output[j], fft_out[i]); |
| j++; |
| } |
| if (do_overlap) { |
| if (do_saved_point) { |
| |
| input[fft_points / 2] = saved_point; |
| do_saved_point = false; |
| } |
| input_ix += fft_points / 2; |
| } |
| else { |
| input_ix += fft_points; |
| } |
| } |
|
|
| return EIDSP_OK; |
| } |
|
|
| static float variance(float *input, size_t size) |
| { |
| float temp; |
| #if EIDSP_USE_HW_MATH |
| hw_variance(input, size, &temp); |
| #else |
| float mean = 0.0f; |
| for (size_t i = 0; i < size; i++) { |
| mean += input[i]; |
| } |
| mean /= size; |
|
|
| temp = 0.0f; |
| for (size_t i = 0; i < size; i++) { |
| temp += (input[i] - mean) * (input[i] - mean); |
| } |
| temp /= (size - 1); |
| #endif |
| return temp; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static void zero_handling(float *input, size_t input_size) |
| { |
| for (size_t ix = 0; ix < input_size; ix++) { |
| if (input[ix] == 0) { |
| input[ix] = 1e-10; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| static void zero_handling(matrix_t *input) |
| { |
| zero_handling(input->buffer, input->rows * input->cols); |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| static void underflow_handling(float* input, size_t input_size, float epsilon = 1e-07f) |
| { |
| for (size_t ix = 0; ix < input_size; ix++) { |
| if (fabs(input[ix]) < epsilon) { |
| input[ix] = 0.0f; |
| } |
| } |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static void scale(float* input, float scale, float* output, size_t size) { |
| for (size_t ix = 0; ix < size; ix++) { |
| output[ix] = input[ix] * scale; |
| } |
| } |
|
|
| __attribute__((unused)) static void scale(fvec& v, float scale) { |
| for (auto& x : v) { |
| x *= scale; |
| } |
| } |
|
|
| __attribute__((unused)) static void sub(fvec& v, float b) { |
| for (auto& x : v) { |
| x -= b; |
| } |
| } |
|
|
| __attribute__((unused)) static void mul(float* y, const float* x, float* b, size_t n) { |
| for (size_t i = 0; i < n; i++) { |
| y[i] = x[i] * b[i]; |
| } |
| } |
|
|
| __attribute__((unused)) static fvec diff(const float* v, size_t n) { |
| fvec d(n - 1); |
| for (size_t i = 0; i < d.size(); i++) { |
| d[i] = v[i + 1] - v[i]; |
| } |
| return d; |
| } |
|
|
| __attribute__((unused)) static float sum(const float* v, size_t n) { |
| float sum = 0; |
| for (size_t i = 0; i < n; i++) { |
| sum += v[i]; |
| } |
| return sum; |
| } |
|
|
| static float mean(const fvec& v) { |
| float mean = 0; |
| for (auto x : v) { |
| mean += x; |
| } |
| mean /= v.size(); |
| return mean; |
| } |
|
|
| static float mean(const float* v, size_t n) { |
| float mean = 0; |
| for (size_t i = 0; i < n; i++) { |
| mean += v[i]; |
| } |
| mean /= n; |
| return mean; |
| } |
|
|
| static float median(const float* v, size_t n) { |
| fvec vc(n); |
| std::copy(v, v + n, vc.begin()); |
| std::sort(vc.begin(), vc.end()); |
| if (vc.size() % 2 == 0) { |
| return (vc[vc.size() / 2 - 1] + vc[vc.size() / 2]) / 2; |
| } |
| return vc[vc.size() / 2]; |
| } |
|
|
| __attribute__((unused)) static float median(const fvec& v) { |
| return median(v.data(), v.size()); |
| } |
|
|
| static float stddev(const float* v, size_t n, float m , int ddof = 0) { |
| float var = 0; |
| for (size_t i = 0; i < n; i++) { |
| var += (v[i] - m) * (v[i] - m); |
| } |
| var /= n - ddof; |
| return sqrt(var); |
| } |
|
|
| __attribute__((unused)) static float stddev(const float* v, size_t n) { |
| return stddev(v, n, mean(v, n), 0); |
| } |
|
|
| __attribute__((unused)) static float stddev(const float* v, size_t n, int ddof) { |
| return stddev(v, n, mean(v, n), ddof); |
| } |
|
|
| __attribute__((unused)) static float stddev(const fvec& v, int ddof = 0) { |
| return stddev(v.data(), v.size(), mean(v), ddof); |
| } |
|
|
| static float rms(const float* v, size_t n) { |
| float rms = 0; |
| for (size_t i = 0; i < n; i++) { |
| rms += v[i] * v[i]; |
| } |
| rms /= n; |
| return sqrt(rms); |
| } |
|
|
| __attribute__((unused)) static float rms(const fvec& v) { |
| return rms(v.data(), v.size()); |
| } |
|
|
| template <typename T> |
| static float max(const ei_vector<T>& v) { |
| return *std::max_element(v.begin(), v.end()); |
| } |
|
|
| __attribute__((unused)) static float max(const float* v, size_t n) { |
| return *std::max_element(v, v + n); |
| } |
|
|
| template <typename T> |
| static float min(const ei_vector<T>& v) { |
| return *std::min_element(v.begin(), v.end()); |
| } |
|
|
| __attribute__((unused)) static float min(const float* v, size_t n) { |
| return *std::min_element(v, v + n); |
| } |
|
|
| __attribute__((unused)) static int argmax(const fvec& v, int start, int end) { |
| return std::max_element(v.begin() + start, v.begin() + end) - v.begin(); |
| } |
|
|
| __attribute__((unused)) static fvec divide(float num, const float* den, size_t n) { |
| fvec v(n); |
| for (size_t i = 0; i < n; i++) { |
| v[i] = num / den[i]; |
| } |
| return v; |
| } |
|
|
| __attribute__((unused)) static ivec histogram(const float* x, size_t n, int a, int b, int inc) { |
| int num_bins = (b - a) / inc; |
| ivec bins(num_bins, 0); |
| for (size_t i = 0; i < n; i++) { |
| int bin = (int)((x[i] - a) / inc); |
| if (bin >= 0 && bin < num_bins) { |
| bins[bin]++; |
| } |
| } |
| return bins; |
| } |
|
|
| __attribute__((unused)) static fvec cumsum(const float* v, size_t n) { |
| fvec c(n); |
| c[0] = v[0]; |
| for (size_t i = 1; i < n; i++) { |
| c[i] = c[i - 1] + v[i]; |
| } |
| return c; |
| } |
|
|
| __attribute__((unused)) static fvec arange(float start, float end, float step) { |
| assert(start < end); |
| assert(step > 0); |
| fvec v(::round((end - start) / step)); |
| for (size_t i = 0; i < v.size(); i++) { |
| v[i] = start + i * step; |
| } |
| return v; |
| } |
|
|
| __attribute__((unused)) static void add(fvec& v, fvec& b) { |
| for (size_t i = 0; i < v.size(); i++) { |
| v[i] += b[i]; |
| } |
| } |
|
|
| __attribute__((unused)) static float trapz(const fvec& x, const fvec& y, size_t lo, size_t hi) { |
| float area = 0; |
| for (size_t i = lo; i < hi; i++) { |
| area += (x[i + 1] - x[i]) * (y[i + 1] + y[i]) / 2; |
| } |
| return area; |
| } |
|
|
| __attribute__((unused)) static fvec quantile(const fvec& v, size_t start, size_t end, const fvec& q) { |
| end = std::min(end, v.size()); |
| fvec vc(end - start); |
| std::copy(v.begin() + start, v.begin() + end, vc.begin()); |
| std::sort(vc.begin(), vc.end()); |
| fvec res(q.size()); |
| for (size_t i = 0; i < q.size(); i++) { |
| res[i] = vc[q[i] * vc.size()]; |
| } |
| return res; |
| } |
|
|
| __attribute__((unused)) static fvec quantile(const float* v, size_t n, const fvec& q) { |
| fvec vc(n); |
| std::copy(v, v + n, vc.begin()); |
| std::sort(vc.begin(), vc.end()); |
| fvec res(q.size()); |
| for (size_t i = 0; i < q.size(); i++) { |
| res[i] = vc[q[i] * vc.size()]; |
| } |
| return res; |
| } |
|
|
| static float dot(const float* x, const float* y, size_t n) { |
| float res = 0; |
| for (size_t i = 0; i < n; i++) { |
| res += x[i] * y[i]; |
| } |
| return res; |
| } |
|
|
|
|
| __attribute__((unused)) static float cosine_similarity(const fvec& x, const fvec& y) { |
| float xy = dot(x.data(), y.data(), x.size()); |
| float magx = dot(x.data(), x.data(), x.size()); |
| float magy = dot(y.data(), y.data(), y.size()); |
| xy /= sqrt(magx * magy); |
| return xy; |
| } |
|
|
| __attribute__((unused)) static void ln(fvec& v) { |
| for (auto& x : v) { |
| x = log(x); |
| } |
| } |
|
|
| static size_t next_power_of_2(size_t x) { |
| size_t res = 1; |
| while (res < x) { |
| res *= 2; |
| } |
| return res; |
| } |
|
|
| static void detrend(float* data, size_t n) { |
| |
| float mean = 0.0; |
| for (size_t i = 0; i < n; i++) { |
| mean += data[i]; |
| } |
| mean /= n; |
|
|
| |
| float x_mean = (n + 1) / 2.0; |
| float y_mean = mean; |
| float numerator = 0.0; |
| float denominator = 0.0; |
| for (size_t i = 0; i < n; i++) { |
| numerator += (i + 1 - x_mean) * (data[i] - y_mean); |
| denominator += (i + 1 - x_mean) * (i + 1 - x_mean); |
| } |
| float slope = numerator / denominator; |
|
|
| |
| for (size_t i = 0; i < n; i++) { |
| data[i] = data[i] - (slope * (i + 1)); |
| } |
|
|
| |
| float detrended_mean = 0.0; |
| for (size_t i = 0; i < n; i++) { |
| detrended_mean += data[i]; |
| } |
| detrended_mean /= n; |
|
|
| |
| for (size_t i = 0; i < n; i++) { |
| data[i] -= detrended_mean; |
| } |
| } |
|
|
| static fvec detrend(const fvec& data) { |
| auto ret = data; |
| detrend(ret.data(), ret.size()); |
| return ret; |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static void mult(const float* x, const float* y, float* z, size_t n) { |
| for (size_t i = 0; i < n; i++) { |
| z[i] = x[i] * y[i]; |
| } |
| |
| |
| } |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| static void add(const float* x, const float* y, float* z, size_t n) { |
| for (size_t i = 0; i < n; i++) { |
| z[i] = x[i] + y[i]; |
| } |
| } |
|
|
| private: |
| |
| |
| |
| |
| |
| |
| static bool handle_fft_hw_failure(int res, size_t n_fft) { |
| static bool first_time = true; |
| if (res == EIDSP_OK) { |
| return false; |
| } |
|
|
| |
| if (res != EIDSP_NO_HW_ACCEL && first_time) { |
| first_time = false; |
| if (res == EIDSP_FFT_SIZE_NOT_SUPPORTED) { |
| EI_LOGI("HW RFFT failed, FFT size not supported. Must be a power of 2 between %d and %d, (size was %d)", |
| ei::fft::MIN_FFT_SIZE, ei::fft::MAX_FFT_SIZE, (int)n_fft); |
| } |
| else { |
| EI_LOGI("HW RFFT failed, falling back to SW"); |
| } |
| } |
| return true; |
| } |
|
|
|
|
| }; |
|
|
| struct fmat { |
| ei_matrix* mat = nullptr; |
| fmat(size_t rows, size_t cols) { |
| mat = new ei_matrix(rows, cols); |
| assert(mat); |
| } |
|
|
| ~fmat() { |
| delete mat; |
| } |
|
|
| void resize(size_t rows, size_t cols) { |
| delete mat; |
| mat = new ei_matrix(rows, cols); |
| } |
|
|
| float* operator[](size_t i) { |
| if (mat == nullptr || i >= mat->rows) { |
| return nullptr; |
| } |
| return mat->get_row_ptr(i); |
| } |
|
|
| void fill(float x) { |
| if (mat == nullptr) { |
| return; |
| } |
| for (size_t i = 0; i < mat->rows; i++) { |
| for (size_t j = 0; j < mat->cols; j++) { |
| (*this)[i][j] = x; |
| } |
| } |
| } |
|
|
| void fill_col(size_t col, float x) { |
| if (mat == nullptr) { |
| return; |
| } |
| for (size_t i = 0; i < mat->rows; i++) { |
| (*this)[i][col] = x; |
| } |
| } |
|
|
| void fill_row(size_t row, float x) { |
| if (mat == nullptr) { |
| return; |
| } |
| for (size_t i = 0; i < mat->cols; i++) { |
| (*this)[row][i] = x; |
| } |
| } |
| }; |
| } |
|
|
| __attribute__((unused)) static bool find_mtx_by_idx(ei_feature_t* mtx, ei::matrix_t** matrix, uint32_t mtx_id, size_t mtx_size) { |
| for (uint32_t i = 0; i < mtx_size; i++) { |
| EI_LOGD("mtx[%d].blockId = %d\n", i, mtx[i].blockId); |
| if (mtx[i].matrix == NULL) { |
| EI_LOGD("Matrix is NULL\n"); |
| continue; |
| } |
| if (mtx[i].blockId == mtx_id || mtx[i].blockId == 0) { |
| EI_LOGD("Found matrix with blockId %d\n", mtx[i].blockId); |
| *matrix = mtx[i].matrix; |
| return true; |
| } |
| } |
| EI_LOGD("Matrix not found\n"); |
| return false; |
| } |
|
|
| __attribute__((unused)) static bool find_mtx_by_idx(ei_feature_t* mtx, ei::matrix_i8_t** matrix, uint32_t mtx_id, size_t mtx_size) { |
| for (uint32_t i = 0; i < mtx_size; i++) { |
| EI_LOGD("mtx[%d].blockId = %d\n", i, mtx[i].blockId); |
| if (mtx[i].matrix_i8 == NULL) { |
| EI_LOGD("Matrix is NULL\n"); |
| continue; |
| } |
| if (mtx[i].blockId == mtx_id || mtx[i].blockId == 0) { |
| EI_LOGD("Found matrix with blockId %d\n", mtx[i].blockId); |
| *matrix = mtx[i].matrix_i8; |
| return true; |
| } |
| } |
| EI_LOGD("Matrix not found\n"); |
| return false; |
| } |
|
|
| __attribute__((unused)) static bool find_mtx_by_idx(ei_feature_t* mtx, ei::matrix_u8_t** matrix, uint32_t mtx_id, size_t mtx_size) { |
| for (uint32_t i = 0; i < mtx_size; i++) { |
| EI_LOGD("mtx[%d].blockId = %d\n", i, mtx[i].blockId); |
| if (mtx[i].matrix_u8 == NULL) { |
| EI_LOGD("Matrix is NULL\n"); |
| continue; |
| } |
| if (mtx[i].blockId == mtx_id || mtx[i].blockId == 0) { |
| EI_LOGD("Found matrix with blockId %d\n", mtx[i].blockId); |
| *matrix = mtx[i].matrix_u8; |
| return true; |
| } |
| } |
| EI_LOGD("Matrix not found\n"); |
| return false; |
| } |
|
|
| __attribute__((unused)) static size_t get_feature_size(ei_feature_t* mtx, uint32_t ids_size, uint32_t* ids, size_t mtx_size) { |
| size_t feat_size = 0; |
| ei::matrix_t* matrix = NULL; |
| for (size_t i = 0; i < ids_size; i++) { |
| size_t cur_mtx = ids[i]; |
|
|
| if (!find_mtx_by_idx(mtx, &matrix, cur_mtx, mtx_size)) { |
| ei_printf("ERR: Cannot find matrix with id %zu\n", cur_mtx); |
| return -1; |
| } |
| feat_size += matrix->rows * matrix->cols; |
| } |
| return feat_size; |
| } |
|
|
| #endif |
|
|