Komplexe Zahlen

Wir wollen uns hier nochmals genauer mit den komplexen Zahlen beschäftigen. Komplexe Zahlen sind hilfreich für viele Methoden in der Mathematik, Physik und Technik. Zum Beispiel verwendet die Wechselstromtechnik komplexe Zahlen. Auch der Frequenzgang basiert auf komplexwertige Funktionen.

Pures Python

Eine komplexe Zahl kann in Python einfach durch das Hinzufügen des Buchstabens ‚j‘ nach einer Zahl erzeugt werden.

1.j
1j

Warnung

Der Buchstabe j alleine würde nicht ausreichen, es muss immer ein Zahl davor stehen.

Wir wollen nun die Definition \(j^2=-1\) überprüfen.

1.j**2
(-1+0j)

Eine komplexe Zahl besitzt einen Realteil und einen Imaginärteil.

z = 4.+3.j

Den Realteil erhalten wir einfach mit dem Attribut real.

z.real
4.0

Den Imaginärteil erhalten wir mit dem Attribut imag.

z.imag
3.0

Wir wollen nun die Datentypen der einzelnen Objekte untersuchen.

print(type(z))
print(type(z.real))
print(type(z.imag))
<class 'complex'>
<class 'float'>
<class 'float'>

Wie erwartet sind der Realteil und der Imaginärteil von Typ float. Um daraus wieder eine komplexe Zahl zu erstellen, müssen wir den Imaginärteil mit 1j multiplizieren.

z.real+z.imag*1j
(4+3j)

Alternative können wir den Konstruktor des komplexen Datentyps complex verwenden.

complex(z.real,z.imag)
(4+3j)

Rechnen in der algebraischen Form

Im folgenden werden wir sehen, dass das Rechnen mit komplexen Zahlen in Python sehr einfach möglich ist.

Addition

Eine Addition zweier komplexer Zahlen \(z_1=a+bj\) mit \(a,b \in \mathbb{R}\) und \(z_2=c+dj\) mit \(c,d \in \mathbb{R}\) erfolgt durch das Addieren der Realteile und der Imaginärteile. Es gilt also

\[ z_1+z_2 = (a+c)+(b+d)j. \]

Wir können diese Notation exakt so in Python verwenden.

a = 4.
b = 3.
c = 4.
d = 3.
z1 = a+b*1j
z2 = c+d*1j
print(z1)
print(z2)
(4+3j)
(4+3j)
z1+z2
(8+6j)

Subtraktion

Eine Addition zweier komplexer Zahlen \(z_1=a+bj\) mit \(a,b \in \mathbb{R}\) und \(z_2=c+dj\) mit \(c,d \in \mathbb{R}\) erfolgt durch das Subtrahieren der Realteile und der Imaginärteile. Es gilt also

\[ z_1+z_2 = (a-c)+(b-d)j. \]

Wir können diese Notation exakt so in Python verwenden.

z1-z2
0j

Multiplikation

Für die Multiplikation zweier komplexer Zahlen z1 und z2 gilt

\[ z_1 z_2 = (ac+bdj^2)+(ad+bc)j = (ac-bd)+(ad+bc)j \]
z1*z2
(7+24j)

Division

Die Division komplexer Zahlen ist etwas schwieriger. Für die Division müssen wir den Bruch mit der konjugiert komplexen Zahl \(\bar{z}_2=c-dj\) erweitern.

\[ \frac{z_1}{z_2} = \frac{z_1}{z_2}\frac{\bar{z}_2}{\bar{z}_2} = \frac{(a+bj)(c-dj)}{(c+dj)(c-dj)} = \frac{ac+bd}{c^2+d^2}+\frac{bc-ad}{c^2+d^2}j \]

Die Rechnung wird dadurch nicht verändert, jedoch ist der Nenner nun reell und positiv womit die Division leicht durchgeführt werden kann.

z1/z2
(1+0j)

Polarform: Betrag und Argument

Der Betrag \(|z|\) einer komplexen Zahl \(z\) ist durch

\[ |z| = \sqrt{a^2+b^2} \]

definiert. In Python können wir einfach die Built-In Funktion abs verwenden.

abs(z)
5.0

Die Phase \(\varphi\) einer komplexen Zahl ist durch

\[ \varphi(z) = \arctan \left( \frac{\Im(z)}{\Re(z)} \right) \]

definiert. Die Funktion atan ist jedoch auf zwei Quadranten beschränkt. Um die Phase für alle vier Quadranten berechnet zu können wir die atan2 Methode verwenden. Es gilt

\[ \varphi(z) = \arctan \left( \Im(z), \Re(z) \right). \]

Diese Methoden stehen im math Modul zur Verfügung.

import math
print(math.atan(z.imag/z.real))
print(math.atan2(z.imag,z.real))
0.6435011087932844
0.6435011087932844
print(math.atan(z.imag/(-z.real)))
print(math.atan2(z.imag,(-z.real)))
-0.6435011087932844
2.498091544796509

Cmath

Für das Rechnen mit komplexen Zahlen steht die Python-Standardbibliothek cmath zur Verfügung. Die Dokumentation ist unter https://docs.python.org/3/library/cmath.html erreichbar.

import cmath

Statt auf die Funktionen atan und atan2 zurückgreifen zu müssen, können wir die Phase direkt mit cmath.phase berechnen.

cmath.phase(z)
0.6435011087932844

Weiters sehen wir, dass die Phase richtig berechnet wird.

z_neg_real = -z.real+1j*z.imag
cmath.phase(z_neg_real)
2.498091544796509

Auch für das Umrechnen in die Polarform kann mit einer Methode math.polar erledigt werden.

r, phi = cmath.polar(z)
print(r)
print(phi)
5.0
0.6435011087932844
cmath.rect(r, phi)
(4+3j)

Weiters sehen wir, dass eine komplexe Zahl immer in der algebraischen Form \(z=a+jb\) gespeichert wird. Auch wenn wir die Zahl in der Polarform angeben, speichert Python diese in der algebraischen Form.

z3 = r*cmath.exp(phi*1j)
z3
(4+3j)

Tipp

Das Multiplizieren und das Dividieren ist in der Polarform einfacher möglich.

Multiplizieren

\[ z_1z_2 = r_1e^{j\varphi_1}r_2e^{j\varphi_2} = r_1r_2e^{j(\varphi_1+\varphi_2)} \]

Die Beträge werden multipliziert und die Argumente werden addiert.

Dividieren

\[ \frac{z_1}{z_2} = \frac{r_1e^{j\varphi_1}}{r_2e^{j\varphi_2}} = \frac{r_1}{r_2}e^{j(\varphi_1-\varphi_2)} \]

Die Beträge werden dividiert und die Argumente werden subtrahiert.

Die Sinusfunktion \(sin(z)\) ist für komplexe Zahlen \(z=a+bj (a,b \in \mathbb{R})\) folgendermaßen definiert:

\[ sin(z) = sin(a+bj) \]
\[ \Re = sin(a)cosh(b), \quad \Im = cos(a)sinh(b) \]
\[ sin(a+bj)=sin(a)cosh(b)+cos(a)sinh(b)j \]

Wir können diese Berechnung mit math erledigen.

math.sin(z.real)*math.cosh(z.imag)+math.cos(z.real)*math.sinh(z.imag)*1j
(-7.61923172032141-6.5481200409110025j)

Der Aufwand ist jedoch sehr groß. Auch hier hilft cmath.

cmath.sin(z)
(-7.61923172032141-6.5481200409110025j)

Fazit

Wir haben gesehen, dass Python komplexe Zahlen vollständig unterstützt. Mit math werden zusätzliche Methoden für komplexe Zahlen angeboten. Werden komplexe Signale benötigt sollte jedoch numpy verwendet werden.