Why use Imaginary Numbers ?¶
Imaginary numbers help us solve problems that involve rotation, it introduces the gaussian dimension (imaginary plane) that can help us visualize the rotation of vectors.
A practical example:
In [1]:
import numpy as np
import matplotlib.pyplot as plt
# Complex vector example
a = 1 + 1j
def complexCalc(complexNum):
""" Returns the Real, imaginary, phase and magnitude of a complex number
Parameters
----------
complexNum: Complex number
Returns
----------
Ra: Real Part
Ima: Imaginary Part
phia: Angle in Radians
maga: Magnitude
"""
# Real and imaginary parts
Ra = complexNum.real
Ima = complexNum.imag
# Phase of the complex vector, in radians (pi radians = 180 degree)
phia = np.angle(complexNum)
# Magnitude of the complex vector
maga = np.abs(complexNum)
print("The Vector", complexNum)
print("Real:",Ra )
print("Imaginary:", Ima)
print("Phase:", (180/np.pi)*phia, "degree")
print("Magnitude:", maga)
return Ra, Ima, phia, maga
Ra, Ima, phia, maga = complexCalc(a)
The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951
We can use the phase and magnitude to represent the vector in polar coordinates $$ z = r e^{j\varphi} $$
In [78]:
# Converting from polar to rectangular
a = 1 + 1j
Ra, Ima, phia, maga = complexCalc(a)
# Calculate real and imaginary parts
Ra = maga * np.cos(phia)
Ima = maga * np.sin(phia)
# Combine into a complex number
aRect = Ra + 1j * Ima
print("--- Back to Rectangular ---")
Ra, Ima, phia, maga = complexCalc(aRect)
The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951 --- Back to Rectangular --- The Vector (1.0000000000000002+1j) Real: 1.0000000000000002 Imaginary: 1.0 Phase: 44.99999999999999 degree Magnitude: 1.4142135623730951
Visualizing the vector¶
In [13]:
# Create a new figure with a polar subplot
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
# Plot vector a in blue
ax.plot(
[0, phia], # Angles from 0 to angle of a
[0, maga], # Magnitude from 0 to magnitude of a
marker='o', # Marker at the end
color='b', # Color blue
label=f'Vector {a}'
)
# Customize angular ticks: Only degrees
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2]) # Set 0°, 90°, 180°, 270°
ax.set_xticklabels(['0°', '90°', '180°', '270°'], fontsize=12)
ax.set_yticks([])
ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1))
# Add axis labels
r_max = maga * 1.2 # Extend radius for label positioning
ax.text(0, r_max, 'Real', fontsize=14, ha='center', va='bottom') # X-axis (Real)
ax.text(np.pi/2, r_max, 'Imaginary', fontsize=14, ha='center', va='bottom') # Y-axis (Imaginary)
# Enable Grid for better readability
ax.grid(True)
# Title for the plot
fig.suptitle('Visualize the Imaginary Vectors', y=0.05, fontsize=14, va='top')
plt.show()
In [15]:
a = 1 + 1j
b = 0 + 1j
Ra, Ima, phia, maga = complexCalc(a)
Rb, Imb, phib, magb = complexCalc(b)
# Create a new figure with a polar subplot
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
# Plot vector a in blue
ax.plot(
[0, phia], # Angles from 0 to angle of a
[0, maga], # Mag from 0 to magnitude of a
marker='o', # Marker at the end
color='b', # Color blue
label=f'Vector {a}'
)
# Customize angular ticks: Only degrees
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2]) # Set 0°, 90°, 180°, 270°
ax.set_xticklabels(['0°', '90°', '180°', '270°'], fontsize=12)
ax.set_yticks([])
ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1))
# Add axis labels
r_max = np.abs(a) * 1.2 # Extend radius for label positioning
ax.text(0, r_max, 'Real', fontsize=14, ha='center', va='bottom') # X-axis (Real)
ax.text(np.pi/2, r_max, 'Imaginary', fontsize=14, ha='center', va='bottom') # Y-axis (Imaginary)
# Enable Grid for better readability
ax.grid(True)
# Title for the plot
fig.suptitle('Visualize the Imaginary Vectors', y=0.05, fontsize=14, va='top')
plt.show()
The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951 The Vector 1j Real: 0.0 Imaginary: 1.0 Phase: 90.0 degree Magnitude: 1.0
In [24]:
# Create a new figure with a polar subplot
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
# Plot vector a in blue
ax.plot(
[0, phia], # Angles from 0 to angle of a
[0, maga], # Radii from 0 to magnitude of a
marker='o', # Marker at the end
color='b', # Color blue
label=f'Vector {a}'
)
ax.plot(
[0, phib], # Angles from 0 to angle of a
[0, magb], # Mag from 0 to magnitude of a
marker='o', # Marker at the end
color='g', # Color blue
label=f'Vector {b}'
)
# Customize angular ticks: Only degrees
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2]) # Set 0°, 90°, 180°, 270°
ax.set_xticklabels(['0°', '90°', '180°', '270°'], fontsize=12)
ax.set_yticks([])
ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1))
# Add axis labels
rmax = np.abs(a) * 1.2 # Extend radius for label positioning
ax.text(0, rmax, 'Real', fontsize=14, ha='center', va='bottom') # X-axis (Real)
ax.text(np.pi/2, rmax, 'Imaginary', fontsize=14, ha='center', va='bottom') # Y-axis (Imaginary)
# Enable Grid for better readability
ax.grid(True)
# Title for the plot
fig.suptitle('Visualize the Imaginary Vectors', y=0.05, fontsize=14, va='top')
plt.show()
In [55]:
complexArr = np.array([1 + 1j, 1 - 1j, 4 - 3j, 2 + 4j])
complexUnpacked = np.zeros((4,4))
def visualIzeComplexNums(complexArr):
""" Plots an array of complex numbers
Parameters
----------
complexArr: Array of complex numbers
Uses a matrix complexUnpacked to store the extracted values
"""
# Check for array
if (isinstance(complexArr, list) or isinstance(complexArr, np.ndarray)):
complexUnpacked = np.zeros((len(complexArr),4))
# complexUnpacked is a matrix -> [0, (0,1,2,3)] = Ra, Ima, phia, maga
else:
print("Not an array of complex numbers")
return 0
# Iterate through each array index
for arrInd, arr in enumerate(complexArr):
complexUnpacked[arrInd,0],complexUnpacked[arrInd,1],complexUnpacked[arrInd,2],complexUnpacked[arrInd,3] = complexCalc(arr)
# Create a new figure with a polar subplot
fig, ax = plt.subplots(figsize=(8, 8), subplot_kw={'projection': 'polar'})
cmap = plt.cm.get_cmap('tab10', len(complexArr))
colors = [cmap(i) for i in range(len(complexArr))]
# Plot vectors
for arrInd, arr in enumerate(complexArr):
ax.plot([0, complexUnpacked[arrInd,2]],[0, complexUnpacked[arrInd,3]],marker='o',color=colors[arrInd],label=f'Vector {arr}')
# Customize angular ticks: Only degrees
ax.set_xticks([0, np.pi/2, np.pi, 3*np.pi/2]) # Set 0°, 90°, 180°, 270°
ax.set_xticklabels(['0°', '90°', '180°', '270°'], fontsize=12)
ax.set_yticks([])
ax.legend(loc='upper right', bbox_to_anchor=(1.1, 1.1))
# Add axis labels
rmax = np.abs(a) * 1.2 # Extend radius for label positioning
ax.text(0, rmax, 'Real', fontsize=14, ha='center', va='bottom') # X-axis (Real)
ax.text(np.pi/2, rmax, 'Imaginary', fontsize=14, ha='center', va='bottom') # Y-axis (Imaginary)
# Enable Grid for better readability
ax.grid(True)
# Title for the plot
fig.suptitle('Visualize the Imaginary Vectors', y=0.05, fontsize=14, va='top')
plt.show()
# Calling the function
visualIzeComplexNums(complexArr)
The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951 The Vector (1-1j) Real: 1.0 Imaginary: -1.0 Phase: -45.0 degree Magnitude: 1.4142135623730951 The Vector (4-3j) Real: 4.0 Imaginary: -3.0 Phase: -36.86989764584402 degree Magnitude: 5.0 The Vector (2+4j) Real: 2.0 Imaginary: 4.0 Phase: 63.43494882292201 degree Magnitude: 4.47213595499958
Operations with complex numbers¶
In [92]:
a = 2+ 4j
# Rotate by 90 degrees
rota = 1j * a
print(rota)
complexArr = [a, rota]
visualIzeComplexNums(complexArr)
(-4+2j) The Vector (2+4j) Real: 2.0 Imaginary: 4.0 Phase: 63.43494882292201 degree Magnitude: 4.47213595499958 The Vector (-4+2j) Real: -4.0 Imaginary: 2.0 Phase: 153.434948822922 degree Magnitude: 4.47213595499958
Complex Conjugate of a complex vector:¶
If a = 2 + 4j, then a* = 2 - 4j
Keeping the real part the same and taking the reflection of the imaginary part, magnitude stays the same, but angle is now shifted by 2pi (opposite)
In [88]:
a = 2+4j
aconj = np.conj(a)
complexArr = [a, aconj]
visualIzeComplexNums(complexArr)
The Vector (2+4j) Real: 2.0 Imaginary: 4.0 Phase: 63.43494882292201 degree Magnitude: 4.47213595499958 The Vector (2-4j) Real: 2.0 Imaginary: -4.0 Phase: -63.43494882292201 degree Magnitude: 4.47213595499958
In [82]:
# Arithmetic
a = 1+ 0.5j
b = 0 + 0.5j
# Sum
z = a + b
print(z)
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
(1+1j) The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951
In [72]:
# Multiplication
z = a*b
print(z)
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
(-0.25+0.5j) The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (-0.25+0.5j) Real: -0.25 Imaginary: 0.5 Phase: 116.56505117707799 degree Magnitude: 0.5590169943749475
In [73]:
# Multiplication in polar
# Addition of the phase and multiplication of the magnitude
a = 1+ 0.5j
b = 0 + 0.5j
Ra, Ima, phia, maga = complexCalc(a)
Rb, Imb, phib, magb = complexCalc(b)
magz = maga * magb
phiz = phia + phib
# Converting from polar to rectangular
# Calculate real and imaginary parts
Rz = magz * np.cos(phiz)
Imz = magz * np.sin(phiz)
# Combine into a complex number
z = Rz + 1j * Imz
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (-0.25+0.5j) Real: -0.25 Imaginary: 0.5 Phase: 116.56505117707799 degree Magnitude: 0.5590169943749475
In [79]:
# Complex Division
z = a/b
print(z)
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
(2-2j) The Vector (1+1j) Real: 1.0 Imaginary: 1.0 Phase: 45.0 degree Magnitude: 1.4142135623730951 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (2-2j) Real: 2.0 Imaginary: -2.0 Phase: -45.0 degree Magnitude: 2.8284271247461903
Mathematically the complex conjugate helps us achieve division, read more here: https://betterexplained.com/articles/intuitive-arithmetic-with-complex-numbers/
In [81]:
# Division in polar
# Subtraction of the phase and division of the magnitude
a = 1+ 0.5j
b = 0 + 0.5j
Ra, Ima, phia, maga = complexCalc(a)
Rb, Imb, phib, magb = complexCalc(b)
magz = maga / magb
phiz = phia - phib
# Converting from polar to rectangular
# Calculate real and imaginary parts
Rz = magz * np.cos(phiz)
Imz = magz * np.sin(phiz)
# Combine into a complex number
z = Rz + 1j * Imz
complexArr = [a, b, z]
visualIzeComplexNums(complexArr)
The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (1+0.5j) Real: 1.0 Imaginary: 0.5 Phase: 26.56505117707799 degree Magnitude: 1.118033988749895 The Vector 0.5j Real: 0.0 Imaginary: 0.5 Phase: 90.0 degree Magnitude: 0.5 The Vector (1.0000000000000002-2j) Real: 1.0000000000000002 Imaginary: -2.0 Phase: -63.43494882292201 degree Magnitude: 2.23606797749979