Skip to content

Commit

Permalink
Merge changes from topic "mixed-rate"
Browse files Browse the repository at this point in the history
* changes:
  Change saturation verification to total input power
  Prepare for Pref definition
  Add utilities
  • Loading branch information
jktjkt authored and gerritforge-ltd committed Sep 19, 2022
2 parents 00ee102 + 33c6038 commit a7ec7e2
Show file tree
Hide file tree
Showing 8 changed files with 96 additions and 26 deletions.
37 changes: 22 additions & 15 deletions gnpy/core/elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from scipy.interpolate import interp1d
from collections import namedtuple

from gnpy.core.utils import lin2db, db2lin, arrange_frequencies, snr_sum
from gnpy.core.utils import lin2db, db2lin, arrange_frequencies, snr_sum, watt2dbm
from gnpy.core.parameters import RoadmParams, FusedParams, FiberParams, PumpParams, EdfaParams, EdfaOperational
from gnpy.core.science_utils import NliSolver, RamanSolver
from gnpy.core.info import SpectralInformation
Expand Down Expand Up @@ -216,21 +216,21 @@ def __init__(self, *args, params=None, **kwargs):
if not params:
params = {}
super().__init__(*args, params=RoadmParams(**params), **kwargs)
self.pch_out_db = self.params.target_pch_out_db
self.ref_pch_out_dbm = self.params.target_pch_out_db
self.loss = 0 # auto-design interest
self.effective_loss = None
self.passive = True
self.restrictions = self.params.restrictions
self.per_degree_pch_out_db = self.params.per_degree_pch_out_db
self.per_degree_pch_out_dbm = self.params.per_degree_pch_out_db

@property
def to_json(self):
return {'uid': self.uid,
'type': type(self).__name__,
'params': {
'target_pch_out_db': self.pch_out_db,
'target_pch_out_db': self.ref_pch_out_dbm,
'restrictions': self.restrictions,
'per_degree_pch_out_db': self.per_degree_pch_out_db
'per_degree_pch_out_db': self.per_degree_pch_out_dbm
},
'metadata': {
'location': self.metadata['location']._asdict()
Expand All @@ -246,7 +246,7 @@ def __str__(self):

return '\n'.join([f'{type(self).__name__} {self.uid}',
f' effective loss (dB): {self.effective_loss:.2f}',
f' pch out (dBm): {self.pch_out_db:.2f}'])
f' pch out (dBm): {self.ref_pch_out_dbm:.2f}'])

def propagate(self, spectral_info, degree):
# pin_target and loss are read from eqpt_config.json['Roadm']
Expand All @@ -258,10 +258,17 @@ def propagate(self, spectral_info, degree):
# if the input power is lower than the target one, use the input power instead because
# a ROADM doesn't amplify, it can only attenuate
# TODO maybe add a minimum loss for the ROADM
per_degree_pch = self.per_degree_pch_out_db[degree] \
if degree in self.per_degree_pch_out_db else self.pch_out_db
self.pch_out_db = min(spectral_info.pref.p_spani, per_degree_pch)
self.effective_loss = spectral_info.pref.p_spani - self.pch_out_db
per_degree_pch = self.per_degree_pch_out_dbm.get(degree, self.ref_pch_out_dbm)
# Definition of ref_pch_out_dbm for the reference channel:
# Depending on propagation upstream from this ROADM, the input power (p_spani) might be smaller than
# the target power out configured for this ROADM degree's egress. Since ROADM does not amplify,
# the power out of the ROADM for the ref channel is the min value between target power and input power.
# (TODO add a minimum loss for the ROADM crossing)
self.ref_pch_out_dbm = min(spectral_info.pref.p_spani, 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
# different carriers. effective_loss records the loss for a reference carrier.
self.effective_loss = spectral_info.pref.p_spani - self.ref_pch_out_dbm
input_power = spectral_info.signal + spectral_info.nli + spectral_info.ase
min_power = min(lin2db(input_power * 1e3))
per_degree_pch = per_degree_pch if per_degree_pch < min_power else min_power
Expand All @@ -271,7 +278,8 @@ def propagate(self, spectral_info, degree):
spectral_info.pdl = sqrt(spectral_info.pdl ** 2 + self.params.pdl ** 2)

def update_pref(self, spectral_info):
spectral_info.pref = spectral_info.pref._replace(p_span0=spectral_info.pref.p_span0, p_spani=self.pch_out_db)
spectral_info.pref = spectral_info.pref._replace(p_span0=spectral_info.pref.p_span0,
p_spani=self.ref_pch_out_dbm)

def __call__(self, spectral_info, degree):
self.propagate(spectral_info, degree=degree)
Expand Down Expand Up @@ -639,7 +647,7 @@ def interpol_params(self, spectral_info):

self.nch = spectral_info.number_of_channels
pin = spectral_info.signal + spectral_info.ase + spectral_info.nli
self.pin_db = lin2db(sum(pin * 1e3))
self.pin_db = watt2dbm(sum(pin))
# The following should be changed when we have the new spectral information including slot widths.
# For now, with homogeneous spectrum, we can calculate it as the difference between neighbouring channels.
self.slot_width = self.channel_freq[1] - self.channel_freq[0]
Expand All @@ -652,15 +660,14 @@ def interpol_params(self, spectral_info):
self.effective_gain = self.target_pch_out_db - pref.p_spani

"""check power saturation and correct effective gain & power accordingly:"""
# Compute the saturation accounting for actual power at the input of the amp
self.effective_gain = min(
self.effective_gain,
self.params.p_max - (pref.p_spani + pref.neq_ch)
self.params.p_max - self.pin_db
)
#print(self.uid, self.effective_gain, self.operational.gain_target)
self.effective_pch_out_db = round(pref.p_spani + self.effective_gain, 2)

"""check power saturation and correct target_gain accordingly:"""
#print(self.uid, self.effective_gain, self.pin_db, pref.p_spani)
self.nf = self._calc_nf()
self.gprofile = self._gain_profile(pin)

Expand Down
4 changes: 2 additions & 2 deletions gnpy/core/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d
"""
power_mode = equipment['Span']['default'].power_mode
next_oms = (n for n in network.successors(this_node) if not isinstance(n, elements.Transceiver))
this_node_degree = {k: v for k, v in this_node.per_degree_pch_out_db.items()} if hasattr(this_node, 'per_degree_pch_out_db') else {}
this_node_degree = getattr(this_node, 'per_degree_pch_out_dbm', {})
for oms in next_oms:
# go through all the OMS departing from the ROADM
prev_node = this_node
Expand Down Expand Up @@ -334,7 +334,7 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d
# print(f'{node.uid}')

if isinstance(this_node, elements.Roadm):
this_node.per_degree_pch_out_db = {k: v for k, v in this_node_degree.items()}
this_node.per_degree_pch_out_dbm = {k: v for k, v in this_node_degree.items()}


def add_roadm_booster(network, roadm):
Expand Down
63 changes: 63 additions & 0 deletions gnpy/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,69 @@ def db2lin(value):
return 10**(value / 10)


def watt2dbm(value):
"""Convert Watt units to dBm
>>> round(watt2dbm(0.001), 1)
0.0
>>> round(watt2dbm(0.02), 1)
13.0
"""
return lin2db(value * 1e3)


def dbm2watt(value):
"""Convert dBm units to Watt
>>> round(dbm2watt(0), 4)
0.001
>>> round(dbm2watt(-3), 4)
0.0005
>>> round(dbm2watt(13), 4)
0.02
"""
return db2lin(value) * 1e-3


def psd2powerdbm(psd_mwperghz, baudrate_baud):
"""computes power in dBm based on baudrate in bauds and psd in mW/GHz
>>> round(psd2powerdbm(0.031176, 64e9),3)
3.0
>>> round(psd2powerdbm(0.062352, 32e9),3)
3.0
>>> round(psd2powerdbm(0.015625, 64e9),3)
0.0
"""
return lin2db(baudrate_baud * psd_mwperghz * 1e-9)


def power_dbm_to_psd_mw_ghz(power_dbm, baudrate_baud):
"""computes power spectral density in mW/GHz based on baudrate in bauds and power in dBm
>>> power_dbm_to_psd_mw_ghz(0, 64e9)
0.015625
>>> round(power_dbm_to_psd_mw_ghz(3, 64e9), 6)
0.031176
>>> round(power_dbm_to_psd_mw_ghz(3, 32e9), 6)
0.062352
"""
return db2lin(power_dbm) / (baudrate_baud * 1e-9)


def psd_mw_per_ghz(power_watt, baudrate_baud):
"""computes power spectral density in mW/GHz based on baudrate in bauds and power in W
>>> psd_mw_per_ghz(2e-3, 32e9)
0.0625
>>> psd_mw_per_ghz(1e-3, 64e9)
0.015625
>>> psd_mw_per_ghz(0.5e-3, 32e9)
0.015625
"""
return power_watt * 1e3 / (baudrate_baud * 1e-9)


def round2float(number, step):
"""Round a floating point number so that its "resolution" is not bigger than 'step'
Expand Down
2 changes: 1 addition & 1 deletion tests/data/testTopology_response.json
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,7 @@
},
{
"metric-type": "SNR-0.1nm",
"accumulative-value": 28.77
"accumulative-value": 28.78
},
{
"metric-type": "OSNR-bandwidth",
Expand Down
2 changes: 1 addition & 1 deletion tests/data/testTopology_response_expected.csv
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ response-id,source,destination,path_bandwidth,Pass?,nb of tsp pairs,total cost,t
1,trx Brest_KLA,trx Vannes_KBE,10.0,True,1,1,Voyager,mode 1,22.65,22.11,18.03,32.0,1.0,trx Brest_KLA | roadm Brest_KLA | east edfa in Brest_KLA to Morlaix | fiber (Brest_KLA → Morlaix)-F060 | east fused spans in Morlaix | fiber (Morlaix → Lannion_CAS)-F059 | west edfa in Lannion_CAS to Morlaix | roadm Lannion_CAS | east edfa in Lannion_CAS to Corlay | fiber (Lannion_CAS → Corlay)-F061 | west fused spans in Corlay | fiber (Corlay → Loudeac)-F010 | west fused spans in Loudeac | fiber (Loudeac → Lorient_KMA)-F054 | west edfa in Lorient_KMA to Loudeac | roadm Lorient_KMA | east edfa in Lorient_KMA to Vannes_KBE | fiber (Lorient_KMA → Vannes_KBE)-F055 | west edfa in Vannes_KBE to Lorient_KMA | roadm Vannes_KBE | trx Vannes_KBE,"-276, 4",,,
3,trx Lannion_CAS,trx Rennes_STA,60.0,True,1,1,vendorA_trx-type1,mode 1,28.29,25.85,21.77,32.0,1.0,trx Lannion_CAS | roadm Lannion_CAS | east edfa in Lannion_CAS to Stbrieuc | fiber (Lannion_CAS → Stbrieuc)-F056 | east edfa in Stbrieuc to Rennes_STA | fiber (Stbrieuc → Rennes_STA)-F057 | west edfa in Rennes_STA to Stbrieuc | roadm Rennes_STA | trx Rennes_STA,"-284, 4",,,
4,trx Rennes_STA,trx Lannion_CAS,150.0,True,1,1,vendorA_trx-type1,mode 2,22.27,22.15,15.05,64.0,0.0,trx Rennes_STA | roadm Rennes_STA | east edfa in Rennes_STA to Ploermel | fiber (Rennes_STA → Ploermel)- | east edfa in Ploermel to Vannes_KBE | fiber (Ploermel → Vannes_KBE)- | west edfa in Vannes_KBE to Ploermel | roadm Vannes_KBE | east edfa in Vannes_KBE to Lorient_KMA | fiber (Vannes_KBE → Lorient_KMA)-F055 | west edfa in Lorient_KMA to Vannes_KBE | roadm Lorient_KMA | east edfa in Lorient_KMA to Loudeac | fiber (Lorient_KMA → Loudeac)-F054 | east fused spans in Loudeac | fiber (Loudeac → Corlay)-F010 | east fused spans in Corlay | fiber (Corlay → Lannion_CAS)-F061 | west edfa in Lannion_CAS to Corlay | roadm Lannion_CAS | trx Lannion_CAS,"-266, 6",,,
5,trx Rennes_STA,trx Lannion_CAS,20.0,True,1,1,vendorA_trx-type1,mode 2,30.79,28.77,21.68,64.0,3.0,trx Rennes_STA | roadm Rennes_STA | east edfa in Rennes_STA to Stbrieuc | fiber (Rennes_STA → Stbrieuc)-F057 | west edfa in Stbrieuc to Rennes_STA | fiber (Stbrieuc → Lannion_CAS)-F056 | west edfa in Lannion_CAS to Stbrieuc | roadm Lannion_CAS | trx Lannion_CAS,"-274, 6",,,
5,trx Rennes_STA,trx Lannion_CAS,20.0,True,1,1,vendorA_trx-type1,mode 2,30.79,28.78,21.68,64.0,3.0,trx Rennes_STA | roadm Rennes_STA | east edfa in Rennes_STA to Stbrieuc | fiber (Rennes_STA → Stbrieuc)-F057 | west edfa in Stbrieuc to Rennes_STA | fiber (Stbrieuc → Lannion_CAS)-F056 | west edfa in Lannion_CAS to Stbrieuc | roadm Lannion_CAS | trx Lannion_CAS,"-274, 6",,,
6,,,,NO_PATH,,,,,,,,,,,,,,
2 changes: 1 addition & 1 deletion tests/invocation/path_requests_run
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ req id demand GSNR@bandwidth A-Z (Z-A) GSNR@0
0 trx Lorient_KMA to trx Vannes_KBE : 24.83 28.92 14 mode 1 100.0 1 (-284,4)
1 trx Brest_KLA to trx Vannes_KBE : 17.75 21.83 14 mode 1 200.0 2 (-272,8)
3 trx Lannion_CAS to trx Rennes_STA : 22.21 26.29 13 mode 1 60.0 1 (-284,4)
4 trx Rennes_STA to trx Lannion_CAS : 16.07 23.29 17 mode 2 150.0 1 (-258,6)
4 trx Rennes_STA to trx Lannion_CAS : 16.06 23.29 17 mode 2 150.0 1 (-258,6)
5 trx Rennes_STA to trx Lannion_CAS : 20.31 27.54 17 mode 2 20.0 1 (-274,6)
7 | 6 trx Lannion_CAS to trx Lorient_KMA : 19.52 23.61 14 mode 1 700.0 7 (-224,28)
7b trx Lannion_CAS to trx Lorient_KMA : 19.61 23.69 14 mode 1 400.0 4 (-172,24)
Expand Down
8 changes: 4 additions & 4 deletions tests/invocation/transmission_saturated
Original file line number Diff line number Diff line change
Expand Up @@ -297,19 +297,19 @@ Fiber fiber (Loudeac → Lorient_KMA)-F054
pch out (dBm): -26.82
Edfa west edfa in Lorient_KMA to Loudeac
type_variety: test
effective gain(dB): 28.00
effective gain(dB): 27.99
(before att_in and before output VOA)
noise figure (dB): 5.76
(including att_in)
pad att_in (dB): 0.00
Power In (dBm): -6.99
Power Out (dBm): 21.04
Power Out (dBm): 21.03
Delta_P (dB): -1.82
target pch (dBm): 1.18
effective pch (dBm): 1.18
effective pch (dBm): 1.17
output VOA (dB): 0.00
Roadm roadm Lorient_KMA
effective loss (dB): 21.18
effective loss (dB): 21.17
pch out (dBm): -20.00
Transceiver trx Lorient_KMA
GSNR (0.1nm, dB): 23.94
Expand Down
4 changes: 2 additions & 2 deletions tests/test_roadm_restrictions.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,14 +271,14 @@ def test_roadm_target_power(prev_node_type, effective_pch_out_db, power_dbm):
if prev_node_type == 'edfa':
# edfa prev_node sets input power to roadm to a high enough value:
# check that target power is correctly set in the ROADM
assert_allclose(el.pch_out_db, effective_pch_out_db, rtol=1e-3)
assert_allclose(el.ref_pch_out_dbm, effective_pch_out_db, rtol=1e-3)
# Check that egress power of roadm is equal to target power
assert_allclose(power_out_roadm, db2lin(effective_pch_out_db - 30), rtol=1e-3)
elif prev_node_type == 'fused':
# fused prev_node does reamplfy power after fiber propagation, so input power
# to roadm is low.
# check that target power correctly reports power_dbm from previous propagation
assert_allclose(el.pch_out_db, effective_pch_out_db + power_dbm, rtol=1e-3)
assert_allclose(el.ref_pch_out_dbm, effective_pch_out_db + power_dbm, rtol=1e-3)
# Check that egress power of roadm is equalized to the min carrier input power.
assert_allclose(power_out_roadm, min_power_in_roadm, rtol=1e-3)
else:
Expand Down

0 comments on commit a7ec7e2

Please sign in to comment.