#!/usr/bin/env python3 # -*- coding: utf-8 -*- # @Author: Jean-Luc Auge # @Date: 2018-02-02 14:06:55 from numpy import zeros, array from gnpy.core.elements import Transceiver, Edfa from gnpy.core.utils import automatic_fmax, lin2db, db2lin, merge_amplifier_restrictions from gnpy.core.info import create_input_spectral_information, ReferenceCarrier from gnpy.core.network import build_network from gnpy.tools.json_io import load_network, load_equipment from pathlib import Path import pytest TEST_DIR = Path(__file__).parent DATA_DIR = TEST_DIR / 'data' test_network = DATA_DIR / 'test_network.json' eqpt_library = DATA_DIR / 'eqpt_config.json' # TODO in elements.py code: pytests doesn't pass with 1 channel: interpolate fail @pytest.fixture( params=[(96, 0.05e12), (60, 0.075e12), (45, 0.1e12), (2, 0.1e12)], ids=['50GHz spacing', '75GHz spacing', '100GHz spacing', '2 channels']) def nch_and_spacing(request): """parametrize channel count vs channel spacing (Hz)""" yield request.param @pytest.fixture() def bw(): """parametrize signal bandwidth (Hz)""" return 45e9 @pytest.fixture() def setup_edfa_variable_gain(): """init edfa class by reading test_network.json file remove all gain and nf ripple""" equipment = load_equipment(eqpt_library) network = load_network(test_network, equipment) build_network(network, equipment, 0, 20) edfa = [n for n in network.nodes() if isinstance(n, Edfa)][0] edfa.gain_ripple = zeros(96) edfa.interpol_nf_ripple = zeros(96) yield edfa @pytest.fixture() def setup_edfa_fixed_gain(): """init edfa class by reading the 2nd edfa in test_network.json file""" equipment = load_equipment(eqpt_library) network = load_network(test_network, equipment) build_network(network, equipment, 0, 20) edfa = [n for n in network.nodes() if isinstance(n, Edfa)][1] yield edfa @pytest.fixture() def setup_trx(): """init transceiver class to access snr and osnr calculations""" equipment = load_equipment(eqpt_library) network = load_network(test_network, equipment) build_network(network, equipment, 0, 20) trx = [n for n in network.nodes() if isinstance(n, Transceiver)][0] return trx @pytest.fixture() def si(nch_and_spacing, bw): """parametrize a channel comb with nb_channel, spacing and signal bw""" nb_channel, spacing = nch_and_spacing f_min = 191.3e12 f_max = automatic_fmax(f_min, spacing, nb_channel) return create_input_spectral_information(f_min=f_min, f_max=f_max, roll_off=0.15, baud_rate=bw, power=1e-3, spacing=spacing, tx_osnr=40.0, ref_carrier=ReferenceCarrier(baud_rate=32e9, slot_width=50e9)) @pytest.mark.parametrize("gain, nf_expected", [(10, 15), (15, 10), (25, 5.8)]) def test_variable_gain_nf(gain, nf_expected, setup_edfa_variable_gain, si): """=> unitary test for variable gain model Edfa._calc_nf() (and Edfa.interpol_params)""" edfa = setup_edfa_variable_gain si.signal /= db2lin(gain) si.nli /= db2lin(gain) si.ase /= db2lin(gain) edfa.operational.gain_target = gain si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) result = edfa.nf assert pytest.approx(nf_expected, abs=0.01) == result[0] @pytest.mark.parametrize("gain, nf_expected", [(15, 10), (20, 5), (25, 5)]) def test_fixed_gain_nf(gain, nf_expected, setup_edfa_fixed_gain, si): """=> unitary test for fixed gain model Edfa._calc_nf() (and Edfa.interpol_params)""" edfa = setup_edfa_fixed_gain si.signal /= db2lin(gain) si.nli /= db2lin(gain) si.ase /= db2lin(gain) edfa.operational.gain_target = gain si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) assert pytest.approx(nf_expected, abs=0.01) == edfa.nf[0] def test_si(si, nch_and_spacing): """basic total power check of the channel comb generation""" nb_channel = nch_and_spacing[0] p_tot = sum(si.signal + si.ase + si.nli) expected_p_tot = si.signal[0] * nb_channel assert pytest.approx(expected_p_tot, abs=0.01) == p_tot @pytest.mark.parametrize("gain", [17, 19, 21, 23]) def test_compare_nf_models(gain, setup_edfa_variable_gain, si): """compare the 2 amplifier models (polynomial and estimated from nf_min and max) => nf_model vs nf_poly_fit for intermediate gain values: between gain_min and gain_flatmax some discrepancy is expected but target < 0.5dB => unitary test for Edfa._calc_nf (and Edfa.interpol_params)""" edfa = setup_edfa_variable_gain si.signal /= db2lin(gain) si.nli /= db2lin(gain) si.ase /= db2lin(gain) edfa.operational.gain_target = gain # edfa is variable gain type si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) nf_model = edfa.nf[0] # change edfa type variety to a polynomial el_config = { "uid": "Edfa1", "operational": { "gain_target": gain, "tilt_target": 0 }, "metadata": { "location": { "region": "", "latitude": 2, "longitude": 0 } } } equipment = load_equipment(eqpt_library) extra_params = equipment['Edfa']['CienaDB_medium_gain'] temp = el_config.setdefault('params', {}) temp = merge_amplifier_restrictions(temp, extra_params.__dict__) el_config['params'] = temp edfa = Edfa(**el_config) # edfa is variable gain type edfa.interpol_params(si) nf_poly = edfa.nf[0] print(nf_poly, nf_model) assert pytest.approx(nf_model, abs=0.5) == nf_poly @pytest.mark.parametrize("gain", [13, 15, 17, 19, 21, 23, 25, 27]) def test_ase_noise(gain, si, setup_trx, bw): """testing 3 different ways of calculating osnr: 1-pin-edfa.nf+58 vs 2-pout/pase afet propagate 3-Transceiver osnr_ase_01nm => unitary test for Edfa.noise_profile (Edfa.interpol_params, Edfa.propagate)""" equipment = load_equipment(eqpt_library) network = load_network(test_network, equipment) edfa = next(n for n in network.nodes() if n.uid == 'Edfa1') span = next(n for n in network.nodes() if n.uid == 'Span1') # update span1 and Edfa1 according to new gain before building network # updating span 1 avoids to overload amp span.params.length = gain * 1e3 / 0.2 edfa.operational.gain_target = gain build_network(network, equipment, 0, 20) edfa.gain_ripple = zeros(96) edfa.interpol_nf_ripple = zeros(96) # propagate in span1 to have si with the correct power level si = span(si) print(span) si.pref = si.pref._replace(p_span0=0, p_spani=-gain) edfa.interpol_params(si) nf = edfa.nf print('nf', nf) pin = lin2db((si.signal[0] + si.ase[0] + si.nli[0]) * 1e3) osnr_expected = pin - nf[0] + 58 si = edfa(si) print(edfa) osnr = lin2db(si.signal[0] / si.ase[0]) - lin2db(12.5e9 / bw) assert pytest.approx(osnr_expected, abs=0.01) == osnr trx = setup_trx si = trx(si) osnr = trx.osnr_ase_01nm[0] assert pytest.approx(osnr_expected, abs=0.01) == osnr