Matrix multiplication is needed, for example, in the calculation of electrical networks. Python can perform these multiplications for you.
If several two-port networks are connected in series (catenary circuit), then the catenary shape (A parameter) can be used to calculate the required input voltage and current for a given output voltage and current by matrix multiplication.
Two matrices are multiplied with each other by multiplying the rows of the first matrix by the columns of the second matrix, element by element, and adding the individual products (according to Falk’s scheme):
A simple example will demonstrate the matrix multiplication using a schema (see the table below). The following two matrices are to be multiplied:
The first matrix is entered in the first and second columns and the third and fourth rows of a table. The second matrix is entered in the third and fourth columns and in the first and second rows of the table.
The first row of the first matrix is multiplied element by element by the first column of the second matrix. The two products are added up. The second row of the first matrix is multiplied by the first column of the second matrix. The two products are added up again. The second column is calculated according to the same schema.
NumPy provides the array([[a11,a12],[a21,a22]]) function for generating the matrices. You can adjust the number of rows and columns as needed.
The easiest way to perform matrix multiplication is to use the infix operator @. Alternatives are matmul(A,B) or multi_dot([A,B,C,...]).
The listing below shows how you can perform matrix multiplication using the numbers from our earlier example.
01 #12_mulmatrix1.py
02 import numpy as np
03 A=np.array ([[1, 2],
04 [3, 4]])
05 B=np.array ([[5, 6],
06 [7, 8]])
07 C=A@B
08 D=B@A
09 #Output
10 print(type(A))
11 print("Matrix A\n",A)
12 print("Matrix B\n",B)
13 print("Product A*B\n",C)
14 print("Product B*A\n",D)
Output
<class 'numpy.ndarray'>
Matrix A
[[1 2]
[3 4]]
Matrix B
[[5 6]
[7 8]]
Product A*B
[[19 22]
[43 50]]
Product B*A
[[23 34]
[31 46]]
Analysis: Lines 03 to 06 define matrices with two rows and two columns each. The values of the individual coefficients are stored in variables A and B.
Line 07 performs the matrix multiplication C=A@B, while line 08 performs the multiplication with an interchanged order of factors D=B@A.
The product for C is correctly output line 13 and matches the value that was manually calculated in the table. The result from line 14, on the other hand, deviates from this. This result is also correct, as you can easily check by recalculation. (You thus learn from this that the commutative law does not apply to a matrix product.)
Let’s say a Python program needs to calculate the matrix of catenary parameters and the required input variables U1 and I1 for given output variables U2 and I2 for a π-substitute circuit, as shown in this figure.
Any passive two-port network can be described in general terms by a linear system of equations with a matrix of four parameters and the column vectors from voltages or currents.
For this problem, the catenary shape must be chosen. On the left-hand side of the equation system, a column vector contains the input variables we are looking for. On the right-hand side, we have a catenary matrix with the four coefficients A11 to A22. The catenary matrix is multiplied by the column vector of the output variables. If the coefficients of the catenary matrix and the column vector of the output variables are known, the input variables U1 and I1 can be calculated:
For the transverse resistors R1 and R3, the following A parameters can be determined from the circuit shown earlier:
For the series resistance R2, the following matrix results:
To obtain the system matrix of the entire circuit, you need to multiply all three partial matrices with each other.
This listing performs the matrix multiplication from the three partial matrices for the π-substitution circuit. You can of course change the values of the resistors for further testing.
01 #13_mulmatrix2.py
02 import numpy as np
03 R1=1
04 R2=2
05 R3=1
06 U2=1
07 I2=1
08 A1q=np.array([[1, 0],
09 [1/R1, 1]])
10 Al=np.array([[1, R2],
11 [0, 1]])
12 A2q=np.array([[1, 0],
13 [1/R3, 1]])
14 A=A1q@Al@A2q
15 b=np.array([[U2],[I2]])
16 E=A@b
17 U1,I1=E[0,0],E[1,0]
18 print("Chain shape A\n",A)
19 print("Input variables\n",E)
20 print("Input voltage U1=%3.2f V" %U1)
21 print("Input current I1=%3.2f A" %I1)
Output
Chain shape A
[[3. 2.]
[4. 3.]]
Input variables
[[5.]
[7.]]
Input voltage U1=5.00 V
Input current I1=7.00 A
Analysis: The values for the output voltage U2; the output current I2; and the three resistors R1, R2, and R3 were taken from the specifications of the circuit.
3
In lines 08 to 13, the three partial matrices A1q, Al, and A2q are defined for the transverse resistances R1 and R3 and the series resistance R2. Line 14 performs the matrix multiplication A=A1q@Al@A2q. Pay attention to the correct sequence of factors. As shown earlier in Listing 3.12, the commutative law does not apply to matrix multiplication! Changing the order of the partial matrices would also represent a different circuit structure.
Line 15 creates the column vector b=np.array([[U2],[I2]]) for the output variables. In line 16, system matrix A is multiplied by column vector b. The result of the matrix multiplication is assigned to column vector E.
The input voltage must be 5 V so that a voltage of U2 = 1 V is present at the output of the π-substitute circuit. A current of I1 = 7 A must flow at the input of the circuit so that a current of I2 = 1 A flows at the output. You can check the results using the circuit.
The output variables U2 and I2 of a two-port network are calculated using the B catenary parameters. The following two-port equations are then obtained for a π-substitute circuit:
For the transverse resistors R1 and R3, the B parameters can be determined from the circuit shown in as follows:
For the series resistance R2, the following matrix is obtained:
In general, the B parameters can be determined from the inverse matrix of A. The following applies:
The listing below calculates the output voltage U2 and output current I2 of a π-substitute circuit with the B catenary parameters.
01 #14_mulmatrix3.py
02 import numpy as np
03 R1=1
04 R2=2
05 R3=1
06 U1=5
07 I1=7
08 B1q=np.array([[1, 0],
09 [-1/R1, 1]])
10 B2l=np.array([[1, -R2],
11 [0, 1]])
12 B3q=np.array([[1, 0],
13 [-1/R3, 1]])
14 B=B1q@B2l@B3q
15 b=np.array([[U1],[I1]])
16 E=B@b
17 U2,I2=E[0,0],E[1,0]
18 print("Chain shape B\n",B)
19 print("Output variables\n",E)
20 print("Output voltage U2=%3.2fV" %U2)
21 print("Output current I2=%3.2fA" %I2)
Output
Chain shape B
[[ 3. -2.]
[-4. 3.]]
Output variables
[[1.]
[1.]]
Output voltage U2=1.00V
Output current I2=1.00A
Analysis: Basically, the program is structured in the same way as shown in earlier, except that the parameters in the secondary diagonal have a negative sign. The result for the output voltage U2 and the output current I2 matches the values determined using Kirchhoff’s circuit laws in the circuit shown.
The next example shows the multiplication of the row vector of an angular velocity with an inertia tensor I (3×3 matrix) and the column vector of an angular velocity.
For the rotational energy, the following applies:
The superscript T means that the vector of angular velocity must be transposed, that is, the column vector is converted into a row vector. In component notation, you obtain the following:
For the inertia tensor of a point mass m, the following applies:
The product of the mass m and the matrix with the location coordinates is referred to as the inertia tensor. If you perform the matrix multiplication, you’ll get the rotational energy, which is stored in the rotating body.
For a case where mass m with radius x = r rotates around the z-axis in the x-y-plane, the following applies in a simplified way:
This listing calculates the rotational energy of a point mass of mass m = 6 kg rotating in space around the z-axis with an angular velocity of .
01 #15_mulmatrix4.py
02 import numpy as np
03 x=1 #distance in m
04 y=0
05 z=0
06 wx=0
07 wy=0
08 wz=1 #angular velocity
09 m=6 #mass in kg
10 w_Z=np.array([wx,wy,wz])
11 I=m*np.array([[y**2+z**2, -x*y, -x*z],
12 [-x*y, x**2+z**2, -y*z],
13 [-x*z, -y*z, x**2+y**2]])
14 w_S=np.array([[wx],
15 [wy],
16 [wz]])
17 #Calculation of the rotational energy
18 Erot=0.5*w_Z@I@w_S
19 #Erot=0.5*w_S.T@I@w_S
20 Er=Erot[0]
21 #Output
22 print("Rotational energy: %3.2f joules" %Er)
Output
Rotational energy: 3.00 joules
Analysis: The rotational energy is calculated according to the rule: “row vector multiplied by 3×3 matrix multiplied by column vector.” Following this sequence is mandatory because the commutative law does not apply with matrices! Line 10 contains the row vector of angular velocity, lines 11 to 13 contain the 3×3 matrix of the inertia tensor, and lines 14 to 16 contain the column vector of the angular velocity.
The statement in line 18 performs the matrix multiplication and stores the result in the Erot variable. Alternatively, you can comment out lines 10 and 18 and remove the comment in line 19. In this line, the column vector from line 14 is transposed into a row vector using the T property.
Editor’s note: This post has been adapted from a section of the book Python for Engineering and Scientific Computing by Veit Steinkamp.