Channel Submodule (skcomm.channel)

This submodule includes routines to emulate a transmission channel.

add_frequency_offset(samples[, sample_rate, ...])

Add frequency offset to complex signal in 1D ndarray 'samples'.

add_phase_noise(samples[, s_rate, ...])

Add laser phase noise to complex signal in 1D ndarray 'samples'.

set_snr(samples[, snr_dB, sps, seed])

Add noise to an array according to a given SNR (in dB).

skcomm.channel.add_frequency_offset(samples, sample_rate=1.0, f_offset=100000000.0)

Add frequency offset to complex signal in 1D ndarray ‘samples’.

Parameters:
  • samples (numpy array, complex) – complex signal.

  • sample_rate (float, optional) – sample rate of the incoming singal. The default is 1.0.

  • f_offset (float, optional) – frequency deviation / frequency offset in Hz. The default is 100 MHz.

Returns:

samples – complex singal containing frequency offset.

Return type:

numpy array, complex

skcomm.channel.add_phase_noise(samples, s_rate=1.0, linewidth=1.0, seed=None)

Add laser phase noise to complex signal in 1D ndarray ‘samples’.

See https://github.com/htw-ikt-noelle/OptischeKommunikationssysteme/blob/master/LaserPhaseNoise.ipynb

TODO: expand to two polatizations (or higher dimension signals)!!!

Parameters:
  • samples (numpy array, complex) – complex signal.

  • s_rate (float, optional) – sample rate of the incoming singal. The default is 1.0.

  • linewidth (float, optional) – 3 dB bandwidth of the generated phase noise in Hz. The default is 1.0.

  • seed (int, optional) – seed of the random number generator. The default is None.

Returns:

results

samplesnumpy array, complex

complex singal including phase noise.

phaseAccnumpy array, real

phase noise vector in rad.

varPNfloat

variance of generated phase noise in rad**2.

Return type:

dict containing following keys

skcomm.channel.rotatePol_pdm(samples_X, samples_Y, theta=0.0, psi=0.0, phi=0.0)

Applies a polarization rotation (a unitary matrix transformation) in 2-D complex Jones space [1] to the input signal, which is given as the two (optical) field components \(E_X\) (1-D array samples_X) and \(E_Y\) (1-D array samples_Y) of the Jones vector, spanned in Jones space by pair of orthogonal unit vectors \(\overrightarrow{e}_X\) and \(\overrightarrow{e}_Y\), corresponding to the X- and Y-polarization basis vectors, respectively. The matrix relation (on a sample-by-sample basis) is given as follows:

\(\overrightarrow{E}_{out}[n] = \mathbf{U} \cdot \overrightarrow{E}_{in}[n]\)

where \(\overrightarrow{E}_{out}[n]\) and \(\overrightarrow{E}_{in}[n]\) are \(2\times1\) vectors (at sample instant \(n\)) with an X-polarization sample in the first row and a Y-polarization sample in the second row, and \(\mathbf{U}(\theta,\psi,\phi)\) is a 2⨯2 (unitary) Jones rotation matrix with elements [2]:

\(\mathbf{U}(\theta,\psi,\phi) = \begin{bmatrix}\cos(\theta)·e^{-j\cdot\psi} & -\sin(\theta)·e^{j\cdot\phi}\\ \sin(\theta)·e^{-j\cdot\phi} & \cos(\theta)·e^{j\cdot\psi}\end{bmatrix}\)

The polarization rotation can be reversed by applying the Hermitian conjugate \(\mathbf{U}^{\dagger}\) to the output signal.

There are three dedicated parameterizations of the matrix \(\mathbf{U}\) that lead to elementary polarization rotations of the signal Stokes vector around the \(S_1\)-, \(S_2\)- and \(S_3\)-axes in Stokes space [2/Table 1], [3], respectively:

\(S_1: \mathbf{U}(0,\psi,0)\) rotates around the \(S_1\)-axis by \(2\cdot\psi\)

\(S_2: \mathbf{U}(\theta,0,\pi/2)\) rotates around the \(S_2\)-axis by \(2\cdot\theta\)

\(S_3: \mathbf{U}(\theta,0,0)\) rotates around the \(S_3\)-axis by \(2\cdot\theta\)

Parameters:
  • samples_X (ndarray) – Input signal samples in X-polarization. Must be of same size as ‘samples_Y’.

  • samples_Y (ndarray) – Input signal samples in Y-polarization. Must be of same size as ‘samples_X’.

  • theta (float) – Rotational parameter \(\theta\) (in rad) for the matrix \(\mathbf{U}(\theta,\psi,\phi)\). Defaults to 0.0.

  • psi (float) – Rotational parameter \(\psi\) (in rad) for the matrix \(\mathbf{U}(\theta,\psi,\phi)\). Defaults to 0.0.

  • phi (float) – Rotational parameter \(\phi\) (in rad) for the matrix \(\mathbf{U}(\theta,\psi,\phi)\). Defaults to 0.0.

Return type:

dict

Returns:

  • results dictionary, containing the following keys

    • samples_Xnp.ndarray[np.complex128 | np.float64]

      Output signal samples after rotation in X-polarization.

    • samples_Ynp.ndarray[np.complex128 | np.float64]

      Output signal samples after rotation in Y-polarization.

    • Unp.ndarray[np.complex128 | np.float64]

      \(2\times2\) Jones (rotation) matrix \(\mathbf{U}\), which was applied to the input signal.

    • U_invnp.ndarray[np.complex128 | np.float64]

      The inverse (Hermitian conjugate) of the Jones (rotation) matrix \(\mathbf{U}\).

References

skcomm.channel.set_snr(samples, snr_dB=10, sps=1.0, seed=None)

Add noise to an array according to a given SNR (in dB).

CAUTION: this function assumes the input signal to be noise free!

If input signal is of type “real” only real noise (with noise power according to SNR) is generated, if signal is of complex type also complex noise (with noise power according to SNR/2 in each quadrature) is added.

Parameters:
  • samples (numpy array, real or complex) – input signal.

  • snr_dB (float, optional) – The desired SNR per symbol in dB. The default is 10.

  • sps (float, optional) – samples per symbol of the input signal. The default is 1.0

  • seed (int, optional) – random seed of the generated noise samples. The default is None.

Returns:

samples_out – output singal with desired SNR (input signal plus random noise samples).

Return type:

numpy array, real or complex

Filter Submodule (skcomm.filters)

This submodule includes filtering routines.

filter_arbitrary(samples, FILTER[, sample_rate])

Arbitrarily filter a signal.

filter_samples(samples, filter[, domain])

Filter the input signal.

ideal_lp(samples[, fc])

Filter a given signal with an ideal lowpass filter.

moving_average(samples[, average, domain])

Filter a given signal with a moving average filter.

raised_cosine_filter(samples[, sample_rate, ...])

Filter a given signal with a (root) raised cosine filter.

time_shift(samples[, sample_rate, tau])

Add a cyclic time shift to the input signal.

windowed_sinc(samples[, fc, order, window])

Filter a given signal with a windowed Si-funtion as impulse response.

skcomm.filters.filter_arbitrary(samples, FILTER, sample_rate=1.0)

Arbitrarily filter a signal.

Filters a given signal with an arbitrary filter defined in a table. This filter is implemented in frequency domain (cyclic convolution). The filter can be defined as single-sided frequency axis (real filter response is assumed), or with double-sided frequency axis (complex filter response is assumed).

Parameters:
  • samples (1D numpy array, real or complex) – input signal of shape = (N,)

  • sample_rate (float) – Sample rate of the signal in Hz. The default is 1.0.

  • FILTER (2D numpy array) – 1st col.: frequency in Hz 2nd col.: magnitude in dB 3rd col.: phase in deg; optional (zero phase assumed if 3rd col. is omitted)

Returns:

  • samples_out (1D numpy array, real or complex) – filtered output signal.

skcomm.filters.filter_samples(samples, filter, domain='freq')

Filter the input signal.

Filter is either implemented in either in the

  • time domain filter (convolution). CAUTION: size of signal vector changes!

  • frequency domain (multiplication of input signal spectrum with transfer

    function…equivalent to a cyclic convolution).

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • filter (1D numpy array, real or complex) – Either inpulse response of the filter (when domain=’time’) or transfer function (double-sided, starting from negative frequencies) of the filter (when domain=’freq’).

  • domain (string, optional) – implementation of the filter either in ‘time’ or in ‘freq’ domain. The default is ‘freq’.

Returns:

samples_out – filtered input signal.

Return type:

1D numpy array, real or complex

skcomm.filters.ideal_lp(samples, fc=0.5)

Filter a given signal with an ideal lowpass filter.

This filter is only implemented in the frequency domain (cyclic convolution) and has NO group delay.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • fc (float, optional) – cut off frequency, 0.0 <= fc <= 1.0, where 1.0 specifies the Nyquist frequency (half the sampling frequency). The default is 0.5.

Returns:

results

samples_out1D numpy array, real or complex

filtered output signal.

real_fcfloat

actual applied cut off frequency (matching the frequency grid of the FFT)

Return type:

dict containing following keys

skcomm.filters.moving_average(samples, average=4, domain='freq')

Filter a given signal with a moving average filter.

In the time domain implementation, a causal impulse response is used, which generates a filter group delay of floor(average/2) samples. CAUTION: The number of samples of the output signal differs from the number of samples of the input signal.

In the frequency domain implementation (cyclic convolution), an acausal filter is used which does not generate any group delay.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • average (int, optional) – number of samples to average. The default is 4.

  • domain (string, optional) – implementation of the filter either in ‘time’ or in ‘freq’ domain. The default is ‘freq’.

Returns:

samples_out – filtered output signal.

Return type:

1D numpy array, real or complex

skcomm.filters.raised_cosine_filter(samples, sample_rate=1.0, symbol_rate=1.0, roll_off=0.0, length=-1, root_raised=False, domain='freq')

Filter a given signal with a (root) raised cosine filter.

  • time domain (convolution):

    data is convolved with an (root) raised cosine impulse response (h). CAUTION: This filter generates a group delay which is equal to ceil(size(h)/2). Further, the number of samples of the output signal differs from the number of samples of the input signal.

  • frequency domain (multiplication of spectra equivalent to a CYCLIC convolution):

    the frequency response of an (root) raised cosine filter is multiplied with the spectrum of the signal. This filter is acausal and does not produce any group delay.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • sample_rate (float, optional) – sample rate of input signal in Hz. The default is 1.0.

  • symbol_rate (float, optional) – symbol rate of the input signal in Bd. The default is 1.0.

  • roll_off (float, optional) – roll off factor of the filter. The default is 0.0.

  • length (int, optional) – length of the filter impulse response, -1 equals to the length of the input singal. The default is -1. This parameter is only reasonably in case of time domain filtering (domain=’time’).

  • root_raised (bool, optional) – is the filter a root-raised cosine filter (True) or a raised-cosine filter (False). The default is False.

  • domain (string, optional) – implementation of the filter either in ‘time’ or in ‘freq’ domain. The default is ‘freq’.

Returns:

samples_out – filtered output signal.

Return type:

1D numpy array, real or complex

skcomm.filters.time_shift(samples, sample_rate=1.0, tau=0.0)

Add a cyclic time shift to the input signal.

A positve time shift tau delays (right shifts) the signal, while a negative time shift advances (left shifts) it. For time shifts equal to an integer sampling duration, the signal is simply rolled.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • sample_rate (float, optional) – sample rate of input signal in Hz. The default is 1.0.

  • tau (float, optional) – time shift in s. The default is 0.0.

Returns:

samples_out – cyclic time shifted input signal.

Return type:

1D numpy array, real or complex

skcomm.filters.windowed_sinc(samples, fc=0.5, order=111, window=None)

Filter a given signal with a windowed Si-funtion as impulse response.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • fc (float, optional) – cut off frequency, 0.0 <= fc <= 1.0, where 1.0 specifies the Nyquist frequency (half the sampling frequency). The default is 0.5.

  • order (int, optional) – length of the inpulse response, which has to be odd. If order=-1, the length is chosen to be the length of the input signal. The default is 111.

  • window (string, optional) –

    type of the window funtion which is multiplied with the sinc-impulse response before filtering. Possible window function are

    • ’none’ –> Si impulse response

    • ’Hamming’

    • ’Blackmann-Harris’.

    The default is None.

Returns:

samples_out – filtered output signal of lenth samples.size+order-1.

Return type:

1D numpy array, real or complex

Note

This filter generates a group delay which is equal to ceil(order/2). Further, the number of samples of the output signal differs from the number of samples of the input signal (see scipy convolution).

Instrument Control Submodule (skcomm.instrument_control)

This submodule includes routines to communicate to laboratory equipment.

get_opt_power_Anritsu_ML910B([GPIB_bus, ...])

Read optical power from Anritsu ML910B optical power meter.

get_opt_power_HP8153A(channels[, GPIB_bus, ...])

Read opitcal power.

get_opt_power_HP8163B([channels, ip_address])

read optical power measurements from HP 8163B optical power meter.

get_samples_DLM2034([channels, address])

get_samples_Tektronix_MSO6B([channels, ...])

Function for reading samples from Tektronix MSO68 Scope

get_screenshot_DLM2034([address, folder, ...])

Get and save screenshot from Yokogawa DLM 2034/3024 sscilloscope as PNG.

get_spectrum_HP_71450B_OSA([traces, ...])

Function for reading spectrum from a HP_71450B optical spectrum analyzer

get_spectrum_IDOSA()

Function for reading the optical spectrum from an ID-Photonics ID-OSA.

set_attenuation_MTA_150([cassettes, ...])

Function for setting the attenuation of the JDS Uniphase MTA 150 optical attenuator.

write_samples_Agilent_33522A(samples[, ...])

Function for writing samples to an Agilent/Keysight 33500 Series 30MHz Function/Arbitrary Waveform Generator

write_samples_TTI_TG5012A([samples, ...])

Write samples to TTI arbitrary waveform generator and set waveform parameters.

write_samples_Tektronix_AWG70002B(samples[, ...])

write_samples_AWG70002B

skcomm.instrument_control.get_opt_power_Anritsu_ML910B(GPIB_bus=0, GPIB_address=11)

Read optical power from Anritsu ML910B optical power meter.

This driver does not set any parameters of the instrument. Make sure that all required paremeters e.g. power unit, range, wavelength and selected channel are correctly set manually via the device panel.The driver simply queries the power values of the selected channels.

Parameters:
  • GPIB_bus (int, optional) – GPIB bus number to which the instrument is connected. The default is 0.

  • GPIB_address (int, optional) – GPIB address set to the instrument. The default is 11.

Returns:

output – A dict containing the keys ‘ch1’ and ‘ch2’, respectively. Each entry consists of a dict with keys ‘value’ and ‘unit’ containing the measured value and corresponding measurement unit.

Return type:

dict of dicts

skcomm.instrument_control.get_opt_power_HP8153A(channels, GPIB_bus=0, GPIB_address=22, power_units=[None], wavelengths=[None], verbose_mode=True, log_mode=False)

Read opitcal power.

Function for reading power values from a HP8153A lightwave multimeter.

Wavelength ranges of the currently used modules:

  • HP 81533A 850 nm to 1700 nm

  • HP 81531A 800 nm to 1700 nm

Parameters:
  • channels (list of strings) –

    Insert here the required channel of the lightwave multimeter as a list of strings.

    • for channel 1:

      >>> channels = ['1']
      
    • for channel 2:

      >>> channels = ['2']
      
    • for channels 1 and 2:

      >>> channels = ['1','2']
      

    The channel assignment of the parameters power_units and wavelengths corresponds to the elements of this list.

  • GPIB_bus (int) – The GPIB bus number of the lightwave multimeter. Use a value between 1 and 30

  • GPIB_address (int) – The GPIB address of the lightwave multimeter. Use a value between 1 and 30

  • log_mode (boolean, optional (default = False)) – Enables a log file for this method.

  • power_units (list of string soptional (default = [None])) –

    Sets the power unit(s) for the acquired channel(s). Available power units are ‘DBM’ and ‘Watt’ (case-sensitive). Maximum number of list items is 2.

    • Examples for one channel :

      >>> power_units = ['DBM']
      >>> power_units = ['Watt']
      
    • Examples for two channels:

      >>> power_units = ['DBM','Watt']
      >>> power_units = ['DBM','DBM']
      

    The assignment of the units corresponds to the elements in the channels list. When the unit list is changed, its length must be the same as the channels list.

    If the unit should not be changed, ignore this parameter or set to ‘None’.

    Special case: The power level of both channels shall be acquired and for one channel the power unit should be changed. In this case, a ‘None’ is used for the channel that should be not changed.

    >>> power_units = ['DBM','None']
    

  • wavelengths (list of floats, optional ( default = [None]).) –

    Sets the calibration wavelength(s) for the acquired channel(s). Maximum number of list items is 2.

    • Example one channel:

      >>> wavelengths = ['1550']
      
    • Example two channels:

      >>> wavelengths = ['1550','1500']
      

    The assignment of the wavelengths corresponds to the elements in the channels list. When the wavelength list is changed, its length must be the same as the channels list.

    If the wavelength(s) should not be changed, ignore this parameter or set it to ‘None’.

    Special case: The power level of both channels should be acquired and for one channel the wavelength should be changed. In this case, a ‘None’ is used for the channel that should not changed.

    • Only channel one should change:

      >>> wavelengths = ['1540','None']
      

    Warning: If the wavelength setting of a channel is out of range, the multimeter will ignore the setting.

  • verbose_mode (boolean (default = True)) – When this mode is activated, additional information such as the current wavelength, the power unit and the module name are returned from the function. If only the current power is required, this mode should be deactivated (False) to save unnecessary IO operations.

Returns:

channel_information: dict

Returns two versions depending on verbose_mode.

  • verbose_mode = False:

    Consist of dicts which only contain the acquired channel power level.

    To access the dict use:

    >>> object[Name of channels][Name of data]
    

    Name of channels:

    • ’1’: channel 1

    • ’2’: channel 2

    Name of data:

    • Power: (float) contains power level of the channel

  • verbose_mode = True:

    Consist of dicts which contain the acquired channel power level, wavelength, power unit and modulename.

    To access the dict:

    >>> object[Name of channels][Name of data]
    

    Name of channels:

    • ’1’: channel 1

    • ’2’: channel 2

    Name of data:

    • Power: (float) contains the power level of the channel

    • Unit: (string) contains the power unit

    • Wavelength: (float) contains the calibration wavelength in nanometers (nm)

    • Module: (string) contains the module name for the channel

Examples

>>> import skcomm as skc

The power of channel 1 should be acquired. The wavelength will be set to 1550 nm and the power unit to dBm. GPIB address will be set to 22. In this example, the verbose mode is activated.

>>> p = skc.instrument_control.get_opt_power_HP8153A(channels = ['1'], GPIB_address = 22, power_units = ['DBM'], wavelengths = [1550.0])

The power of both channels should be acquired. The wavelength of channel 1 should not be changed. For channel 2, the wavelengths will be set to 1550nm. Power unit for channel 1 should be “Watt” and “dBm” for channel 2.

>>> p = skc.instrument_control.get_opt_power_HP8153A(channels = ['1','2'], GPIB_address = 22, power_units = ['Watt','DBM'], wavelengths = [None,1550.0])

Only the power value should be acquired from both channels. Therfore, the verbose_mode can be deactivated.

>>> p = skc.instrument_control.get_opt_power_HP8153A(channels = ['1','2'], GPIB_address = 22, verbose_mode = False)

Note, in this example, no values for wavelengths and power_unit are provided. Hence, the current values of the multimeter will be used.

Access the power level only of channel 1

>>> power_level_ch1 = p['1']['Power']

Access the wavelength of channel 2

>>> wavelength_ch2 = p['2']['Wavelength']
Raises:
  • Type Error: – This will be raised when a wrong data type is used for the input parameter. - Possible errors - Type of channels must be list. - Type of channel items must be string. - Type of GPIB_address must be string. - Type of power units must be string. - Type of power_unit must be list. - Type of wavelength must be float. - Type of wavelength must be list. - Type of verbose_mode must be bool. - Type of log_mod must be boolean.

  • Value Error: – This will be raised when the input parameter is in an wrong range. - Possible errors - Too many channels ({0}). The lightwave mulitimeter has a maximum of 2 channels - Too few channels. Use at least one channel. - Wrong channel naming. Channels are named with 1 or 2. - Wrong power units naming. Allowed power units are the strings DBM and Watt. - Too few wavelength arguments. The number of wavelength arguments must be at least 1. - Too many wavelength arguments. A maximum of 2 arguments is permitted. - Lengths of wavelength and channels lists must be equal.

  • Exception: – Will be raised by diverse errors - Possible errors - No connection to the multimeter.

skcomm.instrument_control.get_opt_power_HP8163B(channels=['1'], ip_address='192.168.1.1')

read optical power measurements from HP 8163B optical power meter.

Parameters:
  • channels (list of strings, optional) – Which channels should be read out? The default is [‘1’].

  • ip_address (string, optional) – IP address of the device. The default is ‘192.168.1.1’.

Returns:

channel_information – dict keys are generated from input parameter channels. Each dict value contains another dict with following keys: ‘Power’: measured power value for channel ‘Unit’ : power unit for channel (‘dBm or Watt’) ‘Wavelength’: wavelength [nm] for channel

Return type:

dict

skcomm.instrument_control.get_samples_DLM2034(channels=[1], address='192.168.1.12')
Parameters:
  • channels (list of integers and / or strings, optional) – list containing the channel(s) to fetch data samples from device. Valid integers are 1,2,3 and 4. Valid strings are ‘1’,’2’,’3’,’4’,’LOGIC’,’MATH1’ and ‘MATH2’. The default is [1].

  • address (string, optional) – IP Adress of device. The default is ‘192.168.1.12’.

Returns:

  • sample_rate (float) – actual sample rate of returned samples.

  • wfm (list of numpy arrays, float) – each list element constains the samples of a requested channel as numpy float array.

skcomm.instrument_control.get_samples_Tektronix_MSO6B(channels=[1], ip_address='192.168.1.20', number_of_bytes=1, log_mode=False)

Function for reading samples from Tektronix MSO68 Scope

Parameters:
  • channels (list of integers, optional) – iterable containing the channel numbers to fetch data samples from device. The default is [1]. For more chennels use [1,2,…] Minimum number of channels is 1 Maximum number of channels is 4 Ensure that the acquired channels are activated at the scope

  • address (string, optional) – IP Adress of device. The default is ‘192.168.1.20’.

  • number_of_bytes (integer, optional) – Defines the length of the requested data from the scope in bytes. Allowed are 1 Byte (signed char), 2 Bytes (signed short) or 4 Bytes (long)

  • log_mode (boolean, optional) – Specifies whether a log file should be created or not

Returns:

  • sample_rate (float) – actual sample rate of returned samples.

  • wfm (list of numpy arrays, float) – each list element constains the samples of a requested channel as numpy float array.

Raises:
  • Type Error: – Will be raised when a wrong data type is used for the input parameter -> Possible errors -> channels is not of type list -> Items of channels are not of type integer -> ip_address is not of type string -> number_of_bytes is not integer

  • Value Error: – Will be raised when the input parameter is in an wrong range -> Possible errors -> Too much channels are used. Maximum is 4 -> Too less channels are used. Minimus is 1 -> Channel numbers must be between 1 and 4 -> Wrong number of bytes (1 Byte (signed char), 2 Bytes (signed short) or 4 Bytes (long))

  • Exception: – Will be raised by diverse errors -> Possible errors -> No connection to the scope -> Required channels are not activated at the scope

skcomm.instrument_control.get_screenshot_DLM2034(address='192.168.1.11', folder='.', fname=None, timestamp=True, tone='COLOR', capture_info='OFF')

Get and save screenshot from Yokogawa DLM 2034/3024 sscilloscope as PNG.

Parameters:
  • address (string, optional) – IP adress of the device. The default is ‘192.168.1.11’.

  • folder (string, optional) – Folder to save the screenshot to. The default is ‘.’.

  • fname (string, optional) – Filename to save the screenshot to. If None the standard name ‘osci_screenshot’ is used. The default is None.

  • timestamp (bool, optional) – Should a timestamp be added to the filename. The default is True.

  • tone (string, optional) – Tone of the output image. Allowed are ‘COLOR’, ‘GRAY’, ‘OFF’, ‘REVERSE’. The default is ‘COLOR’.

  • capture_info (string, optional) – Should oscilloscope settings (e.g. trigger mode) be included in the image? ‘ON’ for yes and ‘OFF’ for no. The default is ‘OFF’.

skcomm.instrument_control.get_spectrum_HP_71450B_OSA(traces=['A'], GPIB_bus=0, GPIB_address=13, log_mode=False, single_sweep=False)

Function for reading spectrum from a HP_71450B optical spectrum analyzer

Parameters:
  • traces (list of stings, optional (default = ['A'])) – Insert here the wanted traces from the OSA as a list of strings. The three traces of the OSA are A, B, and C. It is also possible to use lower case.

  • GPIB_bus (int, optional (default = 0)) – The GPIB bus number of the OSA.

  • GPIB_address (int, optional (default = 13)) – The GPIB address of the OSA.

  • log_mode (boolean, optional (default = False)) – Enables a log file for this method.

  • boolean (single_sweep =) – Starts a new sweep and stops after acquisition. Keeps the OSA in Single mode. Be careful, because saved traces can be overwritten by this! By default the program will acquire the traces, while the OSA is sweeping. The sweeping process is slow enough for this.

  • False) (optional (default =) – Starts a new sweep and stops after acquisition. Keeps the OSA in Single mode. Be careful, because saved traces can be overwritten by this! By default the program will acquire the traces, while the OSA is sweeping. The sweeping process is slow enough for this.

Returns:

trace_information: dict

Consist of dicts which contains the acquired trace data, amplitude unit and wavelength information. To access the dict use:

  • Name of object[<Name of trace>][<Name of data>]

    • <Name of Trace>:

      • A : Trace A

      • B : Trace B

      • C : Trace C

    • <Name of data>:

      • spectrum : (np.array) Contains numpy array with trace data

      • Unit : (string) Contains the unit of the trace data

      • Sensitivity : (float) Contains the amplitude sensitivity of the spectrum (always in dBm)

      • Start_WL : (float) Contains the start wavelength of the spectrum (in m)

      • Stop_WL : (float) Contains the stop wavelength of the spectrum (in m)

      • Resolution_BW: (float) Contains the resolution bandwidth of the spectrum (in m)

      • wavelength : (np.array) Numpy array with evenly spaced wavelengths between Start_WL and Stop_WL (in m)

Raises:
  • Type Error: – Will be raised when a wrong data type is used for the input parameter -> Possible errors -> traces is not of type list -> Items of traces are not of type integer -> ip_address is not of type string -> number_of_bytes is not integer

  • Value Error: – Will be raised when the input parameter is in an wrong range -> Possible errors -> Too many traces are used. Maximum is 3 -> Too few traces are used. Minimus is 1 -> Trace numbers must be between 1 and 3

  • Exception: – Will be raised by diverse errors -> Possible errors -> No connection to the scope -> Required traces are not activated at the scope

skcomm.instrument_control.get_spectrum_IDOSA()

Function for reading the optical spectrum from an ID-Photonics ID-OSA. OSA settings have to be adjusted externally (using e.g., the ID-OSA GUI) before reading th spectrum (for details, see Manual_IDOSA.pdf).

Parameters:
  • ip_address (string, optional (default: '192.168.1.22')) – Th IP-address of the device.

  • new_sweep (boolean or int, optional (default: False)) – If FALSE or 0, the current spectrum will be fetched from the instrument. If TRUE or 1, a new OSA sweep is initiated and the spectrum is fetched thereafter. The device is then reset to the original sweep mode.

  • wl_equidist (boolean or int, optional (default: False)) – If FALSE or 0, the returned wavelengths are calculated from an equidistant frequency vector which is always used internally by the device. If TRUE or 1, the spectrum is interpolated at equidistant wavelengths, where the wavelength is interpolated using the same range and number as the original wavelength axis.

Returns:

trace

The dictionary holds the spectrum measurement results in the following key-value pairs:

key value ‘Resolution_BW_Hz’ (float) The OSA resolution bandwidth in units of [Hz]. ‘Resolution_BW_m’ (float) The resolution bandwidth in units of [m], referenced to center of the spectrum. ‘frequency’ (np.array) Contains the frequency axis (descending) in units of [Hz]. ‘wavelength’ (np.array) Contains the wavelength axis (ascending) in units of [m]. ‘spectrum_dBm’ (np.array) Contains the spectrum in log-domain in units of [dBm]. ‘Ptotal_dBm_IDOSA’ (float) The total optical power in [dBm], interally calculated by the instrument. ‘Ptotal_dBm_int’ (float) The total optical power in [dBm], calculated from the fetched spectrum.

Return type:

dict

skcomm.instrument_control.set_attenuation_MTA_150(cassettes=['1'], attenuations=[None], offsets=[None], wavelengths=[None], GPIB_address='12', log_mode=False)

Function for setting the attenuation of the JDS Uniphase MTA 150 optical attenuator. This method is able to change and read the values of the attenuator. For the write mode, the desired cassettes and the corresponding attenuation, offset and wavelength must be specified. For the read mode, only the desired cassettes must be specified. The default setting is to read the values from cassette 1. It is also possible to change only individual parameters. In this case, the parameters that are not to be changed receive a None.

Information: To change back the MTA to local mode (Controlling with keys), the LCL key must be pressed.

Information: The built-in beam block in each MTA300 cassette is automatically activated when the cassette is powered up.The beam block must be deactivated after power-up so that light can passthrough the attenuator. This method will not do this, so it must be done manualy at the device.

Parameters:
  • cassettes (list of strings, optional (default = ['1'])) –

    The attenuator has several cassettes, the attenuation of each can be individually adjusted. To select the wanted cassette, the numerical index must be put into the list as string. If several cassettes are used, only the numerical indices must be transferred as a list. For example: [‘1’,’2’,’3’] (Three cassettes). Maximum number of cassettes is 8.

    WARNING: If a cassette is selected which is not physically available, the last selected cassette is used. There is a risk that values ​​will be overwritten.

  • attenuations (list of floats or Nones, optional (default = [None])) – Sets the total attenuation to the parameter value by changing the actual attenuation. Value must be between 0dB and 60dB If not used, the value of the MTA is unchanged. If the value of one cassette is to be changed and the others not, a None can simply be inserted in the vector for the value that is not to be changed. For example: [20,None,30] (Value of the second entry will not changed)

  • offsets – Sets the display offset of the MTA system. The value of the offset has no affecton to the actual attenuation, but it does affect the total attenuation. The display offset function can be used to include both the insertion loss of theMTA300 cassette and connection losses in the attenuation value displayed. Att_total = Att_actual + Offset Value must be between -60dB and 60dB. If not used, the value of the MTA is unchanged. If the value of one cassette is to be changed and the others not, a None can simply be inserted in the vector for the value that is not to be changed. For example: [20,None,30] (Value of the second entry will not changed)

Returns:

cassette_informationdict

Consist of dicts which contains the attenuation, offset, wavelength and total attenuation of the sected cassette.

To access the dict use:

<Name of object>[<Name of cassette>][<Name of data>]

  • <Name of cassette>: (string)

    • 1 : Cassette 1

    • 2 : Cassette 2

    • 8 : Cassette 8

  • <Name of data>: (string)

    • attenuation : (float) Contains the selected attenuations (Att_actual)

    • offset : (float) Contains the selected offset

    • wavelength : (float) Contains the selected wavelength

    • Total attenuation: (float) Contains the total attenuation (Att_total = Att_actual + Offset) Corresponds with the showed attenuation of the device.

Examples

>>> import skcomm as skc

Get the data from the cassette 1 and 2. The properties of the device will not be changed.

>>> a = skc.instrument_control.set_attenuation_MTA_150(cassettes=['1','2'])

Change values of attenuation, offset and wavelength for cassette 2

>>> b = skc.instrument_control.set_attenuation_MTA_150(cassettes=['2'],attenuations=[5.0], offsets=[5.0], wavelengths=[1300.5])

Change attenuation of cassette 1 and wavelength of cassette 2

>>> c = skc.instrument_control.set_attenuation_MTA_150(cassettes=['1','2'],attenuations=[5.0,None],wavelengths=[None,1550.0])

Cassettes order can be changed

>>> d = slc.instrument_control.set_attenuation_MTA_150(cassettes=['2','1'],attenuations=[None,0.0],wavelengths=[1500.0,None])

Access actual attenuation value of cassette 1

>>> e = skc.instrument_control.set_attenuation_MTA_150(cassettes=['1','2'])
>>> attenuation_value = e['1']['attenuation']
Raises:
  • Type Error: – Will be raised when a wrong data type is used for the input parameter -> Possible errors -> cassets, attenuations, offsets or wavelengths are not of type list -> Items of cassets are not of type string -> Items of attenuations, offsets or wavelengths are not of type float -> ip_address is not of type string -> number_of_bytes is not integer

  • Value Error: – Will be raised when the input parameter is in an wrong range -> Possible errors -> Too many cassets are used. Maximum is 8 -> Too few cassets are used. Minimum is 1 -> Cassett numbers must be between 0 and 7 -> Attenuation value is wrong. Must be between 0 and 60 -> Offset value is wrong. Must be between -60 and 60 -> Wavelength value is wrong. Must be bewteen 1200 and 1600

  • Exception: – Will be raised by diverse errors -> Possible errors -> No connection to the attenuator -> Required cassettes are not physically present

skcomm.instrument_control.write_samples_Agilent_33522A(samples, ip_address='192.168.1.44', sample_rate=[250000000.0], offset=[0.0], amp_pp=[1.0], channels=[1], out_filter=['normal'], wait_for_ext_trigger=[False], trig_delay=[0.0])

Function for writing samples to an Agilent/Keysight 33500 Series 30MHz Function/Arbitrary Waveform Generator

Parameters:
  • samples (numpy array, n_outputs x n_samples , float) – samples to output, to be scaled between -1 and 1 (values outside this range are clipped).

  • ip_address (string, optional) – The default is ‘192.168.1.44’. Currently, only LAN connection is supported.

  • sample_rate (list of floats, optional) – sample rate of the individual outputs. The default is [250e6]. Range: 1µSa/s to 250 MSa/s, limited to 62.5 MSa/s if out_filter is OFF.

  • offset (list of floats,, optional) – output DC offset of individual channels in V. The default is [0.0].

  • amp_pp (list of floats, optional) – peak-to-peak output amplitude of individual channels in units of Volt. The default is [1.0].

  • channels (list of int, optional) – channels to be programmed and output. The default is [1].

  • out_filter (list of strings, optional) – used output filter of each channel [‘normal’, ‘off’, ‘step’]. The default is [‘normal’].

  • wait_for_ext_trigger (list of bools) – Should the device wait for an external trigger (raising edge at the device backpanel “Ext trig”) to start the ouput? The default is [False].

  • trig_delay (list of floats) – The signal is output trig_delay seconds after the trigger event. This parameter takes only effect if wait_for_eyt_trigger is True. The default is 0.0.

Return type:

None.

skcomm.instrument_control.write_samples_TTI_TG5012A(samples=array([], dtype=float64), ip_address='192.168.1.105', waveform='SINE', amp_pp=1.0, channel=1, repetition_freq=1000.0, memory='ARB1', interpolate='OFF', bit_rate=1000.0, mute_output=False)

Write samples to TTI arbitrary waveform generator and set waveform parameters.

This funtion allows for setting an output waveform of a TTI TG5012A function and arbitrary waveform generator (AWG). Customized waveforms can be uploaded too.

Parameters:
  • samples (numpy array, float) – samples to be output, have to be scaled between -1 and 1 (values outside this range are clipped). The length of the samples array must be between 2 and 131072. The default is np.asarray([]).

  • ip_address (string, optional) – IP address of AWG. The default is ‘192.168.1.105’.

  • waveform (string, optional) – What waveform to output. Allowed are ‘SINE’, ‘SQUARE’, ‘RAMP’, ‘TRIANG’, ‘PULSE’, ‘NOISE’, ‘PRBSPNX’, ‘ARB’, ‘DC’. The default is ‘SINE’. PRBS lengths can be 7, 9, 11, 15, 20 or 23 (e.g. PRBSPN7).

  • amp_pp (float, optional) – Peak-to-peak voltage of the output signal in Volts. Be careful: the peak-to-peak amplitude has different meanings for different waveform types. For example: in case of ‘DC’ it is the amplitude of the DC, while for custom waveforms it is the voltage difference of the smallest and largest uploaded sample. Note that the actual output voltage is also influenced by the setting of the source impedance and the connected load impedance!

  • channel (int, optional) – Output channel that is programmed. The default is 1.

  • mute_output (boolean, optional) – Mute (switch OFF) the selected output during programming to prevent glitches. Note: The output of the selected channel will always be switched to ON after programming. The default is False.

  • repetition_freq (float, optional) – Repetition frequency of the custom waveform in memory in Hz. This is the read-out repetition frequency of the whole memory and therefore, multiplied with the length of the custom waveform, determines the sample rate. For other periodic waveforms (e.g. SINE), the parameter specifies the signal frequency. The default is 1000.0.

  • memory (string, optional) – Internal memory identifier used to store the custom waveform. Allowed names are ‘ARB1’, ‘ARB2’, ‘ARB3’ and ‘ARB4’ . The default is ‘ARB1’.

  • interpolate (string, optional) – The AWG is only able to output waveforms of length 2**14 or 2**17. Uploaded waveforms shorter than 2**14 are extended to 2**14 and signals of length between 2**14 and 2**17 are extended to 2**17. If interpolate is ‘ON’, the missing samples are linearly interpolated. If interpolate is ‘OFF’, the missing samples are generated by repeating samples (see p.79 of data sheet of the AWG).The default is ‘OFF’.

  • bit_rate (float, optional) – Bit rate in case of a PRBS signal in bits/s. The default is 1000.0.

Return type:

None.

skcomm.instrument_control.write_samples_Tektronix_AWG70002B(samples, ip_address='192.168.1.21', sample_rate=[250000000.0], amp_pp=[0.5], channels=[1], log_mode=False)

write_samples_AWG70002B

Function for writing samples to an Tektronix AWG70002B Series 20GHz Function/Arbitrary Waveform Generator

Parameters:
  • samples (numpy array, n_outputs x n_samples , float) – samples to output, to be scaled between -1 and 1 (values outside this range are clipped). Without clipping the AWG would clip the waveform. Only real numbers are allowed. To use complex numbers assign the real and imaginray part to different channels. Maximum vector length is 234e6.

  • ip_address (string, optional) – The default is ‘192.168.1.21’. Currently, only LAN connection is supported.

  • sample_rate (list of floats, optional) – sample rate of the outputs. The default is [250e6]. Must be between 1.49 kSamples/s and 8 GSsamples/s

  • amp_pp (list of floats, optional) – peak-to-peak output amplitude of individual channels in units of Volt. The default is [0.5]. For two channels enter format [x.x,y.y]

  • channels (list of int, optional) – channels to be programmed and output. The default is [1]. For two channels input [1,2]

  • log_mode (Bool, optional) – When True a log file will be created (Default = False) The log file includes error messages and infos about the program flow

Return type:

None.

Raises:
  • Type Error: – Will be raised when a wrong data type is used for the input parameter -> Possible errors -> Parameters are not of type list -> Items of channels, amp_pp or sample_rate are not of type integer -> Items of samples are not of type np.array -> Items of samples are of type complex. -> ip_address is not a string

  • Value Error: – Will be raised when the input parameter is in an wrong range -> Possible errors -> The samples np.arrays contains NaN or Inf -> The lengths of amp_pp, channels and samples have not the same length -> The peak to peak voltage is not between 0.25V and 0.5V -> The sampling_rate ist not between 1.49e3 and 8e9 -> Channel designation is wrong

  • Exception: – Will be raised by diverse errors -> Possible errors -> No connection to the AWG

Pre Distortion Submodule (skcomm.pre_distortion)

This submodule includes routines to linearly pre-distort systems.

dac_sinc_correction(samples[, f_max])

Compensates for the Sinc rolloff of a zero order hold digital-to-analogue converter.

estimate_tf_welch(samples_in, ...[, ...])

Estimate magnitude transfer function (in linear scale) using Welch method and calculate the inverted transfer function up to f_max.

generate_wn_probesignal([n_samples, f_max])

Generate complex white noise samples.

skcomm.pre_distortion.dac_sinc_correction(samples, f_max=1.0)

Compensates for the Sinc rolloff of a zero order hold digital-to-analogue converter.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • f_max (float, optional) – frequency up to which the rolloff is compensated for. 0.0 < f_max <= 1.0, where 1.0 specifies the Nyquist frequency (half the sampling frequency). The default is 1.0.

Returns:

samples_out – output signal.

Return type:

1D numpy array, real or complex

skcomm.pre_distortion.estimate_tf_welch(samples_in, sample_rate_in, samples_out, sample_rate_out, f_max, nperseg=64, visualize=0)

Estimate magnitude transfer function (in linear scale) using Welch method and calculate the inverted transfer function up to f_max.

For calculation of the transfer function, the samples_out are resampled to the input sample rate, if the samples rates do not match.

See documentation of scipy.signal.welch for mor information.

Parameters:
  • samples_in (1D numpy array, real or complex) – input samples to the DUT.

  • sample_rate_in (float) – samples rate of samples_in in Hz.

  • samples_out (1D numpy array, real or complex) – output samples from DUT.

  • sample_rate_out (float) – samples rate of samples_out in Hz..

  • nperseg (int, optional) – block size of Welch method. The default is 64.

  • f_max (float) – frequency up to which the inversion of the transfer function is calculeted. The inverted magnitude transfer function is set to 0 outside this frequency range.

  • visualize (int, optional) – should debug plots (spectra) be generted? Value also specifies the figure number. No plots for visualize=0. The default is 0.

Raises:

ValueError – DESCRIPTION.

Returns:

results

tf1D numpy array, real or complex

estimated linear magnitude transfer function.

tf_inv1D numpy array, real or complex

inverted linear magnitude transfer function up to frequency f_max.

freq1D numpy array, real

frequency axis of tf / tf_inv

Return type:

dict containing following keys

skcomm.pre_distortion.generate_wn_probesignal(n_samples=131072, f_max=1.0)

Generate complex white noise samples.

The amplitudes of the real and imaginary parts are each uniformly distributed between -1.0 and 1.0.

Parameters:
  • n_samples (integer, optional) – Number of noise samples to generate. The default is 2**17.

  • f_max (float, optional) – cut off frequency, 0.0 < f_max <= 1.0, where 1.0 specifies the Nyquist frequency (half the sampling frequency). The default is 1.0.

Returns:

samples – Random complex noise samples where the real and imaginary parts are each unifomrly distributed bewtween -1.0 and 1.0.

Return type:

1D numpy array, complex

Receiver Submodule (skcomm.rx)

This submodule includes receiver routines.

blind_adaptive_equalizer(sig[, n_taps, ...])

Equalize the signal using a blind adaptive equalizer filter.

calc_eq_frequency_response_zf(H)

Calculate equalizer frequency response.

carrier_phase_estimation_VV(symbols[, ...])

Viterbi-Viterbi carrier phase estimation and recovery.

carrier_phase_estimation_bps(samples, ...[, ...])

"Blind phase search" carrier phase estimation and recovery.

combining(sig[, comb_method, weights, ...])

Performs Diversity Combining of the rows of a passed n-dimensional signal- class object, where each row represents the signal captured by an antenna of a SIMO system, according to the passed SNR values per dimension if comb_method == MRC.

count_errors(bits_tx, bits_rx)

Count bit errors.

coRx_phase_imbalance_comp(samples[, ...])

Phase imbalance compensation for a coherent receiver frontend.

cycle_slip_correction(coarse_phase_est, ...)

Function to compensate for cycle slips based on corase and fine phase estimation.

da_cfo_estimation(samples[, shift, sample_rate])

Estimate carrier frequency offset.

da_channel_estimation(ce_header_rx_spec, ...)

Estimate channel frequency resoponse.

da_equalizer(sig_tx, sig_rx[, cfo_comp, ...])

Data-aided equalizer.

da_frame_sync(samples[, shift, ...])

Perform temporal synchronization to a reference frame.

da_snr_estimation(ce_header_rx, pilot_pos, ...)

Estimates the SNR of a received signal using repeated OFDM pilot symbols in the channel estimation headers.

dc_block_and_unit_variance_norm(samples)

Function to cover DC block and normalization to unit variance.

decision(samples, constellation[, norm])

Decide samples to a given constellation alphabet.

demapper(samples, constellation)

Demap samples to bits using a given constellation alphabet.

deskew(samples_1, samples_2[, sample_rate, ...])

Finds the skew between two signals (and compensates for it).

frequency_offset_correction(samples[, ...])

Frequency offset estimation and correction (FOE and FOC).

pilot_aided_coarse_cpe(samples, pilot_symbols)

Pilot-aided coarse carrier-phase-estimation (and correction).

pilot_based_cpe_wrapper(sig_rx[, ...])

Wrapper function to process three-staged CPE.

sampling_clock_adjustment(samples[, ...])

Estimate sampling frequency offset and correct for it.

sampling_phase_adjustment(samples[, ...])

Estimate the sampling phase offset and compensate for it.

stokesEQ_pdm(samples_X, samples_Y)

Performs blind polarization demultiplexing of polarization-multiplexd complex-modulated signals.

symbol_sequence_sync(sig[, dimension])

Estimate and compensate delay and phase shift between reference symbol / bit sequence and physical samples.

skcomm.rx.blind_adaptive_equalizer(sig, n_taps=111, mu_cma=0.005, mu_rde=0.005, mu_dde=0.5, decimate=False, return_info=True, stop_adapting=-1, start_rde=5000, start_dde=5000, exec_mode='auto')

Equalize the signal using a blind adaptive equalizer filter.

A complex valued filter is initialized with a dirac impulse as impulse response of length n_taps samples. Then the first signal sample is filtered.

There exist tree operation modes:

  • constant modulus algorithm (CMA) operation [1]:

    Once each SYMBOL, the error (eps) to the desired output radius is calculated and the filter impulse response is updated using the steepest gradient descent method [1]. A step size parameter (mu_cma) is used to determine the adaptation speed.

  • radially directed equalizer (RDE) operation [2]:

    Once each SYMBOL, the output signal is decided to ONE of the desired radii (the nearest one) [2] and [3]. The error (eps) between the output signal and this decided radius is calculated and the filter impulse response is updated using the steepest gradient descent method. A step size parameter (mu_rde) is used to determine the adaptation speed.

  • decision directed equalizer (DDE) [2]:

    Once each SYMBOL, the output signal is decided to ONE, the nearest constellation point. The error (eps) between the output signal and this decided constellation point is calculated and the filter impulse response is updated using the steepest gradient descent method. A step size parameter (mu_dde) is used to determine the adaptation speed. CAUTION: this option works only very unreliable in case of phase noise!!!

All three modes are in general run sequentially in the order CMA, RDE and DDE. The parameters start_rde and start_dde control when the modes are switched. start_rde defines after how many SYMBOLS the RDE mode ist started after the start of CMA mode. start_rde=0 does not start this mode at all.

start_dde defines after how many SYMBOLS the DDE mode is started AFTER the RDE mode has started. However, if the RDE mode is switched off (start_rde=0) the parameter start_dde defindes after how many SYMBOLS the DDE mode is started AFTER the CMA mode has started. start_dde=0 does not start this mode at all.

Examples

  • start_rde=10e3, start_dde=0 –> 10e3 symbols CMA, rest RDE

  • start_rde=0, start_dde=0 –> all samples filterd with CMA

  • start_rde=0, start_dde=10e3 –> 10e3 symbols CMA, rest DDE

  • start_rde=0, start_dde=1 –> 1 symbol CMA, rest DDE

  • start_rde=5e3, start_dde=10e3 –> 5e3 symbols CMA, 10e3 sybmosl RDE, rest DDE

The equalizer can output every filtered SAMPLE or only every filtered SYMBOL, which is controlled with the parameter decimate.

Further, the adaptation of the impulse response / equalizer can be stopped after stop_adapting SYMBOLS.

The equalizer operates on each signal dimension independently. The parameters can be passed as

  • singular values [int, float or bool], which are broadcasted to every dimension, or

  • lists of length n_dims to specify independent parameters for each signal dimension

Parameters:
  • sig (skcomm.signal.Signal) – input signal to be equalized.

  • n_taps (int or list of ints, optional) – length of the equalizers impulse response in samples for each dimension. Has to be odd. The default is 111.

  • mu_cma (float or list of floats, optional) – adaptation step size of the steepest gradient descent method for CMA operation for each dimension. The default is 5e-3.

  • mu_rde (float or list of floats, optional) – adaptation step size of the steepest gradient descent method for RDE operation for each dimension. The default is 5e-3.

  • mu_dde (float or list of floats, optional) – adaptation step size of the steepest gradient descent method for DDE operation for each dimension. The default is 0.5.

  • decimate (bool or list of bools, optional) – output every SAMPLE or every SYMBOL. The default is False.

  • return_info (bool or list of bools, optional) – should the evolution of the impulse response and the error be recorded and returned. The default is True.

  • stop_adapting (int or list of ints, optional) – equaliter adaptation is stopped after stop_adapting SYMBOLS. -1 results in a continous adaptation untill the last symbol of the input signal. The default is -1.

  • start_rde (int or list of ints, optional) – defines after how many CMA SYMBOLS the RDE mode is started. start_rde=0 means RDE mode does not start at all. See also examples above. The default is 5000.

  • start_dde (int or list of ints, optional) – defines after how many RDE SYMBOLS the DDE mode is started. start_rde=0 means DDE mode does not start at all. See also examples above. The default is 5000.

  • exec_mode (string) – Controls if Python or os-specific Cython implementation is used. ‘auto’: use Cython module if available, otherwise use Python implementation. ‘python’: force to use Python implementation, even if a Cython module is available. ‘cython’: force to use the Cython module, might cause an error if Cython module is not available. The default is ‘auto’.

Returns:

results

sigskcomm.signal.Signal

equalized output signal.

hlist of np.arrays

each list element consists of either a np.array of shape (n_output_samples, n_taps) in case of return_info==True which documents the evolution of the equalizers impulse response or of an empty np.array in case of return_info==False

epslist of np.arrays

each list element consists of either a np.array of shape (n_output_samples,) in case of return_info==True which documents the evolution of the error signal or of an empty np.array in case of return_info==False.

Return type:

dict containing following keys

References

[1] D. Godard, “Self-recovering equalization and carrier tracking in twodimensional data communication systems,” IEEE Trans. Commun., vol. 28, no. 11, pp. 1867–1875, Nov. 1980.

[2] S. Savory, “Digital Coherent Optical Receivers: Algorithms and Subsystems”, IEEE STQE, vol 16, no. 5, 2010

[3] P. Winzer, A. Gnauck, C. Doerr, M. Magarini, and L. Buhl, “Spectrally efficient long-haul optical networking using 112-Gb/s polarizationmultiplexed16-QAM,” J. Lightw. Technol., vol. 28, no. 4, pp. 547–556, Feb. 15, 2010.

skcomm.rx.calc_eq_frequency_response_zf(H)

Calculate equalizer frequency response.

Calculate the equalizer frequency response from a given / measured channel frequency response using the zero forcing approach. The given channel frequency response needs to be a three dimensional array where the first dimension specifies the receiver dimension (n_rx ), the second dimension specifies the transmitter dimension (n_tx) and the third dimension specifies the frequency index (n).

  • for the SISO case the array H should have the shape (1,1,N), where N is the number of frequency bins of the frequency response. In this case the equalizer frequency response is calculated according to

    \[W = H^*/|H|^2\]

    while \(()^*\) means conjugate complex operation, \(/\) means elementwise division and || means absolute value.

  • for the MIMO case the array H should have the shape (n_rx,n_tx,N), where n_rx and n_tx are the receiver and transmitter dimensions, respectively and N is the number of frequency bins of the frequency response. In this case the equalizer frequency response is calculated according to

    \[W(:,:,n) = (H(:,:,n)^HH(:,:,n))^{-1}H(:,:,n)^H\]

    while \(()^H\) means Hermitian (conjugate and transpose) operation and \(()^{-1}\) means matrix inversion

Therefore, the equalizer frequency response array has a shape of (n_tx,n_rx,N).

Warning

This method assumes an oversampling of 2 of the channel estimation header and will lead to incorrect results in all other cases!

Notes about implementation: Because the function is expecting a signal with 2 samples per symbol, we have to deal with this oversampling also in calculating W. Assuming the SISO-case, we want to calculate \(H^{-1}\), which should produce a white spectrum AFTER downsampling. This means we do not expect a white spectrum before downsampling, but have to keep in mind overlapping spectra after downsampling due to expected roll-off of pulseshaping, which is done by the modulus-related term in the equotation(s).

References

[1] M. Kuschnerov et al., “Data-Aided Versus Blind Single-Carrier Coherent Receivers,” in IEEE Photonics Journal, vol. 2, no. 3, pp. 387-403, June 2010, doi: 10.1109/JPHOT.2010.2048308.

[2] Reinhardt, Steffen “Einträgerübertragung mit Frequenzbereichsentzerrung - Erweiterung für Mehrantennensysteme, Synchronisationskonzepte und experimentelle Verifikation”, PhD thesis, Friedrich-Alexander-Universität Erlangen-Nürnberg (FAU), 2007, https://open.fau.de/handle/openfau/396

Parameters:

H (ndarray[complex128]) – Channel frequency response of shape (n_rx,n_tx,N).

Returns:

Equalizer frequency response of shape (n_tx,n_rx,N).

Return type:

W

skcomm.rx.carrier_phase_estimation_VV(symbols, n_taps=31, filter_shape='wiener', mth_power=4, mag_exp=0, rho=0.1)

Viterbi-Viterbi carrier phase estimation and recovery.

This function estimates the phase noise of the carrier using the Viterbi-Viterbi method [1]. Either a rectangular or a Wiener filter shape can be applied for phase averaging.

Parameters:
  • symbols (1D numpy array, real or complex) – input symbols.

  • n_taps (int, optional) – Number of taps of the averaging filter. Must be an odd number. The default is n_taps = 31.

  • filter_shape (string, optional) – Specifies the averaging filter shape (window function): either ‘rect’, ‘wiener’, ‘hyperbolic’ or ‘lorentz’. The default is filter_shape = ‘wiener’.

  • mth_power (int, optional) – Specifies the power to which the symbols are raised to remove the data modulation (i.e., the number of equidistant modulation phase states). The default is mth_power = 4 (corresponding to QPSK).

  • mag_exp (optional) – Specifies the exponent, to which the symbol magnitudes are raised before averaging the phasors. A value > 0 leads to the preference of the outer symbols in the averaging process, while a value <0 accordingly leads to a preference of inner symbols. For mag_exp = 0, the symbol magnitudes are ignored in the phase estimation process (For more information see [1]). The default value is mag_exp = 0.

  • rho (float, optional, rho>0) – Shape parameter for ‘wiener’, ‘hyperbolic’ and ‘lorentz’ filter. For larger rho, the filter shape becomes narrower. For ‘wiener’ filter shape, rho is the ratio between the magnitude of the frequency noise variance σ²_ϕ and the (normalized) AWGN variance σ²_n’ (for more information see [2],[3]). σ²_ϕ is related to the laser linewidth LW as σ²_ϕ = 2*π*LW/symbol_rate. For ‘hyperbolic’ and ‘lorentz’ filter shape (aka Cauchy or Abel window), 1/rho is the FWHM parameter of the filter shape. The default is rho = 0.1.

Returns:

resultsdict containing following keys
rec_symbols1D numpy array, real or complex

recovered symbols.

phi_est1D numpy array, real

estimated phase noise random walk

cpe_window: 1D numpy array, real

applied CPE slicing-average window ()

References

[1] A. Viterbi, “Nonlinear estimation of PSK-modulated carrier phase with application to burst digital transmission,” in IEEE Transactions on Information Theory, vol. 29, no. 4, pp. 543-551, July 1983, doi: 10.1109/TIT.1983.1056713.

[2] Ezra Ip, Alan Pak Tao Lau, Daniel J. F. Barros, and Joseph M. Kahn, “Coherent detection in optical fiber systems,” Opt. Express 16, 753-791 (2008)

[3] E. Ip and J. M. Kahn, “Feedforward Carrier Recovery for Coherent Optical Communications,” in Journal of Lightwave Technology, vol. 25, no. 9, pp. 2675-2692, Sept. 2007, doi: 10.1109/JLT.2007.902118.

[4] Wolfram Language & System Documentation Center, https://reference.wolfram.com/language/ref/CauchyDistribution.html, https://en.wikipedia.org/wiki/Cauchy_distribution

skcomm.rx.carrier_phase_estimation_bps(samples, constellation, n_taps=15, n_test_phases=15, const_symmetry=1.5707963267948966, interpolate=True, exec_mode='auto')

“Blind phase search” carrier phase estimation and recovery.

This method implements a slight modification of the carrier phase estimation and recovery method proposed in [1].

A block of n_taps samples of the input signal (at 1 sample per symbol) is rotated by n_test_phases individual, equally spaced phases between -const_symmetry/2 and const_symmetry.

The rotation phase producing a smallest squared error between these rotated samples and the decided constellation points of the original constellation is assumed to be the phase error produced by the channel (or laser(s)).

Additional to the decided (ideal) constellation per block (as proposed in [1]), also the unwraped estimated random phase walk is calculated and interpolated. This estimated phase walk is subtracted from the phases of the input samples and therefore used to recover the carrier phase of the signal.

Parameters:
  • samples (1D numpy array, real or complex) – input symbols.

  • constellation (1D numpy array, real or complex) – constellation points of the sent (original) signal.

  • n_taps (int, optional) – numer of samples processed in one block. The default is 15.

  • n_test_phases (int, optional) – number of phases which are tested. Defines the accuracy of the phase estimation method. The default is 15.

  • const_symmetry (float, optional) – symmetry (ambiguity) of the original constellation points. The default is pi/2.

  • exec_mode (string) – Controls if Python or os-specific Cython implementation is used. ‘auto’: use Cython module if available, otherwise use Python implementation. ‘python’: force to use Python implementation, even if a Cython module is available. ‘cython’: force to use the Cython module, might cause an error if Cython module is not available. The default is ‘auto’.

Returns:

resultsdict containing following keys
samples_out1D numpy array, real or complex

decided constellation points of the signal closest to the estimated random phase walk.

samples_corrected1D numpy array, real or complex

input symbols with recovered carrier phase.

est_phase_noise1D numpy array, real

estimated (unwraped) random phase walk.

References

[1] T. Pfau, S. Hoffmann and R. Noe, “Hardware-Efficient Coherent Digital Receiver Concept With Feedforward Carrier Recovery for M -QAM Constellations,” in Journal of Lightwave Technology, vol. 27, no. 8, pp. 989-999, April15, 2009, doi: 10.1109/JLT.2008.2010511.

skcomm.rx.coRx_phase_imbalance_comp(samples, switch_IQ=False, two_theta=None, orthogonalization_method='GSOP')

Phase imbalance compensation for a coherent receiver frontend.

Parameters:
  • samples (1D numpy array, real or complex) – input samples

  • switch_IQ (bool) – flag if I/Q should be switched for GSOP calculation / application of phase and amplitude if specified. Default is False.

  • two_theta (float) – Phase deviation from 90° of the optical hybrid. Angle between I/Q-components is defined as (pi/2 - two_theta) in rad. If two_theta is None, the correction angle is estimated with corr-coef variant. If value is given, this value is used for compensation. Default is None.

  • orthogonalization_method (string) – Orthogonalizsation method used for correction phase deviation of the optical hybrid. Could be “GSOP” for Gram-Schmidt orthogonalization or “Loewdin” for Loewdin-orthogonalization. If a not matching string is passed, no phase deviation is compensated. Default is GSOP.

Returns:

results

samples: 1D numpy array, real or complex

samples with corrected imbalance

two_theta: float

Phase deviation from 90° of the optical hybrid in rad.

ampl_imbalance_dB: float

amplitude imbalance between I and Q components, as defined by 20*np.log10(std(I)/std(Q)) [dB].

Return type:

dict containing following keys

References

[1] I. Fatadin, S. J. Savory, and D. Ives, “Compensation of Quadrature Imbalance in an Optical QPSK Coherent Receiver,” IEEE Photonics Technology Letters, vol. 20, no. 20, pp. 1733-1735, Oct. 2008, doi: 10.1109/lpt.2008.2004630.

[2] S. J. Savory, “Digital Coherent Optical Receivers: Algorithms and Subsystems,” Selected Topics in Quantum Electronics, IEEE Journal of, vol. 16, no. 5, pp. 1164-1179, Sep. 2010.

skcomm.rx.combining(sig, comb_method='EGC', weights=None, combine_upto=None)

Performs Diversity Combining of the rows of a passed n-dimensional signal- class object, where each row represents the signal captured by an antenna of a SIMO system, according to the passed SNR values per dimension if comb_method == MRC. If comb_method == EGC, because of equal gain, there is no need for know SNR of the signals.

Parameters:
  • sig (signal-class object) – n-dimensional signal object with list of sample arrays in the ‘samples’ attribute.

  • comb_method (str, optional) – Combining method. MRC, EGC, and SDC are available. The default is ‘MRC’.

  • weigths (1d numpy array, optional for comb_method == EGC) – array of weigthing values matching the number of signal dimensions of the sig object for combination.

  • combine_upto (int, optional) – Combine just first n sample arrays togheter. If None, all sample arrays are combined. Default is None.

Returns:

sig_comb – one-dimensional signal object after combining. The sample attribute now has the combined sample array in the ‘samples’ attribute of its only dimension.

Return type:

signal object

skcomm.rx.count_errors(bits_tx, bits_rx)

Count bit errors.

Count the bit error rate (BER) by comparing two bit sequences. Additionally also the position of the bit errors is returned as a bool array of size bits_tx.size, where True indicates a bit error.

If the bit sequence bits_rx is longer than the sent sequency, the sent sequence is repeated in order to match both lengths.

Parameters:
  • bits_tx (1D numpy array, bool) – first bits sequence.

  • bits_rx (1D numpy array, bool) – first bits sequence.

Returns:

results

berfloat

bit error rate (BER)

err_idx1D numpy array, bool

array indicating the bit error positions as True.

Return type:

dict containing following keys

skcomm.rx.cycle_slip_correction(coarse_phase_est, fine_phase_est, quantize_value=1.5707963267948966, jump_point_avag=1, debug=False)

Function to compensate for cycle slips based on corase and fine phase estimation. Here, the assumption is that coarse phase est cant have cycle slips. Therefore, the fine phase estimation is limited to +-quantize_value/2. If values bigger than these treshold are visible, these values will be assumed as cycle slip and therefore be corrected.

Parameters:
  • coarse_phase_est (1D numpy array, real) – coarse phase estimation array

  • fine_phase_est (1D numpy array, real) – fine phase estimation array

  • quantiue_value (float) – value for detecting cycle slip. +-quantize_value/2 is cycle slip treshold. Default is pi/2.

  • jump_point_avag (int) – avaraging of cycle slip offset array. Used to pretend from hard jumps in array. Default is 1.

  • debug (bool) – debug flag. If True, plots are generated. Default: False.

Returns:

fine_phase_est_corrected – corrected fine phase estimation.

Return type:

1D numpy array, real

References

None

skcomm.rx.da_cfo_estimation(samples, shift=64, sample_rate=1.0)

Estimate carrier frequency offset.

Estimate the amount of (residual) carrier frequency offset (CFO) of the received signal samples by using a known training sequences as suggested in [1]. The training sequence is a random sequence (denoted as ‘B’) which is repeated four times, while the third repetition is negated (‘[B,B,-B,B]’).

References

[1] Shi et al. “Coarse Frame and Carrier Synchronization of OFDM Systems: A New Metric and Comparison”, IEEE Transactions on wirless communiations vol 3, no. 4 2004

Parameters:
  • samples (ndarray[complex128]) – samples of the received signal.

  • shift (int) – length of the individual random sequence which was reapeted four times (i.e. length of ‘B’) including oversampling, i.e. repetition period (in samples) of the sequence.

  • sample_rate (float) – sample rate of the received sampled signal.

Return type:

float

Returns:

Estimated CFO in Hertz.

skcomm.rx.da_channel_estimation(ce_header_rx_spec, pilots, pilot_pos, n_fft)

Estimate channel frequency resoponse.

This method estimates the frequency response of the channel by comparing (dividing) the spectrum of known OFDM pilots within received and sent channel estimation header sequences generated by the transmitter method skcomm.tx.insert_ch_est_seq().

Warning

This method assumes an oversampling of 2 of the channel estimation header and will lead to incorrect results in all other cases!

Parameters:
  • ce_header_rx_spec (ndarray[complex128]) – Spectrum of the received channnel estimation header sequence. The number of frequency bins (length of ce_header_rx_spec) needs to be `n_fft`*2.

  • pilots (ndarray[complex128]) – Array of the actual sent OFDM pilot symbols (as inserted into the signal by method skcomm.tx.insert_ch_est_seq()).

  • pilot_pos (ndarray[int64]) – Array of the indices of the frequency bins of the sent OFDM pilot symbols (as inserted into the signal by method skcomm.tx.insert_ch_est_seq()).

  • n_fft (int) – Size of the FFT used for generating the channel estimation header (as inserted into the signal by method skcomm.tx.insert_ch_est_seq()).

Return type:

ndarray[complex128]

Returns:

Estimated frequency response.

skcomm.rx.da_equalizer(sig_tx, sig_rx, cfo_comp=False, decimate=False, dbg_plt=False, dbg_frame=-1, dbg_dim=-1)

Data-aided equalizer.

Equalize a signal by using given known training sequences. This method bundles multiple data-aided receiver function as a wrapper and iterates over N frames, each consisting of

The steps performed within this function are:

Warning

This method assumes an oversampling of 2 of the channel estimation header and will lead to incorrect results in all other cases!

Parameters:
  • sig_tx (skc.signal.Signal) – Sent signal.

  • sig_rx (skc.signal.Signal) – Received signal.

  • cfo_comp (bool) – Carrier frequency offset estimation and correction active? For details see skcomm.rx.da_cfo_estimation()

  • decimate (bool) – Decimation (downsampling) to one sample per symbol after equalization?

  • dbg_plt (bool) – Show debug plots?

  • dbg_frame (int) – Which frame should be shown in debug plots? Only usable in case of `dbg_plt`=True.

  • dbg_dim (int) – Which rx_dimension should be shown in debug plots? Only usable in case of `dbg_plt`=True. A value of -1 shows the last receiver dimension.

Return type:

dict

Returns:

results with following keys

  • ’sig_rx’skc.signal.Signal

    Equalized (and decimated) signal.

  • ’W_out’list of np.ndarray[np.complex128 | np.float64]

    Equalizer frequency respnses for each individual processed frame. List of length n_frames, each element containing a three dimensional ndarray of shape (# Tx dims,# Rx dims,# frequency bins) representing the (MIMO) equalizer frequency responses.

  • ’H_out’list of np.ndarray[np.complex128 | np.float64]

    Estimated channel frequency respnses for each individual processed frame. List of length n_frames, each element containing a three dimensional ndarray of shape (# Rx dims,# Tx dims,# frequency bins) representing the (MIMO) frequency responses.

  • ’CFO_out’list of np.float64

    Estimated carrier frequency offsets (coarse+fine) for each individual processed frame. List of length n_frames.

  • ’snr_dB_out’list of np.float64

    Estimated SNR in dB for each individual processed frame. List of length n_frames.

skcomm.rx.da_frame_sync(samples, shift=64, search_range=1000, dbg_plot=False, fNum=1, exec_mode='auto')

Perform temporal synchronization to a reference frame.

Perform temporal synchronization of the received signal samples to a known training sequence as suggested in [1]. The training sequence is a random sequence (denoted as ‘B’) which is repeated four times, while the third repetition is negated (‘[B,B,-B,B]’).

References

[1] Shi et al. “Coarse Frame and Carrier Synchronization of OFDM Systems: A New Metric and Comparison”, IEEE Transactions on wirless communiations vol 3, no. 4 2004)

Parameters:
  • samples (ndarray[complex128 | float64]) – samples of the received signal.

  • shift (int) – length of the repeated random sequence (length of ‘B’) including oversampling, i.e. repetition period (in samples) of the sequence.

  • search_range (int) – specifies the range in samples whithin the signal is searched for the frame sync header. Can be shortened to save processing time.

  • dbg_plot (bool) – Should a plot of the calculated frame sync metric be generated? Helpful for debugging purpose.

  • fNum (int) – Figure number of the debut plot graph.

  • exec_mode (str) – Controls if Python or os-specific Cython implementation is used. ‘auto’: use Cython module if available, otherwise use Python implementation. ‘python’: force to use Python implementation, even if a Cython module is available. ‘cython’: force to use the Cython module, might cause an error if Cython module is not available. The default is ‘auto’.

Return type:

int64

Returns:

Estimated shift (in samples) which has to be applied to the received signal to be temporally synchronized to the frame synchronization sequence.

skcomm.rx.da_snr_estimation(ce_header_rx, pilot_pos, n_fft, n_repeat, pilot_neighbors=3, windowed=False, bw_limit=0.5, dbg_plot=False, fNum=None)

Estimates the SNR of a received signal using repeated OFDM pilot symbols in the channel estimation headers.

The signal-to-noise ratio (SNR) of the received signal is measured using known OFDM channel estimation (ce) header sequences ce_header_rx, that are available in all signal dimensions. It is assumed that such sequences were inserted into all transmit signal dimensions with the method skcomm.tx.insert_ch_est_seq().

The method utilizes the property that, when an OFDM symbol is repeated n_repeat times in time domain, it results in a discrete spectrum in frequency domain with a n_repeat times higher frequency resolution and with spectral gaps of width (n_repeat-1) between the ‘original’ OFDM pilot tones. These gaps are used here for an in-band estimation of the noise power, as they are filled (mainly) by additive channel noise.

The signal+noise power (p_sig_and_n) is estimated by adding over all frequency bins in the squared-magnitude spectrum of ce_header_rx that are attributed to OFDM pilots as given in the list pilot_pos, which was defined for the ce-header generation function skcomm.tx.insert_ch_est_seq(). Also, the frequency images of the OFDM pilots, that arise from the assumed 2-times oversampling, are included in the measurement of p_sig_and_n. In addition, symmetrically around each of these pilot positions, \(\pm\) pilot_neighbors frequency bins can be included in order to increase the robustness against carrier-frequency offset (CFO). Alternatively to using pilot_neighbors, a time-domain windowing (Blackmann-Harris) can be applied to the ce_header_rx to increase the CFO robustness.

The noise power spectral density (PSD) p_n_per_bin (noise power per frequency bin) is estimated by averaging the power over all frequency bins in the squared-magnitude spectrum of ce_header_rx that are not attributed for the estimation of p_sig_and_n and at least `pilot_neighbors`+1 bins away from pilot-tone bin positions.

Finally, the SNR per symbol (in dB) is calculated as \(\mathrm{SNR} = 10\cdot\mathrm{log}_{10}(P_{sig}/P_{noise})\), where \(P_{sig}\) is the signal+noise power corrected for the noise power within the frequency range used for measuring p_sig_and_n, and \(P_{noise}\) is the noise PSD p_n_per_bin accumulated over a bandwidth that equals the symbolrate (= 0.5 * samplerate).

Warning

This method strictly assumes a samplerate of 2 samples/symbol for the channel estimation header and will lead to incorrect results if otherwise!

Parameters:
  • ce_header_rx (ndarray[complex128]) – The received channel estimation (ce) header (incl. 2-times oversampling) as generated in the transmitter by the method skcomm.tx.insert_ch_est_seq().

  • pilot_pos (ndarray[int]) – Indices of frequency bins containing OFDM pilot tones (as inserted into the transmit signal by the method skcomm.tx.insert_ch_est_seq()).

  • n_fft (int) – Size of the FFT used for generating the ce-header (as inserted into the signal by the method skcomm.tx.insert_ch_est_seq().

  • n_repeat (int) – Number of repetitions of the OFDM pilot symbol in the applied ce_header_rx. If OFDM guard intervals were eventually removed in the reciver, this number can be smaller than the number of repetitions originally used in the method skcomm.tx.insert_ch_est_seq() at the transmitter.

  • pilot_neighbors (int) – Number of frequency bins on each side of OFDM pilots which are included in the signal-power measurement and excluded from the noise-power measurement. By adding the OFDM-pilot power across multiple frequency bins, the robustness against carrier frequency offset (CFO) can be increased. The default is pilot_neighbors=3.

  • windowed (bool) – If set to True, a Blackmann-Harris window is applied to the ce_header_rx in time-domain before calculating its FFT. This method can be used alternatively to pilot_neighbors to improve CFO robustness.

  • bw_limit (float) – A single-sided bandwidth limit (normalized to the samplerate) that is applied to the signal and noise bins in order to limit the SNR estimation to a frequency range occupied by the signal. The parameter ranges from bw_limit=0.25 to bw_limit=0.5 (default), where 0.5 corresponds to the frequency range -symbolratesymbolrate.

  • dbg_plot (bool) – If set to True, the FFT of the channel estimation header and the markers for power and noise measurements are plotted.

  • fNum (int | None) – Figure number for the debug plot window. The default is None, which uses the “next unused figure number”.

Return type:

dict

Returns:

dictionary with following keys

  • ’p_sig’np.ndarray[np.complex128 | np.float64]

    Estimated signal power (linear units).

  • ’p_n’np.ndarray[np.complex128 | np.float64]

    Estimated noise power within the symbolrate (linear units).

  • ’snr_dB’float

    Estimated SNR per symbol in dB.

skcomm.rx.dc_block_and_unit_variance_norm(samples)

Function to cover DC block and normalization to unit variance. Operation is performed on I and Q individual.

Implementation: \(r' = \frac{r - \mu}{\sqrt{2} \cdot \sigma}\)

where \(\mu\) is the mean and \(\sigma\) is the standard deviation of the respective component.

Parameters:

samples (1D numpy array, complex) – input signal

Returns:

samples – processed signal

Return type:

1D numpy array, complex

skcomm.rx.decision(samples, constellation, norm=True)

Decide samples to a given constellation alphabet.

Find for every sample the closest constellation point in a constellations array and return this value.

Parameters:
  • samples (1D numpy array, real or complex) – sampled input signal.

  • constellation (1D numpy array, real or complex) – possible constellation points of the input signal.

  • norm (bool) – should the samples be normalized (to mean maginitude of constellation) before decision?

Returns:

dec_symbols – clostest constellation point for every input sample.

Return type:

1D numpy array, real or complex

skcomm.rx.demapper(samples, constellation)

Demap samples to bits using a given constellation alphabet.

samples are compared to a given constellation alphabet and the index of the corresponding constellation (integer) is converted to the corresponding bit value.

The resulting bit sequence is therefore of length: np.log2(constellation.size)*samples.size.

Parameters:
  • samples (1D numpy array, real or complex) – sampled input signal.

  • constellation (1D numpy array, real or complex) – possible constellation points of the input signal.

Returns:

bits – converted bit sequence.

Return type:

1D numpy array, bool

skcomm.rx.deskew(samples_1, samples_2, sample_rate=1.0, symbol_rate=2.0, cm_delay=0.0, compensate=True)

Finds the skew between two signals (and compensates for it).

The delay (sampling phase offset) to the ideal sampling instant within the range of [0, 1/symbol_rate] is found for each of the signals. For more information see skcomm.rx.sampling_phase_adjustment().

The found delay can be compensated for for each signal individually, and therefore performing a deskewing.

Parameters:
  • samples_1 (ndarray[complex128 | float64]) – input signal 1.

  • samples_2 (ndarray[complex128 | float64]) – input signal 2.

  • sample_rate (float) – sample rate of input signals in Hz.

  • symbol_rate (float) – symbol rate of input signals in Hz.

  • cm_delay (float) – common delay in seconds to apply on both signals after skew compensation.

  • compensate (bool) – should skew compensation and cm_delay be applied?

Return type:

dict

Returns:

  • results with following keys

    • ‘samples_out_1’np.ndarray[np.complex128 | np.float64]

      output signal 1, if parameter compensate==False, the output signal 1 is equal to the input singal 1.

    • ’samples_out_2’np.ndarray[np.complex128 | np.float64]

      output signal 2, if parameter compensate==False, the output signal 2 is equal to the input singal 2.

    • ’est_shift_1’float

      estimated (and inversely applied) temporal shift in seconds for signal 1.

    • ’est_shift_2’float

      estimated (and inversely applied) temporal shift in seconds for signal 2.

skcomm.rx.frequency_offset_correction(samples, sample_rate=1.0, symbol_rate=1.0, matched_filter=None, roll_off=None, max_FO_expected=None, debug=False)

Frequency offset estimation and correction (FOE and FOC).

This function estimates the carrier frequency offset by using a spectral method described in [1]. The spectral method is performed on symbols, therefore a decimation is applied in case of oversampling.

If specified, the incoming samples are filtered with a matched filter before they are raised to the power of 4. FFT is formed afterwards. If specified, the search range for the frequency offset is is limited to +-max_FO_expected.

For a more accurate estimation, a 2nd order polynomial is fitted to the spectrum before the maximum is determined. The correction is done by multiplying the samples with a complex exponential having a frequency with same amplitude as the estimated frequency offset, but opposite sign.

Please note that only singals with an integer oversampling factor can currently be handled.

Parameters:
  • samples (1D numpy array, real or complex) – input signal. It is assumed that the first sample is taken at the correct (temporal) sampling instant, theefore no timing recovery needs to be performed.

  • sample_rate (float) – sample rate of input signal in Hz. The default is 1.0.

  • symbol_rate (float) – symbol rate of input signal in Hz. The default is 1.0.

  • matched_filter (string) – if not None, matched filter specified by string is applied. Currently only a ‘root raised cosine’ filter (‘rrc’) is implemented. Default is None.

  • roll_off (float) – roll off of the (matched) root raised cosine filter. Default is None.

  • max_FO_expected (float) – if not None, search range of the frequency offset. The frequency offset is expected to be in the range of +- max_FO_expected. Default is None.

  • debug (bool) – Debug flag for generating debug plots. Default is False.

Returns:

results

samples_corrected: 1D numpy array, real or complex

output signal, which is input signal multiplyied with a complex exponential having a frequency with same amplitude as the estimated frequency offset, but opposite sign.

estimated_fo: 1D numpy array, real or complex.

Estimated frequency offset in Hz.

Return type:

dict containing following keys

References

[1] Savory, S. (2010, September/Oktober). Digital Coherent Optical Receivers:

Algorithms and Subsystems. Abgerufen von https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=5464309

[2] Dr. Lichtmann, M.. (o.J.). PySDR: A Guide to SDR and SDP using Python.

Abgerufen von https://pysdr.org/content/frequency_domain.html

skcomm.rx.pilot_aided_coarse_cpe(samples, pilot_symbols, M=100, N=1, debug=True)

Pilot-aided coarse carrier-phase-estimation (and correction). Used as a first stage of a two stage CPE procedure. With the help of the pilot sequence, absolute phase difference is calculated. With the help of a triangle-shaped filter (which is suboptimal, but not wrong in total as seen in reference), a interpolation to symbol rate is performed. Therefore phase offset is corrected. NOTE: Please be aware of boundary effects of filter interpolation in corrected samples. Use filter len to crop if needed.

Parameters:
  • samples (1D numpy array, complex) – input signal on symbol frequency (= 1sps)

  • pilot_symbols (1D numpy array, complex) – zeropadded pilot symbols (= 1sps). Should have the appereance of [pilot1, 0+0j, 0+0j, …, pilot2, …]

  • M (int) – pilot spacing in samples between to pilots. Default is 100 (corresponds to 1% pilot rate).

  • N (int) – avaraging factor N, which makes the filter more width to handle lower SNR. Default is 1.

  • debug (bool) – Debug flag. If true, some plots are generated. Default is True.

Returns:

cpe_results

samples_corrected1D numpy array, real or complex

input symbols with recovered coarse carrier phase.

est_phase_noise_coarse1D numpy array, real

estimated coarse random phase walk.

fitler_lenint

filter width. In this range (from start and from end) of corrected samples, boundary effects form interpolation may be visible. Use filter width for cropping if needed.

Return type:

dict containing following keys

References

[1] M. Magarini et al., “Pilot-Symbols-Aided Carrier-Phase Recovery for 100-G PM-QPSK Digital Coherent Receivers,” IEEE Photonics Technology Letters, vol. 24, Art. no. 9, May 2012, doi: 10.1109/lpt.2012.2187439.

skcomm.rx.pilot_based_cpe_wrapper(sig_rx, pilot_average=5, tap_len=31, test_phases=31, remove_filter_effects=True, debug=True, fNum=None)

Wrapper function to process three-staged CPE. The following process will be done: 1. a pilot-based CPE as coarse first stage, based on pilot symbols. With an interpolation filter, based on the difference between noisy received samples and know pilot symbols, a coarse phase offset will be estimated and interpolated on all samples. 2. BPS as fine second stage. Since pilot-based CPE is to slow to catch all phase noise effects, we use the BPS as fast second stage fine estimation 3. cycle slip correction as last stage. Due to the possibility of cycle slips in BPS, we correct for cycle slips by assuming pilot-based CPE is immune to cylce slips. If BPS produces phase jumps higher than e.g. pi/2, we assume a cycle slip here and correct for by put offset of e.g. -pi/2.

NOTE: The function assumes that pilots in sig_rx object and samples in sig_rx object are in sync and samples with 1 symbol per sample.

NOTE: Function can be applied to single or multiple frame receiver. Function will calculate amount of frames by checkign samples vs symbols.

Parameters:
  • sig_rx (signal-class object) – n-dimensional signal object with list of sample arrays in the ‘samples’ attribute.

  • pilot_average (int) – average parameter to average for Noise in interpolation filter of coarse cpe. Please see related function for further details. Default is 5.

  • tap_len (int) – number of taps for BPS. Please NOTE: in case of frame-structured receiver, tap_len is used to choose a close tap_len which is a full divisior of the payload. Default is 31.

  • test_phases (int) – number of testphase for BPS. Default is 31.

  • remove_filter_effects (bool) – If True, filter effects from coarse CPE will we cropped on both sides of the sample array. This leads to crop frame-whise in the front if frame-structured receiver is applied, to keep synchronisation. Default is True.

  • debug (bool) – debug flag, using plots. Default is True.

  • fNum (int) – number of figure to be generated if Debug is True. Default is None.

Returns:

  • sig_rx (signal-class object) – processed signal object, samples with estimated and compensated carrier phase noise

  • cpe_results_dict (dict containing following keys) –

    dimint, nested dict containing following keys per dimension
    est_phase_noise_coarsearray

    course random phase walk estimated by the first stage (pilot-based) in rad

    est_phase_noise_fine_before_cs_correctionarray

    fine random phase walk estimated by the second stage (BPS) in rad

    est_phase_noise_fine_after_cs_correctionarray

    fine random phase walk estimated by the second stage (BPS) in rad, with cycle slips corrected

skcomm.rx.sampling_clock_adjustment(samples, sample_rate=1.0, symbol_rate=2.0, block_size=500)

Estimate sampling frequency offset and correct for it.

This function estimates the sampling frequency offset between nominal (given) and actual (sample rate of samples) sampling frequency and corrects for the found value. This is done by splitting the singal into blocks of block_size SYMBOLS and estimating the sampling time offset for each of the blocks (see skcomm.rx.sampling_phase_adjustment). Then, the sampling time offest is corrected for by cyclic time shift of the individual blocks. Longer block sizes enhance the accuracy of the time offset estimatin, but cause the sampling clock offset to be larger within one block. CAUTION: method will fail for large sampling clock (frequency) offsets and if the sampling frequency offset leads to a timing error larger than +- 1/symbol_rate over the whole samples.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • sample_rate (float, optional) – sample rate of input signal in Hz. The default is 1.0.

  • symbol_rate (float, optional) – symbol rate of input signal in Hz. The default is 2.0.

  • block_size (int, optional) – signal is split into blocks of block_size SYMBOLS. The default is 500.

Returns:

results

samples_out1D numpy array, real or complex

output signal.

est_shiftfloat or 1D numpy array of floats

estimated (and inversely applied) temporal shift per block.

Return type:

dict containing following keys

skcomm.rx.sampling_phase_adjustment(samples, sample_rate=1.0, symbol_rate=2.0, shift_dir='both', delay=0.0, compensate=True)

Estimate the sampling phase offset and compensate for it.

The sampling phase offset is estimated by finding the phase of the oszillation with the frequency of the symbol rate in the signal abs(samples)**2. This offset is compensated for by a temporal cyclic shift of the input signal.

To contain this frequency component, the signal has to be sampled at least with a rate of three times the symbol rate. If the input signal is sampled with lower frequency, the signal is temporally upsampled.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • sample_rate (float, optional) – sample rate of input signal in Hz. The default is 1.0.

  • symbol_rate (float, optional) – symbol rate of input signal in Hz. The default is 2.0.

  • shift_dir (string, optional) – defines the bahaviour of the compensation of the found temporal shift. Can be either ‘delay’, ‘advance’ or ‘both’. ‘delay’ / ‘advance’ will only compensate for the time shift by exclusively shifting the signal to the right / left. This means that the time shift can be in the range between [-1/symbol_rate, 0] or [0, 1/symbol_rate], respectively. The option ‘both’ will shift the signal either to the left or to the right, depending on the minimum amount of time shift. The time shift will therefore be in the range between [-0.5/symbol_rate, 0.5/symbol_rate].

  • delay (float, optional) – additional delay in seconds to apply on the signal after timing compensation. The dafault value is 0.0

  • compensate (bool, optional) – should the sampling skew compensation and additional delay be applied? The default is True.

Returns:

results

samples_out1D numpy array, real or complex

cyclic shifted output signal.

est_shiftfloat

estimated (and inversely applied) temporal shift.

Return type:

dict containing following keys

skcomm.rx.stokesEQ_pdm(samples_X, samples_Y)

Performs blind polarization demultiplexing of polarization-multiplexd complex-modulated signals. The method is based on finding (in Stokes space) a symmetry plane of the incoming sampled data (including symbol transitions) from a SVD-based least squares fit [1/sect.3.2]. The normal vector of the plane identifies the two orthogonal input polarization states and is used to determine the desired polarization-rotation of the input signal.The method does not involve data demodulation and thus should work independent of the modulation format.

Parameters:
  • samples_X (ndarray) – Input signal samples in X-polarization. Must be of same size as ‘samples_Y’

  • samples_Y (ndarray) – Input signal samples in Y-polarization. Must be of same size as ‘samples_X’

Return type:

dict

Returns:

  • results containing the following keys

    • samples_Xnp.ndarray[np.complex128 | np.float64]

      Output signal samples after polarization separation in X-polarization.

    • samples_Ynp.ndarray[np.complex128 | np.float64]

      Output signal samples after polarization separation in Y-polarization.

    • Unp.ndarray[np.complex128 | np.float64]

      \(2\times2\) Jones (rotation) matrix \(\mathbf{U}\), which was applied to the input signal.

    • Nvnp.ndarray[np.float64]

      \(3\times1\) normal vector of the fitting plane in Stokes space (w/o centroid).

    • Cnp.ndarray[np.float64]

      Centroid (\(3\times1\) average Stokes vector) of all Stokes space samples.

References

skcomm.rx.symbol_sequence_sync(sig, dimension=-1)

Estimate and compensate delay and phase shift between reference symbol / bit sequence and physical samples.

The sig.samples have to be sampled at a rate of one sample per symbol.

A complex correlation between sig.samples and sig.symbols is performed in order to find the delay and the phase shift between both signals.

Further also a complex correlation between conj(sig.samples) and sig.symbols is performed in order to detect a flip (inversion) of the imaginary part.

The found dalay is compensated for by cyclic shift (roll) of the reference symbol and bit sequence (sig.symobls and sig.bits, respectively) while the ambiguity (phase shift and flip of imaginary part) is compensated for by manipulating the physical samples (sig.samples).

This operation can be performed to one specific dimension of the signal or to all dimensions of the signal independently.

Parameters:
  • sig (skcomm.signal.Signal) – signal containing the sequences to be synced.

  • dimension (int) – dimension of the signal to operate on. If -1 the synchronization is performed to all dimensions of the signal. The default is -1.

Returns:

return_dict

number of dimension of signaldict containing following keys
phase_estfloat

estimated phase offset of specified signal dimension

symbol_delay_estint

estimated symbol offset of specified signal dimension

sigsskcomm.signal.Signal

signal containing the synced sequences (all signal dimensions)

Return type:

dict containing following keys

Signal Submodule (skcomm.signal)

This submodule includes the basic Signal class.

Signal.n_dims

number of dimensions included in the the signal class

Signal.samples

sampled signal, each list element contains samples of the corresponding signal dimension

Signal.center_frequency

center frequency, each list element contains the frequency of the corresponding signal dimension

Signal.sample_rate

sample rate, each list element contains the sample rate of the corresponding signal dimension

Signal.bits

logical binary information represented by the signal, each list element contains logical information of the corresponding signal dimension

Signal.symbols

symbols representing the binary information, each list element contains the symbols of the corresponding signal dimension

Signal.symbol_rate

symbol rate, each list element contains the symbol rate of the corresponding signal dimension

Signal.modulation_info

string describing the modulation format, each list element contains the description of the corresponding signal dimension

Signal.constellation

symbol alphabet used to represent the binary information, each list element contains the constellation of the corresponding signal dimension

Signal.add_dimension(sig[, dim])

Adds a one-dimensional signal to the signal space of the existing signal object.

Signal.copy()

Return a copy of the signal object.

Signal.decision()

Decide samples to a given constellation alphabet.

Signal.demapper()

Demap samples to bits using a given constellation alphabet.

Signal.generate_bits([n_bits, type, seed])

Generate an array of shape (n_bits,) binary values.

Signal.generate_constellation([format, order])

Set sig.constellation and sig.modulation_info.

Signal.get_dimensions([dims])

Gets all attributes from specific signal dimensions.

Signal.mapper()

Generate sig.symbols from sig.bits and sig.constellation.

Signal.plot_constellation([dimension, ...])

Plot constellation of signal samples of a given dimension.

Signal.plot_eye([dimension, boundaries])

Plot eye diagramm of signal samples of a given dimension.

Signal.plot_signal([dimension, boundaries])

Plot the signal samples of a given dimension as a function of time.

Signal.plot_spectrum([dimension])

Plot spectum of the signal samples of a given dimension.

Signal.pulseshaper([upsampling, pulseshape, ...])

Upsample and pulseshape the modulated symbols and write them to samples.

Signal.raised_cosine_filter([roll_off, ...])

Filter samples with a raised cosine filter.

Signal.sampling_clock_adjustment([block_size])

Estimate the sampling clock offset and compensate for it.

Signal.sampling_phase_adjustment()

Estimate the sampling phase offset and compensate for it.

Signal.set_dimensions(sig[, dims])

Sets / replaces dimensions of signal object by dimensions of other signal object.

Signal.set_snr([snr_dB, seed])

Set the SNR of the signal.

class skcomm.signal.Signal(n_dims=1)

Overall Signal definition.

samples: list of ndarrays, list of length n_dims, each element containing a complex ndarray of size (nsamples,) representing the complex samples of the signal

center_frequency: list of scalars of length n_dims, float, [Hz]

sample_rate: list of scalars of length n_dims, float, [Hz], positive

bits: list of ndarrays, list of length n_dims, each element containing an ndarray of size (nbits,) representing the logical binary information per complex signal dimension

symbols: list of ndarrays, complex, list of length n_dims, each element containing an ndarray of size (nsymbols,) representing the complex modulation symbols per complex signal dimension

symbol_rate: list of scalars of length n_dims, float, [Hz], positive

modulation_info: list of stings, list of length n_dims, each element containing a descriptive name of the used constellation per complex signal dimension

constellation: list of ndarrays, list of length n_dims, each element containing a complex ndarray of size (nConstellationPoints,) representing representing the complex modulation symbols, while the order specifies the mapping between bits and modulation symbols (see skcomm.tx.mapper() for details)

info: list of dicts, list of length n_dims, each element containing a dict, which can be used to store arbitrary information for each complex signal dimension.

add_dimension(sig, dim=0)

Adds a one-dimensional signal to the signal space of the existing signal object.

The content of a 1-D signal object is inserted into the existing signal ‘self’, increasing the dimensionality of the existing signal object by 1. The dimensional position before which the additional 1-D signal is inserted can be defined using the parameter dim.

Example: signal.add_dimension(sig_1D, dim=3) inserts the one-dimensional signal object sig_1D before the third signal dimension of the existing (parent) signal object.

Parameters:
  • sig (skc.signal.Signal) – One dimensional signal object which will be inserted as a new dimension into the existing signal object.

  • dim (int) – Specifies the position at which the additional signal dimension is to be inserted. dim is the dimensional index of the existing signal to be inserted before. dim=0 inserts the new signal dimension as first dimension while dim≥self.n_dims appends the new signal dimension to the existing signal space. The default value is 0.

property bits

logical binary information represented by the signal, each list element contains logical information of the corresponding signal dimension

property center_frequency

center frequency, each list element contains the frequency of the corresponding signal dimension

property constellation

symbol alphabet used to represent the binary information, each list element contains the constellation of the corresponding signal dimension

copy()

Return a copy of the signal object.

Returns:

sig – Copy of the signal object.

Return type:

skc.signal.Signal

decision()

Decide samples to a given constellation alphabet.

For detailed documentation see skcomm.rx.decision().

demapper()

Demap samples to bits using a given constellation alphabet.

For detailed documentation see skcomm.rx.demapper().

generate_bits(n_bits=32768, type='random', seed=None)

Generate an array of shape (n_bits,) binary values.

For detailed documentation see skcomm.tx.generate_bits().

generate_constellation(format='QAM', order=4)

Set sig.constellation and sig.modulation_info.

For detailed documentation see skcomm.utils.generate_constellation().

get_dimensions(dims=[0])

Gets all attributes from specific signal dimensions.

This method returns a new skcomm.signal.Signal object containing all attributes of the signal dimensions specified by dims.

This method could also be used to reorder, duplicate and extend the dimensions of the signal object.

Examples: 1) signal.get_dimensions(dims=[0,0]) returns a two-dimensional (2-D) signal object containing two identical (duplicated) parent signal dimensions.

2) signal.get_dimensions(dims=[1,0]) returns a 2-D Signal object with re-ordered dimensions of the parent signal object.

3) signal.get_dimensions(dims=[1,2,0,1]) returns a 4-D Signal object with re-ordered and (eventually) extended dimensions of the parent signal object.

Parameters:

dims (list of int) – Specifies which signal dimensions should be returned. The defauls is [0]

Returns:

sig – Signal containing all attributes of specified signal dimensions.

Return type:

skcomm.signal.Signal

property info

information about the signal to store (e.g. used for potential data-aided header structures)

mapper()

Generate sig.symbols from sig.bits and sig.constellation.

For detailed documentation see skcomm.tx.mapper().

property modulation_info

string describing the modulation format, each list element contains the description of the corresponding signal dimension

property n_dims

number of dimensions included in the the signal class

plot_constellation(dimension=0, decimation=1, **kwargs)

Plot constellation of signal samples of a given dimension.

For further documentation see skcomm.visualizer.plot_constellation().

plot_eye(dimension=0, boundaries=[None, None], **kwargs)

Plot eye diagramm of signal samples of a given dimension.

For further documentation see skcomm.visualizer.plot_eye().

plot_signal(dimension=0, boundaries=[None, None], **kwargs)

Plot the signal samples of a given dimension as a function of time.

For further documentation see skcomm.visualizer.plot_signal()

plot_spectrum(dimension=0, **kwargs)

Plot spectum of the signal samples of a given dimension.

For further documentation see skcomm.visualizer.plot_spectrum().

pulseshaper(upsampling=2.0, pulseshape='rc', roll_off=0.2)

Upsample and pulseshape the modulated symbols and write them to samples.

For detailed documentation see skcomm.tx.pulseshaper().

raised_cosine_filter(roll_off=0.0, root_raised=False, **kargs)

Filter samples with a raised cosine filter.

For detailed documentation see skcomm.filters.raised_cosine_filter().

property sample_rate

sample rate, each list element contains the sample rate of the corresponding signal dimension

property samples

sampled signal, each list element contains samples of the corresponding signal dimension

sampling_clock_adjustment(block_size=500)

Estimate the sampling clock offset and compensate for it.

For detailed documentation see skcomm.rx.sampling_clock_adjustment().

sampling_phase_adjustment()

Estimate the sampling phase offset and compensate for it.

For detailed documentation see skcomm.rx.sampling_phase_adjustment().

set_dimensions(sig, dims=[0])

Sets / replaces dimensions of signal object by dimensions of other signal object.

The signal dimensions of signal object ‘sig’ replace the specified dimensions of the existing signal object ‘self’. The positions that are to be replaced in ‘self’ are specified by the parameter dim.

Example: signal.set_dimensions(sig_3D, dims=[1,0]) replaces the second dimension of ‘self’ with the first dimension of the new signal object sig_3D and the first dimension of ‘self’ the second dimension of sig_3D.

Parameters:
  • sig (skc.signal.Signal) – Signal object containing the dimensions which will replace signal dimensions in the original signal object ‘self’.

  • dims (list of int) – Specifies the dimensional position indices in ‘self’ at which the signal dimensions of ‘sig’ are inserted one after the other, so e.g., dims=[self.n_dims,0] replaces the last and the first dimension of the original signal object with the first and second dimension of the signal object ‘sig’, respectively. The defauls is [0].

set_snr(snr_dB=10, seed=None)

Set the SNR of the signal. :no-index: For detailed documentation see skcomm.channel.set_snr().

property symbol_rate

symbol rate, each list element contains the symbol rate of the corresponding signal dimension

property symbols

symbols representing the binary information, each list element contains the symbols of the corresponding signal dimension

Transmitter Submodule (skcomm.tx)

This submodule includes transmitter routines.

generate_bits([n_bits, type, seed])

Generate an array of size (n_bits,) binary values.

mapper(bits, constellation)

Map bits to a given constellation alphabet.

pulseshaper(samples[, upsampling, ...])

Upsample and pulseshape a given sample sequence.

insert_frame_sync_seq(sig[, dim, n_symb, ...])

Insert a frame sync header into the signal sig.

insert_ch_est_seq(sig[, dim, offset, n_fft, ...])

Insert a channel estimation header into the signal sig.

insert_cpe_pilots(sig[, dim, offset, ...])

Periodically insert pilot symbols for data-aided carrier phase estimation.

skcomm.tx.generate_bits(n_bits=32768, type='random', seed=None)

Generate an array of size (n_bits,) binary values.

Parameters:
  • n_bits (int, optional) – Number of bits to be generated. The default is 2**15.

  • type (string, optional) – How should the bits be generated. ‘random’ generates n_bits unifomly distributed bits. The default is ‘random’.

  • seed (int, optional) – Seed of the random number generator. The default is None.

Returns:

bits – np.ndarray of shape (n_bits,) containing bools.

Return type:

1D numpy array, bool

skcomm.tx.insert_ch_est_seq(sig, dim=0, offset=0, n_fft=256, n_pilots=64, pilot_offset=0, n_repetitions=16, mean_power=1.0, seed=11)

Insert a channel estimation header into the signal sig.

The signal sig has to be sampled with a sample rate of 1 sample per symbol to insert the frame sync header.

An OFDM symbol consisting of n_fft samples (frequency bins), which is repeated n_repetitions times for noise averaging, is used as a channel estimation header sequence. Out of the n_fft frequency bins, n_pilots evenly spaced bins are filled with random QPSK modulation symbols, while the other frequency bins are set to zero (and could therefore be used for channel estimation from other MIMO channels). The random number seed of the random number generator to generate the QPSK symbols can be specified by seed.

The location of the n_pilots QPSK modulated frequency bins can be specified with pilot_offset: The first pilot starts at frequency bin pilot_offset and the pilots are inserted equally spaced n_fft/n_pilots frequency bins apart (see example).

The channel estimation header is transfered in the time domain, scaled to have mean_power power and inserted into the dimension dim of sig.samples with an offset n_offset from the start (i.e. in the positions n_offset:n_offset`+`n_fft`*`n_repetitions). Please note that this results in overwritten data payload samples. To ensure a consistent signal structure, the corresponding bit and symbol information (in sig.bits[dim] and sig.symbols[dim]) are removed from the signal structure.

The parameters to reproduce the channel estimation header sequence (i.e. ce_block_len, ce_block, n_pilots, pilots, n_fft, n_repetitions, pilot_offset, pilot_pos, seed, mean_power) are further written into the sig.info[dim][‘ce_header’] dict.

Examples

The parameters n_fft=16, n_pilots=8 and pilot_offset=1 lead to the following pilot grid in the frequency domain, with DC: direct current component, f_N: Nyquist frequency (sample rate/2), df: frequency bin spacing (sample rate/n_fft):

pilot           0   P   0   P   0   P   0   P           0   P   0   P   0   P   0   P
frequency bin   0   1   2   3   4   5   6   7           8   9   10  11  12  13  14  15
frequency       DC  df                     f_N-df      -f_N                        -df
Parameters:
  • sig (Signal) – signal to insert the channel estimation header into.

  • dim (int) – Dimension of the signal into which the frame synchrinization header should be inserted?

  • offset (int) – offset (in time samples) where the channel estimation header will be inserted.

  • n_fft (int) – Number of frequency bins (and resulting time samples) of one OFDM symbol within the channel estimation header.

  • n_pilots (int) – Number of frequency bins to insert random QPSK symbols.

  • pilot_offset (int) – Offset in frequency bins from zero frequency bin (DC component) into which the QPSK pilots will be inserted. Ths parameter therefore specifies the locations of the QPSK pilot symbols in the frequency domain.

  • n_repetitions (int) – Number of repeated OFDM symbols within the channel estimation header.

  • mean_power (float) – Mean power of the inserted channel estimation header.

  • seed (int) – Random number seed of the random number generator generating the QPSK symbols.

Return type:

Signal

Returns:

Signal with inserted channel estimation header sequence.

skcomm.tx.insert_cpe_pilots(sig, dim=0, offset=0, pilot_distance=100, mean_power=1.0, seed=12)

Periodically insert pilot symbols for data-aided carrier phase estimation.

Every pilot_distance sample in sig.samples[dim] is replaced by a random QPSK symbol, starting with the (offset-1)th sample. These pilot symbols can be used at the receiver to perform data-aided carrier phase estimation. To ensure a consistant signal structure, the corresponding bit and symbol information (in sig.bits[dim] and sig.symbols[dim]) are removed from the signal structure.

The QPSK symbols are scaled to have mean_power and the random number generator is seeded with seed.

The parameters to reproduce the CPE pilot sequence (i.e. pilot_pos, cpe_pilots, pilot_overhead) are further written into the sig.info[dim][cpe_pilot_info] dict.

Parameters:
  • sig (Signal) – signal to insert the channel estimation header into.

  • dim (int) – Dimension of the signal into which the pilot symbols should be inserted?

  • offset (int) – offset (in time samples) where the first pilot symbol will be inserted.

  • pilot_distance (int) – Distance (in samples) between two consecutive pilot symbols.

  • mean_power (float) – Mean power of the inserted pilot symbols.

  • seed (int) – Random number seed of the random number generator generating the QPSK symbols.

Return type:

Signal

Returns:

Signal with inserted pilot symbol sequence.

skcomm.tx.insert_frame_sync_seq(sig, dim=0, n_symb=8, fs_header_len=128, mean_power=1.0, seed=10)

Insert a frame sync header into the signal sig.

The signal sig has to be sampled with a sample rate of 1 sample per symbol to insert the frame sync header.

A header sequence for temporal frame synchronization (and carrier frequency offset estimation) is inserted into the specified dimension dim of the signal sig. Therefore a header with a total length of fs_header_len samples is inserted at the begining of sig.samples[dim], while the actual payload data is overwritten. The corresponding logical information at the begining of the signal is removed as well.

This header constists of a symbol sequence (‘B’) of length fs_header_len/4 which is repeated four times, while the third repetition of is multiplied by -1 as proposed in [1].

Each of the ‘B’ sequence consists again of a repeating pattern of (at least) four shorter sub-sequences (‘A’), each containing n_symb random QPSK symbols. Depending on n_symb, also 8, 12,… etc. (an integer multiple of four) sequences ‘A’ can be included in one ‘B’ sequence (compare graph below).

The mean power of the frame synchronization header sequence and the random number seed can be specified via the parameters mean_power and seed, respectively.

All parameters to reproduce the header sequence (i.e. fs_header_len, n_symb, fs_header, seed, mean_power) are written into the sig.info[dim][‘fs_header’] dict.

The following graph visualizes the cascaded ‘A’ and ‘B’ header sequence structure:

==============-------------------------------------
| B           | B         | -B         | B         |
==============-------------------------------------
        |
      /   \
 _____      _______________________________________________________
/                                                                  \
_____________________________________________________________________
| A     | A     | -A    | A     || A    | A     | -A    | A     | ...
_____________________________________________________________________

References

[1] Shi et al. “Coarse Frame and Carrier Synchronization of OFDM Systems: A New Metric and Comparison”, IEEE Transactions on wirless communiations vol 3, no. 4 2004

Parameters:
  • sig (Signal) – signal to insert the frame synchronization header into.

  • dim (int) – Dimension of the signal into which the frame synchrinization header should be inserted.

  • n_symb (int) – Length of the ‘A’ sequence (number of QPSK symbols included in ‘A’ sequence). The lengths of the ‘B’ sequences (fs_header_len/4) divided n_symb must be an integer multiple of four. That means that any ‘B’ sequence must contain an integer mulitple of four ‘A’ sequences (compare graph above).

  • fs_header_len (int) – Length of the overall frame synchronization header (four ‘B’ sequences).

  • mean_power (float) – The framce synchronization sequence is scaled in order to have a mean power of ‘mean_power`.

  • seed (int) – The seed is used to initialize the random number generator which generates the QPSK symbols contained in the ‘A’ sequences.

Return type:

Signal

Returns:

Signal with inserted frame synchronization header sequence.

skcomm.tx.mapper(bits, constellation)

Map bits to a given constellation alphabet.

Bits are grouped into blocks of log2(constellation.size) and converted to decimals. These decimals are used to index the particular constellation value in the constellation array.

Parameters:
  • bits (1D numpy array, bool) – Bits to be mapped to constallation symbols.

  • constellation (1D numpy array, complex) – Constellation (symbol) alphabet onto which the bits (or group of bits) are mapped

Returns:

symbols – np.ndarray of shape (n_bits/np.log2(constellation.size),) containing the constellation (or symbol) sequence after mapping.

Return type:

1D numpy array, complex

skcomm.tx.pulseshaper(samples, upsampling=2.0, pulseshape='rc', roll_off=0.2)

Upsample and pulseshape a given sample sequence.

The provided samples are upsampled by the factor upsampling.

This is done by inserting ceil(upsampling)-1 zeros between each sample followed by applying a pulseshaping filter. (Root) raised cosine and rectangular filter impulse respnses are available. pulseshape = None does not apply any filter to the upsampled sequence.

After the pulseshaping a resampling (downsampling) is performed in case of a fractional upsampling factor.

Parameters:
  • samples (1D numpy array, real or complex) – input signal.

  • upsampling (float, optional) – upsampling factor. The default is 2.0

  • pulseshape (sting, optional) – pulseshaping filter, can either be ‘rc’, ‘rrc’, ‘rect’ or ‘None’, meaning raised cosine filter, root raised cosine filter, rectangular filter or no filter, respectively. The default is ‘rc’.

  • roll_off (float, optional) – rolloff factor in case of (root) raised consine filter. The default is 0.2.

Returns:

samples_out – upsampled and pulseshaped signal samples.

Return type:

1D numpy array, real or complex

Utilities Submodule (skcomm.utils)

This submodule includes utility routines.

ber_awgn([value, modulation_format, ...])

Calculate theoritical BER performances in case of additive white Gaussian noise (AWGN) for various modulation formats.

bits_to_dec(bits, m)

Convert bits to decimals.

calc_evm(sig[, norm, method, opt, dimension])

Calculate the error vector magnitude (EVM).

combine_OSA_traces(x_data, y_data[, ...])

Combine multiple spectra of an optical spectrum analyzer.

create_time_axis([sample_rate, n_samples])

Generate a time axis array.

dec_to_bits(decimals, m)

Convert decimals to bits.

edfa_model(samples, sample_rate[, ...])

Tool for simulation of a very simple EDFA model and related noise behavior.

estimate_SNR_evm(sig, **kwargs)

Estimate SNR (in dB) based on the calculated EVM.

estimate_SNR_m2m4(samples, constellation)

ref.: Aifen Wang; Hua Xu; Jing Ke, "NDA moment-based SNR estimation for envelope-based QAM", 2012 IEEE 11th International Conference on Signal Processing

estimate_osnr_spectrum([power_vector, ...])

Estimate OSNR from spectrum.

estimate_snr_nda(sig[, block_size, bias_comp])

Estimates the SNR per symbol of a noisy signal depending on its modulation format.

estimate_snr_spectrum(x, y, sig_range, ...)

Estimate the signal to noise ratio (SNR) from a given power spectrum.

find_lag(samples, samples_ref[, ...])

Find lag / displacement between a signal and a reference signal.

generate_constellation([format, order])

Generate array of Gray-coded constellation points for a given modulation format of a given order.

load_pickle([folder, f_name, ext])

load python data from file.

save_fig(fig[, fformat, folder, f_name, ...])

save given figure to file.

save_pickle(data[, folder, f_name, ...])

save python data to file.

skcomm.utils.ber_awgn(value=array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]), modulation_format='QAM', modulation_order=4, type='SNR', symbol_rate=32000000000.0, d_lambda=1e-10, ref_wl=1.55e-06, PDM=False)

Calculate theoritical BER performances in case of additive white Gaussian noise (AWGN) for various modulation formats. Currently only QAM format is avaiable. NOTE: QAM-format is interpreted as grey-mapped.

Amount of noise can either be specified as signal-to-noise ratio (SNR), signal-to-noise ratio per bit (SNRB) or as optical signal-to-noise ratio (OSNR), respectively. NOTE: The parameter value is interpreted as logarithmic scale (dB).

Parameters:
  • value (1D array, float) – range which specifies the amount of noise for which the BER perfomance is calculated. NOTE: The value is interpreted as logarithmic value (dB). The default is np.arange(20).

  • modulation_format (string, optional) – modulation format for which the BER performance is calculated. Can be ‘QAM’. The default is ‘QAM’.

  • modulation_order (int, optional) – modulation order (number of bits per symbol) for which the BER performance is calculated. Has to be a power of 2. The default is 4.

  • type (string, optional) – specifies the type how the parameter value is interpreted. Can either be ‘SNR’, SNRB or ‘OSNR’. The default is ‘SNR’.

  • symbol_rate (float, optional) – symbol rate of the signal. Is used to convert from OSNR to SNR and vice versa. Only affects the result in case of tpye=’OSNR’. The default is 32e9.

  • d_lambda (float, optional) – bandwidth (in m) which is used to calculate the OSNR. Only affects the result in case of tpye=’OSNR’. The default is 0.1e-9.

  • ref_wl (float, optional) – center wavelength of the optical signal. Only affects the result in case of tpye=’OSNR’. The default is 1550e-9.

  • PDM (bool, optional) – is the optical signal a polarization-division multiplexed (PDM) signal? Only affects the result in case of tpye=’OSNR’. The default is False.

Returns:

ber – theoretical BER performance for the specified amount of AWGN.

Return type:

1D array, float

References

[1] Essiambre et al., JLT, vol 28, no. 4, 2010, “Capacity Limits of Optical Fiber Networks” [2] Xiong, 2006, “Digital Modulation Techniques”, second edition, Artech House [3] K. Cho and D. Yoon, “On the general BER expression of one- and two-dimensional amplitude modulations,” IEEE Transactions on Communications, vol. 50

skcomm.utils.bits_to_dec(bits, m)

Convert bits to decimals.

Convert 1D array of bits into 1D array of decimals, using a resolution of m bits.

Parameters:
  • bits (iterable of ints of bools) – Bit values to be converted

  • m (int of float) – Resolution of bit values.

Returns:

decimals – Converted decimals.

Return type:

ndarray of floats

skcomm.utils.calc_evm(sig, norm='max', method='blind', opt=False, dimension=-1)

Calculate the error vector magnitude (EVM).

The EVM [1] is calculated for given signal considering the received modulation symbols and the ideal constellation points as reference symbols.

The signal (sig.samples) has to be sampled at one sample per symbol.

The EVM Normalization Reference [2] can be specivied as constellation maximum ‘max’ or as reference RMS ‘rms’.

If the input parameter method is given as ‘blind’ the reference symbols are derived by normalization of the samples (sig.samples) to the same power as the ideal constellation points (sig.constellation) and following decision to these ideal constellation points. In case of ‘data_aided’, the actual sent symbol sequence (sig.symbols) is used as reference after normalization. In this case a temporal and phase synchronizaiton (skcomm.rx.symbol_sequence_sync) is performed before calculation of the error vector. It can further be specified (opt==False), if the normalization of the samples is done by scaling the samples to the same mean power as the ideal constellation points (similar to the ‘blind’ case). In case of opt==True the scaling factor is optimized. Therefore, the samples are ‘clustered’ to the individual sent constellation points and the scaling is adjusted in order to minimize the mean value (in real and imaginary part separate) of all clusters.

NOTE: In case of method==’blind’ the error vector is calculated between the received symbols and the DECIDED constellation points and not between the received symbols and the ACTUALLY (“really”) sent constellations as in case of method==’data_aided’. The former method will therefore lead to an too optimistic EVM in case of low SNR (and many wrong symbol decisions e.g. high BER).

Parameters:
  • sig (skcomm.signal.Signal) – signal containing the symbols (samples) and the original constellation.

  • norm (string, optional) – Specifies the EVM Normalization Reference [2] and can either be constellation maximum ‘max’ or reference RMS ‘rms’. The default is ‘max’.

  • method (string, optional) – Specifies if the reference symbols are derived without knowledge of the sent symbols (case ‘blind’) or not (case ‘data_aided’). The default is ‘blind’.

  • opt (bool, optional) – Specifies if the scaling of the symbols (samples) should be optimized. The default is False.

  • dimension (int, optional) – Which dimension to operate on? -1 operates on all signal dimensions. The default is -1.

Returns:

evm – calculated EVM value per sigmal dimension as ratio (to convert to percent, the ratio has to be multiplied by 100).

Return type:

list of floats

skcomm.utils.combine_OSA_traces(x_data, y_data, operator='-', x0=1.55e-06, save_fig=False, f_name=None)

Combine multiple spectra of an optical spectrum analyzer.

This function combines multiple spectra which are given as lists of np.arrays in x_data and y_data. For each spectrum the method of combination can be specified as addition (‘+’), subtraction (‘-‘), multiplication (‘*’) or division (‘/’) using the operator string.

NOTE: This function can only handle spectra with identical x_axis yet. No interpolation is performed.

Parameters:
  • x_data (list od np.ndarray) – Contains the x_axis (either frequency or wavelength) of the spectra to be combined.

  • y_data (list od np.ndarray) – Contains the y_axis (either dBm W) of the spectra to be combined.

  • operator (string) – Each character of the string specifies the combination method for the individual given spectra. Characters can either be ‘+’, ‘-’, ‘*’ or ‘/’. Note that the number of characters must be by one less than the number of given spectra. The default is ‘-‘.

  • x0 (float, optional) – For the specific x0 value the result of the combination is explicitly plotted. The default is 1550e-9.

Returns:

comb – y values of the combined spectrum.

Return type:

np.ndarray

Examples

This simple example calculates the (amplitude) transfer function of an optical device by subtraction of two measured spectra (one at the input and another at the output of the device). Therefore it assumes that the spectra are given in dBm. One specific attenuation at a wavelength of 1550 nm should explicitly be evaluated.

>>> import skcomm as skc
>>>
>>> # get input spectrum to device and save wavelength data to wl1 and power
>>> # data to spectrum1 (e.g. by using skcomm.instrument_control.get_spectrum_HP_71450B_OSA())
>>>
>>> # get output spectrum from device and save wavelength data to wl2 and power
>>> # data to spectrum2 (e.g. by using skcomm.instrument_control.get_spectrum_HP_71450B_OSA())
>>>
>>> # generate input lists
>>> x_data = [wl1, wl2]
>>> y_data = [spectrum1, spectrum2]
>>> combined = skc.utils.combine_OSA_traces(x_data, y_data, operator='-', x0=1550.15e-9)
skcomm.utils.create_time_axis(sample_rate=1.0, n_samples=1000)

Generate a time axis array.

Parameters:
  • sample_rate (float, optional) – Sample rate of the time axis array. The default is 1.0

  • n_samples (int, optional) – Length of the time axis in samples. The default is 1000.

Returns:

t – Time axis array of length n_samples sampled at equidistant points with time difference 1/sample_rate.

Return type:

1D array

skcomm.utils.dec_to_bits(decimals, m)

Convert decimals to bits.

Convert 1D array of decimals into 1D array of bits, using a resolution of m bits.

Parameters:
  • decimals (ndarray of floats) – Decimal values to be converted.

  • m (int or float) – Resolution of resulting bit values.

Returns:

bits – Converted bits.

Return type:

ndarray of bool

skcomm.utils.edfa_model(samples, sample_rate, opt_mid_wl=1.55e-06, mode='APC', opt_target=0, opt_noise_figure=4.5, seed=None)

Tool for simulation of a very simple EDFA model and related noise behavior. Please note: This model is simple and not physically correct in total. The main assumption for this model is that G(ain) >> 1. This means that if G == 1, this model will produce physically inaccurate results. The output power generated by the model is given by the output power set with opt_target and additionally the noise power.

TODO: 1. Discuss if this model is enough for related work, in terms of inadequacies in physics. 2. Do a better validation in a normal python file

Parameters:
  • samples (np.ndarray) – input signal samples.

  • sample_rate (np.ndarray) – sample rate of the input signal samples.

  • opt_mid_wl (float, optional) – center wavelengt of the input signal. Default is 1550e-9.

  • mode (string, optional) – operation mode of the simulated EDFA. Should be “APC” or “AGC”, where APC is automatic power control and AGC is automatic gain control. Default is “APC”.

  • opt_target (float, optional) – target output power of the EDFA. If APC modus, this value is given in [dBm], if AGC modus, this value means relative gain in [dB]. Default is 0 [dBm].

  • opt_noise_figure (float, optional) – noise figure of the amplifier in [dB]. Specifies the noise behavior. Default is 4.5 [dB].

  • seed (int, optional) – seed for noise vector generation. Default is “None”, for non-fixed seed operation.

Returns:

samples – output samples with edfa noise contribution.

Return type:

np.ndarray

skcomm.utils.estimate_SNR_evm(sig, **kwargs)

Estimate SNR (in dB) based on the calculated EVM.

The EVM is calculated using the method skcomm.utils.calc_evm() and from this result, the SNR is derived according to [1].

For more information about the valid parameters see skcomm.utils.calc_evm().

Parameters:

skcomm.signal.Signal – signal containing the symbols (samples) and the original constellation.

Returns:

Derived SNR values in dB per signal dimension.

Return type:

list of floats

References

[1] R. A. Shafik, et al. “On the Extended Relationships Among EVM, BER and SNR as Performance Metrics” https://doi.org/10.1109/ICECE.2006.355657

skcomm.utils.estimate_SNR_m2m4(samples, constellation)

ref.: Aifen Wang; Hua Xu; Jing Ke, “NDA moment-based SNR estimation for envelope-based QAM”, 2012 IEEE 11th International Conference on Signal Processing

Parameters:
  • samples (TYPE) – DESCRIPTION.

  • constellation (TYPE) – DESCRIPTION.

Returns:

snr_estimate_m2m4 – DESCRIPTION.

Return type:

TYPE

skcomm.utils.estimate_osnr_spectrum(power_vector=[], wavelength_vector=[], interpolation_points=[], integration_area=[], resolution_bandwidth=0.1, polynom_order=3, plotting=False)

Estimate OSNR from spectrum.

Function to calculate the OSNR from OSA (Optical spectrum analyzer) trace data via interpolation method. The function will interpolate the spectral noise shape in a given spectral area, which can be definded by the user. From this data the noise power is estimated. Than the function will calculate the signal power and will afterwards calculate the OSNR.

Parameters:
  • power_vector (numpy array) – Vector with the power values of the OSA trace. Must be dBm. Must be same length as wavelength_vector.

  • wavelength_vector (numpy array) – Vector with the wavelength values of the OSA trace. Must be nm. Must be same length as power vector.

  • interpolation_points (numpy array of length 4 [a,b,c,d]) –

    This array specifies the areas for creating the polynomial. This requires 4 points. The array elements a and b indicate the left area of ​​ the signal spectrum and the elements c and d the right area.

    If the passed wavelength value is not present in the wavelength vector, the passed values ​​are rounded to the nearest existing value.

  • integration_area (numpy array of length 2 [integration_start, integration_stop]) –

    These two points determine the bandwidth in which the noise and signal power are determined.

    If the passed wavelength value is not present in the wavelength vector, the passed values ​​are rounded to the nearest existing value.

  • resolution_bandwidth (float) – Insert here the used resolution bandwidth (rbw) of the OSA.

  • polynom_order (int) – Insert here the polynomial order for the noise interpolation.

  • plotting (boolean, optional (default = False)) – If true, the spectrum is plotted with the interpolation area, integration area and interpolated noise shape. To show the plot, plt.show() must be called in the main script.

Returns:

OSNR_01nm:

The calculated OSNR normalized to a noise bandwidth of 0.1nm.

OSNR_val:

The calculated OSNR of the integration area.

Examples

>>> import skcomm as skc
>>> import numpy as np
>>>
>>> # Set area for polynom creation (Values were randomly selected for this example)
>>> a = 1552.025
>>> b = 1552.325
>>> c = 1552.725
>>> d = 1553.025
>>>
>>> # Set integration area (Values were randomly selected for this example)
>>> integration_start = 1552.375
>>> integration_stop = 1552.675
>>>
>>> # Set polynomial order
>>> poly_ord = 2
>>>
>>> # Get optical spectrum data from OSA or another arbitary source
>>> OSA_trace_dict = skc.instrument_control.get_samples_HP_71450B_OSA()
>>> power = OSA_trace_dict['A']['Trace_data']
>>> wavelength = OSA_trace_dict['A']['WL_Vector']
>>> resolution_bw = OSA_trace_dict['A']['Resolution_BW']*1e9
>>>
>>> # Calculate OSNR with plot
>>> [ONSR_0.1nm,OSNR] = skc.osnr.osnr(power_vector = power,
                    wavelength_vector = wavelength,
                    interpolation_points = np.array([a,b,c,d]),
                    integration_area = np.array([integration_start,integration_stop]),
                    resolution_bandwidth = resolution_bw,
                    polynom_order=poly_ord,
                    plotting = True)
skcomm.utils.estimate_snr_nda(sig, block_size=-1, bias_comp=True)

Estimates the SNR per symbol of a noisy signal depending on its modulation format. The noise is assumed to be Gauss-distributed. Different non-data- aided algorithms are used in conjunction with empirically determined correction/modification terms depending on whether the modulation format is BPSK, QPSK, or QAM of order 16 or upwards. The function assumes that the ‘samples’ attribute of the signal class object contains symbols, i.e. that the signal has been downsampled to 1 sample per symbol, and that no sampling phase error is present.

Parameters:
  • sig (signal-class object) – The signal object on which to operate. The object’s modulation format must be known, i.e. a string variable must be present in the ‘modulation_info’ attribute per dimension of the signal.

  • block_size (int) – The number of symbols to average SNR over. Greater block size means a more accurate estimate. Default value is -1, which treats the entire symbol vector as one block.

  • bias_comp (bool) – Flag determining whether the bias of the BPSK estimation algorithm is compensated according to the data obtained in a Monte Carlo simulation with 10.000 runs for SNR values between 0 dB and 20 dB. Beyond these limits, the bias is extrapolated from the data. Default value is True.

Returns:

snr_estimate – Array with the same shape as sig.samples containing the estimated SNR values.

Return type:

numpy array

References

[1]: Ijaz, A., Awoseyila, A.B., Evans, B.G.: “Improved SNR estimation for BPSK and QPSK signals”, Electronics Letters Vol. 45 No. 16, 2009

[2]: Qun, X., Jian, Z.: “Improved SNR Estimation Algorithm, International Conference on Computer Systems”, Electronics, and Control (ICCSEC), 2017

[3]: Xu, H., Li, Z., Zheng, H.: “A non-data-aided SNR Estimation Algorithm for QAM Signals”, IEEE, 2004

skcomm.utils.estimate_snr_spectrum(x, y, sig_range, noise_range, order=1, noise_bw=12500000000.0, scaling='lin', fit_lin=True, plotting=False, fNum=None)

Estimate the signal to noise ratio (SNR) from a given power spectrum.

The SNR is estimated from a given power spectrum using the so called interpolation method: The signal (and noise (n2)) power (p_sig_n2) is calculated by integration of the spectrum between the given spectral signal range. Then, the noise floor is estimated by fitting a polynomial of given order to the spectral points lying in two specified spectral ranges (given by the four values in noise_range). In general, one spectral range left and another one right from the data signal is specified, which therefore requires some oversampling of the data signal. Two noise powers (p_n1 and p_n2) are calculated from the estimated polynomial by integration within noise_bw (n1) and sig_range (n2), respectively. The SNR is then estimated by SNR = (p_sig_n2 - p_n2) / p_n1.

It can be specified if the polynomial is fitted from the spectrum either in linear or in logarithmic domain.

Parameters:
  • x (1D array, float) – “x-axis” values of the spectrum. In general either frequency or wavelength. The values in this vector must be monotonically increasing.

  • y (1D array, float) – “y-axis” values of the spectrum. Unit should be W/(RBW of x axis).

  • sig_range (1D array, float) – Two values (same unit as x) that specify the left and right corner points of the data signal, respectively, and thus define the integration limits for p_sig_n2.

  • noise_range (1D array, float) – Four values (same unit as x) indicating the first (noise_range[:2]) and second (noise_range[2:]) spectral ranges used to fit the polynomial of the noise floor. These ranges are generally chosen to lie to the left and right of sig_range, respectively.

  • order (int, optional) – Order of the polynomial to be fitted. The default is 1.

  • noise_bw (float, optional) – Noise bandwidth (same unit as x) used to calculate the noise power (p_n1) in the SNR formula. For optical SNR, usually set to 0.1 nm or 12.5 GHz. For electrical SNR, usually set to the symmetrical rate of the data signal. The default value is 12.5e9.

  • scaling (string, optional) – Is the spectrum (y) given in linear ‘lin’ (W, V**2, W/Hz, V**2/nm, …) or in logarithmic ‘log’ (dBm, dBm/Hz, dBm/m, …) scale. The default is ‘lin’.

  • fit_lin (bool, optional) – Is the polynomial fitted from the spectrum linear (True) or logarithmic spectrum (False)? The default is True.

  • plotting (boolean, optional) – Shall the spectrum (plus integration regions and noise fit) be plotted? Useful for tuning sig_range and noise_range and verifying the fitting results. The default is False.

  • fNum (int, optional) – Figure number to plot into. The default is None which uses the “next unused figure number”.

Returns:

resultsdict containing following keys
snr_dBfloat

estimated SNR in dB scale

snr_linfloat

estimated SNR in linear scale

p_sigfloat

estimated signal power from spectrum. Unit depends on input signal.

p_noisefloat

estimated noise power from spectrum. Unit depends on input signal.

skcomm.utils.find_lag(samples, samples_ref, period_length=None, detrend=False, debug=False, fNum=None)

Find lag / displacement between a signal and a reference signal.

The lag / displacement is found by performing a correlation of the two input signals. Further, a linear trend of the signals can be removed before correlation.

Please note that the mean of both signals is removed before correlation in any case.

In case that one (or both) signals are periodic, a period length can be specified. In this case the the lag which produces the maximum correlation is determined. However, the due to the periodicity of the signals, the returned lag is always assumed to be between +-period length. And therefore calculated acoording to lag = lag_m % period_length, where lag_m is the lag of the maximum correlation.

Parameters:
  • samples (1D numpy array, real or complex) – Sampled input signal.

  • samples_ref (1D numpy array, real or complex) – Reference signal.

  • period_length (int or None) – If not None, only lags / displacements between -period_length/2 and

  • valid. (period_length/2 are considered. Otherwise all lags are) – Default is None.

  • detrend (bool) – Should a linear trend be removed from the singals before correlation? For more information see scipy.signal.detrend

  • debug (bool) – Plot (helpful) debugging-based plots about correlation / lag estimation.

Returns:

return_dictdict containing following keys
estimated_lag: int

estimated lag of samples w.r.t. samples_ref. A positive value indicates that samples are delayed (shifted to the right), while a negative value means that samples is advanced (shifted to the left) w.r.t. samples_ref.

max_correlation: complex float

The value of the correlation with the maximum amptidude of the correlation.

correlation: np.array of complex floats

The correlation between both signals of length (len(samples)+len(samples_ref)-1)

correlation_lags: np.array of int

The corresponding lags of the correlation.

skcomm.utils.generate_constellation(format='QAM', order=4)

Generate array of Gray-coded constellation points for a given modulation format of a given order.

For QAM formats, a pure Gray-coded square QAM constellation is generated if order is an even power of 2 (even-bit), and Pseudo-Gray-coded symmetrical QAM constellation based on the proposed implementation in [1] is generated if order is an odd power of 2 (odd-bit) and order is 32 or greater. For the special case of order = 8 (3-bit), an 8-Star-QAM is implemented. For PSK and PAM formats, pure Gray-Coded constellations are always generated, as long as order is a power of 2.

Constellation points in QAM and PAM modulation schemes are currently built with a Euclidean distance of 2 between two neighbouring points, as per the convention in [1]. This might require normalization of the constellation array.

Parameters:
  • format (string, optional) – Modulation format to be used. Options are ‘QAM’, ‘PAM’, and ‘PSK’. The default is ‘QAM’.

  • order (int, optional) – Order of the modulation scheme to be generated. Only powers of 2 are valid. The default is 4.

Raises:
  • ValueError : – If order is not a power of 2 or if a QAM with order 2 is generated (for order = 2, PAM/PSK should be used).

  • TypeError : – If order is not passed as integer.

Returns:

constellation – Array of complex constellation points to map bit words to.

Return type:

ndarray of complex

References

[1] J. G. Smith, “Odd-Bit Amplitude Quadrature-Shift Keying”, IEEE Transactions on Communications, pp. 385-389, 1975

skcomm.utils.jones2stokes_pdm(samples_X, samples_Y)

Converts a dual-polarization input signal (instantaneous field samples) in 2-D complex Jones space [1], given as the two components \(E_X\) (1-D array samples_X) and \(E_Y\) (1-D array samples_Y) of the Jones vector, into its isomorphic representation in the 3-D real-valued Stokes space [2], given as the stokes parameters \((S_0, S_1, S_2, S_3)\). In calculation of the Stokes parameters, it is assumed that the (instantaneous) field is fully polarized \((DOP=1)\) [cf. 3/ch.1.2].

For definition and calculation of the polarimetric parameters \((\chi,\Phi)\) and the spherical polar coordinates (azimuth \(\varphi\), zenith or polar angle \(\Theta\)) in the equations below, refer to [3/ch.1].

Parameters:
  • samples_X (ndarray) – Input signal samples in X-polarization. Must be of same size as ‘samples_Y’

  • samples_Y (ndarray) – Input signal samples in Y-polarization. Must be of same size as ‘samples_X’

Return type:

dict

Returns:

  • results containing the following keys

    • S0np.ndarray[np.float64]

      The instantaneous total power of the field: \(S_0 = \sqrt{S_1^2 + S_2^2 + S_3^2}=P_{tot}=P_X+P_Y=\lvert E_X \rvert^2+|E_Y|^2\)

    • S1np.ndarray[np.float64]

      The instantaneous power difference between linearly X-polarized and linearly Y-polarized field components: \(S_1 = P_X - P_Y = \lvert E_X \rvert^2-|E_Y|^2\) \(S_1 = S_0 \cdot \cos(2\,\chi) = S_0 \cdot \cos(\Theta) \cdot \cos(\varphi)\)

    • S2np.ndarray[np.float64]

      The instantaneous power difference between linearly \(+45^\circ\)-polarized and linearly \(-45^\circ\)-polarized field components: \(S_2 = P_{+45^\circ} - P_{-45^\circ} = E_X \cdot E_Y^\star + E_X^\star \cdot E_Y = 2\,\textrm{Re}(E_X \cdot E_Y^\star)\) \(S_2 = S_0 \cdot \sin(2\,\chi) \cdot \cos(\Phi) = S_0 \cdot \sin(\Theta) \cdot \cos(\varphi)\)

    • S3np.ndarray[np.float64]

      The instantaneous power difference between the right-handed circular polarization (RHCP) and the left-handed circular polarization (LHCP) field components. \(S_3 = P_{RHCP} - P_{LHCP} = i\,(E_X \cdot E_Y^\star - E_X^\star \cdot E_Y) = -2\,\textrm{Im}(E_X \cdot E_Y^\star)\) \(S_3 = S_0 \cdot \sin(2\,\chi) \cdot \sin(\Phi) = S_0 \cdot \sin(\varphi)\)

References

skcomm.utils.load_pickle(folder='.', f_name='tmp', ext='pickle')

load python data from file.

This method is a wrapper for the python “pickle” module. Please note that

“The pickle module is not secure. Only unpickle data you trust.” (see https://docs.python.org/3/library/pickle.html for more information.)

Parameters:
  • folder (string, optional) – folder to save data to.. The default is ‘.’.

  • f_name (string, optional) – filename to save data to.. The default is ‘tmp’.

  • ext (string, optional) – filename extension. The default is ‘pickle’.

Returns:

data – read data object.

Return type:

arbitrary python data object

skcomm.utils.save_fig(fig, fformat='png', folder='.', f_name='tmp', fdpi=200, add_timestamp=False)

save given figure to file.

Parameters:
  • fig (matplotlib Figure object) – handle to the figure to be saved.

  • fformat (string, optional) – format of the saved file, can either be ‘png’, ‘pdf’ or ‘svg’. The default is ‘png’.

  • folder (string, optional) – folder to save figure to. The default is ‘.’.

  • f_name (string, optional) – filename to save figure to. The default is ‘tmp’.

  • fdpi (int, optional) – resolution (dots per inch, DPI) to save the rastered image. Only used in case of format==’png’. The default is 200.

  • add_timestamp (bool, optional) – should a timestamp be added to the filename? The default is False.

skcomm.utils.save_pickle(data, folder='.', f_name='tmp', add_timestamp=False)

save python data to file.

This method is a wrapper for the python “pickle” module.

Parameters:
  • data (arbitrary python data object) – python object to be saved.

  • folder (string, optional) – folder to save data to. The default is ‘.’.

  • f_name (string, optional) – filename to save data to. The default is ‘tmp’.

  • add_timestamp (bool, optional) – should a timestamp be added in fromt of the filename. The default is False.

Visulizer Submodule (skcomm.visualizer)

This submodule includes routines to visualize signal.

place_figures([auto_layout, monitor_num, ...])

Place open figure on screen.

plot_constellation(samples[, decimation, ...])

Plot the constellation diagramm (complex plane) of samples.

plot_eye(samples[, sample_rate, ...])

Plot eye diagram of sampled signal.

plot_poincare_sphere(samplesX, samplesY[, ...])

Plot the signal (given as components of the Jones vector) on the Poincaré sphere.

plot_signal(samples[, sample_rate, fNum, ...])

plot singal as a function of time.

plot_spectrum(samples[, sample_rate, fNum, ...])

Plot the power spectrum of a given time-series samples array.

skcomm.visualizer.place_figures(auto_layout=True, monitor_num=0, nc=4, nr=3, taskbar_offset=35, figure_toolbar=65)

Place open figure on screen.

Place open figures on screen unsing specified layout. Basic programmatic idea taken from [1].

Parameters:
  • auto_layout (bool, optional) – The layout is chosen automatically depending on the number of opened figures. Number of figures must not exceed 32. The default is True.

  • monitor_num (int, optional) – Monitor onto which the figures are placed. Please note that the order is rather random (i.e. the primary monitor is not necessarily number 0). The default is 0.

  • nc (int, optional) – Number of coloums used for the layout. Only used if auto_layout=False. The default is 4.

  • nr (int, optional) – Number of rows used for the layout. Only used if auto_layout=False. The default is 3.

  • taskbar_offset (int, optional) – Height of the (windows) taskbar which should not be covered by the layout. The taskbar is assumed to be on the bottom of the screen. The height depends on many parameters (e.g. monitor scaling, layout of taskbar,… ) and is therefore to determined by the user. The default is 35.

  • figure_toolbar (int, optional) – Height of the toolbar of the individual plot windows. The height depends on many parameters (e.g. graphical backend, monitor scaling,… ) and is therefore to determined by the user. The default is 65.

Return type:

None.

References

[1] JaeJun Lee (2023). automatically arrange figure windows (https://www.mathworks.com/matlabcentral/fileexchange/48480-automatically-arrange-figure-windows), MATLAB Central File Exchange. Retrieved January 23, 2023.

skcomm.visualizer.plot_constellation(samples, decimation=1, fNum=None, tit='constellation', hist=False, axMax=None, nBins=128, save_fig=False, ffolder='.', ffname=None, fformat='png', add_timestamp=False)

Plot the constellation diagramm (complex plane) of samples.

Parameters:
  • samples (1D numpy array, complex) – samples of the input signal.

  • decimation (int, optional) – take only every decimations-th sample of the input signal. The default is 1.

  • fNum (int, optional) – figure number of the plot to be created. The default is None which uses the “next unused figure number”.

  • tit (string, optional) – title of the plot to be created. The default is ‘constellation’.

  • hist (bool, optional) – should the constellation diagramm be plotted as 2D histogramm? The default is False.

  • axMax (float or None) – maximum abolute axis amplitude (equal in x and y axis) if None: 1.1 times maximum absolute value of samples (real and imaginalry part) is used

  • nBins (int) – number of bins (in each quadrature) for plotting the 2D histogramm

  • save_fig (bool, optional) – should the plot be saved to file? The default is False.

  • ffolder (sting, optional) – folder to save figure to. The default is ‘.’.

  • ffname (string, optional) – filename to save figure to. The default is None, which uses the title of the plot as filename.

  • fformat (string, optional) – format of the saved file, can either be ‘png’, ‘pdf’ or ‘svg’. The default is ‘png’.

  • add_timestamp (bool, optional) – should a timestamp be added to the filename? The default is False.

skcomm.visualizer.plot_eye(samples, sample_rate=2.0, symbol_rate=1.0, fNum=None, boundaries=[None, None], histogram=False, sps_int=40, vertical_resolution=256, tit='eye diagramm', save_fig=False, ffolder='.', ffname=None, fformat='png', add_timestamp=False)

Plot eye diagram of sampled signal.

Parameters:
  • samples (ndarray[float64 | complex128]) – sampled signal.

  • sample_rate (float) – Sample rate of the signal. Please note that the sample_rate must be an integer mulitple of the bit_rate.The default is 2.

  • symbol_rate (float) – Symbol rate (or symbol rate) of the signal. The default is 1.

  • fNum (int) – Figure number to plot into. The default is None which uses the “next unused figure number”.

  • boundaries (list) – The boundaries are given as list with two elements (start and end index). The eye diagram is only plotted within these given boundaries. A value of None specifies the first and last signal sample, respectively. The default is [None, None] and therefore the eye diagram contains the whole signal.

  • histogram (bool) – Should the eye diagramm be plotted as histogram?

  • sps_int (int) – Samples per symbol after interpolation. Only evaluated in case of histogram==True.

  • vertical_resolution (int) – Vertical resolution of the Histogram. Only evaluated in case of histogram==True.

  • tit (string, optional) – Title of the plot. The default is ‘eye diagramm’.

  • save_fig (bool, optional) – should the plot be saved to file? The default is False.

  • ffolder (sting, optional) – folder to save figure to. The default is ‘.’.

  • ffname (string, optional) – filename to save figure to. The default is None, which uses the title of the plot as filename.

  • fformat (string, optional) – format of the saved file, can either be ‘png’, ‘pdf’ or ‘svg’. The default is ‘png’.

  • add_timestamp (bool, optional) – should a timestamp be added to the filename? The default is False.

Return type:

None.

skcomm.visualizer.plot_poincare_sphere(samplesX, samplesY, decimation=1, fNum=1, tit='Poincaré sphere', labels=True, save_fig=False, ffolder='.', ffname=None, fformat='png', add_timestamp=False)

Plot the signal (given as components of the Jones vector) on the Poincaré sphere.

This function converts the given signal, specified by the two components of the Jones vector [1] (array samplesX (e_x) and samplesY (e_y)), into the Stokes representation [2] and plots it onto the Poincaré sphere [3] in the three dimensional Stokes space (S1, S2, S3).

Please note that the Stokes parameters S1, S2 and S3 are normalized to the total instantaneous signal power (S0). Therefore, the Poincaré sphere plot in this implementation does not reveal any information on degree of polarization of the signal.

Parameters:
  • samplesX (1D numpy array, complex) – samples of the input signal, representing the (time dependent) first component of the Jones vector (e_x). Commonly reffered to as the X (or horizontal (H)) polarization component.

  • samplesY (1D numpy array, complex) – samples of the input signal, representing the (time dependent) second component of the Jones vector (e_y). Commonly reffered to as the Y (or vertical (V)) polarization component.

  • decimation (int, optional) – take only every decimations-th sample of the input signal. The default is 1.

  • fNum (int, optional) – figure number of the plot to be created. The default is 1.

  • tit (string, optional) – title of the plot to be created. The default is ‘Poincaré sphere’.

  • labels (bool, optional) – Should the Poincaré sphere be plotted with additional labels indicating certain, specific polarization states (like H, V, right circular polarized (RCP), etc. (True) or as a plain sphere only showing the three coordinate axes (False)? The default is True.

  • save_fig (bool, optional) – should the plot be saved to file? The default is False.

  • ffolder (sting, optional) – folder to save figure to. The default is ‘.’.

  • ffname (string, optional) – filename to save figure to. The default is None, which uses the title of the plot as filename.

  • fformat (string, optional) – format of the saved file, can either be ‘png’, ‘pdf’ or ‘svg’. The default is ‘png’.

  • add_timestamp (bool, optional) – should a timestamp be added to the filename? The default is False.

Returns:

handles

figmatplotlib.figure.Figure

Figure object the signal is plotted to.

axmatplotlib.axes._subplots.Axes3DSubplot

Axes object which contains the Poincaré sphere artists

linempl_tooklits.mplot3d.art3d.Line3d

Line object which contains the Stokes parameters (S1, S2, S3).

Return type:

dict containing following keys

skcomm.visualizer.plot_signal(samples, sample_rate=1.0, fNum=None, boundaries=[None, None], tit='time signal', save_fig=False, ffolder='.', ffname=None, fformat='png', add_timestamp=False)

plot singal as a function of time.

Parameters:
  • samples (1D numpy array, real or complex) – sampled signal.

  • sample_rate (float, optional) – The sample rate of the signal. The default is 1.0.

  • fNum (int, optional) – Figure number to plot into. The default is None which uses the “next unused figure number”.

  • boundaries (list of int or None, optional) – The boundaries are given as list with two elements (start and end index). The signal is only plotted within these given boundaries. A value of None specifies the first and last signal sample, respectively. The default is [None, None] and therefore plots the whole signal.

  • tit (string, optional) – Title of the plot. The default is ‘time signal’.

  • save_fig (bool, optional) – should the plot be saved to file? The default is False.

  • ffolder (sting, optional) – folder to save figure to. The default is ‘.’.

  • ffname (string, optional) – filename to save figure to. The default is None, which uses the title of the plot as filename.

  • fformat (string, optional) – format of the saved file, can either be ‘png’, ‘pdf’ or ‘svg’. The default is ‘png’.

  • add_timestamp (bool, optional) – should a timestamp be added to the filename? The default is False.

Return type:

None.

skcomm.visualizer.plot_spectrum(samples, sample_rate=1.0, fNum=None, scale='logNorm', resolution_bw=None, ax_lims=[None, None, None, None], tit='spectrum', save_fig=False, folder='.', fname=None, fformat='png', add_timestamp=False)

Plot the power spectrum of a given time-series samples array.

If the samples are real-valued, a one-sided spectrum (only positive frequencies) is generated, otherwise a two-sided spectrum (negative and positive frequencies) is generated.

The frequency axis and the power spectrum with a resolution_bw is returned.

Additionally, the fft-shifted frequency bins (from -fs/2 up to fs/2) with intrinsic frequency resolution, as given by the sample rate and the number of samples, and the corresponding fft-shifted, complex-valued spectrum is returned from the function.

Parameters:
  • samples (ndarray[complex128 | float64]) – 1D time series of signal samples.

  • sample_rate (float) – sample rate (fs) of the signal in Hz. The default is 1.0

  • fNum (int | None) – figure number to be used for plot. The default is None which uses the “next unused figure number”.

  • scale (str) – scaling of the plot y-axis, which can either be ‘logNorm’, ‘log’, ‘linNorm’, ‘lin’. The y-axis will be scaled in linear or logarithmic dB-scale and can either be normalized to the maximum y-value or not (absolute values). The default is ‘logNorm’.

  • resolution_bw (float | None) – demanded resolution bandwidth of the displayed spectrum given in ‘Hz’. This parameter is used for the estimation of the power spectrum using SciPy’s Welch method. If None, no periodogram averaging is performed (i.e. the intrinsic resolution, as given by sample_rate/samples.size, is used). The default is None.

  • ax_lims (list) – specifies the axis limits of the plot as [xmin, xmax, ymin, ymax]. A value of None sets automatic axis limits. The default is [None, None, None, None].

  • tit (str) – title of the plot. The default is ‘spectrum’.

  • save_fig (bool) – If set to True, the plot will be saved to a file. The default is False.

  • folder (str) – folder to save the figure to. The default is ‘.’.

  • fname (str | None) – Filename to save the figure to. The default is None, which uses the title tit of the plot as filename.

  • fformat (str) – format of the saved image file, can either be ‘png’, ‘pdf’ or ‘svg’. The default is ‘png’.

  • add_timestamp (bool) – if set to True, a timestamp will be added to the filename. The default is False.

Return type:

dict

Returns:

  • Results dictionary with following keys

    • ‘power_spectrum’np.ndarray[np.float64]

      Power spectrum of the time series in a scaling as requested by the scale parameter

    • ’freq’np.ndarray[np.float64]

      Frequency bins of the calculated power spectrum in units of Hz

    • ’resolution_bw’np.float64

      The applied resolution_bw in units of Hz. This can deviate from the demanded resolution_bw due to rounding of the periodogram window length.

    • ’freq_raw’np.ndarray[np.float64]

      FFT-shifted frequency bins (ranging from -fs/2 up to fs/2) in units of Hz with intrinsic resolution as given by sample_rate/samples.size

    • ’spectrum_raw’np.ndarray[np.complex128]

      Complex-valued, FFT-shifted (from -fs/2 up to fs/2) spectrum (FFT) of the input samples without any aritificial reduction of the resolution (raw output from the fft with intrinsic frequency resolution)