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:
EstherLerouzic
2021-08-06 13:55:11 +02:00
parent bd6b278dd1
commit 18610fb7a9
4 changed files with 35 additions and 29 deletions

View File

@@ -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

View File

@@ -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)

View File

@@ -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))

View File

@@ -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,