Understanding NumPy's angle() Function for Complex Number Angles


Purpose

  • numpy.angle() calculates the angle, also known as the phase angle, of complex numbers in a NumPy array.

Input

  • z: This is the mandatory argument that represents a complex number or a sequence of complex numbers (an array). Complex numbers are represented in the form x + yi, where x and y are real numbers, and i is the imaginary unit (the square root of -1).

Optional Argument

  • deg (bool, optional): By default, deg is set to False. If you set it to True, the angles will be returned in degrees. Otherwise, the default behavior is to return them in radians.

Output

  • The function returns a NumPy array containing the angles (phases) of the input complex numbers. The angles are measured counterclockwise from the positive real axis on the complex plane and lie in the range (-pi, pi].

Mathematical Background

  • numpy.angle() essentially calculates the arctangent of the imaginary part (y) divided by the real part (x) of the complex number. This is represented mathematically as:

    angle = arctan2(imag(z), real(z))
    

    where arctan2 is the four-quadrant inverse tangent function that takes into account both the signs of the imaginary and real parts to determine the correct quadrant in the complex plane.

Example

import numpy as np

# Complex numbers as a NumPy array
complex_array = np.array([1 + 2j, 3 - 4j, 5j])

# Calculate angles in radians (default)
radians = np.angle(complex_array)
print(radians)  # Output: [ 1.10714872  2.41421356  1.57079633]

# Calculate angles in degrees
degrees = np.angle(complex_array, deg=True)
print(degrees)  # Output: [ 63.43494882 138.56505119  90.        ]
  • numpy.angle() is useful in various scientific and engineering applications that involve complex numbers, such as signal processing, control theory, and electromagnetism.
  • The output angles are always in the range (-pi, pi] to avoid ambiguity.


Determining Angles between Complex Numbers

This example calculates the angle between two complex numbers z1 and z2:

import numpy as np

z1 = 2 + 3j
z2 = 1 - 2j

# Calculate the difference between complex numbers
difference = z1 - z2

# Calculate the angle of the difference
angle = np.angle(difference)

# Print the angle in degrees
print(f"Angle between {z1} and {z2} (degrees): {np.angle(difference, deg=True)}")

Finding Angles of Complex Numbers in Polar Form

This code assumes the input complex numbers are already in polar form (magnitude and angle) and extracts the angles:

import numpy as np

# Complex numbers in polar form (magnitude, angle)
polar_data = np.array([(2, np.pi/3), (4, np.pi/4), (1, np.pi/2)])

# Extract angles from the second column (assuming angles are stored there)
angles = polar_data[:, 1]

print("Angles:", angles)  # Output: [ 1.04719755  0.78539816  1.57079633] (in radians)

Applying numpy.angle() to Complex Arrays from Calculations

This example showcases using numpy.angle() on the result of complex number calculations:

import numpy as np

def complex_operation(x, y):
  """Performs a complex number operation (example)"""
  return (x + 2j) * (y - 1j)

# Sample complex numbers
x = 3 + 4j
y = 2 - 5j

# Perform the operation
result = complex_operation(x, y)

# Calculate the angle of the result
angle = np.angle(result)

print(f"Angle of the result ({result}): {angle} (radians)")


Manual Calculation using numpy.arctan2

If you only need the angles in radians and don't require NumPy's vectorized operations, you can achieve the same result using numpy.arctan2:

import numpy as np

complex_array = np.array([1 + 2j, 3 - 4j, 5j])

angles_rad = np.arctan2(complex_array.imag, complex_array.real)
print(angles_rad)  # Output: [ 1.10714872  2.41421356  1.57079633]

Using np.unwrap() for Cumulative Phase Angles

If you're dealing with cumulative phase angles in a time series or signal, numpy.unwrap() can be helpful. It unwraps phase angles that have "jumped" across boundaries (e.g., from to 0). This is often used in signal processing:

import numpy as np

# Simulated phase angles with jumps
phase_angles = np.cumsum(np.random.rand(100) * 0.1) + np.pi * np.random.randn(10)

unwrapped_phases = np.unwrap(phase_angles)
print(unwrapped_phases.shape)  # Output: (100,) (same shape as the input)

scipy.signal.argminmax() for Local Phase Maxima/Minima

If you need to find the locations of local maxima or minima in the phase angles, consider scipy.signal.argminmax (from the SciPy library):

from scipy.signal import argmin, argmax

# Assuming you have phase angles (e.g., from `numpy.angle()`)
phase_angles = ...

# Find indices of local minima
minima_idx = argmin(phase_angles)
print(minima_idx)

# Find indices of local maxima (similarly with argmax)

Choosing the Right Approach

The best approach depends on your specific needs:

  • If you need the optimized vectorized operations and output consistency of numpy.angle(), it remains the most efficient option for standard angle calculation.
  • For finding local extrema in phase angles, leverage scipy.signal.argminmax.
  • For unwrapping cumulative phase angles, use numpy.unwrap.
  • For simple angle calculation in radians, numpy.arctan2 can suffice.