Pythonと学ぶ複素数

# 複素数
$a ，b$をともに実数， $𝑖 $を虚数とした時
$z=a+bi$
と表される数を複素数という．

𝑎 を実数成分（real component）
𝑏 を虚数成分（imaginary component）と呼ぶ．

複素数には和，差，積，商等の演算が定義できる．

## 共役
複素数 $z=a+bi$ に対して虚数の符号を反転
させる操作のことを共役という．<br>具体的に
$$\overline{z} =a-bi $$ 
と表される．
実数の共役は実数そのものである．
## 複素数の加減算
二つの複素数<br>
$$z_1=a_1+b_1i$$
$$z_2=a_2 + b_2i$$
に対してその和は
$$z_1+z_2=(a_1+a_2)+(b_1+b_2)𝑖$$

差についても
$$z_1-z_2 = (𝑎_1−𝑎_2 )+(𝑏_1−𝑏_2 )𝑖$$
と定義される．

## 複素数の乗算
乗算は，次のように求められる．
$$𝑧_1 𝑧_2=(𝑎_1+𝑏_1 𝑖)(𝑎_2+𝑏_2 𝑖)$$
$$=(𝑎_1 𝑎_2−𝑏_1 𝑏_2 )+(𝑎_1 𝑏_2+𝑎_2 𝑏_1 )𝑖$$
複素数とその共役の積は必ず実数になる．
$$𝑧\overline{𝑧}=(𝑎+𝑏𝑖)(𝑎−𝑏𝑖)=𝑎^2+𝑏^2$$
特に $\sqrt{𝑧\overline{𝑧}}$  を振幅と呼び |𝑧| と表記する．
信号処理分野では振幅と表現するのが一般的
と定義される．

## 複素数の有理化と除算
有理化とは虚数単位を分子に集める操作．

$$\frac{1}{z}=\frac{\overline{z}}{𝑧\overline{z}}=\frac{𝑎−𝑏𝑖}{𝑎^2+𝑏^2} =\frac{1}{𝑎^2+𝑏^2}(𝑎−𝑏𝑖)$$

$𝑧_1$ と $𝑧_2$ の除算は次の様に求められる．

$$\frac{z_1}{z_2}=z_1\frac{1}{z_2}=(a_1+b_1 i)\frac{a_2−b_2i}{a_2^2+b_2^2 }=\frac{z_1 \overline{z_2}}{|z_2 |^2} $$

## 極座標表示
複素数平面上において，複素数を実軸との角度と原点
からの大きさを用いて表す方法を極座標表示と言う．
この時，実軸との角度 𝜃 を偏角と呼ぶ．
<img width="464" alt="poolar_1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564429/5981906b-d228-d3ba-6f7d-ffe981499aae.png">

## 複素数平面における和と差
2 つの複素数$𝑧_1=1+𝑖 ，𝑧_2=−1−2𝑖$ の和と差は複素数平面上に以下のように示すことができる．
<img width="347" alt="sub.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564429/388d89cf-d04b-1362-7cbb-1c5dd77fb7da.png">
<img width="308" alt="diff.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564429/84092b7a-7914-6785-c8f2-34a4c8a80507.png">


## 複素数平面における積と商
2つの複素数$z_1=|z_1|e^{i\theta},z_2=|z_2|e^{i\theta} $に対する積及び商は以下の図の様に示すことができる．
<img width="314" alt="kaker.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564429/384aae5f-65d8-5404-3300-626fd86ea23f.png">
<img width="354" alt="war.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/564429/41a5b006-9ed9-6c07-29d3-994168326309.png">




## 複素正弦波
ある複素数 𝑥 を極座標表示したとき, 位相が単位時間当たり $\omega$(rad) 増加するとすれば, 𝑥(𝑡) は<br><br>
$𝑥(𝑡)=|𝑥| 𝑒^{i𝜔𝑡}=|𝑥|(cos⁡(𝜔𝑡)+𝑖sin(𝜔𝑡))$<br><br>
と変形でき複素正弦波として表すことができる．
複素正弦波の振幅を 𝑎 倍，正弦波を 𝜃 だけ
平行移動したい場合，以下のように表現できる．

このように線形な演算によって振幅，位相
を変化させることができるのが複素正弦波の特徴である．



# 複素数クラスの実装
以下は複素数のクラスを組み込みのクラスではなく自分で作ったものです。
複素数の計算を理解するのにお使いください．

```python:complex.py

import math

class Complex:  # 複素数クラス
    def __init__(self, real=0., imag=0.):
        if isinstance(real, complex): # a = complex(1+1j) に対応する
            self._real = real.real
            self._imag = real.imag
        else:                         # b = complex(1,1) に対応する
            self._real = float(real)
            self._imag = float(imag)
        
    @property
    def real(self):
        return self._real
    @real.setter
    def real(self, value):
        self._real = value

    @property
    def imag(self):
        return self._imag
    @imag.setter
    def imag(self, value):
        self._imag = value

    @property
    def abs(self):
        return math.sqrt(self._real**2 + self._imag**2)
    @abs.setter
    def abs(self, value):
        self._real = value * math.cos(self.phase)
        self._imag = value * math.sin(self.phase)

    @property
    def phase(self):
        return math.atan2(self._imag, self._real)
    @phase.setter
    def phase(self, value):
        self._real = self.abs * math.cos(self.phase)
        self._imag = self.abs * math.sin(self.phase)

    def degree(self):
        return self.phase / math.pi * 180
    
    def polar(self):
        return self.abs, self.phase
        
    def conjugate(self):
        return Complex(self._real, -1.0 * self._imag)

    def quadrants(self):
        return [[1, 2], [4, 3]][int(self._imag < 0)][int(self._real < 0)]

    def __str__(self):
        str_ = '' if self._real == 0 else str(self._real) + ('' if self._imag < 0 else '+')
        str_ += ('0' if self._imag == 0 else (str(self._imag))) + 'i'
        return str_
    
    def __repr__(self):
        return self.__str__()
                 
    def __eq__(self, other):
        if isinstance(other, Complex):
            return self._real == other.real and self._imag == other.imag
        else:
            return self == Complex(other)

    def __add__(self, other):
        if isinstance(other, Complex):
            return Complex(self._real+other.real, self._imag+other.imag)
        else:
            return Complex(self._real+other, self._imag)
        
    def __sub__(self, other):
        if isinstance(other, Complex):
            return Complex(self._real-other.real, self._imag-other.imag)
        else:
            return Complex(self._real-other, self._imag)

    def __mul__(self, other):
        if isinstance(other, Complex):
            return Complex(self._real*other.real - self._imag*other.imag,
                        self._real*other.imag + self._imag*other.real)
        else:
            return Complex(self._real*other, self._imag*other)

    def __truediv__(self, other):
        if other == 0:
            raise ZeroDivisionError('Complex division by zero')
        if isinstance(other, Complex):
            denominator = other.real**2 + other.imag**2
            return self * other.conjugate() / denominator
        else:
            return self * (1.0 /other)
```

```python
#複素数クラスのインスタンスを生成
a=Complex(1,2)
b=Complex(3,-3)

#複素数
print(a)
print(b)
```

```console
1.0+2.0i
3.0-3.0i
```

```python
#共役を求める
print(str(a)+"の共役 --> "+str(a.conjugate()))
#振幅を求める
print(str(a)+"の振幅 --> "+str(a.abs))
#偏角の実装
print(str(a)+"の偏角 --> "+str(math.degrees(a.phase)))
```

```console
1.0+2.0iの共役 --> 1.0-2.0i
1.0+2.0iの振幅 --> 2.23606797749979
1.0+2.0iの偏角 --> 63.43494882292201
```

```python
#加減乗除
print(str(a)+"と"+str(b)+"の足し算 --> "+str(a+b))
print(str(a)+"と"+str(b)+"の引き算 --> "+str(a-b))
print(str(a)+"と"+str(b)+"の掛け算 --> "+str(a*b))
print(str(a)+"と"+str(b)+"の割り算 --> "+str(a/b))
```

```console
1.0+2.0iと3.0-3.0iの足し算 --> 4.0-1.0i
1.0+2.0iと3.0-3.0iの引き算 --> -2.0+5.0i
1.0+2.0iと3.0-3.0iの掛け算 --> 9.0+3.0i
1.0+2.0iと3.0-3.0iの割り算 --> -0.16666666666666666+0.5i
```