The receiver object captures the properties and responsibilities of reception—the estimation of a symbol vector. Its primary responsibility lay in introducing additive noise and executing MIMO combining to retrieve a symbol vector from a captured received signal vector.

The $N_{\mathrm{s}} \times 1$ received symbol vector $\hat{\mathbf{s}}$ after applying the receiver’s combiner can be written as

where $\mathbf{y}$ is the $N_{\mathrm{r}} \times 1$ complex received signal vector striking the receive array, $\mathbf{n}$ is the $N_{\mathrm{r}} \times 1$ complex noise vector added per-antenna, and $\mathbf{W}$ is the $N_{\mathrm{r}} \times N_{\mathrm{s}}$ combining matrix.

The receiver object is used to represent the portion of a device responsible for reception, including MIMO combining.

The receiver object is responsible for incorporating additive noise (which, in practice, is primarily introduced and amplified by components in the receive chain). Currently, MFM only supports additive white Gaussian noise (AWGN) introduced i.i.d. per-antenna.

To create a receiver object rx, a convenient way is to use

rx = receiver.create();


### Key Properties

The combining matrix $\mathbf{W}$ of a receiver object rx is captured by the property

rx.combiner


Its receive symbol $\hat{\mathbf{s}}$ is represented by

rx.receive_symbol


The symbol bandwidth $B$ (in Hz) and symbol period $T$ (in seconds) are captured by

rx.symbol_bandwidth
rx.symbol_period


The noise power spectral density (in watts per Hz) is captured by

rx.noise_power_per_Hz


The integrated noise power (in watts) is captured by

rx.noise_power


The noise energy per symbol (in joules) is captured by

rx.noise_energy_per_symbol


### Setting the Number of Receive Streams

To set the number of streams multiplexed at the receiver $N_{\mathrm{s}}$, one can use

rx.set_num_streams(Ns)


where the number of streams Ns should be a positive integer.

### Setting the Symbol Bandwidth

To set the symbol bandwidth at a receiver rx, use

rx.set_symbol_bandwidth(B)


where B is the symbol bandwidth in Hz.

This automatically updates the receiver’s symbol period according to

### Setting the Noise Level

Additive noise is introduced per-antenna. Currently, only Gaussian noise is supported in MFM. The noise vector $\mathbf{n}$ is drawn from the complex Gaussian distribution as

where $\sigma_{\mathrm{n}}^2$ is the noise energy per symbol (in joules).

Rather than set the noise energy per symbol directly, it is more practical to set the noise power spectral density and symbol bandwidth, which togther define the noise power and noise energy per symbol.

To set the noise power spectral density of the additive noise at receiver object rx, use

rx.set_noise_power_per_Hz(noise_psd,unit)


where noise_psd is the noise power per Hz and unit is an optional string specifying the units of noise_psd (default of watts per Hz).

For example, to set the noise power spectral density to -174 dBm/Hz, used

rx.set_noise_power_per_Hz(-174,'dBm_Hz')


Based on the current symbol bandwidth, this will automatically update the noise energy per symbol and noise power properties.

Since MFM assumes the relationship $B = T^{-1}$, the noise power spectral density (power per Hz) is equal to the noise energy per symbol.

The noise power (in watts) is equal to the noise power spectral density times the bandwidth as

### Example Setup

Setting up a receiver object rx typically looks something similar to

rx = receiver.create()
rx.set_num_streams(Ns)
rx.set_symbol_bandwidth(B)
rx.set_noise_power_per_Hz(noise_psd,unit)


To set the received signal vector $\mathbf{y}$ striking the receive array, use

rx.set_received_signal(y)


### Setting/Realizing Noise

A new noise vector $\mathbf{n}$ can be realized, according to the current noise level, via

rx.set_noise()


which is reflected in the property rx.noise.

If desired, the noise vector can be set manually to a vector n via

rx.set_noise(n)


### Setting the Combiner

To set the combiner $\mathbf{W}$ of a receiver, use

rx.set_combiner(W)


where W is a combining matrix.

The receive symbol $\hat{\mathbf{s}}$ can be fetched via

s = rx.get_receive_symbol()


where s is the receive symbol vector.

### List of Properties

The receiver object contains the following properties:

• receiver.name
• receiver.type
• receiver.array
• receiver.num_antennas
• receiver.num_streams
• receiver.symbol_bandwidth
• receiver.symbol_period
• receiver.combiner
• receiver.noise
• receiver.received_signal
• receiver.receive_symbol
• receiver.channel_state_information
• receiver.noise_power
• receiver.noise_energy_per_symbol
• receiver.noise_power_per_Hz
• receiver.noise_covariance
• receiver.receive_strategy
• receiver.source

### List of Methods

The receiver object contains the following methods:

### Methods Documentation

#### N0()

Returns the noise energy per symbol.

Usage:
val = N0()
Return Values:
val — the noise energy per symbol

Back to methods

#### Nr()

Returns the number of receive antennas.

Usage:
val = Nr()
Return Values:
val — the number of receive antennas

Back to methods

#### Ns()

Returns the number of streams.

Usage:
val = Ns()
Return Values:
val — the number of streams

Back to methods

#### Rn()

Returns the noise covariance matrix.

Usage:
val = Rn()
Return Values:
val — the noise covariance matrix

Back to methods

#### W()

Returns the combining matrix.

Usage:
val = W()
Return Values:
val — the combining matrix

Back to methods

#### check_combiner_dimensions(W)

Checks to see if the combining matrix has dimensions appropriate for the current number of antennas and streams.

Usage:
out = check_combiner_dimensions()
out = check_combiner_dimensions(W)
Input Arguments:
W — (optional) a combining matrix; if not passed, the receivers’s current combiner will be assessed
Return Values:
out — a boolean indicating if the combiner is of appropriate dimension

Back to methods

#### check_receive_strategy(strategy)

Returns a boolean indicating if a receive strategy is valid.

Usage:
out = check_receive_strategy(strategy)
Input Arguments:
strategy — a string indentifying a specific receive strategy
Return Values:
out — a boolean

Back to methods

#### configure_receiver(strategy)

Configures the receiver’s combiner according to the current/specified receive strategy, incorporating channel state information as applicable.

Usage:
configure_receiver()
configure_receiver(strategy)
Input Arguments:
strategy — (optional) receive strategy to use; if not passed, the current receive strategy will be used

Back to methods

#### configure_receiver_eigen()

Configures the receiver to receive along the strongest components of the desired channel, neglecting interference, etc.

Usage:
configure_receiver_eigen()

Back to methods

#### configure_receiver_identity()

Configures the receive combiner to an identity matrix.

Usage:
configure_receiver_identity()

Back to methods

#### configure_receiver_mmse_desired()

Configures the receiver in an LMMSE fashion to reject noise. Does not reject interference.

Usage:
configure_receiver_mmse_desired()

Back to methods

#### configure_receiver_mmse_interference()

Configures the receiver in an LMMSE fashion to reject noise and interference.

Usage:
configure_receiver_mmse_interference()

Back to methods

#### create(type)

Usage:
obj = receiver.create()
obj = receiver.create(type)
Input Arguments:
type — (optional) a string specifying the type of receiver to create; either ‘digital’ or ‘hybrid’
Return Values:
obj — a receiver object

Back to methods

#### get_receive_symbol()

Returns the receive symbol based on the curent received signal vector, noise, and combiner.

Usage:
s = get_receive_symbol()
Return Values:
s — the receive symbol

Back to methods

#### get_source_channel_state_information_index()

Returns the index of the receive CSI entry whose transmit device corresponds to the receiver’s source device.

Usage:
idx = get_source_channel_state_information_index()
Return Values:
idx — an index; if zero, the CSI entry was not found

Back to methods

#### get_valid_receive_strategies()

Returns a cell containing all valid receive strategy strings.

Usage:
out = get_valid_receive_strategies()
Return Values:
out — a cell of strings
Notes:
This function will differ between a fully-digital receiver and hybrid digital/analog receiver to account for receive strategies that are specific to each.
This function will need to be updated anytime a custom/new receive strategy is added.
The strings should be all lowercase.

Back to methods

#### initialize()

Usage:
initialize()

Back to methods

#### n()

Returns the noise vector (per-antenna).

Usage:
val = n()
Return Values:
val — the noise vector (per-antenna)

Back to methods

#### parse_channel_state_information()

Splits the CSI into two components: (i) a struct containing CSI for receiving from the source and (ii) a cell of structs containing CSI for all other links (e.g., interference channels).

Usage:
[csi_des,csi_int] = parse_channel_state_information()
Return Values:
csi_des — a CSI struct
csi_int — a cell of one or more CSI structs

Back to methods

#### receiver(name)

Creates an instance of a receiver object.

Usage:
obj = receiver()
obj = receiver(name)
Input Arguments:
name — (optional) a name for the receiver
Return Values:
obj — a receiver object

Back to methods

#### s()

Usage:
val = s()
Return Values:
val — the receive symbol vector

Back to methods

#### set_array(array)

Usage:
set_array(array)
Input Arguments:
array — an array object
Notes:

Back to methods

#### set_channel_state_information(csi)

Sets the receive channel state information (CSI).

Usage:
set_channel_state_information(csi)
Input Arguments:
csi — a cell of channel state information structs

Back to methods

#### set_combiner(W)

Usage:
set_combiner(W)
Input Arguments:
W — receive combining matrix

Back to methods

#### set_name(name)

Sets the name of the receiver.

Usage:
set_name()
set_name(name)
Input Arguments:
name — (optional) a string; if not passed, ‘receiver’ is the default name used

Back to methods

#### set_noise(n)

Sets the noise vector at the receive array.

Usage:
set_noise()
set_noise(n)
Input Arguments:
n — (optional) a noise vector; if not passed, noise will be generated according to the noise power

Back to methods

#### set_noise_covariance(Rn)

Sets the noise covariance matrix.

Usage:
set_noise_covariance(Rn)
Input Arguments:
Rn — noise covariance matrix

Back to methods

#### set_noise_power_per_Hz(noise_psd,unit)

Sets the noise power per Hz based for a given noise power spectral density.

Usage:
set_noise_power_per_Hz(noise_psd)
set_noise_power_per_Hz(noise_psd,unit)
Input Arguments:
noise_psd — noise power spectral density (power per Hz) (e.g., -174 dBm/Hz)
unit — an optional unit specifying the units of noise_psd (e.g., ‘dBm_Hz’ for dBm/Hz (default) or ‘watts_Hz’ for watts/Hz)
Notes:
Also updates the noise power and noise covariance.

Back to methods

#### set_num_streams(Ns)

Sets the number of data streams being received.

Usage:
set_num_streams(Ns)
Input Arguments:
Ns — number of data streams

Back to methods

#### set_receive_strategy(strategy)

Usage:
set_receive_strategy()
set_receive_strategy(strategy)
Input Arguments:
strategy — (optional) a string specifying the receive strategy; options vary depending on receiver type (digital vs. hybrid); if not passed, identity reception will be used

Back to methods

#### set_receive_symbol(s)

Usage:
set_receive_symbol(s)
Input Arguments:
s — the receive symbol (e.g., after combiner)

Back to methods

#### set_received_signal(y)

Usage:
set_received_signal(y)
Input Arguments:
y — the received signal vector (i.e., vector impinging the receive array)

Back to methods

#### set_source(device_source)

Sets the source (device the receiver aims to serve).

Usage:
set_source(device_source)
Input Arguments:
device_source — a device object

Back to methods

#### set_symbol_bandwidth(B)

Usage:
set_symbol_bandwidth(B)
Input Arguments:
B — symbol bandwidth in Hertz
Notes:
Also updates the symbol period and noise power.

Back to methods

#### set_type(type)

Sets the type of the receiver.

Usage:
set_type()
set_type(type)
Input Arguments:
type — (optional) a string; if not passed, ‘digital’ is the default type used

Back to methods

#### turn_off()

Turns off the receiver by setting its combiner to a zeros matrix.

Usage:
turn_off()

Back to methods

#### update_noise_covariance()

Updates the noise covariance matrix based on the current number of antennas and noise power.

Usage:
update_noise_covariance()
Notes:
We have assumed i.i.d. noise across antennas.

Back to methods

#### update_noise_power()

Updates the noise power based on the current noise power per Hz and symbol bandwidth.

Usage:
update_noise_power()
Notes:
Also updates the noise covariance matrix.
As of now (Jan. 12, 2021), noise per symbol is equal to the noise power per Hz. Changes to notation or future accommodations may change how we define these two quantities so we are leaving them both present for the time being.

Back to methods

#### update_receive_symbol()

Usage:
update_receive_symbol()
Notes:
Should be called when the combiner, received signal, or noise are changed.

Back to methods

#### y()

val = y()
val — the received signal vector