mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-11-01 18:47:48 +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
|
# 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)
|
input_power_dbm = watt2dbm(spectral_info.signal + spectral_info.nli + spectral_info.ase)
|
||||||
# apply min ROADM loss if it exists
|
# 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)
|
spectral_info.apply_attenuation_db(roadm_maxloss_db)
|
||||||
# records the total power after applying minimum loss
|
# records the total power after applying minimum loss
|
||||||
net_input_power_dbm = watt2dbm(spectral_info.signal + spectral_info.nli + spectral_info.ase)
|
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.
|
# 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]
|
ref_pch_in_dbm = self.ref_pch_in_dbm[from_degree]
|
||||||
# Calculate the output power for the reference channel (only for visualization)
|
# 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:
|
# Definition of effective_loss:
|
||||||
# Optical power of carriers are equalized by the ROADM, so that the experienced loss is not the same for
|
# 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)
|
spectral_info.apply_attenuation_db(delta_power)
|
||||||
|
|
||||||
# Update the PMD information
|
# 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)
|
spectral_info.pmd = sqrt(spectral_info.pmd ** 2 + pmd_impairment ** 2)
|
||||||
|
|
||||||
# Update the PMD information
|
# 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)
|
spectral_info.pdl = sqrt(spectral_info.pdl ** 2 + pdl_impairment ** 2)
|
||||||
|
|
||||||
# Update the per channel power with the result of propagation
|
# Update the per channel power with the result of propagation
|
||||||
@@ -487,13 +487,19 @@ class Roadm(_Node):
|
|||||||
"""
|
"""
|
||||||
# initialize impairment with params.pmd, params.cd
|
# initialize impairment with params.pmd, params.cd
|
||||||
# if more detailed parameters are available for the Roadm, the use them instead
|
# if more detailed parameters are available for the Roadm, the use them instead
|
||||||
roadm_global_impairment = {'roadm-pmd': self.params.pmd,
|
roadm_global_impairment = {
|
||||||
'roadm-pdl': self.params.pdl}
|
'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']:
|
if path_type in ['add', 'drop']:
|
||||||
# without detailed imparments, we assume that add OSNR contribution is the same as drop contribution
|
# 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_drop_osnr_db = - 10log10(1/add_osnr + 1/drop_osnr) with add_osnr = drop_osnr
|
||||||
# = add_osnr_db + 10log10(2)
|
# = 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)
|
impairment = RoadmImpairment(roadm_global_impairment)
|
||||||
|
|
||||||
if impairment_id is None:
|
if impairment_id is None:
|
||||||
@@ -534,6 +540,34 @@ class Roadm(_Node):
|
|||||||
return self.roadm_path_impairments[impairment_id].path_type
|
return self.roadm_path_impairments[impairment_id].path_type
|
||||||
return None
|
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):
|
def __call__(self, spectral_info, degree, from_degree):
|
||||||
self.propagate(spectral_info, degree=degree, from_degree=from_degree)
|
self.propagate(spectral_info, degree=degree, from_degree=from_degree)
|
||||||
return spectral_info
|
return spectral_info
|
||||||
|
|||||||
@@ -137,7 +137,7 @@ class RoadmParams(Parameters):
|
|||||||
for path_impairment in path_impairments_list:
|
for path_impairment in path_impairments_list:
|
||||||
index = path_impairment['roadm-path-impairments-id']
|
index = path_impairment['roadm-path-impairments-id']
|
||||||
path_type = next(key for key in path_impairment if key in authorized_path_types.keys())
|
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)
|
roadm_path_impairments[index] = RoadmImpairment(impairment_dict)
|
||||||
return roadm_path_impairments
|
return roadm_path_impairments
|
||||||
|
|
||||||
@@ -158,26 +158,24 @@ class RoadmPath:
|
|||||||
|
|
||||||
class RoadmImpairment:
|
class RoadmImpairment:
|
||||||
"""Generic definition of impairments for express, add and drop"""
|
"""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):
|
def __init__(self, params):
|
||||||
"""Records roadm internal paths and types"""
|
|
||||||
self.path_type = params.get('path-type')
|
self.path_type = params.get('path-type')
|
||||||
self.pmd = params.get('roadm-pmd')
|
self.impairments = params['impairment']
|
||||||
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)
|
|
||||||
|
|
||||||
|
|
||||||
class FusedParams(Parameters):
|
class FusedParams(Parameters):
|
||||||
|
|||||||
@@ -367,7 +367,8 @@ def propagate(path, req, equipment):
|
|||||||
for i, el in enumerate(path):
|
for i, el in enumerate(path):
|
||||||
if isinstance(el, Roadm):
|
if isinstance(el, Roadm):
|
||||||
si = el(si, degree=path[i + 1].uid, from_degree=path[i - 1].uid)
|
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:
|
else:
|
||||||
si = el(si)
|
si = el(si)
|
||||||
path[0].update_snr(si.tx_osnr)
|
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):
|
for i, el in enumerate(path):
|
||||||
if isinstance(el, Roadm):
|
if isinstance(el, Roadm):
|
||||||
spc_info = el(spc_info, degree=path[i + 1].uid, from_degree=path[i - 1].uid)
|
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:
|
else:
|
||||||
spc_info = el(spc_info)
|
spc_info = el(spc_info)
|
||||||
for this_mode in modes_to_explore:
|
for this_mode in modes_to_explore:
|
||||||
|
|||||||
@@ -128,6 +128,19 @@
|
|||||||
"roadm-pmax": 2.5,
|
"roadm-pmax": 2.5,
|
||||||
"roadm-osnr": 41,
|
"roadm-osnr": 41,
|
||||||
"roadm-noise-figure": 23
|
"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,
|
"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-path-impairments-id": 1,
|
||||||
"roadm-add-path": [{
|
"roadm-add-path": [{
|
||||||
|
"frequency-range": {
|
||||||
|
"lower-frequency": 191.3e12,
|
||||||
|
"upper-frequency": 196.1e12
|
||||||
|
},
|
||||||
"roadm-osnr": 41,
|
"roadm-osnr": 41,
|
||||||
}]
|
}]
|
||||||
}, {
|
}, {
|
||||||
"roadm-path-impairments-id": 3,
|
"roadm-path-impairments-id": 3,
|
||||||
"roadm-add-path": [{
|
"roadm-add-path": [{
|
||||||
|
"frequency-range": {
|
||||||
|
"lower-frequency": 191.3e12,
|
||||||
|
"upper-frequency": 196.1e12
|
||||||
|
},
|
||||||
"roadm-inband-crosstalk": 0,
|
"roadm-inband-crosstalk": 0,
|
||||||
"roadm-osnr": 20,
|
"roadm-osnr": 20,
|
||||||
"roadm-noise-figure": 23
|
"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)
|
build_network(network, equipment, 0.0, 20.0)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize('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), # roadm instance parameters pre-empts library
|
('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),
|
('express', 'example_test', 5.0e-12, 0.5, None, [191.3e12]),
|
||||||
('express', 'example_detailed_impairments', 0, 0, None), # detailed parameters pre-empts global instance ones
|
('express', 'example_detailed_impairments', 0, 0, None, [191.3e12]), # detailed parameters pre-empts global ones
|
||||||
('add', 'default', 5.0e-12, 0.5, None),
|
('add', 'default', 5.0e-12, 0.5, None, [191.3e12]),
|
||||||
('add', 'example_test', 5.0e-12, 0.5, None),
|
('add', 'example_test', 5.0e-12, 0.5, None, [191.3e12]),
|
||||||
('add', 'example_detailed_impairments', 0, 0, 41)])
|
('add', 'example_detailed_impairments', 0, 0, 41, [191.3e12]),
|
||||||
def test_impairment_initialization(path_type, type_variety, expected_pmd, expected_pdl, expected_osnr):
|
('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:
|
"""Check that impairments are correctly initialized, with this order:
|
||||||
- use equipment roadm impairments if no impairment are set in the ROADM instance
|
- use equipment roadm impairments if no impairment are set in the ROADM instance
|
||||||
- use roadm global impairment if roadm global impairment are set
|
- 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 = Roadm(**roadm_config)
|
||||||
roadm.set_roadm_paths(from_degree='tata', to_degree='toto', path_type=path_type)
|
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').path_type == path_type
|
||||||
assert roadm.get_roadm_path(from_degree='tata', to_degree='toto').impairment.pmd == expected_pmd
|
assert_allclose(roadm.get_impairment('roadm-pmd', freq, from_degree='tata', degree='toto'),
|
||||||
assert roadm.get_roadm_path(from_degree='tata', to_degree='toto').impairment.pdl == expected_pdl
|
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':
|
if path_type == 'add':
|
||||||
# we assume for simplicity that add contribution is the same as drop contribution
|
# we assume for simplicity that add contribution is the same as drop contribution
|
||||||
# add_drop_osnr_db = 10log10(1/add_osnr + 1/drop_osnr)
|
# add_drop_osnr_db = 10log10(1/add_osnr + 1/drop_osnr)
|
||||||
if type_variety in ['default', 'example_test']:
|
if type_variety in ['default', 'example_test']:
|
||||||
assert roadm.get_roadm_path(from_degree='tata',
|
assert_allclose(roadm.get_impairment('roadm-osnr', freq, from_degree='tata', degree='toto'),
|
||||||
to_degree='toto').impairment.osnr == roadm.params.add_drop_osnr + lin2db(2)
|
roadm.params.add_drop_osnr + lin2db(2), rtol=1e-12)
|
||||||
else:
|
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