Beam Pattern

Table of Contents

Beamforming

Around the decades, multi-input multi-output (MIMO), a.k.a. multiantenna transmission, has been the focus of the research relating to wireless communications, and attracted the interests and attentions from both academic circle and industrial area. By deliberately designing the complex-valued coefficients of each antenna elements, the transmitted power or its majority can be limited to a specified direction or area. The operation is termed beamforming, and accordingly the weights of all the antenna elements involved are termed a beamforming vector or a beamformer. In this case, the SINR and the power of the received signal at the receiver can be remarkably enhanced.

Beam pattern

Clearly, what matters most for beamforming is the beamformer design. Consequently, a variety of beamforming schemes have been proposed.

DFT beam

For a DFT beam, the beamformer is essentially a linear phase ramp, and the formed beam points to a specified direction, i.e.,

\begin{align*} \mathbf{w}(n, d, \theta) = \begin{bmatrix} 1 & e^{j2\pi d \cos\theta} & e^{j4\pi d \cos\theta} & \dots e^{j2(n-1)\pi d \cos\theta} \end{bmatrix}^T, \end{align*}

where

  • \(n\) is the number of antenna elements in the array.
  • \(d\) is the inter-antenna element distance (normalized to wave length).
  • \(\theta\) is the desired angle, which is defined from the plane where the array lies. Note that \(\theta = \pi/2\) means the boresight direction.
#!/usr/bin/env python

import numpy as np
import matplotlib.pyplot as plt
import sys

def gen_dft_beam(n: int, d: float, theta: float) -> np.ndarray:
    '''
    Generate a linear phase ramp, which corresponds with a DFT beam.
    '''
    return np.exp(1j * 2.0 * np.pi * d * np.cos(theta) * np.arange(n)) / np.sqrt(n)

Wide beam

For DFT beams, the beamwidth depends on the aperture size of an antenna array. Given an antenna array, however, wide beam is sometimes expected for wider coverage. An example beamformer can be generated by following script.

#!/usr/bin/env python

import numpy as np
import matplotlib.pyplot as plt
import sys

def gen_wide_beam(n: int, theta: float, x: int) -> np.ndarray:
    '''
    Generate a wide beam, which is `x' times wider than a DFT beam.
    '''
    grp_sz = int(n / x)
    phi = np.array([(2 * g + 1) / grp_sz * np.pi for g in np.arange(x / 2)])
    w_prime = np.zeros(int(n / 2), dtype=complex)
    idx_range = np.zeros(grp_sz, dtype=int)
    for g in np.arange(x / 2, dtype=int):
        idx_range = grp_sz * g + np.arange(grp_sz)
        w_prime[idx_range] = np.exp(-1j * phi[g] * idx_range)
    w_prime = np.concatenate((w_prime, w_prime[::-1]))
    w = np.zeros(n, dtype=complex)
    for g in np.arange(x):
        idx_range = grp_sz * g + np.arange(grp_sz)
        w[idx_range] = w_prime[idx_range] * np.exp(1j * np.pi * (idx_range - (n - 1) / 2) * np.cos(theta))
    return w / np.sqrt(n)

PAS

Power angle spectrum (PAS) is usually used to depict the beam pattern. It is essentially a relationship between angles and beamforming gains. Following scripts can plot PAS curves for various beam patterns.

#!/usr/bin/env python

import numpy as np
import matplotlib.pyplot as plt
import sys

def calc_gain(d: float, w: np.ndarray, theta: float) -> float:
    '''
    Calculate the beamforming gain of a given precoder (w) in the specified direction (of angle theta).
    '''
    g = np.dot(w.conj(), gen_dft_beam(len(w), d, theta))
    return 20 * np.log10(np.abs(g))

def gen_pas(d: float, w: np.ndarray):
    '''
    Generate a power angle spectrum (PAS) corresponding to the given precoder (w).
    '''
    angle = np.linspace(0, np.pi, 181)
    gain = np.array([calc_gain(d, w, theta) for theta in angle])
    return angle, gain

def plot_pas(angle: np.ndarray, gain: np.ndarray, lab: str):
    '''
    Plot the PAS with the given values.
    '''
    plt.rcParams['font.size'] = 12
    plt.plot(angle, gain, label=lab, linewidth=3)
    plt.title('Power angle spectrum (PAS)')
    plt.xlabel('$\\theta$')
    plt.ylabel('Beamforming gain (dB)')
    plt.xlim([angle.min(), angle.max()])
    plt.ylim(top=0)
    plt.grid(True)
    plt.legend()
    plt.tight_layout()
    plt.show()