Hello,
While debugging a DSP algorithm, I realized the problem is duo to the CMSIS matrix inverse function: arm_mat_inverse_f32. It's really strange and is driving me crazy. arm_mat_inverse_f32 returns the right result for some Matrices but wrong result for some other! I assure you the matrices are not singular or anything like this, the algorithm works just fine with the same input data on MATLAB. I have no idea what the problem could be, any suggestions?
Regards
It might help to post some actual test cases that demonstrate the phenomenon.
You write your post as if you think every reader would actually know what "the problem" is. Exactly how do you think we can know what issues you are having? You think we are reading you monitor at the same time as you?
You may either post the source code here that allows us to duplicate the issue or report the problem to support.intl@keil.com.
Ok, here is the part of my code that uses this function:
arm_mat_init_f32(&m1, SIZE, SIZE, Matrix); arm_mat_init_f32(&m2, SIZE, SIZE, Matrix_Inverse); status=arm_mat_inverse_f32(&m1,&m2);
I tested with the following 6 by 6 matrices and some other. The first one works just fine, the second one doesn't. I'm writing my own inverse function using Gauss_Jordan method, but I really would like to know whats going on here.
float32_t Matrix[SIZE*SIZE]={ 7.6294, 1.1843, 1.0842, 1.7056, 1.3111, 0.8036, 1.1843, 7.0938, 1.4429, 1.9244, 0.9154, 1.0024, 1.0842, 1.4429, 7.6006, 0.7976, 1.1649, 1.1927, 1.7056, 1.9244, 0.7976, 6.0714, 1.2414, 0.9802, 1.3111, 0.9154, 1.1649, 1.2414, 7.3110, 0.2683, 0.8036, 1.0024, 1.1927, 0.9802, 0.2683, 7.6469};
float32_t Matrix[SIZE*SIZE]={ 2.4086, -1.7141, 0.9385, 1.9594, -0.4342, 1.3369, 5.1228, 0.3019, -1.9435, 0.3259, 0.0788, 1.3030, -1.8536, -1.3981, 0.0812, -3.1542, 0.2977, 1.2532, -8.8154, 0.4773, -0.6195, 1.2333, -0.1475, 1.1768, 1.6616, 1.9255, 0.8342, -1.4220, -0.6654, 1.0847, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000, 1.0000};
Without having time to try to run your code, I get interested about one thing.
Your declaration of an array is as a one-dimensional array of SIZE*SIZE entries. Are you sure that your sequence of numbers correlates correctly with the row and column order of the matrice, so that when you test to invert the matrix yourself you are working with the same matrix values as you send to arm_mat_inverse_f32()?
That's what I thought at first, but it doesn't even matter, since I tried multiplying the inverse matrix to the original using "arm_mat_mult_f32" function. Again only the first set of data results in Identity matrix! Any matrix multiplied by it's inverse should result the Identity matrix.
Never mind...I found out what's the problem. A stupid mistake by me! sorry for the waste of time.
A stupid mistake by me! sorry for the waste of time.
It would be less of a waste if you told what that mistake actually was. As-is, nobody but you learned anything from this exercise, so it would be quite an improvement if future readers were to find a "Don't do ...this..., because it won't work" kind of lesson in this place.
absolutely spot on.
Hello all,
The fumction arm_mat_init_f32() stores only a pointer to the matrix data in the matrix instance. It does not copy the matrix data. The function arm_mat_inverse_f32() overwrites the matrix data from the source matrix when it generates the inverse matrix. This behaviour is not yet documented in the CMSIS DSP_Lib documentation.
Please see code below for matrix inversion. This test uses the data mentioned above.
#include "arm_math.h" #include "math_helper.h" #define SIZE (6) float32_t Matrix1[SIZE*SIZE] ={ 7.6294, 1.1843, 1.0842, 1.7056, 1.3111, 0.8036, 1.1843, 7.0938, 1.4429, 1.9244, 0.9154, 1.0024, 1.0842, 1.4429, 7.6006, 0.7976, 1.1649, 1.1927, 1.7056, 1.9244, 0.7976, 6.0714, 1.2414, 0.9802, 1.3111, 0.9154, 1.1649, 1.2414, 7.3110, 0.2683, 0.8036, 1.0024, 1.1927, 0.9802, 0.2683, 7.6469 }; float32_t Matrix1S[SIZE*SIZE]; /* Second Matrix */ float32_t Matrix1I[SIZE*SIZE]; /* Inverse Matrix */ float32_t Matrix1U[SIZE*SIZE]; /* Unity Matrix */ arm_matrix_instance_f32 m1; /* Matrix 1 Instance */ arm_matrix_instance_f32 m1S; /* Matrix 1 Second Instance */ arm_matrix_instance_f32 m1I; /* Matrix 1 Inverse Instance */ arm_matrix_instance_f32 m1U; /* Matrix 1 Unity Instance */ int32_t main(void) { uint32_t i; arm_status status = ARM_MATH_TEST_FAILURE; uint16_t rows = SIZE; uint16_t columns = SIZE; /* copy matrix data because arm_mat_inverse_f32(...) overwrites the data from the source matrix */ for (i = 0; i < (SIZE*SIZE); i++) Matrix1S[i] = Matrix1[i]; /* initialize the used matrix instances */ arm_mat_init_f32(&m1, rows, columns, Matrix1); arm_mat_init_f32(&m1S, rows, columns, Matrix1S); arm_mat_init_f32(&m1I, rows, columns, Matrix1I); arm_mat_init_f32(&m1U, rows, columns, Matrix1U); /* generate the inverse matrix */ status = arm_mat_inverse_f32(&m1S ,&m1I); /* matrix * inverse matrix = unity matrix */ status = arm_mat_mult_f32(&m1, &m1I, &m1U); while(1); }
Best regards, Martin Guenther
Missing documentation costs end users huge amounts of money and time. Been there, seen that happen.
I'm glad that KEIL/ARM has stepped up and admitted they did not document something. That is rare in a company. Thumbs up. Now go fix the documentation.
Microchip is one of the worst when it comes to documentation.