mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-30 17:47:50 +00:00
Add ref_carrier to Pref and remove req_power from ReferenceCarrier
ref_carrier is added in Pref conveys the reference channel type information ie the channel that was used for design (would it be auto-design or for a given design). Other attributes (like slot_width or roll-off) may be added here for future equalization types. Pref object already records the req_power, so let's remove it from ReferenceCarrier and only use ref_carrier to record info that will be useful for PSD equalization ie baud_rate. This reference baud_rate is required to compute reference target power based on spectral density values during propagation. It is thus required because of on-the-fly evaluation of loss for p_span_i and for printing loss and target power of ROADM during propagation. Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com> Change-Id: Ic7441afa12ca5273ff99dea0268e439276107257
This commit is contained in:
@@ -42,10 +42,11 @@ class Channel(namedtuple('Channel',
|
||||
"""
|
||||
|
||||
|
||||
class Pref(namedtuple('Pref', 'p_span0, p_spani')):
|
||||
class Pref(namedtuple('Pref', 'p_span0, p_spani, ref_carrier')):
|
||||
"""noiseless reference power in dBm:
|
||||
p_span0: inital target carrier power for a reference channel defined by user
|
||||
p_spani: carrier power after element i for a reference channel defined by user
|
||||
ref_carrier records the baud rate of the reference channel
|
||||
"""
|
||||
|
||||
|
||||
@@ -236,7 +237,7 @@ class SpectralInformation(object):
|
||||
delta_pdb_per_channel=append(self.delta_pdb_per_channel,
|
||||
other.delta_pdb_per_channel),
|
||||
tx_osnr=append(self.tx_osnr, other.tx_osnr),
|
||||
ref_power=Pref(self.pref.p_span0, self.pref.p_spani))
|
||||
ref_power=Pref(self.pref.p_span0, self.pref.p_spani, self.pref.ref_carrier))
|
||||
except SpectrumError:
|
||||
raise SpectrumError('Spectra cannot be summed: channels overlapping.')
|
||||
|
||||
@@ -295,7 +296,7 @@ def create_arbitrary_spectral_information(frequency: Union[ndarray, Iterable, in
|
||||
raise
|
||||
|
||||
|
||||
def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing, tx_osnr):
|
||||
def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing, tx_osnr, ref_carrier=None):
|
||||
""" Creates a fixed slot width spectral information with flat power.
|
||||
all arguments are scalar values"""
|
||||
number_of_channels = automatic_nch(f_min, f_max, spacing)
|
||||
@@ -305,21 +306,24 @@ def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power,
|
||||
delta_pdb_per_channel = zeros(number_of_channels)
|
||||
return create_arbitrary_spectral_information(frequency, slot_width=spacing, signal=power, baud_rate=baud_rate,
|
||||
roll_off=roll_off, delta_pdb_per_channel=delta_pdb_per_channel,
|
||||
tx_osnr=tx_osnr, ref_power=Pref(p_span0=p_span0, p_spani=p_spani))
|
||||
tx_osnr=tx_osnr,
|
||||
ref_power=Pref(p_span0=p_span0, p_spani=p_spani,
|
||||
ref_carrier=ref_carrier))
|
||||
|
||||
|
||||
def carriers_to_spectral_information(initial_spectrum: dict[Union[int, float], Carrier],
|
||||
def carriers_to_spectral_information(initial_spectrum: dict[Union[int, float], Carrier], power: float,
|
||||
ref_carrier: ReferenceCarrier) -> SpectralInformation:
|
||||
"""Initial spectrum is a dict with key = carrier frequency, and value a Carrier object.
|
||||
:param initial_spectrum: indexed by frequency in Hz, with power offset (delta_pdb), baudrate, slot width,
|
||||
tx_osnr and roll off.
|
||||
:param ref_carrier: reference carrier (baudrate and power) used for the reference channel
|
||||
:param power: power of the request
|
||||
:param ref_carrier: reference carrier (baudrate) used for the reference channel
|
||||
"""
|
||||
frequency = list(initial_spectrum.keys())
|
||||
signal = [ref_carrier.req_power * db2lin(c.delta_pdb) for c in initial_spectrum.values()]
|
||||
signal = [power * db2lin(c.delta_pdb) for c in initial_spectrum.values()]
|
||||
roll_off = [c.roll_off for c in initial_spectrum.values()]
|
||||
baud_rate = [c.baud_rate for c in initial_spectrum.values()]
|
||||
delta_pdb_per_channel = array([c.delta_pdb for c in initial_spectrum.values()])
|
||||
delta_pdb_per_channel = [c.delta_pdb for c in initial_spectrum.values()]
|
||||
slot_width = [c.slot_width for c in initial_spectrum.values()]
|
||||
tx_osnr = [c.tx_osnr for c in initial_spectrum.values()]
|
||||
p_span0 = watt2dbm(ref_carrier.req_power)
|
||||
@@ -327,7 +331,8 @@ def carriers_to_spectral_information(initial_spectrum: dict[Union[int, float], C
|
||||
return create_arbitrary_spectral_information(frequency=frequency, signal=signal, baud_rate=baud_rate,
|
||||
slot_width=slot_width, roll_off=roll_off,
|
||||
delta_pdb_per_channel=delta_pdb_per_channel, tx_osnr=tx_osnr,
|
||||
ref_power=Pref(p_span0=p_span0, p_spani=p_spani))
|
||||
ref_power=Pref(p_span0=p_span0, p_spani=p_spani,
|
||||
ref_carrier=ref_carrier))
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -345,13 +350,15 @@ class Carrier:
|
||||
|
||||
@dataclass
|
||||
class ReferenceCarrier:
|
||||
"""Reference channel is used during autodesign to determine target power
|
||||
based on power spectral density values during propagation in ROADMs for equalization purpose.
|
||||
It is also required to correctly compute the loss experienced by p_span_i in Roadm element.
|
||||
"""Reference channel type is used to determine target power out of ROADM for the reference channel when
|
||||
constant power spectral density (PSD) equalization is set. Reference channel is the type that has been defined
|
||||
in SI block and used for the initial design of the network.
|
||||
Computing the power out of ROADM for the reference channel is required to correctly compute the loss
|
||||
experienced by p_span_i in Roadm element.
|
||||
|
||||
In typical scenarios, users would pick a 32 GBaud channel at 0dBm, which will
|
||||
neatly lead to the same power spectral density for a 64 GBaud channel at 3 dBm.
|
||||
Baud rate is required to find the target power in constant PSD: power = PSD_target * baud_rate.
|
||||
For example, if target PSD is 3.125e4mW/GHz and reference carrier type a 32 GBaud channel then
|
||||
output power should be -20 dBm and for a 64 GBaud channel power target would need 3 dB more: -17 dBm.
|
||||
Other attributes (like slot_width or roll-off) may be added there for future equalization purpose.
|
||||
"""
|
||||
baud_rate: float
|
||||
req_power: float
|
||||
|
||||
@@ -340,12 +340,12 @@ def compute_constrained_path(network, req):
|
||||
return total_path
|
||||
|
||||
|
||||
def ref_carrier(req_power, equipment):
|
||||
def ref_carrier(equipment):
|
||||
"""Create a reference carier based SI information with the specified request's power:
|
||||
req_power records the power in W that the user has defined for a given request
|
||||
(which might be different from the one used for the design).
|
||||
"""
|
||||
return ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate, req_power=req_power)
|
||||
return ReferenceCarrier(baud_rate=equipment['SI']['default'].baud_rate)
|
||||
|
||||
|
||||
def propagate(path, req, equipment):
|
||||
@@ -353,11 +353,11 @@ def propagate(path, req, equipment):
|
||||
"""
|
||||
if req.initial_spectrum is not None:
|
||||
si = carriers_to_spectral_information(initial_spectrum=req.initial_spectrum,
|
||||
ref_carrier=ref_carrier(req.power, equipment))
|
||||
power=req.power, ref_carrier=ref_carrier(equipment))
|
||||
else:
|
||||
si = create_input_spectral_information(
|
||||
f_min=req.f_min, f_max=req.f_max, roll_off=req.roll_off, baud_rate=req.baud_rate,
|
||||
power=req.power, spacing=req.spacing, tx_osnr=req.tx_osnr)
|
||||
power=req.power, spacing=req.spacing, tx_osnr=req.tx_osnr, ref_carrier=ref_carrier(equipment))
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
si = el(si, degree=path[i+1].uid)
|
||||
@@ -396,12 +396,11 @@ def propagate_and_optimize_mode(path, req, equipment):
|
||||
# this case is not yet handled: spectrum can not be defined for the path-request-run function
|
||||
# and this function is only called in this case. so coming here should not be considered yet.
|
||||
msg = f'Request: {req.request_id} contains a unexpected initial_spectrum.'
|
||||
LOGGER.critical(msg)
|
||||
raise ServiceError(msg)
|
||||
spc_info = create_input_spectral_information(f_min=req.f_min, f_max=req.f_max,
|
||||
roll_off=equipment['SI']['default'].roll_off,
|
||||
baud_rate=this_br, power=req.power, spacing=req.spacing,
|
||||
tx_osnr=req.tx_osnr)
|
||||
tx_osnr=req.tx_osnr, ref_carrier=ref_carrier(equipment))
|
||||
for i, el in enumerate(path):
|
||||
if isinstance(el, Roadm):
|
||||
spc_info = el(spc_info, degree=path[i+1].uid)
|
||||
|
||||
@@ -13,7 +13,7 @@ def test_create_arbitrary_spectral_information():
|
||||
baud_rate=32e9, signal=[1, 1, 1],
|
||||
delta_pdb_per_channel=[1, 1, 1],
|
||||
tx_osnr=40.0,
|
||||
ref_power=Pref(1, 1))
|
||||
ref_power=Pref(1, 1, None))
|
||||
assert_array_equal(si.baud_rate, array([32e9, 32e9, 32e9]))
|
||||
assert_array_equal(si.slot_width, array([37.5e9, 37.5e9, 37.5e9]))
|
||||
assert_array_equal(si.signal, ones(3))
|
||||
@@ -35,7 +35,8 @@ def test_create_arbitrary_spectral_information():
|
||||
slot_width=array([50e9, 50e9, 50e9]),
|
||||
baud_rate=32e9, signal=array([1, 2, 3]),
|
||||
tx_osnr=40.0,
|
||||
ref_power=Pref(1, 1))
|
||||
ref_power=Pref(1, 1, None))
|
||||
|
||||
assert_array_equal(si.signal, array([3, 2, 1]))
|
||||
|
||||
with pytest.raises(SpectrumError, match='Spectrum baud rate, including the roll off, '
|
||||
@@ -43,17 +44,16 @@ def test_create_arbitrary_spectral_information():
|
||||
create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=1,
|
||||
baud_rate=[64e9, 32e9, 64e9], slot_width=50e9,
|
||||
tx_osnr=40.0,
|
||||
ref_power=Pref(1, 1))
|
||||
ref_power=Pref(1, 1, None))
|
||||
with pytest.raises(SpectrumError, match='Spectrum required slot widths larger than the frequency spectral '
|
||||
r'distances between channels: \[\(1, 2\), \(3, 4\)\].'):
|
||||
create_arbitrary_spectral_information(frequency=[193.26e12, 193.3e12, 193.35e12, 193.39e12], signal=1,
|
||||
tx_osnr=40.0, baud_rate=32e9, slot_width=50e9, ref_power=Pref(1, 1))
|
||||
tx_osnr=40.0, baud_rate=32e9, slot_width=50e9, ref_power=Pref(1, 1, None))
|
||||
with pytest.raises(SpectrumError, match='Spectrum required slot widths larger than the frequency spectral '
|
||||
r'distances between channels: \[\(1, 2\), \(2, 3\)\].'):
|
||||
create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=1, baud_rate=49e9,
|
||||
tx_osnr=40.0, roll_off=0.1, ref_power=Pref(1, 1))
|
||||
|
||||
tx_osnr=40.0, roll_off=0.1, ref_power=Pref(1, 1, None))
|
||||
with pytest.raises(SpectrumError,
|
||||
match='Dimension mismatch in input fields.'):
|
||||
create_arbitrary_spectral_information(frequency=[193.25e12, 193.3e12, 193.35e12], signal=[1, 2], baud_rate=49e9,
|
||||
tx_osnr=40.0, ref_power=Pref(1, 1))
|
||||
tx_osnr=40.0, ref_power=Pref(1, 1, None))
|
||||
|
||||
@@ -45,7 +45,7 @@ def test_fiber():
|
||||
baud_rate = array([32e9, 42e9, 64e9, 42e9, 32e9])
|
||||
signal = 1e-3 + array([0, -1e-4, 3e-4, -2e-4, +2e-4])
|
||||
delta_pdb_per_channel = [0, 0, 0, 0, 0]
|
||||
pref = Pref(p_span0=0, p_spani=0)
|
||||
pref = Pref(p_span0=0, p_spani=0, ref_carrier=None)
|
||||
spectral_info_input = create_arbitrary_spectral_information(frequency=frequency, slot_width=slot_width,
|
||||
signal=signal, baud_rate=baud_rate, roll_off=0.15,
|
||||
delta_pdb_per_channel=delta_pdb_per_channel,
|
||||
|
||||
Reference in New Issue
Block a user