mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-30 01:32:21 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user