NumPy Master Class

Chapter3 Mathematical Functions: Notebook5 Handling Complex Numbers

Shin's Lab 2020. 1. 9. 18:31
3_5_Handling_Complex_Numbers

NumPy Master Class

Chapter3 Mathematical Functions

Notebook5 Handling Complex Numbers

우리가 Engineering 분야에 대한 분석을 하면 빠질 수 없는 것이 Complex number들이다. 그리고 NumPy에서는 image number를 j로 표시한다.

Engineering 분야에서 특히 전자공학에서 i대신 j를 쓰는 이유는 저자가 생각하기에 i는 current라는 매우 중요한 측정치가 사용하고 있기 때문에 하나 밀려나서 j라고 사용하는 것 같고, NumPy도 이 j를 사용하고 있다.

이 Complex number를 더 편리하게 사용하기 위해 다음과 같은 method들을 배워보도록 하자.

1. np.real()
2. np.imag()
3. np.angle()
4. np.conj()
In [43]:
import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm

Making ndarray with Complex Numbers

NumPy에서 imaginary number는 j로 표시한다고 했으므로 다음과 같이 ndarray를 만들어낼 수 있다.

In [9]:
test_np = np.array([1+1j, 1-1j, 3+2j, 5-2j])
print(test_np)
[1.+1.j 1.-1.j 3.+2.j 5.-2.j]

이때 중요한 점은 1*j라고 하더라도 j라고만 쓰면 NumPy는 j를 variable로 인식하기 때문에 1j로 써줘야 한다.

그리고 j도 하나의 scalar이기 때문에 다음과 같이 ndarray를 만드는 것도 가능하다.

In [24]:
real_np = np.arange(10)
imag_np = np.arange(10)[::-1]*1j
cpx_np = real_np + imag_np

print("real_np:", real_np)
print("imag_np:", imag_np)
print("cpx_np:", cpx_np)
real_np: [0 1 2 3 4 5 6 7 8 9]
imag_np: [0.+9.j 0.+8.j 0.+7.j 0.+6.j 0.+5.j 0.+4.j 0.+3.j 0.+2.j 0.+1.j 0.+0.j]
cpx_np: [0.+9.j 1.+8.j 2.+7.j 3.+6.j 4.+5.j 5.+4.j 6.+3.j 7.+2.j 8.+1.j 9.+0.j]

np.real(), np.imag()

이름에서 알 수 있듯이 np.real(), np.imag()는 각 complex number의 real part, imaginary part를 뽑아주는 역할을 한다.

In [26]:
print("cpx_np:", cpx_np)
print("np.real(cpx_np):", np.real(cpx_np))
print("np.imag(cpx_np):", np.imag(cpx_np))
cpx_np: [0.+9.j 1.+8.j 2.+7.j 3.+6.j 4.+5.j 5.+4.j 6.+3.j 7.+2.j 8.+1.j 9.+0.j]
np.real(cpx_np): [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
np.imag(cpx_np): [9. 8. 7. 6. 5. 4. 3. 2. 1. 0.]

또한 np의 method 말고 ndarray의 method들로도 다음과 같이 이용할 수 있다.

In [27]:
print("cpx_np:", cpx_np)
print("cpx_np.real:", cpx_np.real)
print("cpx_np.imag:", cpx_np.imag)
cpx_np: [0.+9.j 1.+8.j 2.+7.j 3.+6.j 4.+5.j 5.+4.j 6.+3.j 7.+2.j 8.+1.j 9.+0.j]
cpx_np.real: [0. 1. 2. 3. 4. 5. 6. 7. 8. 9.]
cpx_np.imag: [9. 8. 7. 6. 5. 4. 3. 2. 1. 0.]

np.angle()

np.angle()을 사용하기 위해 다음과 같이 complex unit circle을 만들어보자.

다음은 Euler's Formula를 이용한다.

$e^{j\theta} = cos(\theta) + jsin(\theta)$

In [57]:
radian_range = np.linspace(0, 2*np.pi)
cpx_circle = np.cos(radian_range) + np.sin(radian_range)*1j

그리고 real, imag를 뽑아내서 결과를 확인해보자.

In [59]:
real_part = cpx_circle.real
imag_part = cpx_circle.imag

fig, ax = plt.subplots(figsize = (7,7))
ax.scatter(real_part, imag_part)
Out[59]:
<matplotlib.collections.PathCollection at 0x7ff914263358>

complex unit circle이 잘 만들어진 것 같으니 cpx_circle를 확인해보자.

In [60]:
print(cpx_circle)
[ 1.        +0.00000000e+00j  0.99179001+1.27877162e-01j
  0.96729486+2.53654584e-01j  0.92691676+3.75267005e-01j
  0.8713187 +4.90717552e-01j  0.80141362+5.98110530e-01j
  0.71834935+6.95682551e-01j  0.6234898 +7.81831482e-01j
  0.51839257+8.55142763e-01j  0.40478334+9.14412623e-01j
  0.28452759+9.58667853e-01j  0.1595999 +9.87181783e-01j
  0.03205158+9.99486216e-01j -0.09602303+9.95379113e-01j
 -0.22252093+9.74927912e-01j -0.34536505+9.38468422e-01j
 -0.46253829+8.86599306e-01j -0.57211666+8.20172255e-01j
 -0.67230089+7.40277997e-01j -0.76144596+6.48228395e-01j
 -0.8380881 +5.45534901e-01j -0.90096887+4.33883739e-01j
 -0.94905575+3.15108218e-01j -0.98155916+1.91158629e-01j
 -0.99794539+6.40702200e-02j -0.99794539-6.40702200e-02j
 -0.98155916-1.91158629e-01j -0.94905575-3.15108218e-01j
 -0.90096887-4.33883739e-01j -0.8380881 -5.45534901e-01j
 -0.76144596-6.48228395e-01j -0.67230089-7.40277997e-01j
 -0.57211666-8.20172255e-01j -0.46253829-8.86599306e-01j
 -0.34536505-9.38468422e-01j -0.22252093-9.74927912e-01j
 -0.09602303-9.95379113e-01j  0.03205158-9.99486216e-01j
  0.1595999 -9.87181783e-01j  0.28452759-9.58667853e-01j
  0.40478334-9.14412623e-01j  0.51839257-8.55142763e-01j
  0.6234898 -7.81831482e-01j  0.71834935-6.95682551e-01j
  0.80141362-5.98110530e-01j  0.8713187 -4.90717552e-01j
  0.92691676-3.75267005e-01j  0.96729486-2.53654584e-01j
  0.99179001-1.27877162e-01j  1.        -2.44929360e-16j]

이제 위의 complex number들에 대해 np.angle()을 적용해보면 다음과 같다.

In [68]:
angle_np = np.angle(cpx_circle)

plt.figure(figsize = (10,4))
plt.grid()
plt.plot(angle_np)
Out[68]:
[<matplotlib.lines.Line2D at 0x7ff9140d9be0>]

즉, 0부터 PI까지 제대로 나오는 것을 확인할 수 있다. 그리고, angle은 -PI부터 PI까지만 다루므로 PI를 넘어가면 -2PI의 offset 걸어 radian boundary안에 들어가도록 수정해주는 모습 또한 볼 수 있다.


np.conj()

complex conjugate은 angle의 부호를 바꿔주는 역할을 한다. 그러면 위의 결과에서 npconj()을 사용하여 부호를 바꿔주는지 확인해보자.

In [77]:
angle_np = np.angle(cpx_circle)
angle_conj_np = np.angle(np.conj(cpx_circle))

plt.figure(figsize = (10,4))
plt.grid()
plt.plot(angle_np, label = 'angle_np')
plt.plot(angle_conj_np, label = 'angle_conj_np')
plt.legend()
Out[77]:
<matplotlib.legend.Legend at 0x7ff912c0dc50>

위와 같이 절대값은 바뀌지 않고, angle의 부호만 바뀌는 것을 확인할 수 있다.