查看: 320|回复: 0

Python复数complex创建运算与傅里叶变换应用实践

[复制链接]
发表于 2 小时前 | 显示全部楼层 |阅读模式
在Python的内置类型中,complex复数类型虽然不如int和float常用,但它在信号处理、图像旋转、电路分析、分形绘图等场景中有着不可替代的作用。多数主流语言并不直接内置复数,往往需要引入第三方库;Python则把复数作为一等公民,支持字面量、构造器以及完整的cmath数学函数库。这篇文章从复数的创建、运算、函数支持到典型代码实践逐步展开,帮助开发者在需要时能直接写出可运行的复数处理逻辑。

一、Python中复数的创建方式

复数由实部与虚部构成,形如a + bj。Python沿用了工程领域的惯例,用j而不是数学中的i表示虚数单位,因为i在电路分析中常代表电流。创建复数有两种主要方式。

第一种是字面量方式,虚部系数必须紧贴j。
  1. z1 = 3 + 4j      # 实部3 虚部4
  2. z2 = 1 - 2j
  3. z3 = 5j          # 纯虚数 相当于0+5j
  4. z4 = 2 + 0j      # 实数为2 但类型是complex
  5. z5 = 1 + 1j      # 正确写法
  6. # z5 = 1 + j     # 错误 这里的j会被当作变量名 导致NameError
复制代码
第二种是使用complex()函数,可以接收一个或两个数值参数,也可以接收字符串参数。
  1. complex(5)          # (5+0j)
  2. complex(3.14)       # (3.14+0j)
  3. complex(3, 4)       # (3+4j)
  4. complex(-1, 2.5)    # (-1+2.5j)
  5. complex('3+4j')     # (3+4j)
  6. complex('-1-2j')    # (-1-2j)
  7. complex('5j')       # 5j
  8. complex('3')        # (3+0j)
复制代码
注意,complex()解析字符串时不允许出现空格,例如complex('3 + 4j')会抛出异常;字符串中也不能使用i代替j。

访问实部和虚部以及取共轭可以使用对象的属性与方法:
  1. z = 3 + 4j
  2. print(z.real)       # 3.0 返回float
  3. print(z.imag)       # 4.0 返回float
  4. print(z.conjugate()) # (3-4j)
复制代码

二、复数运算与比较限制

复数的加减乘除、幂运算与普通数值类型一致,可以直接使用运算符。以a = 3 + 4j,b = 1 - 2j为例:
  1. a = 3 + 4j
  2. b = 1 - 2j
  3. print(a + b)   # (4+2j)
  4. print(a - b)   # (2+6j)
  5. print(a * b)   # (11-2j)
  6. print(a / b)   # (-1+2j)
  7. print(a ** 2)  # (-7+24j)
复制代码
乘法结果的推算过程:3×1 + 3×(-2j) + 4j×1 + 4j×(-2j) = 3 - 6j + 4j - 8j²,因j² = -1,所以最后是11 - 2j。除法可通过共轭分母化简得到结果。幂运算也遵守同样的复数运算法则。

复数只能判断相等或不等,不能比较大小。这在数学上也有意义,因为复数不是有序域。下面代码会触发TypeError:
  1. a = 3 + 4j
  2. b = 3 + 4j
  3. print(a == b)   # True
  4. print(a != b)   # False
  5. # print(a > b)  # TypeError: '>' not supported between instances of 'complex' and 'complex'
复制代码

内置函数abs()可用于求复数的模,即sqrt(实部² + 虚部²)。round()不能直接用于复数对象。

三、cmath模块:面向复数的数学函数

Python的math模块面向实数,复数运算需要使用cmath模块。cmath提供复变函数、极坐标转换以及判断函数。
  1. import cmath
  2. z = 3 + 4j
  3. print(abs(z))             # 5.0 模长
  4. print(cmath.sqrt(z))      # (2+1j) 因为(2+j)²=3+4j
  5. print(cmath.polar(z))     # (5.0, 0.9272952180016122) 返回(模, 辐角)
  6. print(cmath.rect(5.0, 0.9272952180016122))  # (3+4j) 极坐标转直角坐标
复制代码
cmath.exp支持欧拉公式形式的指数运算,例如e^(jx) = cos(x) + j*sin(x):
  1. x = 0.5
  2. print(cmath.exp(1j * x))  # (0.87758+0.47943j)
复制代码
cmath模块还包括log、log10、三角函数、反三角函数和双曲函数:
  1. z = 1 + 1j
  2. cmath.exp(z)
  3. cmath.log(z)      # 自然对数
  4. cmath.log10(z)
  5. cmath.sin(z)
  6. cmath.cos(z)
  7. cmath.tan(z)
  8. cmath.asin(z)
  9. cmath.acos(z)
  10. cmath.atan(z)
  11. cmath.sinh(z)
  12. cmath.cosh(z)
  13. cmath.tanh(z)
复制代码
判断与比较方面的工具:
  1. cmath.isinf(complex(float('inf'), 0))  # True
  2. cmath.isnan(complex(float('nan'), 0))  # True
  3. cmath.isclose(1+2j, 1+2.0000000001j)  # True 容差比较
复制代码

四、复数的实际应用代码实践

信号处理中DFT核心计算会使用复数指数。手写离散傅里叶变换有助于理解频谱形成的原理。下面代码直接定义DFT函数,并分析由50Hz和120Hz正弦波叠加的信号:
  1. import cmath
  2. import math
  3. def discrete_fourier_transform(samples):
  4.     n = len(samples)
  5.     result = []
  6.     for k in range(n):
  7.         frequency_component = 0j
  8.         for t in range(n):
  9.             angle = -2 * cmath.pi * 1j * k * t / n
  10.             frequency_component += samples[t] * cmath.exp(angle)
  11.         result.append(frequency_component)
  12.     return result
  13. sample_rate = 500
  14. duration = 1.0
  15. n_samples = int(sample_rate * duration)
  16. samples = []
  17. for i in range(n_samples):
  18.     t = i / sample_rate
  19.     value = math.sin(2 * math.pi * 50 * t) + 0.5 * math.sin(2 * math.pi * 120 * t)
  20.     samples.append(value)
  21. frequency_spectrum = discrete_fourier_transform(samples)
  22. print('频率分析结果:')
  23. for i in range(10):
  24.     magnitude = abs(frequency_spectrum[i])
  25.     frequency = i * sample_rate / n_samples
  26.     print(f'{frequency:.0f}Hz: 幅度={magnitude:.2f}')
复制代码
运行后能从频谱幅度中明显看到50Hz与120Hz两个峰值对应的频率分量。

图像处理或二维坐标系变换中,可以用复数表示平面上的点,实部为x坐标,虚部为y坐标。矩阵旋转因此可以简化为复数乘法:
  1. import math
  2. def rotate_point(x, y, angle_degrees):
  3.     point = complex(x, y)
  4.     angle_radians = math.radians(angle_degrees)
  5.     rotation = complex(math.cos(angle_radians), math.sin(angle_radians))
  6.     rotated = point * rotation
  7.     return rotated.real, rotated.imag
  8. print(rotate_point(1, 0, 90))   # (0.0, 1.0)
复制代码
同理,缩放点可以直接乘以常数因子。

电路分析中的交流阻抗也用复数表示:电阻为实数,电感和电容为纯虚数。下面实现RLC串联总阻抗的计算:
  1. import cmath
  2. def impedance_resistor(r):
  3.     return complex(r, 0)
  4. def impedance_inductor(inductance, frequency):
  5.     omega = 2 * 3.14159 * frequency
  6.     return complex(0, omega * inductance)
  7. def impedance_capacitor(capacitance, frequency):
  8.     omega = 2 * 3.14159 * frequency
  9.     return complex(0, -1 / (omega * capacitance))
  10. def series_impedance(*impedances):
  11.     return sum(impedances)
  12. R = 100.0
  13. L = 0.1
  14. C = 10e-6
  15. f = 1000.0
  16. Z_total = series_impedance(
  17.     impedance_resistor(R),
  18.     impedance_inductor(L, f),
  19.     impedance_capacitor(C, f)
  20. )
  21. print(f'总阻抗:{Z_total}')
  22. print(f'阻抗模:{abs(Z_total):.2f}欧姆')
  23. print(f'相位角:{cmath.phase(Z_total):.2f}弧度')
复制代码
这段代码验证了复数运算在电子仿真中的直接性。

曼德勃罗集是复数迭代的经典示例。用字符串字符着色可以快速在终端生成ASCII图案:
  1. def mandelbrot(c, max_iterations=100):
  2.     z = 0j
  3.     for n in range(max_iterations):
  4.         z = z * z + c
  5.         if abs(z) > 2:
  6.             return n
  7.     return max_iterations
  8. def generate_mandelbrot(width=100, height=40, max_iter=50):
  9.     x_min, x_max = -2.0, 1.0
  10.     y_min, y_max = -1.0, 1.0
  11.     for y in range(height):
  12.         line = ''
  13.         for x in range(width):
  14.             real = x_min + (x / width) * (x_max - x_min)
  15.             imag = y_min + (y / height) * (y_max - y_min)
  16.             c = complex(real, imag)
  17.             m = mandelbrot(c, max_iter)
  18.             if m == max_iter:
  19.                 line += '#'
  20.             elif m > max_iter * 0.8:
  21.                 line += '*'
  22.             elif m > max_iter * 0.5:
  23.                 line += '+'
  24.             elif m > max_iter * 0.2:
  25.                 line += '.'
  26.             else:
  27.                 line += ' '
  28.         print(line)
  29. generate_mandelbrot()
复制代码
执行后终端会出现经典的曼德勃罗集轮廓。

五、类型转换与易错点

复数不能直接转换为int或float,需要先取绝对值或分别取实部与虚部:
  1. z = 3 + 4j
  2. str(z)        # '(3+4j)'
  3. abs(z)        # 5.0 float类型
  4. # int(z)      # TypeError
  5. # float(z)    # TypeError
复制代码
其他数值类型或字符串可以转换为复数,complex(5)、(3.14)或complex('1+2j')都会得到complex对象。

两个常见坑需要关注。第一个坑是求负数的平方根时,math.sqrt会直接报ValueError,必须改用cmath.sqrt,但cmath.sqrt返回的永远是complex类型,即使结果恰为实数:
  1. import cmath
  2. import math
  3. result = cmath.sqrt(-1)   # 1j
  4. print(cmath.sqrt(4))      # (2+0j)
复制代码
如果希望正数返回float、负数返回complex,可以封装一个安全开方函数:
  1. def safe_sqrt(x):
  2.     if x >= 0:
  3.         return math.sqrt(x)
  4.     else:
  5.         return cmath.sqrt(x)
  6. print(safe_sqrt(4))   # 2.0
  7. print(safe_sqrt(-4))  # 2j
复制代码
第二个坑是复数的实部和虚部在Python内部总是float类型。即使写成3 + 4j,访问z.real得到的是3.0而不是整数3。这也意味着complex对象可以承载inf和nan等特殊浮点值:
  1. z = 3 + 4j
  2. print(type(z.real))  # <class 'float'>
  3. print(type(z.imag))  # <class 'float'>
  4. z1 = complex(float('inf'), 0)
  5. z2 = complex(0, float('nan'))
复制代码

总结:Python内置complex使复数运算免去额外安装科学计算库的成本。创建上字面量最简洁、complex()最灵活;运算上支持四则与幂,但不能比较大小;函数支持依赖cmath模块;实际场景中DFT、图像旋转、交流阻抗与曼德勃罗集都能直接用原生代码落地。写代码时重点注意j的位置、字符解析空格和cmath返回类型的特性,就能避免多数报错。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

指导单位

江苏省公安厅

江苏省通信管理局

浙江省台州刑侦支队

DEFCON GROUP 86025

Hacking Group 021A

旗下站点

态势感知中心

应急响应中心

红盟安全

联系我们

官方QQ群:112851260

官方邮箱:security#ihonker.org(#改成@)

官方核心成员

关注微信公众号

Archiver|手机版|小黑屋| ( 沪ICP备2021026908号 )

GMT+8, 2026-9-7 12:23 , Processed in 0.019438 second(s), 18 queries , Gzip On, Redis On.

Powered by ihonker.com

Copyright © 2015-现在.

  • 返回顶部