From 8e246df48de4f6dba86532c447662cb69e7c475c Mon Sep 17 00:00:00 2001 From: EstherLerouzic Date: Wed, 27 Mar 2024 13:07:18 +0100 Subject: [PATCH] fix Raman gain estimation during design - Replaced multiple calls to the span_loss function with recording the span loss result in the fiber elements, reducing computation time. - Updated Raman gain estimation based on design target powers to ensure accurate Edfa gain calculation or gain reduction during design. - display the computed and design Raman gain in RamanFiber string output - do not add padding on Raman fibers - Added to_json function to preserve user input SimParams values, which were previously overwritten by initializing SimParams with fake values during design. Next step is to allow users to balance computation time and target accuracy of the design by inputing their own SimParams and ref channels design values. Signed-off-by: EstherLerouzic Change-Id: I1ca4954d0621858cefb3d776a538131992cae3e3 --- gnpy/core/elements.py | 8 +- gnpy/core/network.py | 106 ++++++----- gnpy/core/parameters.py | 11 ++ .../transmission_main_example__raman | 174 +++++++++--------- 4 files changed, 167 insertions(+), 132 deletions(-) diff --git a/gnpy/core/elements.py b/gnpy/core/elements.py index 3fc13fdc3..7ae32b07e 100644 --- a/gnpy/core/elements.py +++ b/gnpy/core/elements.py @@ -242,7 +242,6 @@ def __init__(self, *args, params=None, **kwargs): # on the path, since it depends on the equalization definition on the degree. self.ref_pch_out_dbm = None self.loss = 0 # auto-design interest - # Optical power of carriers are equalized by the ROADM, so that the experienced loss is not the same for # different carriers. The ref_effective_loss records the loss for a reference carrier. self.ref_effective_loss = None @@ -707,11 +706,16 @@ def __init__(self, *args, params=None, **kwargs): def to_json(self): return dict(super().to_json, operational=self.operational) + def __str__(self): + return super().__str__() + f'\n reference gain (dB): {round(self.estimated_gain, 2)}' \ + + f'\n actual gain (dB): {round(self.actual_raman_gain, 2)}' + def propagate(self, spectral_info: SpectralInformation): """Modifies the spectral information computing the attenuation, the non-linear interference generation, the CD and PMD accumulation. """ # apply the attenuation due to the input connector loss + pin = watt2dbm(sum(spectral_info.signal)) attenuation_in_db = self.params.con_in + self.params.att_in spectral_info.apply_attenuation_db(attenuation_in_db) @@ -741,6 +745,8 @@ def propagate(self, spectral_info: SpectralInformation): spectral_info.apply_attenuation_db(attenuation_out_db) self.pch_out_dbm = watt2dbm(spectral_info.signal + spectral_info.nli + spectral_info.ase) self.propagated_labels = spectral_info.label + pout = watt2dbm(sum(spectral_info.signal)) + self.actual_raman_gain = self.loss + pout - pin class Edfa(_Node): diff --git a/gnpy/core/network.py b/gnpy/core/network.py index ecfefd36c..58b8b2d58 100644 --- a/gnpy/core/network.py +++ b/gnpy/core/network.py @@ -19,6 +19,7 @@ from gnpy.core.info import ReferenceCarrier, create_input_spectral_information from gnpy.tools import json_io from gnpy.core.parameters import SimParams +from gnpy.core.science_utils import RamanSolver logger = getLogger(__name__) @@ -141,7 +142,6 @@ def target_power(network, node, equipment): # get_fiber_dp POWER_SLOPE = 0.3 dp_range = list(equipment['Span']['default'].delta_power_range_db) node_loss = span_loss(network, node, equipment) - try: dp = round2float((node_loss - SPAN_LOSS_REF) * POWER_SLOPE, dp_range[2]) dp = max(dp_range[0], dp) @@ -187,63 +187,74 @@ def next_node_generator(network, node): yield from next_node_generator(network, next_node) -def estimate_raman_gain(node, equipment): +def estimate_raman_gain(node, equipment, power_dbm): """If node is RamanFiber, then estimate the possible Raman gain if any - for this purpose propagate a fake signal in a copy. - to be accurate the nb of channel should be the same as in SI, but this increases computation time + for this purpose computes stimulated_raman_scattering loss_profile. This may be time consuming. """ - f_min = equipment['SI']['default'].f_min - f_max = equipment['SI']['default'].f_max - roll_off = equipment['SI']['default'].roll_off - baud_rate = equipment['SI']['default'].baud_rate - power_dbm = equipment['SI']['default'].power_dbm - power = dbm2watt(equipment['SI']['default'].power_dbm) - spacing = equipment['SI']['default'].spacing - tx_osnr = equipment['SI']['default'].tx_osnr - - sim_params = { - "raman_params": { - "flag": True, - "result_spatial_resolution": 10e3, - "solver_spatial_resolution": 50 - }, - "nli_params": { - "method": "ggn_spectrally_separated", - "dispersion_tolerance": 1, - "phase_shift_tolerance": 0.1, - "computed_channels": [1, 18, 37, 56, 75] - } - } if isinstance(node, elements.RamanFiber): + if hasattr(node, "estimated_gain"): + return node.estimated_gain + f_min = equipment['SI']['default'].f_min + f_max = equipment['SI']['default'].f_max + roll_off = equipment['SI']['default'].roll_off + baud_rate = equipment['SI']['default'].baud_rate + power = dbm2watt(power_dbm) + spacing = equipment['SI']['default'].spacing + tx_osnr = equipment['SI']['default'].tx_osnr + + # reduce the nb of channels to speed up + spacing = spacing * 3 + power = power * 3 + + sim_params = { + "raman_params": { + "flag": True, + "result_spatial_resolution": 50e3, + "solver_spatial_resolution": 100 + } + } + # in order to take into account gain generated in RamanFiber, propagate in the RamanFiber with - # SI reference channel. - spectral_info_input = create_input_spectral_information(f_min=f_min, f_max=f_max, roll_off=roll_off, - baud_rate=baud_rate, power=power, spacing=spacing, - tx_osnr=tx_osnr) - n_copy = deepcopy(node) - # need to set ref_pch_in_dbm in order to correctly run propagate of the element, because this - # setting has not yet been done by autodesign - n_copy.ref_pch_in_dbm = power_dbm + if hasattr(node, "estimated_gain"): + # do not compute twice to save on time + return node.estimated_gain + spectral_info = create_input_spectral_information(f_min=f_min, f_max=f_max, roll_off=roll_off, + baud_rate=baud_rate, power=power, spacing=spacing, + tx_osnr=tx_osnr) + pin = watt2dbm(sum(spectral_info.signal)) + attenuation_in_db = node.params.con_in + node.params.att_in + spectral_info.apply_attenuation_db(attenuation_in_db) + save_sim_params = {"raman_params": SimParams._shared_dict['raman_params'].to_json(), + "nli_params": SimParams._shared_dict['nli_params'].to_json()} SimParams.set_params(sim_params) - pin = watt2dbm(sum(spectral_info_input.signal)) - spectral_info_out = n_copy(spectral_info_input) - pout = watt2dbm(sum(spectral_info_out.signal)) - estimated_gain = pout - pin + node.loss + stimulated_raman_scattering = RamanSolver.calculate_stimulated_raman_scattering(spectral_info, node) + attenuation_fiber = stimulated_raman_scattering.loss_profile[:spectral_info.number_of_channels, -1] + spectral_info.apply_attenuation_lin(attenuation_fiber) + attenuation_out_db = node.params.con_out + spectral_info.apply_attenuation_db(attenuation_out_db) + pout = watt2dbm(sum(spectral_info.signal)) + estimated_loss = pin - pout + estimated_gain = node.loss - estimated_loss + node.estimated_gain = estimated_gain + SimParams.set_params(save_sim_params) return round(estimated_gain, 2) else: return 0.0 -def span_loss(network, node, equipment): - """Total loss of a span (Fiber and Fused nodes) which contains the given node""" +def span_loss(network, node, equipment, input_power=None): + """Total loss of a span (Fiber and Fused nodes) which contains the given node + Do not recompute, if it was already computed: records it in design_span_loss""" + if hasattr(node, "design_span_loss"): + return node.design_span_loss loss = node.loss if node.passive else 0 loss += sum(n.loss for n in prev_node_generator(network, node)) loss += sum(n.loss for n in next_node_generator(network, node)) # add the possible Raman gain - gain = estimate_raman_gain(node, equipment) - gain += sum(estimate_raman_gain(n, equipment) for n in prev_node_generator(network, node)) - gain += sum(estimate_raman_gain(n, equipment) for n in next_node_generator(network, node)) - + gain = estimate_raman_gain(node, equipment, input_power) + gain += sum(estimate_raman_gain(n, equipment, input_power) for n in prev_node_generator(network, node)) + gain += sum(estimate_raman_gain(n, equipment, input_power) for n in next_node_generator(network, node)) + node.design_span_loss = loss - gain return loss - gain @@ -399,7 +410,8 @@ def set_egress_amplifier(network, this_node, equipment, pref_ch_db, pref_total_d node.target_pch_out_dbm = round(node.delta_p + pref_ch_db, 2) elif node.delta_p is None: node.target_pch_out_dbm = None - + elif isinstance(node, elements.RamanFiber): + _ = span_loss(network, node, equipment, input_power=pref_ch_db + dp) prev_dp = dp prev_voa = voa prev_node = node @@ -701,6 +713,9 @@ def add_fiber_padding(network, fibers, padding, equipment): next_node = get_next_node(fiber, network) if isinstance(next_node, elements.Fused): continue + # do not pad if this is a Raman Fiber + if isinstance(fiber, elements.RamanFiber): + continue this_span_loss = span_loss(network, fiber, equipment) if this_span_loss < padding: # add a padding att_in at the input of the 1st fiber: @@ -710,6 +725,7 @@ def add_fiber_padding(network, fibers, padding, equipment): # just after a roadm: need to check that first_fiber is really a fiber if isinstance(first_fiber, elements.Fiber): first_fiber.params.att_in = first_fiber.params.att_in + padding - this_span_loss + first_fiber.design_span_loss += first_fiber.params.att_in def add_missing_elements_in_network(network, equipment): diff --git a/gnpy/core/parameters.py b/gnpy/core/parameters.py index e23accc19..28e915db2 100644 --- a/gnpy/core/parameters.py +++ b/gnpy/core/parameters.py @@ -46,6 +46,11 @@ def __init__(self, flag=False, result_spatial_resolution=10e3, solver_spatial_re self.result_spatial_resolution = result_spatial_resolution # [m] self.solver_spatial_resolution = solver_spatial_resolution # [m] + def to_json(self): + return {"flag": self.flag, + "result_spatial_resolution": self.result_spatial_resolution, + "solver_spatial_resolution": self.solver_spatial_resolution} + class NLIParams(Parameters): def __init__(self, method='gn_model_analytic', dispersion_tolerance=1, phase_shift_tolerance=0.1, @@ -62,6 +67,12 @@ def __init__(self, method='gn_model_analytic', dispersion_tolerance=1, phase_shi self.phase_shift_tolerance = phase_shift_tolerance self.computed_channels = computed_channels + def to_json(self): + return {"method": self.method, + "dispersion_tolerance": self.dispersion_tolerance, + "phase_shift_tolerance": self.phase_shift_tolerance, + "computed_channels": self.computed_channels} + class SimParams(Parameters): _shared_dict = {'nli_params': NLIParams(), 'raman_params': RamanParams()} diff --git a/tests/invocation/transmission_main_example__raman b/tests/invocation/transmission_main_example__raman index 0dc242d35..5249b5ee0 100644 --- a/tests/invocation/transmission_main_example__raman +++ b/tests/invocation/transmission_main_example__raman @@ -25,112 +25,114 @@ RamanFiber Span1 (conn loss out includes EOL margin defined in eqpt_config.json) reference pch out (dBm): -7.20 actual pch out (dBm): -7.47 + reference gain (dB): 9.74 + actual gain (dB): 9.8 Fused Fused1 loss (dB): 0.00 Edfa Edfa1 type_variety: std_low_gain - effective gain(dB): 5.20 + effective gain(dB): 5.26 (before att_in and before output VOA) - noise figure (dB): 13.80 + noise figure (dB): 13.74 (including att_in) - pad att_in (dB): 2.80 + pad att_in (dB): 2.74 Power In (dBm): 11.61 - Power Out (dBm): 16.81 + Power Out (dBm): 16.87 Delta_P (dB): -2.00 target pch (dBm): -2.00 - actual pch out (dBm): -2.26 + actual pch out (dBm): -2.21 output VOA (dB): 0.00 Transceiver Site_B - GSNR (0.1nm, dB): 31.42 - GSNR (signal bw, dB): 27.34 - OSNR ASE (0.1nm, dB): 34.21 - OSNR ASE (signal bw, dB): 30.13 + GSNR (0.1nm, dB): 31.44 + GSNR (signal bw, dB): 27.35 + OSNR ASE (0.1nm, dB): 34.24 + OSNR ASE (signal bw, dB): 30.16 CD (ps/nm): 1336.00 PMD (ps): 0.36 PDL (dB): 0.00 Latency (ms): 0.39 Transmission result for input power = 0.00 dBm: - Final GSNR (0.1 nm): 31.42 dB + Final GSNR (0.1 nm): 31.44 dB The GSNR per channel at the end of the line is: Ch. # Channel frequency (THz) Channel power (dBm) OSNR ASE (signal bw, dB) SNR NLI (signal bw, dB) GSNR (signal bw, dB) - 1 191.35000 0.22 31.64 31.55 28.58 - 2 191.40000 0.18 31.62 31.46 28.53 - 3 191.45000 0.15 31.60 31.37 28.47 - 4 191.50000 0.11 31.58 31.28 28.42 - 5 191.55000 0.05 31.54 31.20 28.36 - 6 191.60000 -0.01 31.51 31.11 28.30 - 7 191.65000 -0.07 31.48 31.03 28.24 - 8 191.70000 -0.12 31.45 30.95 28.18 - 9 191.75000 -0.18 31.42 30.87 28.13 - 10 191.80000 -0.25 31.38 30.79 28.07 - 11 191.85000 -0.31 31.35 30.72 28.01 - 12 191.90000 -0.38 31.31 30.64 27.95 - 13 191.95000 -0.44 31.27 30.57 27.90 - 14 192.00000 -0.51 31.24 30.50 27.84 - 15 192.05000 -0.58 31.20 30.42 27.78 - 16 192.10000 -0.64 31.16 30.35 27.73 - 17 192.15000 -0.71 31.12 30.29 27.67 - 18 192.20000 -0.78 31.08 30.22 27.62 - 19 192.25000 -0.85 31.04 30.22 27.60 - 20 192.30000 -0.93 31.00 30.22 27.58 - 21 192.35000 -1.00 30.96 30.23 27.57 - 22 192.40000 -1.08 30.91 30.23 27.55 - 23 192.45000 -1.16 30.87 30.23 27.53 - 24 192.50000 -1.23 30.82 30.24 27.51 - 25 192.55000 -1.30 30.78 30.24 27.49 - 26 192.60000 -1.37 30.74 30.24 27.47 - 27 192.65000 -1.44 30.70 30.25 27.46 - 28 192.70000 -1.52 30.65 30.25 27.44 - 29 192.75000 -1.59 30.61 30.25 27.42 - 30 192.80000 -1.66 30.57 30.26 27.40 - 31 192.85000 -1.73 30.52 30.26 27.38 - 32 192.90000 -1.80 30.48 30.26 27.36 - 33 192.95000 -1.87 30.43 30.27 27.34 - 34 193.00000 -1.94 30.39 30.27 27.32 - 35 193.05000 -2.01 30.35 30.27 27.30 - 36 193.10000 -2.08 30.30 30.28 27.28 - 37 193.15000 -2.15 30.26 30.28 27.26 - 38 193.20000 -2.22 30.22 30.29 27.24 - 39 193.25000 -2.29 30.17 30.31 27.23 - 40 193.30000 -2.36 30.13 30.32 27.21 - 41 193.35000 -2.43 30.08 30.33 27.19 - 42 193.40000 -2.50 30.04 30.35 27.18 - 43 193.45000 -2.56 29.99 30.36 27.16 - 44 193.50000 -2.63 29.95 30.37 27.14 - 45 193.55000 -2.71 29.90 30.39 27.12 - 46 193.60000 -2.78 29.85 30.40 27.11 - 47 193.65000 -2.85 29.80 30.41 27.09 - 48 193.70000 -2.93 29.75 30.43 27.07 - 49 193.75000 -3.00 29.70 30.44 27.05 - 50 193.80000 -3.07 29.65 30.45 27.02 - 51 193.85000 -3.15 29.60 30.47 27.00 - 52 193.90000 -3.22 29.55 30.48 26.98 - 53 193.95000 -3.29 29.50 30.50 26.96 - 54 194.00000 -3.37 29.45 30.51 26.94 - 55 194.05000 -3.44 29.40 30.52 26.92 - 56 194.10000 -3.52 29.35 30.54 26.89 - 57 194.15000 -3.59 29.30 30.59 26.89 - 58 194.20000 -3.66 29.25 30.64 26.88 - 59 194.25000 -3.74 29.19 30.70 26.87 - 60 194.30000 -3.81 29.14 30.75 26.86 - 61 194.35000 -3.89 29.09 30.81 26.86 - 62 194.40000 -3.96 29.04 30.87 26.85 - 63 194.45000 -4.04 28.98 30.93 26.84 - 64 194.50000 -4.11 28.93 30.98 26.83 - 65 194.55000 -4.18 28.88 31.04 26.82 - 66 194.60000 -4.25 28.83 31.10 26.81 - 67 194.65000 -4.31 28.78 31.17 26.80 - 68 194.70000 -4.38 28.74 31.23 26.79 - 69 194.75000 -4.45 28.69 31.29 26.79 - 70 194.80000 -4.51 28.64 31.35 26.78 - 71 194.85000 -4.58 28.59 31.42 26.77 - 72 194.90000 -4.65 28.54 31.48 26.76 - 73 194.95000 -4.71 28.49 31.55 26.74 - 74 195.00000 -4.78 28.44 31.62 26.73 - 75 195.05000 -4.85 28.39 31.69 26.72 - 76 195.10000 -4.91 28.34 31.69 26.69 + 1 191.35000 0.27 31.66 31.55 28.60 + 2 191.40000 0.24 31.64 31.46 28.54 + 3 191.45000 0.20 31.62 31.37 28.48 + 4 191.50000 0.17 31.60 31.28 28.43 + 5 191.55000 0.11 31.57 31.20 28.37 + 6 191.60000 0.05 31.54 31.11 28.31 + 7 191.65000 -0.01 31.51 31.03 28.25 + 8 191.70000 -0.07 31.47 30.95 28.20 + 9 191.75000 -0.13 31.44 30.87 28.14 + 10 191.80000 -0.19 31.41 30.79 28.08 + 11 191.85000 -0.26 31.37 30.72 28.02 + 12 191.90000 -0.32 31.34 30.64 27.97 + 13 191.95000 -0.39 31.30 30.57 27.91 + 14 192.00000 -0.45 31.26 30.50 27.85 + 15 192.05000 -0.52 31.23 30.42 27.80 + 16 192.10000 -0.59 31.19 30.35 27.74 + 17 192.15000 -0.66 31.15 30.29 27.69 + 18 192.20000 -0.72 31.11 30.22 27.63 + 19 192.25000 -0.79 31.07 30.22 27.62 + 20 192.30000 -0.87 31.03 30.22 27.60 + 21 192.35000 -0.95 30.99 30.23 27.58 + 22 192.40000 -1.02 30.94 30.23 27.56 + 23 192.45000 -1.10 30.90 30.23 27.54 + 24 192.50000 -1.18 30.85 30.24 27.52 + 25 192.55000 -1.25 30.81 30.24 27.51 + 26 192.60000 -1.32 30.77 30.24 27.49 + 27 192.65000 -1.39 30.73 30.25 27.47 + 28 192.70000 -1.46 30.68 30.25 27.45 + 29 192.75000 -1.53 30.64 30.25 27.43 + 30 192.80000 -1.60 30.60 30.26 27.41 + 31 192.85000 -1.67 30.55 30.26 27.39 + 32 192.90000 -1.74 30.51 30.26 27.37 + 33 192.95000 -1.81 30.47 30.27 27.35 + 34 193.00000 -1.89 30.42 30.27 27.33 + 35 193.05000 -1.95 30.38 30.27 27.32 + 36 193.10000 -2.02 30.34 30.28 27.30 + 37 193.15000 -2.09 30.29 30.28 27.28 + 38 193.20000 -2.16 30.25 30.29 27.26 + 39 193.25000 -2.23 30.20 30.31 27.24 + 40 193.30000 -2.30 30.16 30.32 27.23 + 41 193.35000 -2.37 30.11 30.33 27.21 + 42 193.40000 -2.44 30.07 30.35 27.20 + 43 193.45000 -2.51 30.02 30.36 27.18 + 44 193.50000 -2.58 29.98 30.37 27.16 + 45 193.55000 -2.65 29.93 30.39 27.14 + 46 193.60000 -2.72 29.88 30.40 27.12 + 47 193.65000 -2.80 29.83 30.41 27.10 + 48 193.70000 -2.87 29.79 30.43 27.08 + 49 193.75000 -2.94 29.74 30.44 27.06 + 50 193.80000 -3.02 29.69 30.45 27.04 + 51 193.85000 -3.09 29.64 30.47 27.02 + 52 193.90000 -3.16 29.59 30.48 27.00 + 53 193.95000 -3.24 29.54 30.50 26.98 + 54 194.00000 -3.31 29.49 30.51 26.96 + 55 194.05000 -3.38 29.44 30.52 26.94 + 56 194.10000 -3.46 29.39 30.54 26.91 + 57 194.15000 -3.53 29.33 30.59 26.91 + 58 194.20000 -3.61 29.28 30.64 26.90 + 59 194.25000 -3.68 29.23 30.70 26.89 + 60 194.30000 -3.76 29.18 30.75 26.89 + 61 194.35000 -3.83 29.13 30.81 26.88 + 62 194.40000 -3.91 29.07 30.87 26.87 + 63 194.45000 -3.98 29.02 30.93 26.86 + 64 194.50000 -4.05 28.97 30.98 26.85 + 65 194.55000 -4.12 28.92 31.04 26.84 + 66 194.60000 -4.19 28.87 31.10 26.84 + 67 194.65000 -4.26 28.82 31.17 26.83 + 68 194.70000 -4.32 28.77 31.23 26.82 + 69 194.75000 -4.39 28.72 31.29 26.81 + 70 194.80000 -4.46 28.68 31.35 26.80 + 71 194.85000 -4.52 28.63 31.42 26.79 + 72 194.90000 -4.59 28.58 31.48 26.78 + 73 194.95000 -4.66 28.53 31.55 26.77 + 74 195.00000 -4.72 28.48 31.62 26.76 + 75 195.05000 -4.79 28.43 31.69 26.75 + 76 195.10000 -4.86 28.38 31.69 26.71 (No source node specified: picked Site_A)