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 the containing 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.

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.

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).

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.

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.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, 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.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.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.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, modformat='complex')

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. At least 3 input samples per polarization have to be provided together that form 3 linearly independent Stokes vectors for plane fitting. 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’

  • modformat ("complex", "real") –

    • “complex”:

      Specifies that the modulation format of the incoming signal is a complex modulation per polarization (PDQ-QAM).

    • ”real”:

      Specifies that the incoming signals modulation format is a real-valued modulation per polarization (PDQ-BPSK, PDM-ASK, PDM-PAM).

    The default is “complex”.

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)

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

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.

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.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, erctangular 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)

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)