0

I wanted to multiply 2 matrices in codesys. I have implemented the code in the structured text language. However I am not able to generate the results correctly. Below is the logic which i am trying to implement.

Initialisation in codesys:

    PROGRAM POU
VAR
    a: ARRAY [1..5,1..2] OF INT:= [1,2,3,4,5,6,7,8,9,1]; 
    b: ARRAY [1..2,1..5] OF INT := [1,2,3,4,5,6,7,8,9,1];
    r1: INT:= 5; // no. of rows in a;
    c1: INT:=2; // no. of columns in a;
    r2: INT:= 2; //no. Of rows in b;
    c2: INT:= 5; //no. of columns in b;
    i: INT;
    j: INT ;
    k: INT;
    z: INT:=2;
    result: ARRAY [1..5,1..5] OF INT:= 0;
END_VAR

Program logic:

    FOR i:=1 TO r1 DO
    FOR j:=1 TO c2 DO
        FOR k:=1 TO z DO 
        result[i,j]:= result[i,j]+(a[i,k]*b[k,j]);
    END_FOR
    END_FOR
    END_FOR

What may be the reason for not getting the desired output?

1 Answers1

0

The only obvious problem I see is, if you want to initialize an array with a specific value, don't do result: ARRAY [1..5, 1..5] OF INT := 0 as you would should get an error C0032: Cannot convert type 'BIT' to type 'ARRAY [1..5, 1..5] OF INT', instead do this: result: ARRAY [1..5, 1..5] OF INT := [ 25(0) ], although in codesys arrays Elements to which no initialization value is assigned explicitly are initialized internally with the default value of the basic data type, which in case of an INT is 0.

Also, to avoid errors, instad of hardcoding the boundaries I'd recomment to instad use the built in LOWER_BOUND an UPPER_BOUND functions.

Here's an example generic function for Matrix multiplication based on the code in your question:

METHOD IntMatrixProduct : BOOL
VAR_IN_OUT
    A: ARRAY [*, *] OF INT;
    B: ARRAY [*, *] OF INT;
    C: ARRAY [*, *] OF INT;
END_VAR
VAR_INPUT
    zero_C: BOOL := TRUE;
END_VAR
VAR
    al1: DINT := LOWER_BOUND(A, 1);
    au1: DINT := UPPER_BOUND(A, 1);
    al2: DINT := LOWER_BOUND(A, 2);
    au2: DINT := UPPER_BOUND(A, 2);
    bl1: DINT := LOWER_BOUND(B, 1);
    bu1: DINT := UPPER_BOUND(B, 1);
    bl2: DINT := LOWER_BOUND(B, 2);
    bu2: DINT := UPPER_BOUND(B, 2);
    cl1: DINT := LOWER_BOUND(C, 1);
    cu1: DINT := UPPER_BOUND(C, 1);
    cl2: DINT := LOWER_BOUND(C, 2);
    cu2: DINT := UPPER_BOUND(C, 2);
    height: DINT := au1 - al1;
    width: DINT := bu2 - bl2;
    common: DINT := au2 - al2;
    i, j, k: DINT;
END_VAR

IF (common <> bu1 - bl1 // Width of A != Height of B
    OR_ELSE cu1 - cl1 <> height // Height of C != Height of A
    OR_ELSE cu2 - cl2 <> width) THEN // Width of C != Width of B
    IntMatrixProduct := FALSE; // Error!
    RETURN;
END_IF

// Zero C
IF (zero_C) THEN
    FOR i := 0 TO height DO
        FOR j := 0 TO width DO
            result[cl1 + i, cl2 + j] := 0;
        END_FOR
    END_FOR
END_IF

// Calcutale A*B
FOR i := 0 TO height DO
    FOR j := 0 TO width DO
        FOR k := 0 TO common DO 
            result[cl1 + i, cl2 + j] := result[cl1 + i, cl2 + j] + (a[al1 + i, al2 + k] * b[bl1 + k, bl2 + j]);
        END_FOR
    END_FOR
END_FOR

IntMatrixProduct := TRUE; // Success

You can also try importing the code using PLCOpen from here.

PS. Here's the result I get after running the above function:

Codesys result array screenshot

Guiorgy
  • 1,405
  • 9
  • 26
  • Thanks will have a look at it and update the result. – Nehal Trivedi Aug 25 '22 at 15:01
  • Works just fine for me, what version of codesys are you using? – Guiorgy Aug 25 '22 at 17:28
  • I am using codesys v3.5 sp9 patch7 hotfix 3+ – Nehal Trivedi Aug 25 '22 at 20:26
  • I imported the code in my codesys which worked fine, but i have created a POU where i have written the program logic and then called the method IntMatrixMultiplication. Until i import this i do not get any error but if i import the POU in my PLC program i get the error stating cannot convert type 'BOOL' to type 'INTMATRIXMULTIPLICATION' – Nehal Trivedi Aug 25 '22 at 20:29
  • try the updated version – Guiorgy Aug 25 '22 at 20:35
  • I tried the updated version, no errors but does the code take time to run? Because currently i see values continuously getting updated in some range of 1000's. – Nehal Trivedi Aug 25 '22 at 20:52
  • The function takes the A and B matrixes and the C matrix where A\*B will be calculated, but I also added `zero_C: BOOL;` input, which, if true, will zero the C matrix before calculating A\*B (in other words write 0s into C). If your result matrix is already zeroed (like at the start) you can skip this step by setting `zero_C := FALSE`. In my example you were only meant to run the function once, since that's all it takes to calculate the product. Try running 1 cycle (Ctrl + F5) – Guiorgy Aug 26 '22 at 09:29
  • Thanks for the suggestions that finally worked. But what if i have a continuous data coming from a real-time system and this data needs to get multiplied because in this case my system generates continuous data and at each time instant it should get updated so will this logic still work? – Nehal Trivedi Aug 26 '22 at 11:58
  • just set the `zero_C := TRUE`.... – Guiorgy Aug 26 '22 at 13:11
  • Is it possible to multiply the result of this matrix again with b matrix and how do you assign this new result to a new variable? For example something like (u = result * b) – Nehal Trivedi Sep 01 '22 at 10:00
  • This is just a function that multiplies A and B and writes the result into C. You can call it as many times as you want while passing different arrays to A,B,C – Guiorgy Sep 01 '22 at 12:50