mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-30 01:32:21 +00:00
@@ -98,7 +98,8 @@
|
||||
],
|
||||
"Roadms":[{
|
||||
"gain_mode_default_loss": 20,
|
||||
"power_mode_pout_target": -20
|
||||
"power_mode_pout_target": -20,
|
||||
"add_drop_osnr": 38
|
||||
}],
|
||||
"SI":[{
|
||||
"f_min": 191.3e12,
|
||||
@@ -108,11 +109,8 @@
|
||||
"power_dbm": 0,
|
||||
"power_range_db": [0,0,0.5],
|
||||
"roll_off": 0.15,
|
||||
"OSNR": 11,
|
||||
"bit_rate":100e9,
|
||||
"tx_osnr": 45,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost":1
|
||||
"tx_osnr": 40,
|
||||
"sys_margins": 0
|
||||
}],
|
||||
"Transceiver":[
|
||||
{
|
||||
@@ -129,7 +127,7 @@
|
||||
"OSNR": 11,
|
||||
"bit_rate": 100e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 45,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost":1
|
||||
},
|
||||
@@ -139,7 +137,7 @@
|
||||
"OSNR": 15,
|
||||
"bit_rate": 200e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 45,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost":1
|
||||
}
|
||||
@@ -158,7 +156,7 @@
|
||||
"OSNR": 12,
|
||||
"bit_rate": 100e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 45,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost":1
|
||||
},
|
||||
@@ -168,7 +166,7 @@
|
||||
"OSNR": 18,
|
||||
"bit_rate": 300e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 45,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 62.5e9,
|
||||
"cost":1
|
||||
},
|
||||
@@ -178,7 +176,7 @@
|
||||
"OSNR": 21,
|
||||
"bit_rate": 400e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 45,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost":1
|
||||
},
|
||||
@@ -188,7 +186,7 @@
|
||||
"OSNR": 16,
|
||||
"bit_rate": 200e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 45,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost":1
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@
|
||||
"type": "Roadm"
|
||||
},
|
||||
{
|
||||
"uid": "ingress fused spans in Corlay",
|
||||
"uid": "west fused spans in Corlay",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Corlay",
|
||||
@@ -133,7 +133,7 @@
|
||||
"type": "Fused"
|
||||
},
|
||||
{
|
||||
"uid": "ingress fused spans in Loudeac",
|
||||
"uid": "west fused spans in Loudeac",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Loudeac",
|
||||
@@ -145,7 +145,7 @@
|
||||
"type": "Fused"
|
||||
},
|
||||
{
|
||||
"uid": "ingress fused spans in Morlaix",
|
||||
"uid": "west fused spans in Morlaix",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Morlaix",
|
||||
@@ -157,7 +157,7 @@
|
||||
"type": "Fused"
|
||||
},
|
||||
{
|
||||
"uid": "egress fused spans in Corlay",
|
||||
"uid": "east fused spans in Corlay",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Corlay",
|
||||
@@ -169,7 +169,7 @@
|
||||
"type": "Fused"
|
||||
},
|
||||
{
|
||||
"uid": "egress fused spans in Loudeac",
|
||||
"uid": "east fused spans in Loudeac",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Loudeac",
|
||||
@@ -181,7 +181,7 @@
|
||||
"type": "Fused"
|
||||
},
|
||||
{
|
||||
"uid": "egress fused spans in Morlaix",
|
||||
"uid": "east fused spans in Morlaix",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Morlaix",
|
||||
@@ -652,34 +652,34 @@
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
@@ -748,18 +748,18 @@
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
"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"
|
||||
},
|
||||
{
|
||||
|
||||
@@ -74,14 +74,20 @@ def requests_from_json(json_data,equipment):
|
||||
# params['power'] is updated
|
||||
if req['path-constraints']['te-bandwidth']['output-power']:
|
||||
params['power'] = req['path-constraints']['te-bandwidth']['output-power']
|
||||
|
||||
# same process for nb-channel
|
||||
fmin = params['frequency']['min']
|
||||
fmax = params['frequency']['max']
|
||||
f_min = params['f_min']
|
||||
f_max_from_si = params['f_max']
|
||||
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 :
|
||||
params['nb_channel'] = automatic_nch(fmin,fmax,params['spacing'])
|
||||
consitency_check(params)
|
||||
params['nb_channel'] = automatic_nch(f_min,f_max_from_si,params['spacing'])
|
||||
|
||||
consistency_check(params, f_max_from_si)
|
||||
|
||||
try :
|
||||
params['path_bandwidth'] = req['path-constraints']['te-bandwidth']['path_bandwidth']
|
||||
except KeyError:
|
||||
@@ -89,11 +95,11 @@ def requests_from_json(json_data,equipment):
|
||||
requests_list.append(Path_request(**params))
|
||||
return requests_list
|
||||
|
||||
def consitency_check(params):
|
||||
fmin = params['frequency']['min']
|
||||
fmax = params['frequency']['max']
|
||||
max_recommanded_nb_channels = automatic_nch(fmin,fmax,
|
||||
params['spacing'])
|
||||
def consistency_check(params, f_max_from_si):
|
||||
f_min = params['f_min']
|
||||
f_max = params['f_max']
|
||||
max_recommanded_nb_channels = automatic_nch(f_min,f_max,
|
||||
params['spacing'])
|
||||
if params['baud_rate'] is not None:
|
||||
#implicitely means that a mode is defined with min_spacing
|
||||
if params['min_spacing']>params['spacing'] :
|
||||
@@ -103,10 +109,10 @@ def consitency_check(params):
|
||||
print(msg)
|
||||
logger.critical(msg)
|
||||
exit()
|
||||
if params['nb_channel']>max_recommanded_nb_channels:
|
||||
if f_max>f_max_from_si:
|
||||
msg = dedent(f'''
|
||||
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}
|
||||
Computation stopped.''')
|
||||
logger.critical(msg)
|
||||
@@ -206,7 +212,7 @@ def compute_path_with_disjunction(network, equipment, pathreqlist, pathlist):
|
||||
logger.warning(msg)
|
||||
total_path = []
|
||||
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
|
||||
# a warning is shown in the propagate_and_optimize_mode
|
||||
if mode is not None :
|
||||
|
||||
@@ -25,7 +25,7 @@ from collections import namedtuple
|
||||
|
||||
from gnpy.core.node import Node
|
||||
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):
|
||||
def __init__(self, *args, **kwargs):
|
||||
@@ -35,20 +35,47 @@ class Transceiver(Node):
|
||||
self.osnr_nli = None
|
||||
self.snr = None
|
||||
self.passive = False
|
||||
self.baud_rate = None
|
||||
|
||||
def _calc_snr(self, spectral_info):
|
||||
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]
|
||||
ratio_01nm = [lin2db(12.5e9/c.baud_rate)
|
||||
for c in spectral_info.carriers]
|
||||
self.osnr_ase_01nm = [ase - ratio for ase, ratio
|
||||
in zip(self.osnr_ase, ratio_01nm)]
|
||||
self.osnr_nli = [lin2db(divide(c.power.signal, c.power.nli))
|
||||
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]
|
||||
self.snr = [lin2db(divide(c.power.signal, c.power.nli+c.power.ase))
|
||||
self.raw_snr = [lin2db(divide(c.power.signal, c.power.nli+c.power.ase))
|
||||
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
|
||||
def to_json(self):
|
||||
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 \
|
||||
max_loss padding EOL con_in con_out')
|
||||
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 \
|
||||
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',
|
||||
'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:
|
||||
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:
|
||||
mode_params = next(mode for trx in trxs \
|
||||
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,
|
||||
"cost":None}
|
||||
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
|
||||
# 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:
|
||||
# default transponder charcteristics
|
||||
# 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['spacing'] = default_si_data.spacing
|
||||
trx_params['OSNR'] = default_si_data.OSNR
|
||||
trx_params['bit_rate'] = default_si_data.bit_rate
|
||||
trx_params['cost'] = default_si_data.cost
|
||||
trx_params['OSNR'] = None
|
||||
trx_params['bit_rate'] = None
|
||||
trx_params['cost'] = None
|
||||
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['min_spacing'] = default_si_data.min_spacing
|
||||
nch = automatic_nch(trx_params['frequency']['min'],
|
||||
trx_params['frequency']['max'],
|
||||
trx_params['spacing'])
|
||||
trx_params['min_spacing'] = None
|
||||
nch = automatic_nch(trx_params['f_min'], trx_params['f_max'], trx_params['spacing'])
|
||||
trx_params['nb_channel'] = nch
|
||||
print(f'There are {nch} channels propagating')
|
||||
|
||||
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):
|
||||
return int((f_max - f_min)//spacing)
|
||||
|
||||
def automatic_fmax(f_min, spacing, nch):
|
||||
return f_min + spacing * nch
|
||||
|
||||
def load_equipment(filename):
|
||||
json_data = load_json(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):
|
||||
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
||||
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)
|
||||
else:
|
||||
equipment[key][subkey] = typ(**entry)
|
||||
equipment = update_trx_osnr(equipment)
|
||||
return equipment
|
||||
|
||||
@@ -14,6 +14,7 @@ from numpy import array
|
||||
from gnpy.core.utils import lin2db, db2lin
|
||||
from json import loads
|
||||
from gnpy.core.utils import load_json
|
||||
from gnpy.core.equipment import automatic_nch, automatic_spacing
|
||||
|
||||
class ConvenienceAccess:
|
||||
|
||||
@@ -56,18 +57,17 @@ def merge_input_spectral_information(*si):
|
||||
#TODO
|
||||
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 = lin2db(power * 1e3)
|
||||
ase_power = (power / db2lin(tx_osnr)) * (baud_rate / 12.5e9)
|
||||
si = SpectralInformation(pref=Pref(pref, pref))
|
||||
nb_channel = automatic_nch(f_min, f_max, spacing)
|
||||
si = si.update(carriers=[
|
||||
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
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pref = lin2db(power * 1e3)
|
||||
si = SpectralInformation(
|
||||
|
||||
@@ -34,7 +34,7 @@ logger = getLogger(__name__)
|
||||
|
||||
|
||||
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')
|
||||
|
||||
class Path_request:
|
||||
@@ -51,7 +51,8 @@ class Path_request:
|
||||
self.spacing = params.spacing
|
||||
self.power = params.power
|
||||
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.OSNR = params.OSNR
|
||||
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)
|
||||
set_roadm_loss(path, equipment, lin2db(req.power*1e3))
|
||||
si = create_input_spectral_information(
|
||||
req.frequency['min'], req.roll_off, req.baud_rate,
|
||||
req.power, req.spacing, req.nb_channel, req.tx_osnr)
|
||||
req.f_min, req.f_max, req.roll_off, req.baud_rate,
|
||||
req.power, req.spacing)
|
||||
for el in path:
|
||||
si = el(si)
|
||||
if show :
|
||||
print(el)
|
||||
path[-1].update_snr(req.tx_osnr, equipment['Roadms']['default'].add_drop_osnr)
|
||||
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)
|
||||
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
|
||||
# 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
|
||||
baudrate_to_explore = list(set([m['baud_rate'] for m in equipment['Transceiver'][req.tsp].mode
|
||||
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)
|
||||
if baudrate_to_explore :
|
||||
# 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
|
||||
# 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
|
||||
si = create_input_spectral_information(
|
||||
req.f_min, req.f_max, equipment['SI']['default'].roll_off,
|
||||
b, req.power, req.spacing)
|
||||
for el in path:
|
||||
si = el(si)
|
||||
for m in modes_to_explore :
|
||||
si = create_input_spectral_information(
|
||||
req.frequency['min'], equipment['SI']['default'].roll_off,
|
||||
b, req.power, req.spacing, req.nb_channel, m['tx_osnr'])
|
||||
for el in path:
|
||||
si = el(si)
|
||||
if show :
|
||||
print(el)
|
||||
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'] :
|
||||
found_a_feasible_mode = True
|
||||
return path, m
|
||||
@@ -869,7 +869,8 @@ def compare_reqs(req1,req2,disjlist) :
|
||||
req1.spacing == req2.spacing and \
|
||||
req1.power == req2.power 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.OSNR == req2.OSNR and \
|
||||
req1.roll_off == req2.roll_off and \
|
||||
|
||||
@@ -120,6 +120,10 @@ def freq2wavelength(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):
|
||||
""" deltawl2deltaf(delta_wl, wavelength):
|
||||
|
||||
@@ -66,7 +66,8 @@
|
||||
],
|
||||
"Roadms":[{
|
||||
"gain_mode_default_loss": 20,
|
||||
"power_mode_pout_target": -20
|
||||
"power_mode_pout_target": -20,
|
||||
"add_drop_osnr": 100
|
||||
}],
|
||||
"SI":[{
|
||||
"f_min": 191.3e12,
|
||||
@@ -76,11 +77,8 @@
|
||||
"power_dbm": 0,
|
||||
"power_range_db": [0,0.5,0.5],
|
||||
"roll_off": 0.15,
|
||||
"OSNR": 15,
|
||||
"bit_rate":100e9,
|
||||
"tx_osnr": 100,
|
||||
"min_spacing": 50e9,
|
||||
"cost":1
|
||||
"sys_margins": 0
|
||||
}],
|
||||
"Transceiver":[
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ from json import load
|
||||
from gnpy.core.elements import Transceiver, Fiber, Edfa
|
||||
from gnpy.core.utils import lin2db, db2lin
|
||||
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 pathlib import Path
|
||||
import pytest
|
||||
@@ -66,7 +66,9 @@ def setup_trx():
|
||||
def si(nch_and_spacing, bw):
|
||||
"""parametrize a channel comb with nb_channel, spacing and signal bw"""
|
||||
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)])
|
||||
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)
|
||||
total_path = propagate(total_path,pathreq,equipment, show=False)
|
||||
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
|
||||
# a warning is shown in the propagate_and_optimize_mode
|
||||
if mode is not None :
|
||||
|
||||
Reference in New Issue
Block a user