Impairments Module#

The impairments module provides functions to model real-world effects that degrade phased array performance, including mutual coupling, phase quantization, element failures, and scan blindness.

Mutual Coupling#

phased_array.mutual_coupling_matrix_theoretical(geometry, k, coupling_model='sinc', coupling_coeff=0.3)[source]#

Compute theoretical mutual coupling matrix.

Parameters:
  • geometry (ArrayGeometry) – Array geometry

  • k (float) – Wavenumber (2*pi/wavelength)

  • coupling_model (str) – ‘sinc’ - sinc function model (good for dipoles) ‘exponential’ - exponential decay model

  • coupling_coeff (float) – Coupling coefficient (typical: 0.1-0.5)

Returns:

C – N x N complex mutual coupling matrix

Return type:

ndarray

phased_array.mutual_coupling_matrix_measured(s_parameters)[source]#

Convert measured S-parameters to coupling matrix.

The coupling matrix relates actual element currents to excitation voltages: I = C^(-1) @ V

Parameters:

s_parameters (ndarray) – N x N S-parameter matrix (complex)

Returns:

C – Mutual coupling matrix

Return type:

ndarray

phased_array.apply_mutual_coupling(weights, C, mode='transmit')[source]#

Apply mutual coupling to element weights.

Parameters:
  • weights (ndarray) – Ideal element weights (N,)

  • C (ndarray) – Mutual coupling matrix (N x N)

  • mode (str) – ‘transmit’ - coupling affects radiated field ‘receive’ - coupling affects received signal ‘compensate’ - pre-distort to compensate coupling

Returns:

effective_weights – Weights after coupling effects

Return type:

ndarray

phased_array.active_element_pattern(theta, phi, geometry, element_idx, C, k, isolated_element_pattern=None)[source]#

Compute active element pattern including mutual coupling.

The active element pattern is the pattern of a single element when all other elements are terminated in matched loads.

Parameters:
  • theta (ndarray) – Observation theta angles

  • phi (ndarray) – Observation phi angles

  • geometry (ArrayGeometry) – Array geometry

  • element_idx (int) – Index of the element to compute pattern for

  • C (ndarray) – Mutual coupling matrix

  • k (float) – Wavenumber

  • isolated_element_pattern (callable, optional) – Pattern function for isolated element

Returns:

pattern – Active element pattern (complex)

Return type:

ndarray

Phase Quantization#

phased_array.quantize_phase(weights, n_bits)[source]#

Quantize phase shifter settings to discrete levels.

Parameters:
  • weights (ndarray) – Complex weights (phase will be quantized)

  • n_bits (int) – Number of bits for phase quantization (e.g., 3 bits = 8 levels)

Returns:

quantized_weights – Weights with quantized phases

Return type:

ndarray

Examples

Quantize to 3-bit phase shifters (8 levels, 45 deg steps):

>>> import numpy as np
>>> import phased_array as pa
>>> geom = pa.create_rectangular_array(8, 8, dx=0.5, dy=0.5)
>>> k = pa.wavelength_to_k(1.0)
>>> weights = pa.steering_vector(k, geom.x, geom.y, theta0_deg=15, phi0_deg=0)
>>> weights_q = pa.quantize_phase(weights, n_bits=3)
>>> weights_q.shape
(64,)

Check phase quantization levels:

>>> phases_deg = np.rad2deg(np.angle(weights_q))
>>> np.unique(np.round(phases_deg / 45) * 45).size <= 8
True

Compare effect of different bit depths:

>>> rms_3bit = pa.quantization_rms_error(3)  # ~13 degrees
>>> rms_6bit = pa.quantization_rms_error(6)  # ~1.6 degrees
>>> rms_3bit > rms_6bit
True
phased_array.quantization_rms_error(n_bits)[source]#

Compute theoretical RMS phase error for quantization.

Parameters:

n_bits (int) – Number of phase quantization bits

Returns:

rms_error_deg – RMS phase error in degrees

Return type:

float

phased_array.quantization_sidelobe_increase(n_bits)[source]#

Estimate sidelobe level increase due to phase quantization.

Parameters:

n_bits (int) – Number of phase quantization bits

Returns:

increase_dB – Expected sidelobe increase in dB

Return type:

float

phased_array.analyze_quantization_effect(weights, geometry, k, n_bits, theta_range=(0, 1.5707963267948966), n_points=361)[source]#

Analyze effect of phase quantization on the pattern.

Parameters:
  • weights (ndarray) – Ideal complex weights

  • geometry (ArrayGeometry) – Array geometry

  • k (float) – Wavenumber

  • n_bits (int) – Quantization bits

  • theta_range (tuple) – Range for pattern computation

  • n_points (int) – Number of angle points

Returns:

results – ‘theta_deg’: angle array ‘pattern_ideal_dB’: ideal pattern ‘pattern_quantized_dB’: quantized pattern ‘difference_dB’: pattern difference

Return type:

dict

Element Failures#

phased_array.simulate_element_failures(weights, failure_rate, mode='off', seed=None)[source]#

Simulate random element failures.

Parameters:
  • weights (ndarray) – Nominal element weights

  • failure_rate (float) – Probability of failure per element (0 to 1)

  • mode (str) – ‘off’ - failed elements have zero output ‘stuck’ - failed elements stuck at nominal magnitude, random phase ‘full’ - failed elements at full power, random phase

  • seed (int, optional) – Random seed

Returns:

  • degraded_weights (ndarray) – Weights with failures applied

  • failure_mask (ndarray) – Boolean array, True for failed elements

Return type:

Tuple[ndarray, ndarray]

Examples

Simulate 5% element failure rate:

>>> import numpy as np
>>> import phased_array as pa
>>> geom = pa.create_rectangular_array(16, 16, dx=0.5, dy=0.5)
>>> k = pa.wavelength_to_k(1.0)
>>> weights = pa.steering_vector(k, geom.x, geom.y, theta0_deg=0, phi0_deg=0)
>>> degraded, mask = pa.simulate_element_failures(
...     weights, failure_rate=0.05, mode='off', seed=42
... )
>>> n_failed = np.sum(mask)
>>> degraded.shape
(256,)

Compare failure modes:

>>> # 'off' mode: failed elements produce no output
>>> w_off, m_off = pa.simulate_element_failures(weights, 0.1, mode='off', seed=1)
>>> np.all(w_off[m_off] == 0)
True

Analyze graceful degradation:

>>> results = pa.analyze_graceful_degradation(
...     geom, k, weights, failure_rates=[0.0, 0.05, 0.1]
... )
phased_array.analyze_graceful_degradation(weights, geometry, k, failure_rates, n_trials=100, mode='off')[source]#

Monte Carlo analysis of graceful degradation vs failure rate.

Parameters:
  • weights (ndarray) – Nominal weights

  • geometry (ArrayGeometry) – Array geometry

  • k (float) – Wavenumber

  • failure_rates (list) – Failure rates to test

  • n_trials (int) – Number of Monte Carlo trials per rate

  • mode (str) – Failure mode

Returns:

results – ‘failure_rates’: input rates ‘gain_loss_mean_dB’: mean gain loss ‘gain_loss_std_dB’: std of gain loss ‘sidelobe_increase_mean_dB’: mean sidelobe increase

Return type:

dict

Scan Blindness#

phased_array.surface_wave_scan_angle(dx, dy, substrate_er=4.0, substrate_h=0.1)[source]#

Estimate scan blindness angles due to surface wave excitation.

Parameters:
  • dx (float) – Element spacing in x (wavelengths)

  • dy (float) – Element spacing in y (wavelengths)

  • substrate_er (float) – Substrate relative permittivity

  • substrate_h (float) – Substrate height (wavelengths)

Returns:

  • theta_blind_E (float) – Blind angle in E-plane (degrees)

  • theta_blind_H (float) – Blind angle in H-plane (degrees)

Return type:

Tuple[float, float]

phased_array.scan_blindness_model(theta, phi, theta_blind, phi_blind=None, null_width_deg=5.0, null_depth_dB=-30.0)[source]#

Model scan blindness as a Gaussian null at the blind angle.

Parameters:
  • theta (ndarray) – Observation theta angles (radians)

  • phi (ndarray) – Observation phi angles (radians)

  • theta_blind (float) – Blind angle theta (degrees)

  • phi_blind (float, optional) – Blind angle phi (degrees). If None, blindness is phi-independent

  • null_width_deg (float) – Width of the null (degrees, 1-sigma)

  • null_depth_dB (float) – Depth of null in dB (negative)

Returns:

factor – Multiplicative factor (0 to 1)

Return type:

ndarray

phased_array.apply_scan_blindness(pattern, theta, phi, theta_blind_list, phi_blind_list=None, null_width_deg=5.0, null_depth_dB=-30.0)[source]#

Apply scan blindness model to a computed pattern.

Parameters:
  • pattern (ndarray) – Complex or magnitude pattern

  • theta (ndarray) – Theta angles (radians)

  • phi (ndarray) – Phi angles (radians)

  • theta_blind_list (list) – List of blind angles (degrees)

  • phi_blind_list (list, optional) – List of blind phi angles

  • null_width_deg (float) – Null width

  • null_depth_dB (float) – Null depth

Returns:

modified_pattern – Pattern with scan blindness applied

Return type:

ndarray

phased_array.compute_scan_loss(geometry, weights, k, theta_scan_deg, phi_scan_deg, element_pattern_func=None)[source]#

Compute scan loss (reduction in peak gain at scan angle).

Parameters:
  • geometry (ArrayGeometry) – Array geometry

  • weights (ndarray) – Element weights

  • k (float) – Wavenumber

  • theta_scan_deg (float) – Scan angle theta

  • phi_scan_deg (float) – Scan angle phi

  • element_pattern_func (callable, optional) – Element pattern function

Returns:

scan_loss_dB – Reduction in gain relative to broadside (negative or zero)

Return type:

float