pyphysim.modulators package

Submodules

pyphysim.modulators.fundamental module

Module with class for some fundamental modulators, such as PSK and M-QAM.

All fundamental modulators inherit from the Modulator class and should call the self.setConstellation method in their __init__ method, as well as implement the calcTheoreticalSER and calcTheoreticalBER methods.

class pyphysim.modulators.fundamental.BPSK[source]

Bases: pyphysim.modulators.fundamental.Modulator

BPSK Class

calcTheoreticalBER(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical (approximation) bit error rate for the BPSK scheme.

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

BER – The theoretical bit error rate.

Return type

float | np.ndarray

calcTheoreticalSER(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical (approximation) symbol error rate for the BPSK scheme.

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

SER – The theoretical symbol error rate.

Return type

float | np.ndarray

demodulate(receivedData: numpy.ndarray)numpy.ndarray[source]

Demodulate the data.

Parameters

receivedData (np.ndarray) – Data to be demodulated.

Returns

demodulated_data – The demodulated data.

Return type

np.ndarray

modulate(inputData: numpy.ndarray)numpy.ndarray[source]

Modulate the input data (decimal data).

Parameters

inputData (np.ndarray) – Data to be modulated.

Returns

modulated_data – The modulated data

Return type

np.ndarray

Raises

ValueError – If inputData has any invalid value such as values greater than self._M - 1. Note that inputData should not have negative values but no check is done for this.

property name

Get the name property.

Returns

The name of the modulator.

Return type

str

class pyphysim.modulators.fundamental.Modulator[source]

Bases: object

Base class for digital modulators.

The derived classes need to at least call setConstellation to set the constellation in their constructors as well as implement calcTheoreticalSER and calcTheoreticalBER.

Examples

>>> np.set_printoptions(linewidth=70)
>>> constellation = np.array([1 + 1j, - 1 + 1j, - 1 - 1j, 1 - 1j])
>>> m=Modulator()
>>> m.setConstellation(constellation)
>>> m.symbols
array([ 1.+1.j, -1.+1.j, -1.-1.j,  1.-1.j])
>>> m.M
4
>>> m.K
2.0
>>> m
4-Modulator object
>>> m.modulate(np.array([0, 0, 3, 3, 1, 3, 3, 3, 2, 2]))
array([ 1.+1.j,  1.+1.j,  1.-1.j,  1.-1.j, -1.+1.j,  1.-1.j,  1.-1.j,
        1.-1.j, -1.-1.j, -1.-1.j])
>>> m.demodulate(np.array([ 1. + 1.j, 1. + 1.j, 1. - 1.j, 1. - 1.j,                                 - 1. + 1.j, 1. - 1.j, 1. - 1.j, 1. - 1.j,                                 - 1. - 1.j, - 1. - 1.j]))
array([0, 0, 3, 3, 1, 3, 3, 3, 2, 2])
property K

Get method for the K property.

The K property corresponds to the number of bits represented by each symbol in the constellation. It is equal to log2(M), where M is the constellation size.

See also

M

property M

Get method for the M property.

The M property corresponds to the number of symbols in the constellation.

See also

K

calcTheoreticalBER(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical bit error rate.

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

BER – The theoretical bit error rate.

Return type

float | np.ndarray

Notes

This function should be implemented in the derived classes

calcTheoreticalPER(SNR: NumberOrArray, packet_length: int) → NumberOrArray[source]

Calculates the theoretical package error rate.

A package is a group of bits, where if a single bit is in error then the whole package is considered to be in error.

The package error rate (PER) is a direct mapping of the bit error rate (BER), such that

\[PER = 1 - (1 - BER)^{L}\]

where \(L\) is the package_length.

Parameters
  • SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

  • packet_length (int) – The package length. That is, the number of bits in each package.

Returns

PER – The theoretical package error rate.

Return type

float | np.ndarray

calcTheoreticalSER(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical symbol error rate.

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

SER – The theoretical symbol error rate.

Return type

float | np.ndarray

Notes

This function should be implemented in the derived classes

calcTheoreticalSpectralEfficiency(SNR: NumberOrArray, packet_length: Optional[int] = None) → NumberOrArray[source]

Calculates the theoretical spectral efficiency.

If there was no error in the transmission, the spectral efficiency would be equal to the K property, that is, equal to the number of bits represented by each symbol in the constellation. However, due to bit errors the effective spectral efficiency will be lower.

The calcTheoreticalSpectralEfficiency method calculates the effective spectral efficiency from the K property and the package error rate (PER) for the given SNR and packet_length ‘L’, such that

\[se = K * (1 - PER)\]
Parameters
  • SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

  • packet_length (int, optional) – The package length. That is, the number of bits in each package.

Returns

se – The theoretical spectral efficiency.

Return type

float | np.ndarray

demodulate(receivedData: numpy.ndarray)numpy.ndarray[source]

Demodulate the data.

Parameters

receivedData (np.ndarray) – Data to be demodulated.

Returns

demodulated_data – The demodulated data.

Return type

np.ndarray

modulate(inputData: Union[int, numpy.ndarray])numpy.ndarray[source]

Modulate the input data (decimal data).

Parameters

inputData (np.ndarray | int) – Data to be modulated.

Returns

modulated_data – The modulated data

Return type

np.ndarray

Raises

ValueError – If inputData has any invalid value such as values greater than self._M - 1. Note that inputData should not have negative values but no check is done for this.

property name

Get method for the ‘name’ property.

Returns

The name of the modulator.

Return type

str

plotConstellation()None[source]

Plot the constellation (in a scatter plot).

setConstellation(symbols: numpy.ndarray)None[source]

Set the constellation of the modulator.

This function should be called in the constructor of the derived classes.

Parameters

symbols (np.ndarray) – A an numpy array with the symbol table.

class pyphysim.modulators.fundamental.PSK(M: int, phaseOffset: float = 0)[source]

Bases: pyphysim.modulators.fundamental.Modulator

PSK Class

static _createConstellation(M: int, phaseOffset: float)numpy.ndarray[source]

Generates the Constellation for the PSK modulation scheme.

Parameters
  • M (int) – The modulation cardinality

  • phaseOffset (float) – A phase offset (in radians) to be applied to the PSK constellation.

Returns

symbols – The PSK constellation with the desired cardinality and phase offset.

Return type

np.ndarray

calcTheoreticalBER(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical (approximation) bit error rate for the M-PSK scheme using Gray coding.

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

BER – The theoretical bit error rate.

Return type

float | np.ndarray

calcTheoreticalSER(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical (approximation for high M and high SNR) symbol error rate for the M-PSK scheme.

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

SER – The theoretical symbol error rate.

Return type

float | np.ndarray

setPhaseOffset(phaseOffset: float)None[source]

Set a new phase offset for the constellation

Parameters

phaseOffset (float) – A phase offset (in radians) to be applied to the PSK constellation.

class pyphysim.modulators.fundamental.QAM(M: int)[source]

Bases: pyphysim.modulators.fundamental.Modulator

QAM Class

_calcTheoreticalSingleCarrierErrorRate(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical (approximation) error rate of a single carrier in the QAM system (QAM has two carriers).

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

Psc – The theoretical single carrier error rate.

Return type

float | np.ndarray

Notes

This method is used in the calcTheoreticalSER() implementation.

static _calculateGrayMappingIndexQAM(L: int)numpy.ndarray[source]

Calculates the indexes that should be applied to the constellation created by _createConstellation in order to correspond to Gray mapping.

Notice that the square M-QAM constellation is a matrix of dimension L x L, where L is the square root of M. Since the constellation was generated without taking into account the Gray mapping, then we need to reorder the generated constellation and this function calculates the indexes that can be applied to the original constellation in order to do exactly that.

As an example, for the 16-QAM modulation the indexes can be organized (row order) in the matrix below

/

00

01

11

10

00

0000

0001

0011

0010

01

0100

0101

0111

0110

11

1100

1101

1111

1110

10

1000

1001

1011

1010

This is equivalent to concatenate a Gray mapping for the row with a Gray mapping for the column, and the corresponding indexes are [0, 1, 3, 2, 4, 5, 7, 6, 12, 13, 15, 14, 8, 9, 11, 10]

Parameters

L (int) – Square root of the modulation cardinality (must be an integer).

Returns

indexes – indexes that should be applied to the constellation created by _createConstellation in order to correspond to Gray mapping

Return type

np.ndarray

static _createConstellation(M: int)numpy.ndarray[source]

Generates the Constellation for the (SQUARE) M-QAM modulation scheme.

Parameters

M (int) – The modulation cardinality

Returns

symbols – The QAM constellation with the desired cardinality.

Return type

np.ndarray

calcTheoreticalBER(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical (approximation) bit error rate for the QAM scheme.

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

BER – The theoretical bit error rate.

Return type

float | np.ndarray

calcTheoreticalSER(SNR: NumberOrArray) → NumberOrArray[source]

Calculates the theoretical (approximation) symbol error rate for the QAM scheme.

Parameters

SNR (float | np.ndarray) – Signal-to-noise-value (in dB).

Returns

SER – The theoretical symbol error rate.

Return type

float | np.ndarray

class pyphysim.modulators.fundamental.QPSK[source]

Bases: pyphysim.modulators.fundamental.PSK

QPSK Class

pyphysim.modulators.ofdm module

Module implementing OFDM modulation and demodulation.

class pyphysim.modulators.ofdm.OFDM(fft_size: int, cp_size: int, num_used_subcarriers: Optional[int] = None)[source]

Bases: object

OFDM class.

_add_CP(input_data: numpy.ndarray)numpy.ndarray[source]

Add the Cyclic prefix to the input data.

Parameters

input_data (np.ndarray) – OFDM modulated data (after the IFFT). This must be a 2D numpy array with shape (Number of OFDM symbols, IFFT size).

Returns

output – The input_data with the cyclic prefix added. The shape of the output is (Number of OFDM symbols, IFFT size + CP Size).

Return type

np.ndarray

_calc_zeropad(input_data_size: int) → Tuple[int, int][source]

Calculates the number of zeros that must be added to the input data to make it a multiple of the OFDM size.

The number of zeros that must be added to the input data is returned along with the number of OFDM symbols that will be generated.

Parameters

input_data_size (int) – Size the the data that will be modulated by the OFDM object.

Returns

(zeropad, num_ofdm_symbols) – A tuple with zeropad and num_ofdm_symbols. Zeropad is the number of zeros added to the input data to make the total number of elements a multiple of the number of used subcarriers. Num_ofdm_symbols is the number of OFDM symbols required to transmit input_data_size symbols.

Return type

tuple[int,int]

_calculate_power_scale()float[source]

Calculate the power scale that needs to be applied in the modulator and removed in the demodulate methods.

The power is applied in the modulator method so that the total power of the OFDM samples is similar to the total power of the symbols modulated by OFDM.

Note that this total power is shared among useful samples and the cyclic prefix in one OFDM symbol. Therefore, the larger the cyclic prefix size the lower is this power scale to account energy loss due to sending the cyclic prefix.

Returns

power_scale – The calculated power scale. You should take the square root of this before multiplying by the samples.

Return type

float

_get_subcarrier_numbers()numpy.ndarray[source]

Get the indexes of all subcarriers, including the negative, the DC and the positive subcarriers.

Note that these indexes are not suitable for indexing in python. They are the actual indexes of the subcarriers in an OFDM symbol. For instance, an OFDM symbol with 16 subcarriers will have indexes from -8 to 7. However, due to the way the fft is implemented in numpy the indexes here are actually from 0 to 7 followed by -8 to -1.

Returns

Numbers of all subcarriers, including the negative, the DC and the positive subcarriers

Return type

np.ndarray

Examples

>> ofdm_obj = OFDM(16, 4, 16) >> ofdm_obj._get_subcarrier_numbers() array([ 0, 1, 2, 3, 4, 5, 6, 7, -8, -7, -6, -5, -4, -3, -2, -1])

_get_used_subcarrier_numbers()numpy.ndarray[source]

Get the subcarrier indexes of the actually used subcarriers.

Note that these indexes are not suitable for indexing in python. They are the actual indexes of the subcarriers in an OFDM symbol. See the documentation of the _get_subcarrier_numbers function.

Returns

Number of the actually used subcarriers.

Return type

np.ndarray

Examples

>> ofdm_obj = OFDM(16, 4, 10) >> ofdm_obj._get_used_subcarrier_numbers() array([ 1, 2, 3, 4, 5, -5, -4, -3, -2, -1]) >> ofdm_obj = OFDM(16, 4, 14) >> ofdm_obj._get_used_subcarrier_numbers() array([ 1, 2, 3, 4, 5, 6, 7, -7, -6, -5, -4, -3, -2, -1])

_prepare_decoded_signal(decoded_signal: numpy.ndarray)numpy.ndarray[source]

Prepare the decoded signal that was processed by the FFT in the demodulate function.

This is equivalent of reversing the indexing that was done by the _prepare_input_signal method.

Parameters

decoded_signal (np.ndarray) – Signal that was decoded by the FFT in the OFDM demodulate method.

Returns

demodulated_samples – Demodulated samples of the symbols that were modulated by the OFDM object (for instance the PSK or M-QAM symbols passed to OFDM).

Return type

np.ndarray

Notes

This method should be called AFTER the Cyclic Prefix was removed and the FFT was performed.

Also, because the number of zeropad was not saved, then _prepare_decoded_signal has no way to remove them.

_prepare_input_signal(input_signal: numpy.ndarray)numpy.ndarray[source]

Prepare the input signal to be passed to the IFFT in the modulate function.

The input signal must be prepared before it is passed to the IFFT in the OFDM modulate function.

  • First, zeros must be added so that the input signal size is multiple of the number of used subcarriers.

  • After that the input signal must be allocated to subcarriers in the center of the spectrum (except for the DC component). That is, zeros will be allocated to the lower and higher subcarriers such that only num_used_subcarriers are used from fft_size subcarriers.

This preparation is performed by the _prepare_input_signal function.

Parameters

input_signal (np.ndarray) – Input signal that must be modulated by the OFDM modulate function.

Returns

input_ifft – Signal suitable to be passed to the IFFT function to actually perform the OFDM modulation.

Return type

np.ndarray

_remove_CP(received_data: numpy.ndarray)numpy.ndarray[source]

Remove the Cyclic prefix of the received data.

Parameters

received_data (np.ndarray) – Data that must be demodulated by the OFDM object.

Returns

output – Received data without the Cyclic prefix.

Return type

np.ndarray

Notes

The _remove_CP method will also change the shape so that it is suitable to be passed to the FFT function.

demodulate(received_signal: numpy.ndarray)numpy.ndarray[source]

Perform the OFDM demodulation of the received_signal.

Parameters

received_signal (np.ndarray) – An array with the samples of the received OFDM symbols.

Returns

demodulated_data – Demodulated symbols.

Return type

np.ndarray

get_used_subcarrier_indexes()numpy.ndarray[source]

Get the subcarrier indexes of the subcarriers actually used in a way suitable for python indexing (going from 0 to fft_size-1).

Returns

indexes – Subcarrier indexes of the subcarriers actually used in a way suitable for python indexing.

Return type

np.ndarray

Notes

This is the function actually used in the modulate function.

Examples

Consider the example below where we have 16 subcarriers and only 10 subcarriers are used. The lower and higher subcarrier as well as the DC subcarrier will not be used. The index of the used subcarriers should go then from 11 to 15 (5 subcarriers), skip subcarrier 0, and then go from 1 to 5 (the other 5 subcarriers).

>>> ofdm_obj = OFDM(16, 4, 10)
>>> ofdm_obj.get_used_subcarrier_indexes()
array([11, 12, 13, 14, 15,  1,  2,  3,  4,  5])
>>> ofdm_obj = OFDM(16,4,14)
>>> ofdm_obj.get_used_subcarrier_indexes()
array([ 9, 10, 11, 12, 13, 14, 15,  1,  2,  3,  4,  5,  6,  7])
modulate(input_signal: numpy.ndarray)numpy.ndarray[source]

Perform the OFDM modulation of the input_signal.

Parameters

input_signal (np.ndarray) – Input signal that must be modulated by the OFDM modulate function.

Returns

output – An array with the samples of the modulated OFDM symbols.

Return type

np.ndarray

set_parameters(fft_size: int, cp_size: int, num_used_subcarriers: Optional[int] = None)None[source]

Set the OFDM parameters.

Parameters
  • fft_size (int) – Size of the FFT and IFFT used by the OFDM class.

  • cp_size (int) – Size of the cyclic prefix (in samples).

  • num_used_subcarriers (int, optional) – Number of used subcarriers. Must be greater than or equal to 2 and lower than or equal to fft_size. If not provided, fft_size will be used

Raises

ValueError – If the any of the parameters are invalid.

class pyphysim.modulators.ofdm.OfdmOneTapEqualizer(ofdm_obj: pyphysim.modulators.ofdm.OFDM)[source]

Bases: object

The OfdmOneTapEqualizer class performs the one-tap equalization often required in OFDM transmissions to compensate the effect of the channel at each subcarrier.

Parameters

ofdm_obj (OFDM) – The OFDM object used to modulate/demodulate the data.

_equalize_data(data_reshaped: numpy.ndarray, mean_freq_response: numpy.ndarray)numpy.ndarray[source]

Perform the one-tap equalization and return data after the channel compensation.

Parameters
  • data_reshaped (np.ndarray) – The data to be equalized. If must be a 2D numpy array, where different rows correspond to different OFDM symbols and the different columns correspond to the USED subcarriers. Dimension: num OFDM symbols x num Used subcarriers

  • mean_freq_response (np.ndarray) – The frequency response for each OFDM symbol. Dimension: num OFDM symbols x FFT size

Returns

The received data after the one-tap equalization to compensate the channel effect. Dimension: num OFDM symbols x num Used subcarriers

Return type

np.ndarray

equalize_data(data: numpy.ndarray, impulse_response: pyphysim.channels.fading.TdlImpulseResponse)numpy.ndarray[source]

Perform the one-tap equalization and return data after the channel compensation.

Parameters
  • data (np.ndarray) – The data to be equalized.

  • impulse_response (fading.TdlImpulseResponse) – The impulse response of the channel.

Returns

The received data after the one-tap equalization to compensate the channel effect.

Return type

np.ndarray

Module contents

Package containing modulators.