As there are a variety of modulation formats, pypho offers a simple generic signal modulator.
You can define each constellation in the complex plain in a list:
For exampel a 16QAM:
constpts = [([1.0]*16),
([2.0*np.pi*x/16.0 for x in range(0,16)] ),
([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)]
)]
Every item of the list is an array with the same number of elements.
Fig. 1 : 16QAM constellation diagramm
In the follwoing example you can find definitions of the most important modulation formats.
##!/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_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 = 4*128, sps = 128, symbolrate = 10e9)
bitsrc = pypho_bits(glova = gp, nob = gp.nos, pattern = 'ones')
esigsrc = pypho_signalsrc(glova = gp, pulseshape = 'gauss_rz' , fwhm = 0.33)
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.2, gamma = 1.14, phi_max = 0.01)
DCF = pypho_fiber(glova = gp, l = 1.0e3, D = -SSMF.D*SSMF.l*1.0e-3, S = 0, alpha = 0.2e-12, gamma = 1.0e-9, phi_max = 10.0)
amp = pypho_oamp(glova = gp, Pmean = 3.0, NF = 5)
osnr = pypho_osnr(glova = gp)
modulator= pypho_arbmod(glova = gp)
cstdgr = pypho_sample(glova = gp)
# Simulation
# Create bitpattern (enough up to 4 bits per symbol)
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)
# OOK
constpts_ook = [( [0.001, 1.0]),
( [0.0, 0.0] ),
( [colors.values()[x] for x in range(0,2)]),
( [x for x in range(0,2)]),
( [(0)], [(1)] )]
# 8-PSK
constpts_8psk = [( [1.0]*8),
( [ 2.0*np.pi*x/8.0 for x in range(0,8)] ),
( [colors.values()[x] for x in range(0,8)]),
( [x for x in range(0,8)]),
([(0),(0),(0)], [(0),(0),(1)], [(0),(1),(0)], [(0),(1),(1)], [(1),(1),(1)], [(1),(1),(0)], [(1),(0),(1)], [(1),(0),(0)],
)]
# 16-PSK
constpts_16psk = [( [1.0]*16),
( [ 2.0*np.pi*x/16.0 for x in range(0,16)] ),
( [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)]
)]
# 4-QAM
constpts_4qam = [( [1.0]*4),
( [ 2.0*np.pi*x/4.0+np.pi/4 for x in range(0,4)] ),
( [colors.values()[x] for x in range(0,4)]),
( [x for x in range(0,4)]),
( [(0),(0)], [(0),(1)], [(1),(1)], [(1),(0)] )]
# 16-QAM
alpha = np.arctan(np.sqrt(1.0)/3.0)
constpts_16qam = [( [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 = constpts_4qam
E = modulator( E = E_Tx, constpoints = [constpts, constpts], bits = [bits_x, bits_y]) # Modulate
P0 = 4
E = amp(E = E, Pmean = P0)
E = osnr( E = E, OSNR = 58.0 ) # Set initial OSNR to 58 dB
plt.figure(1)
cstdgr(E = E, constpoints = [constpts, constpts], bits = [bits_x, bits_y], style = 'o,o') # Plot constallation diagramme
E_Tx = copy.deepcopy(E)
n_span = 10
E = amp(E = E, Pmean = P0)
for c in range(0, n_span): # Transmission fiber
print('Span: ', c)
fibres = pypho_fiber_birefringence.create_pmd_fibre(SSMF.l, 1.0e3, 0.00)
E = SSMF(E = E, birefarray = fibres)
E = amp(E = E, Pmean = P0)
for c in range(0, n_span): # Dispersion compensation
E = DCF(E = E)
plt.figure(2)
cstdgr(E = E, sampletime = gp.sps/2, constpoints = [constpts, constpts], bits = [bits_x, bits_y], style = 'o,o') # Plot constallation diagramme
plt.subplot(2, 1, 1); plt.grid(True); plt.title("Output signal", loc='left'); plt.subplot(2, 1, 2); plt.grid(True); plt.show()
# Plot power and phase of the signal
plt.figure(3)
plt.subplot(2, 1, 1)
plt.title("Input signal", loc='left')
plt.plot(gp.timeax*1.0e12, np.abs(E[0]['E'][0])**2, 'r', label='$E_x(0, t)$')
plt.plot(gp.timeax*1.0e12, np.abs(E[0]['E'][1])**2, 'g', label='$E_y(0, t)$')
plt.ylabel('$10log |E_{x,y}|^2$'); plt.xlabel('Time [ps]'); plt.grid(True)
plt.subplot(2, 1, 2)
plt.plot(gp.timeax*1.0e12, np.angle(E[0]['E'][0]), 'r')
plt.plot(gp.timeax*1.0e12, np.angle(E[0]['E'][1]), 'g')
plt.ylabel('$ \phi_{x,y} $'); plt.xlabel('Time [ps]');plt.grid(True); plt.legend(); plt.show()