mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-11-03 03:28:04 +00:00
@@ -98,7 +98,8 @@
|
|||||||
],
|
],
|
||||||
"Roadms":[{
|
"Roadms":[{
|
||||||
"gain_mode_default_loss": 20,
|
"gain_mode_default_loss": 20,
|
||||||
"power_mode_pout_target": -20
|
"power_mode_pout_target": -20,
|
||||||
|
"add_drop_osnr": 38
|
||||||
}],
|
}],
|
||||||
"SI":[{
|
"SI":[{
|
||||||
"f_min": 191.3e12,
|
"f_min": 191.3e12,
|
||||||
@@ -108,11 +109,8 @@
|
|||||||
"power_dbm": 0,
|
"power_dbm": 0,
|
||||||
"power_range_db": [0,0,0.5],
|
"power_range_db": [0,0,0.5],
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"OSNR": 11,
|
"tx_osnr": 40,
|
||||||
"bit_rate":100e9,
|
"sys_margins": 0
|
||||||
"tx_osnr": 45,
|
|
||||||
"min_spacing": 37.5e9,
|
|
||||||
"cost":1
|
|
||||||
}],
|
}],
|
||||||
"Transceiver":[
|
"Transceiver":[
|
||||||
{
|
{
|
||||||
@@ -129,7 +127,7 @@
|
|||||||
"OSNR": 11,
|
"OSNR": 11,
|
||||||
"bit_rate": 100e9,
|
"bit_rate": 100e9,
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 45,
|
"tx_osnr": 40,
|
||||||
"min_spacing": 37.5e9,
|
"min_spacing": 37.5e9,
|
||||||
"cost":1
|
"cost":1
|
||||||
},
|
},
|
||||||
@@ -139,7 +137,7 @@
|
|||||||
"OSNR": 15,
|
"OSNR": 15,
|
||||||
"bit_rate": 200e9,
|
"bit_rate": 200e9,
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 45,
|
"tx_osnr": 40,
|
||||||
"min_spacing": 75e9,
|
"min_spacing": 75e9,
|
||||||
"cost":1
|
"cost":1
|
||||||
}
|
}
|
||||||
@@ -158,7 +156,7 @@
|
|||||||
"OSNR": 12,
|
"OSNR": 12,
|
||||||
"bit_rate": 100e9,
|
"bit_rate": 100e9,
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 45,
|
"tx_osnr": 40,
|
||||||
"min_spacing": 37.5e9,
|
"min_spacing": 37.5e9,
|
||||||
"cost":1
|
"cost":1
|
||||||
},
|
},
|
||||||
@@ -168,7 +166,7 @@
|
|||||||
"OSNR": 18,
|
"OSNR": 18,
|
||||||
"bit_rate": 300e9,
|
"bit_rate": 300e9,
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 45,
|
"tx_osnr": 40,
|
||||||
"min_spacing": 62.5e9,
|
"min_spacing": 62.5e9,
|
||||||
"cost":1
|
"cost":1
|
||||||
},
|
},
|
||||||
@@ -178,7 +176,7 @@
|
|||||||
"OSNR": 21,
|
"OSNR": 21,
|
||||||
"bit_rate": 400e9,
|
"bit_rate": 400e9,
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 45,
|
"tx_osnr": 40,
|
||||||
"min_spacing": 75e9,
|
"min_spacing": 75e9,
|
||||||
"cost":1
|
"cost":1
|
||||||
},
|
},
|
||||||
@@ -188,7 +186,7 @@
|
|||||||
"OSNR": 16,
|
"OSNR": 16,
|
||||||
"bit_rate": 200e9,
|
"bit_rate": 200e9,
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 45,
|
"tx_osnr": 40,
|
||||||
"min_spacing": 75e9,
|
"min_spacing": 75e9,
|
||||||
"cost":1
|
"cost":1
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -121,7 +121,7 @@
|
|||||||
"type": "Roadm"
|
"type": "Roadm"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"uid": "ingress fused spans in Corlay",
|
"uid": "west fused spans in Corlay",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"location": {
|
"location": {
|
||||||
"city": "Corlay",
|
"city": "Corlay",
|
||||||
@@ -133,7 +133,7 @@
|
|||||||
"type": "Fused"
|
"type": "Fused"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"uid": "ingress fused spans in Loudeac",
|
"uid": "west fused spans in Loudeac",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"location": {
|
"location": {
|
||||||
"city": "Loudeac",
|
"city": "Loudeac",
|
||||||
@@ -145,7 +145,7 @@
|
|||||||
"type": "Fused"
|
"type": "Fused"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"uid": "ingress fused spans in Morlaix",
|
"uid": "west fused spans in Morlaix",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"location": {
|
"location": {
|
||||||
"city": "Morlaix",
|
"city": "Morlaix",
|
||||||
@@ -157,7 +157,7 @@
|
|||||||
"type": "Fused"
|
"type": "Fused"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"uid": "egress fused spans in Corlay",
|
"uid": "east fused spans in Corlay",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"location": {
|
"location": {
|
||||||
"city": "Corlay",
|
"city": "Corlay",
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
"type": "Fused"
|
"type": "Fused"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"uid": "egress fused spans in Loudeac",
|
"uid": "east fused spans in Loudeac",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"location": {
|
"location": {
|
||||||
"city": "Loudeac",
|
"city": "Loudeac",
|
||||||
@@ -181,7 +181,7 @@
|
|||||||
"type": "Fused"
|
"type": "Fused"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"uid": "egress fused spans in Morlaix",
|
"uid": "east fused spans in Morlaix",
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"location": {
|
"location": {
|
||||||
"city": "Morlaix",
|
"city": "Morlaix",
|
||||||
@@ -652,34 +652,34 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Lannion_CAS → Corlay)-F061",
|
"from_node": "fiber (Lannion_CAS → Corlay)-F061",
|
||||||
"to_node": "ingress fused spans in Corlay"
|
"to_node": "west fused spans in Corlay"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "ingress fused spans in Corlay",
|
"from_node": "west fused spans in Corlay",
|
||||||
"to_node": "fiber (Corlay → Loudeac)-F010"
|
"to_node": "fiber (Corlay → Loudeac)-F010"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Loudeac → Corlay)-F010",
|
"from_node": "fiber (Loudeac → Corlay)-F010",
|
||||||
"to_node": "egress fused spans in Corlay"
|
"to_node": "east fused spans in Corlay"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "egress fused spans in Corlay",
|
"from_node": "east fused spans in Corlay",
|
||||||
"to_node": "fiber (Corlay → Lannion_CAS)-F061"
|
"to_node": "fiber (Corlay → Lannion_CAS)-F061"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Corlay → Loudeac)-F010",
|
"from_node": "fiber (Corlay → Loudeac)-F010",
|
||||||
"to_node": "ingress fused spans in Loudeac"
|
"to_node": "west fused spans in Loudeac"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "ingress fused spans in Loudeac",
|
"from_node": "west fused spans in Loudeac",
|
||||||
"to_node": "fiber (Loudeac → Lorient_KMA)-F054"
|
"to_node": "fiber (Loudeac → Lorient_KMA)-F054"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Lorient_KMA → Loudeac)-F054",
|
"from_node": "fiber (Lorient_KMA → Loudeac)-F054",
|
||||||
"to_node": "egress fused spans in Loudeac"
|
"to_node": "east fused spans in Loudeac"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "egress fused spans in Loudeac",
|
"from_node": "east fused spans in Loudeac",
|
||||||
"to_node": "fiber (Loudeac → Corlay)-F010"
|
"to_node": "fiber (Loudeac → Corlay)-F010"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -748,18 +748,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Lannion_CAS → Morlaix)-F059",
|
"from_node": "fiber (Lannion_CAS → Morlaix)-F059",
|
||||||
"to_node": "ingress fused spans in Morlaix"
|
"to_node": "west fused spans in Morlaix"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "ingress fused spans in Morlaix",
|
"from_node": "west fused spans in Morlaix",
|
||||||
"to_node": "fiber (Morlaix → Brest_KLA)-F060"
|
"to_node": "fiber (Morlaix → Brest_KLA)-F060"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Brest_KLA → Morlaix)-F060",
|
"from_node": "fiber (Brest_KLA → Morlaix)-F060",
|
||||||
"to_node": "egress fused spans in Morlaix"
|
"to_node": "east fused spans in Morlaix"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "egress fused spans in Morlaix",
|
"from_node": "east fused spans in Morlaix",
|
||||||
"to_node": "fiber (Morlaix → Lannion_CAS)-F059"
|
"to_node": "fiber (Morlaix → Lannion_CAS)-F059"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,14 +74,20 @@ def requests_from_json(json_data,equipment):
|
|||||||
# params['power'] is updated
|
# params['power'] is updated
|
||||||
if req['path-constraints']['te-bandwidth']['output-power']:
|
if req['path-constraints']['te-bandwidth']['output-power']:
|
||||||
params['power'] = req['path-constraints']['te-bandwidth']['output-power']
|
params['power'] = req['path-constraints']['te-bandwidth']['output-power']
|
||||||
|
|
||||||
# same process for nb-channel
|
# same process for nb-channel
|
||||||
fmin = params['frequency']['min']
|
f_min = params['f_min']
|
||||||
fmax = params['frequency']['max']
|
f_max_from_si = params['f_max']
|
||||||
if req['path-constraints']['te-bandwidth']['max-nb-of-channel'] is not None :
|
if req['path-constraints']['te-bandwidth']['max-nb-of-channel'] is not None :
|
||||||
params['nb_channel'] = req['path-constraints']['te-bandwidth']['max-nb-of-channel']
|
nch = req['path-constraints']['te-bandwidth']['max-nb-of-channel']
|
||||||
|
params['nb_channel'] = nch
|
||||||
|
spacing = params['spacing']
|
||||||
|
params['f_max'] = f_min + nch*spacing
|
||||||
else :
|
else :
|
||||||
params['nb_channel'] = automatic_nch(fmin,fmax,params['spacing'])
|
params['nb_channel'] = automatic_nch(f_min,f_max_from_si,params['spacing'])
|
||||||
consitency_check(params)
|
|
||||||
|
consistency_check(params, f_max_from_si)
|
||||||
|
|
||||||
try :
|
try :
|
||||||
params['path_bandwidth'] = req['path-constraints']['te-bandwidth']['path_bandwidth']
|
params['path_bandwidth'] = req['path-constraints']['te-bandwidth']['path_bandwidth']
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@@ -89,10 +95,10 @@ def requests_from_json(json_data,equipment):
|
|||||||
requests_list.append(Path_request(**params))
|
requests_list.append(Path_request(**params))
|
||||||
return requests_list
|
return requests_list
|
||||||
|
|
||||||
def consitency_check(params):
|
def consistency_check(params, f_max_from_si):
|
||||||
fmin = params['frequency']['min']
|
f_min = params['f_min']
|
||||||
fmax = params['frequency']['max']
|
f_max = params['f_max']
|
||||||
max_recommanded_nb_channels = automatic_nch(fmin,fmax,
|
max_recommanded_nb_channels = automatic_nch(f_min,f_max,
|
||||||
params['spacing'])
|
params['spacing'])
|
||||||
if params['baud_rate'] is not None:
|
if params['baud_rate'] is not None:
|
||||||
#implicitely means that a mode is defined with min_spacing
|
#implicitely means that a mode is defined with min_spacing
|
||||||
@@ -103,10 +109,10 @@ def consitency_check(params):
|
|||||||
print(msg)
|
print(msg)
|
||||||
logger.critical(msg)
|
logger.critical(msg)
|
||||||
exit()
|
exit()
|
||||||
if params['nb_channel']>max_recommanded_nb_channels:
|
if f_max>f_max_from_si:
|
||||||
msg = dedent(f'''
|
msg = dedent(f'''
|
||||||
Requested channel number {params["nb_channel"]}, baud rate {params["baud_rate"]} GHz and requested spacing {params["spacing"]*1e-9}GHz
|
Requested channel number {params["nb_channel"]}, baud rate {params["baud_rate"]} GHz and requested spacing {params["spacing"]*1e-9}GHz
|
||||||
is not consistent with frequency range {fmin*1e-12} THz, {fmax*1e-12} THz, min recommanded spacing {params["min_spacing"]*1e-9}GHz.
|
is not consistent with frequency range {f_min*1e-12} THz, {f_max*1e-12} THz, min recommanded spacing {params["min_spacing"]*1e-9}GHz.
|
||||||
max recommanded nb of channels is {max_recommanded_nb_channels}
|
max recommanded nb of channels is {max_recommanded_nb_channels}
|
||||||
Computation stopped.''')
|
Computation stopped.''')
|
||||||
logger.critical(msg)
|
logger.critical(msg)
|
||||||
@@ -206,7 +212,7 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
|||||||
logger.warning(msg)
|
logger.warning(msg)
|
||||||
total_path = []
|
total_path = []
|
||||||
else:
|
else:
|
||||||
total_path,mode = propagate_and_optimize_mode(total_path,pathreq,equipment, show=False)
|
total_path,mode = propagate_and_optimize_mode(total_path,pathreq,equipment)
|
||||||
# if no baudrate satisfies spacing, no mode is returned and an empty path is returned
|
# if no baudrate satisfies spacing, no mode is returned and an empty path is returned
|
||||||
# a warning is shown in the propagate_and_optimize_mode
|
# a warning is shown in the propagate_and_optimize_mode
|
||||||
if mode is not None :
|
if mode is not None :
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from collections import namedtuple
|
|||||||
|
|
||||||
from gnpy.core.node import Node
|
from gnpy.core.node import Node
|
||||||
from gnpy.core.units import UNITS
|
from gnpy.core.units import UNITS
|
||||||
from gnpy.core.utils import lin2db, db2lin, itufs
|
from gnpy.core.utils import lin2db, db2lin, itufs, snr_sum
|
||||||
|
|
||||||
class Transceiver(Node):
|
class Transceiver(Node):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
@@ -35,20 +35,47 @@ class Transceiver(Node):
|
|||||||
self.osnr_nli = None
|
self.osnr_nli = None
|
||||||
self.snr = None
|
self.snr = None
|
||||||
self.passive = False
|
self.passive = False
|
||||||
|
self.baud_rate = None
|
||||||
|
|
||||||
def _calc_snr(self, spectral_info):
|
def _calc_snr(self, spectral_info):
|
||||||
with errstate(divide='ignore'):
|
with errstate(divide='ignore'):
|
||||||
self.osnr_ase = [lin2db(divide(c.power.signal, c.power.ase))
|
self.baud_rate = [c.baud_rate for c in spectral_info.carriers]
|
||||||
|
ratio_01nm = [lin2db(12.5e9/b_rate) for b_rate in self.baud_rate]
|
||||||
|
|
||||||
|
#set raw values to record original calculation, before update_snr()
|
||||||
|
self.raw_osnr_ase = [lin2db(divide(c.power.signal, c.power.ase))
|
||||||
for c in spectral_info.carriers]
|
for c in spectral_info.carriers]
|
||||||
ratio_01nm = [lin2db(12.5e9/c.baud_rate)
|
self.raw_osnr_ase_01nm = [ase - ratio for ase, ratio
|
||||||
|
in zip(self.raw_osnr_ase, ratio_01nm)]
|
||||||
|
self.raw_osnr_nli = [lin2db(divide(c.power.signal, c.power.nli))
|
||||||
for c in spectral_info.carriers]
|
for c in spectral_info.carriers]
|
||||||
self.osnr_ase_01nm = [ase - ratio for ase, ratio
|
self.raw_snr = [lin2db(divide(c.power.signal, c.power.nli+c.power.ase))
|
||||||
in zip(self.osnr_ase, ratio_01nm)]
|
|
||||||
self.osnr_nli = [lin2db(divide(c.power.signal, c.power.nli))
|
|
||||||
for c in spectral_info.carriers]
|
|
||||||
self.snr = [lin2db(divide(c.power.signal, c.power.nli+c.power.ase))
|
|
||||||
for c in spectral_info.carriers]
|
for c in spectral_info.carriers]
|
||||||
|
|
||||||
|
self.osnr_ase = self.raw_osnr_ase
|
||||||
|
self.osnr_ase_01nm = self.raw_osnr_ase_01nm
|
||||||
|
self.osnr_nli = self.raw_osnr_nli
|
||||||
|
self.snr = self.raw_snr
|
||||||
|
|
||||||
|
def update_snr(self, *args):
|
||||||
|
"""
|
||||||
|
snr_added in 0.1nm
|
||||||
|
compute SNR penalties such as transponder Tx_osnr or Roadm add_drop_osnr
|
||||||
|
only applied in request.py / propagate on the last Trasceiver node of the path
|
||||||
|
all penalties are added in a single call because to avoid uncontrolled cumul
|
||||||
|
"""
|
||||||
|
#use raw_values so that the added snr penalties are not cumulated
|
||||||
|
snr_added = 0
|
||||||
|
for s in args:
|
||||||
|
snr_added += db2lin(-s)
|
||||||
|
snr_added = -lin2db(snr_added)
|
||||||
|
self.osnr_ase = list(map(lambda x,y:snr_sum(x,y,snr_added),
|
||||||
|
self.raw_osnr_ase, self.baud_rate))
|
||||||
|
self.snr = list(map(lambda x,y:snr_sum(x,y,snr_added),
|
||||||
|
self.raw_snr, self.baud_rate))
|
||||||
|
self.osnr_ase_01nm = list(map(lambda x:snr_sum(x,12.5e9,snr_added),
|
||||||
|
self.raw_osnr_ase_01nm))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return {'uid' : self.uid,
|
return {'uid' : self.uid,
|
||||||
|
|||||||
@@ -25,9 +25,9 @@ Fiber = namedtuple('Fiber', 'type_variety dispersion gamma')
|
|||||||
Spans = namedtuple('Spans', 'power_mode delta_power_range_db max_length length_units \
|
Spans = namedtuple('Spans', 'power_mode delta_power_range_db max_length length_units \
|
||||||
max_loss padding EOL con_in con_out')
|
max_loss padding EOL con_in con_out')
|
||||||
Transceiver = namedtuple('Transceiver', 'type_variety frequency mode')
|
Transceiver = namedtuple('Transceiver', 'type_variety frequency mode')
|
||||||
Roadms = namedtuple('Roadms', 'gain_mode_default_loss power_mode_pout_target')
|
Roadms = namedtuple('Roadms', 'gain_mode_default_loss power_mode_pout_target add_drop_osnr')
|
||||||
SI = namedtuple('SI', 'f_min f_max baud_rate spacing roll_off \
|
SI = namedtuple('SI', 'f_min f_max baud_rate spacing roll_off \
|
||||||
power_dbm power_range_db OSNR bit_rate tx_osnr min_spacing cost')
|
power_dbm power_range_db tx_osnr sys_margins')
|
||||||
AmpBase = namedtuple(
|
AmpBase = namedtuple(
|
||||||
'AmpBase',
|
'AmpBase',
|
||||||
'type_variety type_def gain_flatmax gain_min p_max'
|
'type_variety type_def gain_flatmax gain_min p_max'
|
||||||
@@ -162,6 +162,8 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
trxs = equipment['Transceiver']
|
trxs = equipment['Transceiver']
|
||||||
|
#if called from path_requests_run.py, trx_mode is filled with None when not specified by user
|
||||||
|
#if called from transmission_main.py, trx_mode is ''
|
||||||
if trx_mode is not None:
|
if trx_mode is not None:
|
||||||
mode_params = next(mode for trx in trxs \
|
mode_params = next(mode for trx in trxs \
|
||||||
if trx == trx_type_variety \
|
if trx == trx_type_variety \
|
||||||
@@ -184,7 +186,8 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F
|
|||||||
"min_spacing":None,
|
"min_spacing":None,
|
||||||
"cost":None}
|
"cost":None}
|
||||||
trx_params = {**mode_params}
|
trx_params = {**mode_params}
|
||||||
trx_params['frequency'] = equipment['Transceiver'][trx_type_variety].frequency
|
trx_params['f_min'] = equipment['Transceiver'][trx_type_variety].frequency['min']
|
||||||
|
trx_params['f_max'] = equipment['Transceiver'][trx_type_variety].frequency['max']
|
||||||
|
|
||||||
# TODO: novel automatic feature maybe unwanted if spacing is specified
|
# TODO: novel automatic feature maybe unwanted if spacing is specified
|
||||||
# trx_params['spacing'] = automatic_spacing(trx_params['baud_rate'])
|
# trx_params['spacing'] = automatic_spacing(trx_params['baud_rate'])
|
||||||
@@ -198,21 +201,18 @@ def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=F
|
|||||||
else:
|
else:
|
||||||
# default transponder charcteristics
|
# default transponder charcteristics
|
||||||
# mainly used with transmission_main_example.py
|
# mainly used with transmission_main_example.py
|
||||||
trx_params['frequency'] = {'min': default_si_data.f_min, 'max': default_si_data.f_max}
|
trx_params['f_min'] = default_si_data.f_min
|
||||||
|
trx_params['f_max'] = default_si_data.f_max
|
||||||
trx_params['baud_rate'] = default_si_data.baud_rate
|
trx_params['baud_rate'] = default_si_data.baud_rate
|
||||||
trx_params['spacing'] = default_si_data.spacing
|
trx_params['spacing'] = default_si_data.spacing
|
||||||
trx_params['OSNR'] = default_si_data.OSNR
|
trx_params['OSNR'] = None
|
||||||
trx_params['bit_rate'] = default_si_data.bit_rate
|
trx_params['bit_rate'] = None
|
||||||
trx_params['cost'] = default_si_data.cost
|
trx_params['cost'] = None
|
||||||
trx_params['roll_off'] = default_si_data.roll_off
|
trx_params['roll_off'] = default_si_data.roll_off
|
||||||
trx_params['nb_channel'] = automatic_nch(trx_params['frequency']['min'],
|
|
||||||
trx_params['frequency']['max'],
|
|
||||||
trx_params['spacing'])
|
|
||||||
trx_params['tx_osnr'] = default_si_data.tx_osnr
|
trx_params['tx_osnr'] = default_si_data.tx_osnr
|
||||||
trx_params['min_spacing'] = default_si_data.min_spacing
|
trx_params['min_spacing'] = None
|
||||||
nch = automatic_nch(trx_params['frequency']['min'],
|
nch = automatic_nch(trx_params['f_min'], trx_params['f_max'], trx_params['spacing'])
|
||||||
trx_params['frequency']['max'],
|
trx_params['nb_channel'] = nch
|
||||||
trx_params['spacing'])
|
|
||||||
print(f'There are {nch} channels propagating')
|
print(f'There are {nch} channels propagating')
|
||||||
|
|
||||||
trx_params['power'] = db2lin(default_si_data.power_dbm)*1e-3
|
trx_params['power'] = db2lin(default_si_data.power_dbm)*1e-3
|
||||||
@@ -229,10 +229,20 @@ def automatic_spacing(baud_rate):
|
|||||||
def automatic_nch(f_min, f_max, spacing):
|
def automatic_nch(f_min, f_max, spacing):
|
||||||
return int((f_max - f_min)//spacing)
|
return int((f_max - f_min)//spacing)
|
||||||
|
|
||||||
|
def automatic_fmax(f_min, spacing, nch):
|
||||||
|
return f_min + spacing * nch
|
||||||
|
|
||||||
def load_equipment(filename):
|
def load_equipment(filename):
|
||||||
json_data = load_json(filename)
|
json_data = load_json(filename)
|
||||||
return equipment_from_json(json_data, filename)
|
return equipment_from_json(json_data, filename)
|
||||||
|
|
||||||
|
def update_trx_osnr(equipment):
|
||||||
|
"""add sys_margins to all Transceivers OSNR values"""
|
||||||
|
for trx in equipment['Transceiver'].values():
|
||||||
|
for m in trx.mode:
|
||||||
|
m['OSNR'] = m['OSNR'] + equipment['SI']['default'].sys_margins
|
||||||
|
return equipment
|
||||||
|
|
||||||
def equipment_from_json(json_data, filename):
|
def equipment_from_json(json_data, filename):
|
||||||
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
||||||
edfa type type_variety, fiber type_variety
|
edfa type type_variety, fiber type_variety
|
||||||
@@ -257,4 +267,5 @@ def equipment_from_json(json_data, filename):
|
|||||||
equipment[key][subkey] = Amp.from_default_json(config, **entry)
|
equipment[key][subkey] = Amp.from_default_json(config, **entry)
|
||||||
else:
|
else:
|
||||||
equipment[key][subkey] = typ(**entry)
|
equipment[key][subkey] = typ(**entry)
|
||||||
|
equipment = update_trx_osnr(equipment)
|
||||||
return equipment
|
return equipment
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ from numpy import array
|
|||||||
from gnpy.core.utils import lin2db, db2lin
|
from gnpy.core.utils import lin2db, db2lin
|
||||||
from json import loads
|
from json import loads
|
||||||
from gnpy.core.utils import load_json
|
from gnpy.core.utils import load_json
|
||||||
|
from gnpy.core.equipment import automatic_nch, automatic_spacing
|
||||||
|
|
||||||
class ConvenienceAccess:
|
class ConvenienceAccess:
|
||||||
|
|
||||||
@@ -56,18 +57,17 @@ def merge_input_spectral_information(*si):
|
|||||||
#TODO
|
#TODO
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def create_input_spectral_information(f_min, roll_off, baud_rate, power, spacing, nb_channel, tx_osnr):
|
def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing):
|
||||||
# pref in dB : convert power lin into power in dB
|
# pref in dB : convert power lin into power in dB
|
||||||
pref = lin2db(power * 1e3)
|
pref = lin2db(power * 1e3)
|
||||||
ase_power = (power / db2lin(tx_osnr)) * (baud_rate / 12.5e9)
|
|
||||||
si = SpectralInformation(pref=Pref(pref, pref))
|
si = SpectralInformation(pref=Pref(pref, pref))
|
||||||
|
nb_channel = automatic_nch(f_min, f_max, spacing)
|
||||||
si = si.update(carriers=[
|
si = si.update(carriers=[
|
||||||
Channel(f, (f_min+spacing*f),
|
Channel(f, (f_min+spacing*f),
|
||||||
baud_rate, roll_off, Power(power, 0, ase_power)) for f in range(1,nb_channel+1)
|
baud_rate, roll_off, Power(power, 0, 0)) for f in range(1,nb_channel+1)
|
||||||
])
|
])
|
||||||
return si
|
return si
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
pref = lin2db(power * 1e3)
|
pref = lin2db(power * 1e3)
|
||||||
si = SpectralInformation(
|
si = SpectralInformation(
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ logger = getLogger(__name__)
|
|||||||
|
|
||||||
|
|
||||||
RequestParams = namedtuple('RequestParams','request_id source destination trx_type'+
|
RequestParams = namedtuple('RequestParams','request_id source destination trx_type'+
|
||||||
' trx_mode nodes_list loose_list spacing power nb_channel frequency format baud_rate OSNR bit_rate roll_off tx_osnr min_spacing cost path_bandwidth')
|
' trx_mode nodes_list loose_list spacing power nb_channel f_min f_max format baud_rate OSNR bit_rate roll_off tx_osnr min_spacing cost path_bandwidth')
|
||||||
DisjunctionParams = namedtuple('DisjunctionParams','disjunction_id relaxable link_diverse node_diverse disjunctions_req')
|
DisjunctionParams = namedtuple('DisjunctionParams','disjunction_id relaxable link_diverse node_diverse disjunctions_req')
|
||||||
|
|
||||||
class Path_request:
|
class Path_request:
|
||||||
@@ -51,7 +51,8 @@ class Path_request:
|
|||||||
self.spacing = params.spacing
|
self.spacing = params.spacing
|
||||||
self.power = params.power
|
self.power = params.power
|
||||||
self.nb_channel = params.nb_channel
|
self.nb_channel = params.nb_channel
|
||||||
self.frequency = params.frequency
|
self.f_min = params.f_min
|
||||||
|
self.f_max = params.f_max
|
||||||
self.format = params.format
|
self.format = params.format
|
||||||
self.OSNR = params.OSNR
|
self.OSNR = params.OSNR
|
||||||
self.bit_rate = params.bit_rate
|
self.bit_rate = params.bit_rate
|
||||||
@@ -388,23 +389,23 @@ def propagate(path, req, equipment, show=False):
|
|||||||
#update roadm loss in case of power sweep (power mode only)
|
#update roadm loss in case of power sweep (power mode only)
|
||||||
set_roadm_loss(path, equipment, lin2db(req.power*1e3))
|
set_roadm_loss(path, equipment, lin2db(req.power*1e3))
|
||||||
si = create_input_spectral_information(
|
si = create_input_spectral_information(
|
||||||
req.frequency['min'], req.roll_off, req.baud_rate,
|
req.f_min, req.f_max, req.roll_off, req.baud_rate,
|
||||||
req.power, req.spacing, req.nb_channel, req.tx_osnr)
|
req.power, req.spacing)
|
||||||
for el in path:
|
for el in path:
|
||||||
si = el(si)
|
si = el(si)
|
||||||
if show :
|
if show :
|
||||||
print(el)
|
print(el)
|
||||||
|
path[-1].update_snr(req.tx_osnr, equipment['Roadms']['default'].add_drop_osnr)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def propagate_and_optimize_mode(path, req, equipment, show=False):
|
def propagate_and_optimize_mode(path, req, equipment):
|
||||||
#update roadm loss in case of power sweep (power mode only)
|
#update roadm loss in case of power sweep (power mode only)
|
||||||
set_roadm_loss(path, equipment, lin2db(req.power*1e3))
|
set_roadm_loss(path, equipment, lin2db(req.power*1e3))
|
||||||
# if mode is unknown : loops on the modes starting from the highest baudrate fiting in the
|
# if mode is unknown : loops on the modes starting from the highest baudrate fiting in the
|
||||||
# spacing. TODO add a min_spacing attribute in transceivers. for now just using baudrate*1.1
|
|
||||||
# step 1: create an ordered list of modes based on baudrate
|
# step 1: create an ordered list of modes based on baudrate
|
||||||
baudrate_to_explore = list(set([m['baud_rate'] for m in equipment['Transceiver'][req.tsp].mode
|
baudrate_to_explore = list(set([m['baud_rate'] for m in equipment['Transceiver'][req.tsp].mode
|
||||||
if float(m['min_spacing'])<= req.spacing]))
|
if float(m['min_spacing'])<= req.spacing]))
|
||||||
# TODO be carefull on limits cases if min_spacing very close to req spacing eg 50.001 50.000
|
# TODO be carefull on limits cases if spacing very close to req spacing eg 50.001 50.000
|
||||||
baudrate_to_explore = sorted(baudrate_to_explore, reverse=True)
|
baudrate_to_explore = sorted(baudrate_to_explore, reverse=True)
|
||||||
if baudrate_to_explore :
|
if baudrate_to_explore :
|
||||||
# at least 1 baudrate can be tested wrt spacing
|
# at least 1 baudrate can be tested wrt spacing
|
||||||
@@ -418,15 +419,14 @@ def propagate_and_optimize_mode(path, req, equipment, show=False):
|
|||||||
found_a_feasible_mode = False
|
found_a_feasible_mode = False
|
||||||
# TODO : the case of roll of is not included: for now use SI one
|
# TODO : the case of roll of is not included: for now use SI one
|
||||||
# TODO : if the loop in mode optimization does not have a feasible path, then bugs
|
# TODO : if the loop in mode optimization does not have a feasible path, then bugs
|
||||||
for m in modes_to_explore :
|
|
||||||
si = create_input_spectral_information(
|
si = create_input_spectral_information(
|
||||||
req.frequency['min'], equipment['SI']['default'].roll_off,
|
req.f_min, req.f_max, equipment['SI']['default'].roll_off,
|
||||||
b, req.power, req.spacing, req.nb_channel, m['tx_osnr'])
|
b, req.power, req.spacing)
|
||||||
for el in path:
|
for el in path:
|
||||||
si = el(si)
|
si = el(si)
|
||||||
if show :
|
for m in modes_to_explore :
|
||||||
print(el)
|
|
||||||
if path[-1].snr is not None:
|
if path[-1].snr is not None:
|
||||||
|
path[-1].update_snr(m['tx_osnr'], equipment['Roadms']['default'].add_drop_osnr)
|
||||||
if round(min(path[-1].snr+lin2db(b/(12.5e9))),2) > m['OSNR'] :
|
if round(min(path[-1].snr+lin2db(b/(12.5e9))),2) > m['OSNR'] :
|
||||||
found_a_feasible_mode = True
|
found_a_feasible_mode = True
|
||||||
return path, m
|
return path, m
|
||||||
@@ -869,7 +869,8 @@ def compare_reqs(req1,req2,disjlist) :
|
|||||||
req1.spacing == req2.spacing and \
|
req1.spacing == req2.spacing and \
|
||||||
req1.power == req2.power and \
|
req1.power == req2.power and \
|
||||||
req1.nb_channel == req2.nb_channel and \
|
req1.nb_channel == req2.nb_channel and \
|
||||||
req1.frequency == req2.frequency and \
|
req1.f_min == req2.f_min and \
|
||||||
|
req1.f_max == req2.f_max and \
|
||||||
req1.format == req2.format and \
|
req1.format == req2.format and \
|
||||||
req1.OSNR == req2.OSNR and \
|
req1.OSNR == req2.OSNR and \
|
||||||
req1.roll_off == req2.roll_off and \
|
req1.roll_off == req2.roll_off and \
|
||||||
|
|||||||
@@ -120,6 +120,10 @@ def freq2wavelength(value):
|
|||||||
"""
|
"""
|
||||||
return c() / value
|
return c() / value
|
||||||
|
|
||||||
|
def snr_sum(snr, bw, snr_added, bw_added=12.5e9):
|
||||||
|
snr_added = snr_added - lin2db(bw/bw_added)
|
||||||
|
snr = -lin2db(db2lin(-snr)+db2lin(-snr_added))
|
||||||
|
return snr
|
||||||
|
|
||||||
def deltawl2deltaf(delta_wl, wavelength):
|
def deltawl2deltaf(delta_wl, wavelength):
|
||||||
""" deltawl2deltaf(delta_wl, wavelength):
|
""" deltawl2deltaf(delta_wl, wavelength):
|
||||||
|
|||||||
@@ -66,7 +66,8 @@
|
|||||||
],
|
],
|
||||||
"Roadms":[{
|
"Roadms":[{
|
||||||
"gain_mode_default_loss": 20,
|
"gain_mode_default_loss": 20,
|
||||||
"power_mode_pout_target": -20
|
"power_mode_pout_target": -20,
|
||||||
|
"add_drop_osnr": 100
|
||||||
}],
|
}],
|
||||||
"SI":[{
|
"SI":[{
|
||||||
"f_min": 191.3e12,
|
"f_min": 191.3e12,
|
||||||
@@ -76,11 +77,8 @@
|
|||||||
"power_dbm": 0,
|
"power_dbm": 0,
|
||||||
"power_range_db": [0,0.5,0.5],
|
"power_range_db": [0,0.5,0.5],
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"OSNR": 15,
|
|
||||||
"bit_rate":100e9,
|
|
||||||
"tx_osnr": 100,
|
"tx_osnr": 100,
|
||||||
"min_spacing": 50e9,
|
"sys_margins": 0
|
||||||
"cost":1
|
|
||||||
}],
|
}],
|
||||||
"Transceiver":[
|
"Transceiver":[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ from json import load
|
|||||||
from gnpy.core.elements import Transceiver, Fiber, Edfa
|
from gnpy.core.elements import Transceiver, Fiber, Edfa
|
||||||
from gnpy.core.utils import lin2db, db2lin
|
from gnpy.core.utils import lin2db, db2lin
|
||||||
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power, Pref
|
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power, Pref
|
||||||
from gnpy.core.equipment import load_equipment
|
from gnpy.core.equipment import load_equipment, automatic_fmax
|
||||||
from gnpy.core.network import build_network, load_network, set_roadm_loss
|
from gnpy.core.network import build_network, load_network, set_roadm_loss
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import pytest
|
import pytest
|
||||||
@@ -66,7 +66,9 @@ def setup_trx():
|
|||||||
def si(nch_and_spacing, bw):
|
def si(nch_and_spacing, bw):
|
||||||
"""parametrize a channel comb with nb_channel, spacing and signal bw"""
|
"""parametrize a channel comb with nb_channel, spacing and signal bw"""
|
||||||
nb_channel, spacing = nch_and_spacing
|
nb_channel, spacing = nch_and_spacing
|
||||||
return create_input_spectral_information(191.3e12, 0.15, bw, 1e-3, spacing, nb_channel, 100)
|
f_min = 191.3e12
|
||||||
|
f_max = automatic_fmax(f_min, spacing, nb_channel)
|
||||||
|
return create_input_spectral_information(f_min, f_max, 0.15, bw, 1e-3, spacing)
|
||||||
|
|
||||||
@pytest.mark.parametrize("gain, nf_expected", [(10, 15), (15, 10), (25, 5.8)])
|
@pytest.mark.parametrize("gain, nf_expected", [(10, 15), (15, 10), (25, 5.8)])
|
||||||
def test_variable_gain_nf(gain, nf_expected, setup_edfa_variable_gain, si):
|
def test_variable_gain_nf(gain, nf_expected, setup_edfa_variable_gain, si):
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ def test_automaticmodefeature(net,eqpt,serv,expected_mode):
|
|||||||
path_res_list.append(pathreq.format)
|
path_res_list.append(pathreq.format)
|
||||||
total_path = propagate(total_path,pathreq,equipment, show=False)
|
total_path = propagate(total_path,pathreq,equipment, show=False)
|
||||||
else:
|
else:
|
||||||
total_path,mode = propagate_and_optimize_mode(total_path,pathreq,equipment, show=False)
|
total_path,mode = propagate_and_optimize_mode(total_path,pathreq,equipment)
|
||||||
# if no baudrate satisfies spacing, no mode is returned and an empty path is returned
|
# if no baudrate satisfies spacing, no mode is returned and an empty path is returned
|
||||||
# a warning is shown in the propagate_and_optimize_mode
|
# a warning is shown in the propagate_and_optimize_mode
|
||||||
if mode is not None :
|
if mode is not None :
|
||||||
|
|||||||
Reference in New Issue
Block a user