### pypho v3

#### Example 10: BER estimation

This example shows how to estimate the bit error ration (BER) of signal for a given OSNR.

For this first a function named get_decision_matrix(). This functions finds the optimum decision lines in the IQ-plane for the X- and Y-polarisation for the given constellation points.

For example a 16QAM as shown in Fig. 1. The algorithm finds the optimum decision lines for the back-to-back case. Fig. 1 : Optimum decision lines for 16QAM back-to-back

If the transmission of the signal over 800km SSMF is taken into account, then non-linear fiber effects rotates the phase of the signal and so the whole constellation diagramme. Due to different amplitudes of the symbols the phase shift by intra-channel XPM of each synbol is different and results in phase noise. Fig. 2 : Optimum decision lines for 16QAM after 800km SSMF

After finding the optimum decision lines, they can be used to estimate the BER. The function calc_BER() is a simple Monte-Carlo Simulation adding noise defined by the OSNR to the signal. Fig 3. shows the result from a BER estimation. Crosses are the samples leadig to an incread BER. In the example below the BER of the X- and Y polarisation plane is $10^{-2.15}$ and $10^{-2.17}$ Fig. 3 : Results from Monte-Carlo-Simulation. Crosses show the samples identificated wrong leading to an increased BER.

##!/usr/bin/env python2
# -*- coding: utf-8 -*-

#Import functions and libraries
import sys
sys.path.append('../')
from pypho_setup import pypho_setup
from pypho_bits import pypho_bits
from pypho_signalsrc import pypho_signalsrc
from pypho_lasmod import pypho_lasmod
from pypho_fiber import pypho_fiber
from pypho_fiber_birefringence import pypho_fiber_birefringence
from pypho_arbmod import pypho_arbmod
from pypho_oamp import pypho_oamp
from pypho_osnr import pypho_osnr
from pypho_sample import pypho_sample
from pypho_optfi import pypho_optfi
from pypho_cwlaser import pypho_cwlaser

from pypho_functions import *
import numpy as np
import copy
import matplotlib.pyplot as plt

from matplotlib import colors as mcolors
colors = dict(mcolors.BASE_COLORS, **mcolors.CSS4_COLORS)

plt.close('all')

# Define network elements
gp          = pypho_setup(nos = 512, sps = 128, symbolrate = 10e9)
bitsrc      = pypho_bits(glova = gp, nob = gp.nos, pattern = 'ones')
esigsrc     = pypho_signalsrc(glova = gp, pulseshape = 'gauss_rz' , fwhm = 0.25)
sig_1550    = pypho_lasmod(glova = gp, power = 0, Df = 0, teta = np.pi/4.0)
SSMF        = pypho_fiber(glova = gp, l = 80.0e3,  D = 17.0,   S = 0, alpha = 0.3, gamma = 1.14, phi_max = 0.4)
DCF         = pypho_fiber(glova = gp, l = 1.0e3,  D = -SSMF.D*SSMF.l,   S = 0, alpha = 0.2e-12, gamma = 1.0e-12, phi_max = 10.0)
amp         = pypho_oamp(glova = gp, Pmean = 3.0, NF = 5)
osnr        = pypho_osnr(glova = gp)
modulator   = pypho_arbmod(glova = gp)
sigsampler  = pypho_sample(glova = gp)
cw_src      = pypho_cwlaser(glova = gp, power = 3 , Df = 0,  teta = np.pi/4.0)
filter_f0   = pypho_optfi(glova = gp, Df = 0, B = 50)

# Simulation

# Create bitpattern
bits_x = np.append(bitsrc(pattern = 'random'), [bitsrc(pattern = 'random'), bitsrc(pattern = 'random'), bitsrc(pattern = 'random')])
bits_y = np.append(bitsrc(pattern = 'random'), [bitsrc(pattern = 'random'), bitsrc(pattern = 'random'), bitsrc(pattern = 'random')])

# Create pulsetrain
onebits = bitsrc(pattern = 'ones')
esig = esigsrc(bitsequence = onebits)
E_Tx = sig_1550(esig = esig)

# Define constellation points: 16-QAM
alpha = np.arctan(np.sqrt(1.0)/3.0)
constpts_x = [(           [np.sqrt(3.0**2 + 1.0)]*8 + [np.sqrt(2.0)]*4 + [np.sqrt(2*3.0**2)]*4),
(          [2.0*np.pi*x/4.0+alpha for x in range(0,4)] + [2.0*np.pi*x/4.0+np.pi-alpha for x in range(0,4)] + [2.0*np.pi*x/4.0+np.pi/4 for x in range(0,8)] ),
(          [colors.values()[x] for x in range(0,16)]),
(          [x for x in range(0,16)]),
([(0),(0),(0),(0)], [(0),(0),(0),(1)], [(0),(0),(1),(0)], [(0),(0),(1),(1)], [(0),(1),(0),(0)], [(0),(1),(0),(1)], [(0),(1),(1),(0)], [(0),(1),(1),(1)],
[(1),(1),(1),(1)], [(1),(1),(1),(0)], [(1),(1),(0),(1)], [(1),(1),(0),(0)], [(1),(0),(1),(1)], [(1),(0),(1),(0)], [(1),(0),(0),(1)], [(1),(0),(0),(0)]
)]  # codes not optimized!

constpts_y = constpts_x         # Constellation

E   = modulator( E = E_Tx, constpoints = [constpts_x, constpts_y], bits = [bits_x, bits_y])          # Modulate

P0  = 0.0

E   = amp(E = E, Pmean = 0)
LO  = cw_src(power = 10.0*np.log10(1e5*np.mean( np.abs( E['E'])**2 ) ))   # Local oscillator
E   = amp(E = E, Pmean = P0)
E   = osnr( E = E, OSNR = 15.0 )          # Set initial OSNR to bad 20 dB

for c in range(0, 10):
print('Span: ', c)
fibres = pypho_fiber_birefringence.create_pmd_fibre(SSMF.l, 1e3, 0.00)
E = SSMF(E = E, birefarray = fibres)
E = DCF(E = E, l = 1.0)
E = amp(E = E, Pmean = P0)
print('OSNR = ', osnr( E = E))

############################
# Calculate decision matrix
############################

E = amp(E = E, Pmean = 0)

#Ein = copy.deepcopy(E)
plt.figure(1)
# Get decision matrix
Dec_x, Esx_re_ax, Esx_im_ax, Dec_y, Esy_re_ax, Esy_im_ax = get_decision_matrix(gp, E, [constpts_x, constpts_y], [bits_x, bits_y], LO, filter_f0, sigsampler)

# Plot decision matrix
plt.figure(1)
plt.subplot(2, 1, 1); h = plt.contourf(Esx_re_ax, Esx_im_ax, Dec_x, 32, cmap=plt.cm.bone  )
plt.subplot(2, 1, 2); h = plt.contourf(Esy_re_ax, Esy_im_ax, Dec_y, 32, cmap=plt.cm.bone )

############################
# Calculate BER
############################

BER = calc_BER (gp, E, [constpts_x, constpts_y], osnr( E = E), Dec_x, Dec_y, Esx_re_ax, Esx_im_ax, Esy_re_ax, Esy_im_ax, 1, LO, filter_f0, sigsampler)
print(BER)