Add a user defined initial spectrum in propagation functions

A new function is added to build spectrum information based on
the actual mixture of channels to be simulated (baud rate, slot width,
power per frequency).

Propagation function is changed so that, if the user defines a
specific distribution, then it uses it, else it uses as before,
all identical channels based on the initial request. In this case,
as before this change, we assume full load, with same channel for
the spectral info and not the resulting mixt of channels after
routing.

Signed-off-by: EstherLerouzic <esther.lerouzic@orange.com>
Change-Id: Icf56396837b77009e98accd27fcebd2dded6d112
This commit is contained in:
EstherLerouzic
2021-08-05 15:07:35 +02:00
parent ffc7dbc241
commit e143d25339
2 changed files with 76 additions and 7 deletions

View File

@@ -12,6 +12,7 @@ from __future__ import annotations
from collections import namedtuple
from collections.abc import Iterable
from typing import Union
from dataclasses import dataclass
from numpy import argsort, mean, array, append, ones, ceil, any, zeros, outer, full, ndarray, asarray
from gnpy.core.utils import automatic_nch, db2lin, watt2dbm
@@ -292,3 +293,50 @@ def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power,
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,
ref_power=Pref(p_span0=p_span0, p_spani=p_spani))
def carriers_to_spectral_information(initial_spectrum: dict[Union[int, float], Carrier],
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
and roll off.
:param ref_carrier: reference carrier (baudrate and power) 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()]
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()])
slot_width = [c.slot_width for c in initial_spectrum.values()]
p_span0 = watt2dbm(ref_carrier.req_power)
p_spani = watt2dbm(ref_carrier.req_power)
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,
ref_power=Pref(p_span0=p_span0, p_spani=p_spani))
@dataclass
class Carrier:
"""One channel in the initial mixed-type spectrum definition, each type being defined by
its delta_pdb (power offset with respect to reference power), baud rate, slot_width, roll_off
and tx_osnr. delta_pdb offset is applied to target power out of Roadm.
"""
delta_pdb: float
baud_rate: float
slot_width: float
roll_off: float
@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.
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.
Other attributes (like slot_width or roll-off) may be added there for future equalization purpose.
"""
baud_rate: float
req_power: float

View File

@@ -23,7 +23,7 @@ from networkx.utils import pairwise
from numpy import mean, argmin
from gnpy.core.elements import Transceiver, Roadm
from gnpy.core.utils import lin2db
from gnpy.core.info import create_input_spectral_information
from gnpy.core.info import create_input_spectral_information, carriers_to_spectral_information, ReferenceCarrier
from gnpy.core.exceptions import ServiceError, DisjunctionError
import gnpy.core.ansi_escapes as ansi_escapes
from copy import deepcopy
@@ -72,6 +72,7 @@ class PathRequest:
if params.effective_freq_slot is not None:
self.N = params.effective_freq_slot['N']
self.M = params.effective_freq_slot['M']
self.initial_spectrum = None
def __str__(self):
return '\n\t'.join([f'{type(self).__name__} {self.request_id}',
@@ -339,10 +340,24 @@ def compute_constrained_path(network, req):
return total_path
def ref_carrier(req_power, 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)
def propagate(path, req, equipment):
si = create_input_spectral_information(
req.f_min, req.f_max, req.roll_off, req.baud_rate,
req.power, req.spacing)
""" propagates signals in each element according to initial spectrum set by user
"""
if req.initial_spectrum is not None:
si = carriers_to_spectral_information(initial_spectrum=req.initial_spectrum,
ref_carrier=ref_carrier(req.power, equipment))
else:
si = create_input_spectral_information(
req.f_min, req.f_max, req.roll_off, req.baud_rate,
req.power, req.spacing)
for i, el in enumerate(path):
if isinstance(el, Roadm):
si = el(si, degree=path[i+1].uid)
@@ -378,9 +393,15 @@ def propagate_and_optimize_mode(path, req, equipment):
# step2: computes propagation for each baudrate: stop and select the first that passes
# TODO: the case of roll of is not included: for now use SI one
# TODO: if the loop in mode optimization does not have a feasible path, then bugs
spc_info = create_input_spectral_information(req.f_min, req.f_max,
equipment['SI']['default'].roll_off,
this_br, req.power, req.spacing)
if req.initial_spectrum is not None:
# 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)
for i, el in enumerate(path):
if isinstance(el, Roadm):
spc_info = el(spc_info, degree=path[i+1].uid)