mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-29 17:22:42 +00:00
Add frequency dependency on ROADM impairments
Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com> Change-Id: Icb88bf9c42c09deb0064e3299b78b080462fef79
This commit is contained in:
committed by
Esther Le Rouzic
parent
03da959724
commit
29f5dd1dc4
@@ -418,7 +418,7 @@ class Roadm(_Node):
|
||||
# record input powers to compute the actual loss at the end of the process
|
||||
input_power_dbm = watt2dbm(spectral_info.signal + spectral_info.nli + spectral_info.ase)
|
||||
# apply min ROADM loss if it exists
|
||||
roadm_maxloss_db = self.get_roadm_path(from_degree, degree).impairment.maxloss
|
||||
roadm_maxloss_db = self.get_impairment('roadm-maxloss', spectral_info.frequency, from_degree, degree)
|
||||
spectral_info.apply_attenuation_db(roadm_maxloss_db)
|
||||
# records the total power after applying minimum loss
|
||||
net_input_power_dbm = watt2dbm(spectral_info.signal + spectral_info.nli + spectral_info.ase)
|
||||
@@ -433,7 +433,7 @@ class Roadm(_Node):
|
||||
# the power out of the ROADM for the ref channel is the min value between target power and input power.
|
||||
ref_pch_in_dbm = self.ref_pch_in_dbm[from_degree]
|
||||
# Calculate the output power for the reference channel (only for visualization)
|
||||
self.ref_pch_out_dbm = min(ref_pch_in_dbm - roadm_maxloss_db, ref_per_degree_pch)
|
||||
self.ref_pch_out_dbm = min(ref_pch_in_dbm - max(roadm_maxloss_db), ref_per_degree_pch)
|
||||
|
||||
# Definition of effective_loss:
|
||||
# Optical power of carriers are equalized by the ROADM, so that the experienced loss is not the same for
|
||||
@@ -465,11 +465,11 @@ class Roadm(_Node):
|
||||
spectral_info.apply_attenuation_db(delta_power)
|
||||
|
||||
# Update the PMD information
|
||||
pmd_impairment = self.get_roadm_path(from_degree=from_degree, to_degree=degree).impairment.pmd
|
||||
pmd_impairment = self.get_impairment('roadm-pmd', spectral_info.frequency, from_degree, degree)
|
||||
spectral_info.pmd = sqrt(spectral_info.pmd ** 2 + pmd_impairment ** 2)
|
||||
|
||||
# Update the PMD information
|
||||
pdl_impairment = self.get_roadm_path(from_degree=from_degree, to_degree=degree).impairment.pdl
|
||||
pdl_impairment = self.get_impairment('roadm-pdl', spectral_info.frequency, from_degree, degree)
|
||||
spectral_info.pdl = sqrt(spectral_info.pdl ** 2 + pdl_impairment ** 2)
|
||||
|
||||
# Update the per channel power with the result of propagation
|
||||
@@ -487,13 +487,19 @@ class Roadm(_Node):
|
||||
"""
|
||||
# initialize impairment with params.pmd, params.cd
|
||||
# if more detailed parameters are available for the Roadm, the use them instead
|
||||
roadm_global_impairment = {'roadm-pmd': self.params.pmd,
|
||||
'roadm-pdl': self.params.pdl}
|
||||
roadm_global_impairment = {
|
||||
'impairment': [{
|
||||
'roadm-pmd': self.params.pmd,
|
||||
'roadm-pdl': self.params.pdl,
|
||||
'frequency-range': {
|
||||
'lower-frequency': None,
|
||||
'upper-frequency': None
|
||||
}}]}
|
||||
if path_type in ['add', 'drop']:
|
||||
# without detailed imparments, we assume that add OSNR contribution is the same as drop contribution
|
||||
# add_drop_osnr_db = - 10log10(1/add_osnr + 1/drop_osnr) with add_osnr = drop_osnr
|
||||
# = add_osnr_db + 10log10(2)
|
||||
roadm_global_impairment['roadm-osnr'] = self.params.add_drop_osnr + lin2db(2)
|
||||
roadm_global_impairment['impairment'][0]['roadm-osnr'] = self.params.add_drop_osnr + lin2db(2)
|
||||
impairment = RoadmImpairment(roadm_global_impairment)
|
||||
|
||||
if impairment_id is None:
|
||||
@@ -534,6 +540,34 @@ class Roadm(_Node):
|
||||
return self.roadm_path_impairments[impairment_id].path_type
|
||||
return None
|
||||
|
||||
def get_impairment(self, impairment: str, frequency_array: array, from_degree: str, degree: str) \
|
||||
-> array:
|
||||
"""
|
||||
Retrieves the specified impairment values for the given frequency array.
|
||||
|
||||
Parameters:
|
||||
impairment (str): The type of impairment to retrieve (roadm-pmd, roamd-maxloss...).
|
||||
frequency_array (array): The frequencies at which to check for impairments.
|
||||
from_degree (str): The ingress degree for the roadm internal path.
|
||||
degree (str): The egress degree for the roadm internal path.
|
||||
|
||||
Returns:
|
||||
array: An array of impairment values for the specified frequencies.
|
||||
"""
|
||||
result = []
|
||||
impairment_per_band = self.get_roadm_path(from_degree, degree).impairment.impairments
|
||||
for frequency in frequency_array:
|
||||
for item in impairment_per_band:
|
||||
f_min = item['frequency-range']['lower-frequency']
|
||||
f_max = item['frequency-range']['upper-frequency']
|
||||
if (f_min is None or f_min <= frequency <= f_max):
|
||||
item[impairment] = item.get(impairment, RoadmImpairment.default_values[impairment])
|
||||
if item[impairment] is not None:
|
||||
result.append(item[impairment])
|
||||
break # Stop searching after the first match for this frequency
|
||||
if result:
|
||||
return array(result)
|
||||
|
||||
def __call__(self, spectral_info, degree, from_degree):
|
||||
self.propagate(spectral_info, degree=degree, from_degree=from_degree)
|
||||
return spectral_info
|
||||
|
||||
@@ -137,7 +137,7 @@ class RoadmParams(Parameters):
|
||||
for path_impairment in path_impairments_list:
|
||||
index = path_impairment['roadm-path-impairments-id']
|
||||
path_type = next(key for key in path_impairment if key in authorized_path_types.keys())
|
||||
impairment_dict = dict({'path-type': authorized_path_types[path_type]}, **path_impairment[path_type][0])
|
||||
impairment_dict = {'path-type': authorized_path_types[path_type], 'impairment': path_impairment[path_type]}
|
||||
roadm_path_impairments[index] = RoadmImpairment(impairment_dict)
|
||||
return roadm_path_impairments
|
||||
|
||||
@@ -158,26 +158,24 @@ class RoadmPath:
|
||||
|
||||
class RoadmImpairment:
|
||||
"""Generic definition of impairments for express, add and drop"""
|
||||
default_values = {
|
||||
'roadm-pmd': None,
|
||||
'roadm-cd': None,
|
||||
'roadm-pdl': None,
|
||||
'roadm-inband-crosstalk': None,
|
||||
'roadm-maxloss': 0,
|
||||
'roadm-osnr': None,
|
||||
'roadm-pmax': None,
|
||||
'roadm-noise-figure': None,
|
||||
'minloss': None,
|
||||
'typloss': None,
|
||||
'pmin': None,
|
||||
'ptyp': None
|
||||
}
|
||||
|
||||
def __init__(self, params):
|
||||
"""Records roadm internal paths and types"""
|
||||
self.path_type = params.get('path-type')
|
||||
self.pmd = params.get('roadm-pmd')
|
||||
self.cd = params.get('roadm-cd')
|
||||
self.pdl = params.get('roadm-pdl')
|
||||
self.inband_crosstalk = params.get('roadm-inband-crosstalk')
|
||||
self.maxloss = params.get('roadm-maxloss', 0)
|
||||
if params.get('frequency-range') is not None:
|
||||
self.fmin = params.get('frequency-range')['lower-frequency']
|
||||
self.fmax = params.get('frequency-range')['upper-frequency']
|
||||
else:
|
||||
self.fmin, self.fmax = None, None
|
||||
self.osnr = params.get('roadm-osnr', None)
|
||||
self.pmax = params.get('roadm-pmax', None)
|
||||
self.nf = params.get('roadm-noise-figure', None)
|
||||
self.minloss = params.get('minloss', None)
|
||||
self.typloss = params.get('typloss', None)
|
||||
self.pmin = params.get('pmin', None)
|
||||
self.ptyp = params.get('ptyp', None)
|
||||
self.impairments = params['impairment']
|
||||
|
||||
|
||||
class FusedParams(Parameters):
|
||||
|
||||
@@ -367,7 +367,8 @@ def propagate(path, req, equipment):
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
si = el(si, degree=path[i + 1].uid, from_degree=path[i - 1].uid)
|
||||
roadm_osnr.append(el.get_roadm_path(from_degree=path[i - 1].uid, to_degree=path[i + 1].uid).impairment.osnr)
|
||||
roadm_osnr.append(el.get_impairment('roadm-osnr', si.frequency,
|
||||
from_degree=path[i - 1].uid, degree=path[i + 1].uid))
|
||||
else:
|
||||
si = el(si)
|
||||
path[0].update_snr(si.tx_osnr)
|
||||
@@ -413,7 +414,8 @@ def propagate_and_optimize_mode(path, req, equipment):
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
spc_info = el(spc_info, degree=path[i + 1].uid, from_degree=path[i - 1].uid)
|
||||
roadm_osnr.append(el.get_roadm_path(from_degree=path[i - 1].uid, to_degree=path[i + 1].uid).impairment.osnr)
|
||||
roadm_osnr.append(el.get_impairment('roadm-osnr', spc_info.frequency,
|
||||
from_degree=path[i - 1].uid, degree=path[i + 1].uid))
|
||||
else:
|
||||
spc_info = el(spc_info)
|
||||
for this_mode in modes_to_explore:
|
||||
|
||||
@@ -128,6 +128,19 @@
|
||||
"roadm-pmax": 2.5,
|
||||
"roadm-osnr": 41,
|
||||
"roadm-noise-figure": 23
|
||||
}, {
|
||||
"frequency-range": {
|
||||
"lower-frequency": 186.3e12,
|
||||
"upper-frequency": 190.1e12
|
||||
},
|
||||
"roadm-pmd": 0,
|
||||
"roadm-cd": 0,
|
||||
"roadm-pdl": 0.5,
|
||||
"roadm-inband-crosstalk": 0,
|
||||
"roadm-maxloss": 5,
|
||||
"roadm-pmax": 0,
|
||||
"roadm-osnr": 35,
|
||||
"roadm-noise-figure": 6
|
||||
}]
|
||||
}, {
|
||||
"roadm-path-impairments-id": 2,
|
||||
|
||||
@@ -596,11 +596,19 @@ def test_roadm_per_degree_impairments(type_variety, from_degree, to_degree, impa
|
||||
{
|
||||
"roadm-path-impairments-id": 1,
|
||||
"roadm-add-path": [{
|
||||
"frequency-range": {
|
||||
"lower-frequency": 191.3e12,
|
||||
"upper-frequency": 196.1e12
|
||||
},
|
||||
"roadm-osnr": 41,
|
||||
}]
|
||||
}, {
|
||||
"roadm-path-impairments-id": 3,
|
||||
"roadm-add-path": [{
|
||||
"frequency-range": {
|
||||
"lower-frequency": 191.3e12,
|
||||
"upper-frequency": 196.1e12
|
||||
},
|
||||
"roadm-inband-crosstalk": 0,
|
||||
"roadm-osnr": 20,
|
||||
"roadm-noise-figure": 23
|
||||
@@ -657,14 +665,15 @@ def test_wrong_roadm_per_degree_impairments(from_degree, to_degree, impairment_i
|
||||
build_network(network, equipment, 0.0, 20.0)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('path_type, type_variety, expected_pmd, expected_pdl, expected_osnr', [
|
||||
('express', 'default', 5.0e-12, 0.5, None), # roadm instance parameters pre-empts library
|
||||
('express', 'example_test', 5.0e-12, 0.5, None),
|
||||
('express', 'example_detailed_impairments', 0, 0, None), # detailed parameters pre-empts global instance ones
|
||||
('add', 'default', 5.0e-12, 0.5, None),
|
||||
('add', 'example_test', 5.0e-12, 0.5, None),
|
||||
('add', 'example_detailed_impairments', 0, 0, 41)])
|
||||
def test_impairment_initialization(path_type, type_variety, expected_pmd, expected_pdl, expected_osnr):
|
||||
@pytest.mark.parametrize('path_type, type_variety, expected_pmd, expected_pdl, expected_osnr, freq', [
|
||||
('express', 'default', 5.0e-12, 0.5, None, [191.3e12]), # roadm instance parameters pre-empts library
|
||||
('express', 'example_test', 5.0e-12, 0.5, None, [191.3e12]),
|
||||
('express', 'example_detailed_impairments', 0, 0, None, [191.3e12]), # detailed parameters pre-empts global ones
|
||||
('add', 'default', 5.0e-12, 0.5, None, [191.3e12]),
|
||||
('add', 'example_test', 5.0e-12, 0.5, None, [191.3e12]),
|
||||
('add', 'example_detailed_impairments', 0, 0, 41, [191.3e12]),
|
||||
('add', 'example_detailed_impairments', [0, 0], [0.5, 0], [35, 41], [188.5e12, 191.3e12])])
|
||||
def test_impairment_initialization(path_type, type_variety, expected_pmd, expected_pdl, expected_osnr, freq):
|
||||
"""Check that impairments are correctly initialized, with this order:
|
||||
- use equipment roadm impairments if no impairment are set in the ROADM instance
|
||||
- use roadm global impairment if roadm global impairment are set
|
||||
@@ -687,13 +696,16 @@ def test_impairment_initialization(path_type, type_variety, expected_pmd, expect
|
||||
roadm = Roadm(**roadm_config)
|
||||
roadm.set_roadm_paths(from_degree='tata', to_degree='toto', path_type=path_type)
|
||||
assert roadm.get_roadm_path(from_degree='tata', to_degree='toto').path_type == path_type
|
||||
assert roadm.get_roadm_path(from_degree='tata', to_degree='toto').impairment.pmd == expected_pmd
|
||||
assert roadm.get_roadm_path(from_degree='tata', to_degree='toto').impairment.pdl == expected_pdl
|
||||
assert_allclose(roadm.get_impairment('roadm-pmd', freq, from_degree='tata', degree='toto'),
|
||||
expected_pmd, rtol=1e-12)
|
||||
assert_allclose(roadm.get_impairment('roadm-pdl', freq, from_degree='tata', degree='toto'),
|
||||
expected_pdl, rtol=1e-12)
|
||||
if path_type == 'add':
|
||||
# we assume for simplicity that add contribution is the same as drop contribution
|
||||
# add_drop_osnr_db = 10log10(1/add_osnr + 1/drop_osnr)
|
||||
if type_variety in ['default', 'example_test']:
|
||||
assert roadm.get_roadm_path(from_degree='tata',
|
||||
to_degree='toto').impairment.osnr == roadm.params.add_drop_osnr + lin2db(2)
|
||||
assert_allclose(roadm.get_impairment('roadm-osnr', freq, from_degree='tata', degree='toto'),
|
||||
roadm.params.add_drop_osnr + lin2db(2), rtol=1e-12)
|
||||
else:
|
||||
assert roadm.get_roadm_path(from_degree='tata', to_degree='toto').impairment.osnr == expected_osnr
|
||||
assert_allclose(roadm.get_impairment('roadm-osnr', freq, from_degree='tata', degree='toto'),
|
||||
expected_osnr, rtol=1e-12)
|
||||
|
||||
Reference in New Issue
Block a user