diff --git a/core/__main__.py b/core/__main__.py index 8b6e4084..9ff0f006 100644 --- a/core/__main__.py +++ b/core/__main__.py @@ -10,6 +10,17 @@ from networkx import (draw_networkx_nodes, draw_networkx_edges, from . import network_from_json from .elements import Transceiver, Fiber +from .info import SpectralInformation, Channel, Power +from .algorithms import closed_paths + +logger = getLogger(__package__ or __file__) + +def format_si(spectral_infos): + return '\n'.join([ + f'#{idx} Carrier(frequency={c.frequency},\n power=Power(signal={c.power.signal}, nli={c.power.nli}, ase={c.power.ase}))' + for idx, si in sorted(set(spectral_infos)) + for c in set(si.carriers) + ]) logger = getLogger('gnpy.core') @@ -25,9 +36,38 @@ def main(args): for n in network.nodes()] labels = {n: n.location.city if isinstance(n, Transceiver) else '' for n in network.nodes()} - draw_networkx_nodes(network, pos=pos, node_size=size, node_color=color) - draw_networkx_edges(network, pos=pos) - draw_networkx_labels(network, pos=labels_pos, labels=labels, font_size=14) + + si = SpectralInformation( + Channel(1, 193.95e12, '16-qam', 32e9, 0, # 193.95 THz, 32 Gbaud + Power(1e-3, 1e-6, 1e-6)), # 1 mW, 1uW, 1uW + Channel(1, 195.95e12, '16-qam', 32e9, 0, # 195.95 THz, 32 Gbaud + Power(1.2e-3, 1e-6, 1e-6)), # 1.2 mW, 1uW, 1uW + ) + + nodes = [n for n in network.nodes() if isinstance(n, Transceiver)] + source, sink = choice(nodes), choice(nodes) + + results = list(islice(closed_paths(network, source, sink, si), 3)) + paths = [[n for _, n, _ in r] for r in results] + infos = {} + for idx, r in enumerate(results): + for in_si, node, out_si in r: + infos.setdefault(node, []).append((idx, out_si)) + + node_color = ['#ff0000' if n is source or n is sink else + '#900000' if any(n in p for p in paths) else + '#ffdede' if isinstance(n, Transceiver) else '#dedeff' + for n in network.nodes()] + edge_color = ['#ff9090' if any(u in p for p in paths) and + any(v in p for p in paths) else '#dedede' + for u, v in network.edges()] + + fig = figure() + plot = draw_networkx_nodes(network, pos=pos, node_size=size, node_color=node_color, figure=fig) + draw_networkx_edges(network, pos=pos, figure=fig, edge_color=edge_color) + draw_networkx_labels(network, pos=labels_pos, labels=labels, font_size=14, figure=fig) + + title(f'Propagating from {source.loc.city} to {sink.loc.city}') axis('off') show() diff --git a/core/elements.py b/core/elements.py index ccf4c149..5ca54cef 100644 --- a/core/elements.py +++ b/core/elements.py @@ -1,9 +1,12 @@ #!/usr/bin/env python3 - from core.node import Node from core.units import UNITS +import numpy as np +from scipy.constants import c +# network elements + class Transceiver(Node): def __init__(self, config): super().__init__(config) @@ -11,7 +14,6 @@ class Transceiver(Node): def __call__(self, spectral_info): return spectral_info - class Fiber(Node): def __init__(self, config): super().__init__(config) @@ -20,6 +22,51 @@ class Fiber(Node): def __repr__(self): return f'{type(self).__name__}(uid={self.uid}, length={self.length})' + + def effective_length(self, loss_coef): + alpha_dict = self.dbkm_2_lin(loss_coef) + alpha = alpha_dict['alpha_acoef'] + leff = 1 - np.exp(-2 * alpha * self.span_length) + return leff + + def asymptotic_length(self, loss_coef): + alpha_dict = self.dbkm_2_lin(loss_coef) + alpha = alpha_dict['alpha_acoef'] + aleff = 1/(2 * alpha) + return aleff + + def dbkm_2_lin(self, loss_coef): + """ calculates the linear loss coefficient + """ + alpha_pcoef = loss_coef + alpha_acoef = alpha_pcoef/(2*4.3429448190325184) + s = 'alpha_pcoef is linear loss coefficient in [dB/km^-1] units' + s = ''.join([s, "alpha_acoef is linear loss field amplitude \ + coefficient in [km^-1] units"]) + d = {'alpha_pcoef': alpha_pcoef, 'alpha_acoef': alpha_acoef, + 'description:': s} + return d + + def beta2(self, dispersion, ref_wavelength=None): + """ Returns beta2 from dispersion parameter. Dispersion is entered in + ps/nm/km. Disperion can be a numpy array or a single value. If a + value ref_wavelength is not entered 1550e-9m will be assumed. + ref_wavelength can be a numpy array. + """ + if ref_wavelength is None: + ref_wavelength = 1550e-9 + wl = ref_wavelength + D = np.abs(dispersion) + b2 = (10**21) * (wl**2) * D / (2 * np.pi * c) +# 10^21 scales to ps^2/km + return b2 + + # convenience access + loss = property(lambda self: self.loss_.value) + length = property(lambda self: self.length_.value) + loc = property(lambda self: self.location) + lat = property(lambda self: self.location.latitude) + long = property(lambda self: self.location.longitude) def propagate(self, *carriers): for carrier in carriers: @@ -32,3 +79,4 @@ class Fiber(Node): def __call__(self, spectral_info): carriers = tuple(self.propagate(*spectral_info.carriers)) return spectral_info.update(carriers=carriers) + diff --git a/core/info.py b/core/info.py new file mode 100644 index 00000000..cb0b1882 --- /dev/null +++ b/core/info.py @@ -0,0 +1,42 @@ +#!/usr/bin/env python3 + +from collections import namedtuple + +class ConvenienceAccess: + def __init_subclass__(cls): + for abbrev, field in getattr(cls, '_ABBREVS', {}).items(): + setattr(cls, abbrev, property(lambda self, f=field: getattr(self, f))) + + def update(self, **kwargs): + for abbrev, field in getattr(self, '_ABBREVS', {}).items(): + if abbrev in kwargs: + kwargs[field] = kwargs.pop(abbrev) + return self._replace(**kwargs) + +class Power(namedtuple('Power', 'signal nonlinear_interference amplified_spontaneous_emission'), ConvenienceAccess): + _ABBREVS = {'nli': 'nonlinear_interference', + 'ase': 'amplified_spontaneous_emission',} + +class Channel(namedtuple('Channel', 'channel_number frequency modulation baud_rate alpha power'), ConvenienceAccess): + _ABBREVS = {'channel': 'channel_number', + 'num_chan': 'channel_number', + 'num_carriers': 'num_carriers', + 'ffs': 'frequency', + 'freq': 'frequency',} + +class SpectralInformation(namedtuple('SpectralInformation', 'carriers'), ConvenienceAccess): + def __new__(cls, *carriers): + return super().__new__(cls, carriers) + +if __name__ == '__main__': + si = SpectralInformation( + Channel(1, 193.95e12, '16-qam', 32e9, 0, # 193.95 THz, 32 Gbaud + Power(1e-3, 1e-6, 1e-6)), # 1 mW, 1uW, 1uW + Channel(1, 195.95e12, '16-qam', 32e9, 0, # 195.95 THz, 32 Gbaud + Power(1.2e-3, 1e-6, 1e-6)), # 1.2 mW, 1uW, 1uW + ) + print(f'si = {si}') + print(f'si = {si.carriers[0].power.nli}') + si2 = si.update(carriers=tuple(c.update(power = c.power.update(nli = c.power.nli * 1e5)) + for c in si.carriers)) + print(f'si2 = {si2}') diff --git a/examples/convert.py b/examples/convert.py index 637d6dba..ae446b9a 100644 --- a/examples/convert.py +++ b/examples/convert.py @@ -10,12 +10,36 @@ from collections import namedtuple, Counter from itertools import chain from json import dumps from uuid import uuid4 +import math +import numpy as np Node = namedtuple('Node', 'city state country region latitude longitude') class Link(namedtuple('Link', 'from_city to_city distance distance_units')): def __new__(cls, from_city, to_city, distance, distance_units='km'): return super().__new__(cls, from_city, to_city, distance, distance_units) +def define_span_range(min_span, max_span, nspans): + srange = (max_span - min_span) + min_span*np.random.rand(nspans) + return srange + +def amp_spacings(min_span,max_span,length): + nspans = math.ceil(length/100) + spans = define_span_range(min_span, max_span, nspans) + tot = spans.sum() + delta = length -tot + if delta > 0 and delta < 25: + ind = np.where(np.min(spans)) + spans[ind] = spans[ind] + delta + elif delta >= 25 and delta < 40: + spans = spans + delta/float(nspans) + elif delta > 40 and delta < 100: + spans = np.append(spans,delta) + elif delta > 100: + spans = np.append(spans, [delta/2, delta/2]) + elif delta < 0: + spans = spans + delta/float(nspans) + return list(spans) + def parse_excel(args): with open_workbook(args.workbook) as wb: nodes_sheet = wb.sheet_by_name('Nodes') @@ -113,4 +137,4 @@ if __name__ == '__main__': for x in links]))) } - print(dumps(data, indent=2)) + print(dumps(data, indent=2)) \ No newline at end of file diff --git a/examples/edfa_model/DFG_96.txt b/examples/edfa_model/DFG_96.txt new file mode 100755 index 00000000..4edd1fd0 --- /dev/null +++ b/examples/edfa_model/DFG_96.txt @@ -0,0 +1 @@ + 2.5135969849999999e+01 2.5118228139999999e+01 2.5095421330000001e+01 2.5062457710000000e+01 2.5026027650000000e+01 2.4996379529999999e+01 2.4981672549999999e+01 2.4975306679999999e+01 2.4983207260000000e+01 2.4997185649999999e+01 2.5017572470000001e+01 2.5038327809999998e+01 2.5054955849999999e+01 2.5067071899999998e+01 2.5070914110000000e+01 2.5070943650000000e+01 2.5071143240000001e+01 2.5075336270000001e+01 2.5087310179999999e+01 2.5103139360000000e+01 2.5122762040000001e+01 2.5142394790000001e+01 2.5159456330000001e+01 2.5173927039999999e+01 2.5176737670000001e+01 2.5170371410000001e+01 2.5152162539999999e+01 2.5131143099999999e+01 2.5108023350000000e+01 2.5085487770000000e+01 2.5069166750000001e+01 2.5058481759999999e+01 2.5054473130000002e+01 2.5051544410000002e+01 2.5049460589999999e+01 2.5047178490000000e+01 2.5045516559999999e+01 2.5044676490000001e+01 2.5040729200000001e+01 2.5032854080000000e+01 2.5023488300000000e+01 2.5016592339999999e+01 2.5013321359999999e+01 2.5011234340000001e+01 2.5010300149999999e+01 2.5009365480000000e+01 2.5008739640000002e+01 2.5008425350000000e+01 2.5006964660000001e+01 2.5004043100000001e+01 2.5000709980000000e+01 2.4998423200000001e+01 2.4993063320000001e+01 2.4983524209999999e+01 2.4971251030000001e+01 2.4960381080000001e+01 2.4948887209999999e+01 2.4935314890000001e+01 2.4921319270000001e+01 2.4908986970000001e+01 2.4898965140000001e+01 2.4889584630000002e+01 2.4880838700000002e+01 2.4872100920000001e+01 2.4864620259999999e+01 2.4858397730000000e+01 2.4854458380000001e+01 2.4851554430000000e+01 2.4851766009999999e+01 2.4854080140000001e+01 2.4859096240000000e+01 2.4864744580000000e+01 2.4872034859999999e+01 2.4880365200000000e+01 2.4889106689999998e+01 2.4897213130000001e+01 2.4902826040000001e+01 2.4906566900000001e+01 2.4908650800000000e+01 2.4910939440000000e+01 2.4913430790000000e+01 2.4915923440000000e+01 2.4921553509999999e+01 2.4930318610000000e+01 2.4940528120000000e+01 2.4949046689999999e+01 2.4957571229999999e+01 2.4967818449999999e+01 2.4981800929999999e+01 2.4997826860000000e+01 2.5013931830000001e+01 2.5028098459999999e+01 2.5040325750000001e+01 2.5052569810000001e+01 2.5064797009999999e+01 2.5077046970000001e+01 diff --git a/examples/edfa_model/DGT_96.txt b/examples/edfa_model/DGT_96.txt new file mode 100755 index 00000000..8807236c --- /dev/null +++ b/examples/edfa_model/DGT_96.txt @@ -0,0 +1 @@ + 2.7145266811316859e+00 2.7054438192385049e+00 2.6947834587664494e+00 2.6841217449620203e+00 2.6681935771243177e+00 2.6521732021128046e+00 2.6303964408153848e+00 2.6028603502864280e+00 2.5696460593920065e+00 2.5364027376452056e+00 2.4994462867966041e+00 2.4587748041127506e+00 2.4143984371852212e+00 2.3699990328716107e+00 2.3223736962293420e+00 2.2715207713712529e+00 2.2174389328192197e+00 2.1633756538423898e+00 2.1183028432496016e+00 2.0822250998736478e+00 2.0551007720052352e+00 2.0279625371819305e+00 2.0008103857988204e+00 1.9736443063300082e+00 1.9482128147680253e+00 1.9245345552113182e+00 1.9026104247588487e+00 1.8806927939516411e+00 1.8622356724442459e+00 1.8472755032011290e+00 1.8358140813807049e+00 1.8243814368429321e+00 1.8139629377087627e+00 1.8045606557581335e+00 1.7961751115773796e+00 1.7877868031023945e+00 1.7793941781790852e+00 1.7709972329654864e+00 1.7625959636196327e+00 1.7541903672600494e+00 1.7459181197626403e+00 1.7377807579136351e+00 1.7297783508684146e+00 1.7217732861435076e+00 1.7137640932265894e+00 1.7057507692361864e+00 1.6918150918099673e+00 1.6719047669939942e+00 1.6460167077689267e+00 1.6201194134191075e+00 1.5986915141218316e+00 1.5817353179379183e+00 1.5691997641843789e+00 1.5566577309558969e+00 1.5453741527614671e+00 1.5353620432989845e+00 1.5266220576235803e+00 1.5178910621476225e+00 1.5097346239790443e+00 1.5021530399096861e+00 1.4951454560626991e+00 1.4881342434792260e+00 1.4811193973568100e+00 1.4741004422522110e+00 1.4670307626366115e+00 1.4599103316162523e+00 1.4527395948591399e+00 1.4455651371583680e+00 1.4340878115214444e+00 1.4182738067303231e+00 1.3981208704326855e+00 1.3779439775587023e+00 1.3598972673004606e+00 1.3439818461440451e+00 1.3301807335621048e+00 1.3163839268630830e+00 1.3040618749785347e+00 1.2932153453410835e+00 1.2838336236692311e+00 1.2744470198196236e+00 1.2650555289898042e+00 1.2556591482982988e+00 1.2428104897182262e+00 1.2264996957264114e+00 1.2067249615595257e+00 1.1869318618366975e+00 1.1672278304018044e+00 1.1476135933863398e+00 1.1280891949729075e+00 1.1085552896156590e+00 1.0895983485572227e+00 1.0712204022764056e+00 1.0534217504465226e+00 1.0356155337864215e+00 1.0178077678537021e+00 1.0000000000000000e+00 diff --git a/examples/edfa_model/NFR_96.txt b/examples/edfa_model/NFR_96.txt new file mode 100755 index 00000000..43a7d090 --- /dev/null +++ b/examples/edfa_model/NFR_96.txt @@ -0,0 +1 @@ + -3.1537433199999998e-01 -3.1537433199999998e-01 -3.1540091571002721e-01 -3.1849146117510951e-01 -3.2158358425400546e-01 -3.2467728615499991e-01 -3.2762368641496226e-01 -3.2054138461232762e-01 -3.1345546385118733e-01 -3.0636592135697482e-01 -2.9920267890990127e-01 -2.7061972852631744e-01 -2.4202215770774693e-01 -2.1340995523361256e-01 -1.8478227130158695e-01 -1.4809761118389625e-01 -1.1139416731807622e-01 -7.4671925273579881e-02 -3.8026748965679924e-02 -1.9958469399422092e-02 -1.8809287980157928e-03 1.6205879960573561e-02 3.4301964005709673e-02 5.2407330474054062e-02 7.0521986509597359e-02 7.9578036683472006e-02 8.8546647361909522e-02 9.7519863231965306e-02 1.0649768784154924e-01 9.7741380449907406e-02 8.8803437172660038e-02 7.9860899732845866e-02 7.0913764587403796e-02 6.3335892740565308e-02 5.5756212252058776e-02 4.8172631747863209e-02 4.0585148217162359e-02 3.3381591675710129e-02 2.6178308595650738e-02 1.8971315351761126e-02 1.1760609076833628e-02 1.6950294922759991e-02 2.2274991357701439e-02 2.7602433189104329e-02 3.2932622540790261e-02 3.8265561538776145e-02 4.3601252311271169e-02 3.4856990743481552e-02 2.5991055149117932e-02 1.7120541224980364e-02 8.2757587359203223e-03 1.9423214065246042e-03 -4.3943890171043590e-03 -1.0734375072893196e-02 -1.7077639301414434e-02 -2.4679702899572852e-02 -3.2297970403821680e-02 -3.9920180090477250e-02 -4.7534566327530239e-02 -4.9234003141433724e-02 -5.0934320036547187e-02 -5.2635517696692252e-02 -5.4337596806402461e-02 -5.6040558050919301e-02 -5.7718452237076875e-02 -5.6840590379175944e-02 -5.5962273198734966e-02 -5.5083500341416583e-02 -5.4204271452516814e-02 -5.8396088726955113e-02 -6.2627330169715334e-02 -6.6860769089203700e-02 -7.0901736256069450e-02 -5.2096097309052243e-02 -3.3280684121412940e-02 -1.4455489070928059e-02 4.3150387579057158e-03 1.4839202394482527e-02 2.5368841662503576e-02 3.5903960836465652e-02 4.6444564195321399e-02 5.6990656022467459e-02 6.7542240605774059e-02 1.0002709623672751e-01 1.3258013095133617e-01 1.6515013362773309e-01 1.9773711753599391e-01 2.3194802687829724e-01 2.6618779883837107e-01 3.0044543658085349e-01 3.3472095409250663e-01 3.5929034770587287e-01 3.8384389188855605e-01 4.0841026111391787e-01 4.3298946543290784e-01 4.3298946543290784e-01 diff --git a/examples/edfa_model/Pchan2D.txt b/examples/edfa_model/Pchan2D.txt new file mode 100755 index 00000000..9fc25f60 --- /dev/null +++ b/examples/edfa_model/Pchan2D.txt @@ -0,0 +1,8 @@ + -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 + -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 + -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 -2.0000000000000000e+01 + -2.0500000000000000e+01 -2.0489473680000000e+01 -2.0478947370000000e+01 -2.0468421050000000e+01 -2.0457894740000000e+01 -2.0447368420000000e+01 -2.0436842110000001e+01 -2.0426315790000000e+01 -2.0415789470000000e+01 -2.0405263160000001e+01 -2.0394736840000000e+01 -2.0384210530000001e+01 -2.0373684210000000e+01 -2.0363157890000000e+01 -2.0352631580000001e+01 -2.0342105260000000e+01 -2.0331578950000001e+01 -2.0321052630000001e+01 -2.0310526320000001e+01 -2.0300000000000001e+01 -2.0289473680000000e+01 -2.0278947370000001e+01 -2.0268421050000001e+01 -2.0257894740000001e+01 -2.0247368420000001e+01 -2.0236842110000001e+01 -2.0226315790000001e+01 -2.0215789470000001e+01 -2.0205263160000001e+01 -2.0194736840000001e+01 -2.0184210530000001e+01 -2.0173684210000001e+01 -2.0163157890000001e+01 -2.0152631580000001e+01 -2.0142105260000001e+01 -2.0131578950000002e+01 -2.0121052630000001e+01 -2.0110526320000002e+01 -2.0100000000000001e+01 -2.0089473680000001e+01 -2.0078947370000002e+01 -2.0068421050000001e+01 -2.0057894739999998e+01 -2.0047368420000002e+01 -2.0036842109999998e+01 -2.0026315790000002e+01 -2.0015789470000001e+01 -2.0005263159999998e+01 -1.9994736840000002e+01 -1.9984210529999999e+01 -1.9973684209999998e+01 -1.9963157890000002e+01 -1.9952631579999998e+01 -1.9942105260000002e+01 -1.9931578949999999e+01 -1.9921052629999998e+01 -1.9910526319999999e+01 -1.9899999999999999e+01 -1.9889473679999998e+01 -1.9878947369999999e+01 -1.9868421049999998e+01 -1.9857894739999999e+01 -1.9847368419999999e+01 -1.9836842109999999e+01 -1.9826315789999999e+01 -1.9815789469999999e+01 -1.9805263159999999e+01 -1.9794736839999999e+01 -1.9784210529999999e+01 -1.9773684209999999e+01 -1.9763157889999999e+01 -1.9752631579999999e+01 -1.9742105259999999e+01 -1.9731578949999999e+01 -1.9721052629999999e+01 -1.9710526320000000e+01 -1.9699999999999999e+01 -1.9689473679999999e+01 -1.9678947369999999e+01 -1.9668421049999999e+01 -1.9657894740000000e+01 -1.9647368419999999e+01 -1.9636842110000000e+01 -1.9626315790000000e+01 -1.9615789469999999e+01 -1.9605263160000000e+01 -1.9594736839999999e+01 -1.9584210530000000e+01 -1.9573684210000000e+01 -1.9563157889999999e+01 -1.9552631580000000e+01 -1.9542105260000000e+01 -1.9531578950000000e+01 -1.9521052630000000e+01 -1.9510526320000000e+01 -1.9500000000000000e+01 + -2.0500000000000000e+01 -2.0489473680000000e+01 -2.0478947370000000e+01 -2.0468421050000000e+01 -2.0457894740000000e+01 -2.0447368420000000e+01 -2.0436842110000001e+01 -2.0426315790000000e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.9573684210000000e+01 -1.9563157889999999e+01 -1.9552631580000000e+01 -1.9542105260000000e+01 -1.9531578950000000e+01 -1.9521052630000000e+01 -1.9510526320000000e+01 -1.9500000000000000e+01 + -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.4460000000000001e+01 + -1.4460000000000001e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 -1.4460000000000001e+01 + -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.4460000000000001e+01 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 -1.0000000000000000e+02 diff --git a/examples/edfa_model/Pchan2DLegend.txt b/examples/edfa_model/Pchan2DLegend.txt new file mode 100755 index 00000000..87cbaee9 --- /dev/null +++ b/examples/edfa_model/Pchan2DLegend.txt @@ -0,0 +1,8 @@ + 7.0000000000000000e+01 1.1700000000000000e+02 1.0800000000000000e+02 1.0800000000000000e+02 3.2000000000000000e+01 7.0000000000000000e+01 1.0800000000000000e+02 9.7000000000000000e+01 1.1600000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 + 7.9000000000000000e+01 1.1000000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 7.1000000000000000e+01 1.1400000000000000e+02 1.1100000000000000e+02 1.1700000000000000e+02 1.1200000000000000e+02 3.2000000000000000e+01 6.6000000000000000e+01 1.0800000000000000e+02 1.1700000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 + 7.9000000000000000e+01 1.1000000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 7.1000000000000000e+01 1.1400000000000000e+02 1.1100000000000000e+02 1.1700000000000000e+02 1.1200000000000000e+02 3.2000000000000000e+01 8.2000000000000000e+01 1.0100000000000000e+02 1.0000000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 + 7.0000000000000000e+01 1.1700000000000000e+02 1.0800000000000000e+02 1.0800000000000000e+02 3.2000000000000000e+01 1.1900000000000000e+02 3.2000000000000000e+01 8.3000000000000000e+01 8.2000000000000000e+01 8.3000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 + 6.6000000000000000e+01 1.1100000000000000e+02 1.1600000000000000e+02 1.0400000000000000e+02 3.2000000000000000e+01 6.9000000000000000e+01 1.1000000000000000e+02 1.0000000000000000e+02 1.1500000000000000e+02 3.2000000000000000e+01 1.1900000000000000e+02 3.2000000000000000e+01 8.3000000000000000e+01 8.2000000000000000e+01 8.3000000000000000e+01 + 1.0400000000000000e+02 1.0100000000000000e+02 9.7000000000000000e+01 1.1800000000000000e+02 1.2100000000000000e+02 3.2000000000000000e+01 9.8000000000000000e+01 1.0800000000000000e+02 1.1700000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 + 1.0400000000000000e+02 1.0100000000000000e+02 9.7000000000000000e+01 1.1800000000000000e+02 1.2100000000000000e+02 3.2000000000000000e+01 1.1400000000000000e+02 1.0100000000000000e+02 1.0000000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 + 1.1900000000000000e+02 1.1100000000000000e+02 1.1400000000000000e+02 1.1500000000000000e+02 1.1600000000000000e+02 3.2000000000000000e+01 9.9000000000000000e+01 9.7000000000000000e+01 1.1500000000000000e+02 1.0100000000000000e+02 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 3.2000000000000000e+01 diff --git a/examples/edfa_model/amplifier.py b/examples/edfa_model/amplifier.py new file mode 100644 index 00000000..f5a8d2e2 --- /dev/null +++ b/examples/edfa_model/amplifier.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Mon Nov 27 12:32:04 2017 + +@author: briantaylor +""" +import numpy as np +from numpy import polyfit, polyval, mean +from utilities import lin2db, db2lin, itufs, freq2wavelength +import matplotlib.pyplot as plt +from scipy.constants import h + + +def noise_profile(nf, gain, ffs, df): + """ noise_profile(nf, gain, ffs, df) computes amplifier ase + + :param nf: Noise figure in dB + :param gain: Actual gain calculated for the EDFA in dB units + :param ffs: A numpy array of frequencies + :param df: the reference bw in THz + :type nf: numpy.ndarray + :type gain: numpy.ndarray + :type ffs: numpy.ndarray + :type df: float + :return: the asepower in dBm + :rtype: numpy.ndarray + + ASE POWER USING PER CHANNEL GAIN PROFILE + INPUTS: + NF_dB - Noise figure in dB, vector of length number of channels or + spectral slices + G_dB - Actual gain calculated for the EDFA, vector of length number of + channels or spectral slices + ffs - Center frequency grid of the channels or spectral slices in THz, + vector of length number of channels or spectral slices + dF - width of each channel or spectral slice in THz, + vector of length number of channels or spectral slices + OUTPUT: + ase_dBm - ase in dBm per channel or spectral slice + NOTE: the output is the total ASE in the channel or spectral slice. For + 50GHz channels the ASE BW is effectively 0.4nm. To get to noise power in + 0.1nm, subtract 6dB. + + ONSR is usually quoted as channel power divided by + the ASE power in 0.1nm RBW, regardless of the width of the actual + channel. This is a historical convention from the days when optical + signals were much smaller (155Mbps, 2.5Gbps, ... 10Gbps) than the + resolution of the OSAs that were used to measure spectral power which + were set to 0.1nm resolution for convenience. Moving forward into + flexible grid and high baud rate signals, it may be convenient to begin + quoting power spectral density in the same BW for both signal and ASE, + e.g. 12.5GHz.""" + + h_mWThz = 1e-3*h*(1e14)**2 + nf_lin = db2lin(nf) + g_lin = db2lin(gain) + ase = h_mWThz*df*ffs*(nf_lin*g_lin - 1) + asedb = lin2db(ase) + + return asedb + + +def gain_profile(dfg, dgt, Pin , gp , gtp): + """ + :param dfg: design flat gain + :param dgt: design gain tilt + :param Pin: channing input power profile + :param gp: Average gain setpoint in dB units + :param gtp: gain tilt setting + :type dfg: numpy.ndarray + :type dgt: numpy.ndarray + :type Pin: numpy.ndarray + :type gp: float + :type gtp: float + :return: gain profile in dBm + :rtype: numpy.ndarray + + AMPLIFICATION USING INPUT PROFILE + INPUTS: + DFG - vector of length number of channels or spectral slices + DGT - vector of length number of channels or spectral slices + Pin - input powers vector of length number of channels or + spectral slices + Gp - provisioned gain length 1 + GTp - provisioned tilt length 1 + + OUTPUT: + amp gain per channel or spectral slice + NOTE: there is no checking done for violations of the total output power + capability of the amp. + Ported from Matlab version written by David Boerges at Ciena. + Based on: + R. di Muro, "The Er3+ fiber gain coefficient derived from a dynamic + gain + tilt technique", Journal of Lightwave Technology, Vol. 18, Iss. 3, + Pp. 343-347, 2000. + """ + err_tolerance = 1.0e-11 + simple_opt = True + + # TODO make all values linear unit and convert to dB units as needed within + # this function. + nchan = list(range(len(Pin))) + + # TODO find a way to use these or lose them. Primarily we should have a + # way to determine if exceeding the gain or output power of the amp + tot_in_power_db = lin2db(np.sum(db2lin(Pin))) + avg_gain_db = lin2db(mean(db2lin(dfg))) + + #Linear fit to get the + p = polyfit(nchan, dgt, 1) + dgt_slope = p[0] + + # Calculate the target slope- Currently assumes equal spaced channels + # TODO make it so that supports arbitrary channel spacing. + targ_slope = gtp / (len(nchan)-1) + + # 1st estimate of DGT scaling + dgts1 = targ_slope / dgt_slope + + # when simple_opt is true code makes 2 attempts to compute gain and + # the internal voa value. This is currently here to provide direct + # comparison with original Matlab code. Will be removed. + # TODO replace with loop + + if simple_opt: + + # 1st estimate of Er gain & voa loss + g1st = dfg + dgt*dgts1 + voa = lin2db(mean(db2lin(g1st))) - gp + + # 2nd estimate of Amp ch gain using the channel input profile + g2nd = g1st - voa + pout_db = lin2db(np.sum(db2lin(Pin + g2nd))) + dgts2 = gp - (pout_db - tot_in_power_db) + + #Center estimate of amp ch gain + xcent = dgts2 + gcent = g1st - voa + dgt*xcent + pout_db = lin2db(np.sum(db2lin(Pin + gcent))) + gavg_cent = pout_db - tot_in_power_db + + # Lower estimate of Amp ch gain + deltax = np.max(g1st) - np.min(g1st) + xlow = dgts2 - deltax + glow = g1st - voa + xlow*dgt + pout_db = lin2db(np.sum(db2lin(Pin + glow))) + gavg_low = pout_db - tot_in_power_db + + # Upper gain estimate + xhigh =dgts2 + deltax + ghigh = g1st - voa + xhigh*dgt + pout_db = lin2db(np.sum(db2lin(Pin + ghigh))) + gavg_high = pout_db - tot_in_power_db + + # compute slope + slope1 = (gavg_low - gavg_cent)/(xlow - xcent) + slope2 = (gavg_cent - gavg_high)/(xcent - xhigh) + + if np.abs(gp - gavg_cent) <= err_tolerance: + dgts3 = xcent + elif gp < gavg_cent: + dgts3 = xcent - (gavg_cent - gp)/slope1 + else: + dgts3 = xcent + (-gavg_cent + gp)/slope2 + + gprofile = g1st - voa +dgt*dgts3 + else: + gprofile = None + + return gprofile + +if __name__ == '__main__': + + plt.close('all') + fc = itufs(0.05) + lc = freq2wavelength(fc)/1000 + nchan = list(range(len(lc))) + df = np.array([0.05]*(nchan[-1] + 1)) + # TODO remove path dependence + path = '' + + """ + DFG_96: Design flat gain at each wavelength in the 96 channel 50GHz ITU + grid in dB. This can be experimentally determined by measuring the gain + at each wavelength using a full, flat channel (or ASE) load at the input. + The amplifier should be set to its maximum flat gain (tilt = 0dB). This + measurement captures the ripple of the amplifier. If the amplifier was + designed to be mimimum ripple at some other tilt value, then the ripple + reflected in this measurement will not be that minimum. However, when + the DGT gets applied through the provisioning of tilt, the model should + accurately reproduce the expected ripple at that tilt value. One could + also do the measurement at some expected tilt value and back-calculate + this vector using the DGT method. Alternatively, one could re-write the + algorithm to accept a nominal tilt and a tiled version of this vector. + """ + + dfg_96 = np.loadtxt(path + 'DFG_96.txt') + + """maximum gain for flat operation - the amp in the data file was designed + for 25dB gain and has an internal VOA for setting the external gain + """ + + avg_dfg = dfg_96.mean() + + """ + DGT_96: This is the so-called Dynamic Gain Tilt of the EDFA in dB/dB. It + is the change in gain at each wavelength corresponding to a 1dB change at + the longest wavelength supported. The value can be obtained + experimentally or through analysis of the cross sections or Giles + parameters of the Er fibre. This is experimentally measured by changing + the gain of the amplifier above the maximum flat gain while not changing + the internal VOA (i.e. the mid-stage VOA is set to minimum and does not + change during the measurement). Note that the measurement can change the + gain by an arbitrary amount and divide by the gain change (in dB) which + is measured at the reference wavelength (the red end of the band). + """ + + dgt_96 = np.loadtxt(path + 'DGT_96.txt') + + """ + pNFfit3: Cubic polynomial fit coefficients to noise figure in dB + averaged across wavelength as a function of gain change from design flat: + + NFavg = pNFfit3(1)*dG^3 + pNFfit3(2)*dG^2 pNFfit3(3)*dG + pNFfit3(4) + where + dG = GainTarget - average(DFG_96) + note that dG will normally be a negative value. + """ + + nf_fitco = np.loadtxt(path + 'pNFfit3.txt') + + """NFR_96: Noise figure ripple in dB away from the average noise figure + across the band. This captures the wavelength dependence of the NF. To + calculate the NF across channels, one uses the cubic fit coefficients + with the external gain target to get the average nosie figure, NFavg and + then adds this to NFR_96: + NF_96 = NFR_96 + NFavg + """ + + nf_ripple = np.loadtxt(path + 'NFR_96.txt') + + # This is an example to set the provisionable gain and gain-tilt values + # Tilt is in units of dB/THz + gain_target = 20.0 + tilt_target = -0.7 + + # calculate the NF for the EDFA at this gain setting + dg = gain_target - avg_dfg + nf_avg = polyval(nf_fitco, dg) + nf_96 = nf_ripple + nf_avg + + # get the input power profiles to show + pch2d = np.loadtxt(path + 'Pchan2D.txt') + + # Load legend and assemble legend text + pch2d_legend_data = np.loadtxt(path + 'Pchan2DLegend.txt') + pch2d_legend = [] + for ea in pch2d_legend_data: + s = ''.join([chr(xx) for xx in ea.astype(dtype=int)]).strip() + pch2d_legend.append(s) + + #assemble plot + axis_font = {'fontname': 'Arial', 'size':'16', 'fontweight':'bold'} + title_font = {'fontname': 'Arial', 'size':'17', 'fontweight':'bold'} + tic_font = {'fontname': 'Arial', 'size':'12'} + + plt.rcParams["font.family"] = "Arial" + plt.figure() + plt.plot(nchan, pch2d.T, '.-', lw=2) + plt.xlabel('Channel Number', **axis_font) + plt.ylabel('Channel Power [dBm]', **axis_font) + plt.title('Input Power Profiles for Different Channel Loading', + **title_font) + plt.legend(pch2d_legend, loc=5) + plt.grid() + plt.ylim((-100, -10)) + plt.xlim((0,110)) + plt.xticks(np.arange(0,100,10), **tic_font) + plt.yticks(np.arange(-110,-10,10), **tic_font) + + plt.figure() + ea = pch2d[1,:] + for ea in pch2d: + chgain = gain_profile(dfg_96, dgt_96, ea, gain_target, tilt_target) + pase = noise_profile(nf_96, chgain, fc, df) + pout = lin2db(db2lin(ea + chgain) + db2lin(pase)) + plt.plot(nchan, pout, '.-', lw=2) + plt.title('Output Power with ASE for Different Channel Loading', + **title_font) + plt.xlabel('Channel Number', **axis_font) + plt.ylabel('Channel Power [dBm]', **axis_font) + plt.grid() + plt.ylim((-50, 10)) + plt.xlim((0,100)) + plt.xticks(np.arange(0,100,10), **tic_font) + plt.yticks(np.arange(-50,10,10), **tic_font) + plt.legend(pch2d_legend, loc=5) + diff --git a/examples/edfa_model/pNFfit3.txt b/examples/edfa_model/pNFfit3.txt new file mode 100755 index 00000000..124b5213 --- /dev/null +++ b/examples/edfa_model/pNFfit3.txt @@ -0,0 +1 @@ + 1.6824099999999999e-04 4.6996099999999999e-02 3.5954899999999998e-02 5.8285099999999996e+00 diff --git a/examples/edfa_model/utilities.py b/examples/edfa_model/utilities.py new file mode 100644 index 00000000..99a20028 --- /dev/null +++ b/examples/edfa_model/utilities.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Nov 10 17:50:46 2017 + +@author: briantaylor +""" +import numpy as np +from numpy import pi, cos, sqrt, log10 + +def c(): + """ + Returns the speed of light in meters per second + """ + return 299792458.0 + +def itufs(spacing, startf=191.35, stopf=196.10): + """Creates an array of frequencies whose default range is + 191.35-196.10 THz + + :param spacing: Frequency spacing in THz + :param starf: Start frequency in THz + :param stopf: Stop frequency in THz + :type spacing: float + :type startf: float + :type stopf: float + :return an array of frequnecies determined by the spacing parameter + :rtype: numpy.ndarray + """ + return np.arange(startf, stopf + spacing/2, spacing) + +def h(): + """ + Returns plank's constant in J*s + """ + return 6.62607004e-34 + +def lin2db(value): + return 10*log10(value) + + +def db2lin(value): + return 10**(value/10) + + +def wavelength2freq(value): + """ Converts wavelength units to frequeuncy units. + """ + return c()/value + + +def freq2wavelength(value): + """ Converts frequency units to wavelength units. + """ + return c()/value + + +def deltawl2deltaf(delta_wl, wavelength): + """ deltawl2deltaf(delta_wl, wavelength): + delta_wl is BW in wavelength units + wavelength is the center wl + units for delta_wl and wavelength must be same + + + + :param delta_wl: delta wavelength BW in same units as wavelength + :param wavelength: wavelength BW is relevant for + :type delta_wl: float or numpy.ndarray + :type wavelength: float + :return: The BW in frequency units + :rtype: float or ndarray + + """ + f = wavelength2freq(wavelength) + return delta_wl*f/wavelength + + +def deltaf2deltawl(delta_f, frequency): + """ deltawl2deltaf(delta_f, frequency): + converts delta frequency to delta wavelength + units for delta_wl and wavelength must be same + + + :param delta_f: delta frequency in same units as frequency + :param frequency: frequency BW is relevant for + :type delta_f: float or numpy.ndarray + :type frequency: float + :return: The BW in wavelength units + :rtype: float or ndarray + + """ + wl = freq2wavelength(frequency) + return delta_f*wl/frequency + + +def rrc(ffs, baud_rate, alpha): + """ rrc(ffs, baud_rate, alpha): computes the root-raised cosine filter + function. + + :param ffs: A numpy array of frequencies + :param baud_rate: The Baud Rate of the System + :param alpha: The roll-off factor of the filter + :type ffs: numpy.ndarray + :type baud_rate: float + :type alpha: float + :return: hf a numpy array of the filter shape + :rtype: numpy.ndarray + + """ + Ts = 1/baud_rate + l_lim = (1 - alpha)/(2 * Ts) + r_lim = (1 + alpha)/(2 * Ts) + hf = np.zeros(np.shape(ffs)) + slope_inds = np.where( + np.logical_and(np.abs(ffs) > l_lim, np.abs(ffs) < r_lim)) + hf[slope_inds] = 0.5 * (1 + cos((pi * Ts / alpha) * + (np.abs(ffs[slope_inds]) - l_lim))) + p_inds = np.where(np.logical_and(np.abs(ffs) > 0, np.abs(ffs) < l_lim)) + hf[p_inds] = 1 + return sqrt(hf) \ No newline at end of file diff --git a/utilities.py b/utilities.py new file mode 100644 index 00000000..99a20028 --- /dev/null +++ b/utilities.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +Created on Fri Nov 10 17:50:46 2017 + +@author: briantaylor +""" +import numpy as np +from numpy import pi, cos, sqrt, log10 + +def c(): + """ + Returns the speed of light in meters per second + """ + return 299792458.0 + +def itufs(spacing, startf=191.35, stopf=196.10): + """Creates an array of frequencies whose default range is + 191.35-196.10 THz + + :param spacing: Frequency spacing in THz + :param starf: Start frequency in THz + :param stopf: Stop frequency in THz + :type spacing: float + :type startf: float + :type stopf: float + :return an array of frequnecies determined by the spacing parameter + :rtype: numpy.ndarray + """ + return np.arange(startf, stopf + spacing/2, spacing) + +def h(): + """ + Returns plank's constant in J*s + """ + return 6.62607004e-34 + +def lin2db(value): + return 10*log10(value) + + +def db2lin(value): + return 10**(value/10) + + +def wavelength2freq(value): + """ Converts wavelength units to frequeuncy units. + """ + return c()/value + + +def freq2wavelength(value): + """ Converts frequency units to wavelength units. + """ + return c()/value + + +def deltawl2deltaf(delta_wl, wavelength): + """ deltawl2deltaf(delta_wl, wavelength): + delta_wl is BW in wavelength units + wavelength is the center wl + units for delta_wl and wavelength must be same + + + + :param delta_wl: delta wavelength BW in same units as wavelength + :param wavelength: wavelength BW is relevant for + :type delta_wl: float or numpy.ndarray + :type wavelength: float + :return: The BW in frequency units + :rtype: float or ndarray + + """ + f = wavelength2freq(wavelength) + return delta_wl*f/wavelength + + +def deltaf2deltawl(delta_f, frequency): + """ deltawl2deltaf(delta_f, frequency): + converts delta frequency to delta wavelength + units for delta_wl and wavelength must be same + + + :param delta_f: delta frequency in same units as frequency + :param frequency: frequency BW is relevant for + :type delta_f: float or numpy.ndarray + :type frequency: float + :return: The BW in wavelength units + :rtype: float or ndarray + + """ + wl = freq2wavelength(frequency) + return delta_f*wl/frequency + + +def rrc(ffs, baud_rate, alpha): + """ rrc(ffs, baud_rate, alpha): computes the root-raised cosine filter + function. + + :param ffs: A numpy array of frequencies + :param baud_rate: The Baud Rate of the System + :param alpha: The roll-off factor of the filter + :type ffs: numpy.ndarray + :type baud_rate: float + :type alpha: float + :return: hf a numpy array of the filter shape + :rtype: numpy.ndarray + + """ + Ts = 1/baud_rate + l_lim = (1 - alpha)/(2 * Ts) + r_lim = (1 + alpha)/(2 * Ts) + hf = np.zeros(np.shape(ffs)) + slope_inds = np.where( + np.logical_and(np.abs(ffs) > l_lim, np.abs(ffs) < r_lim)) + hf[slope_inds] = 0.5 * (1 + cos((pi * Ts / alpha) * + (np.abs(ffs[slope_inds]) - l_lim))) + p_inds = np.where(np.logical_and(np.abs(ffs) > 0, np.abs(ffs) < l_lim)) + hf[p_inds] = 1 + return sqrt(hf) \ No newline at end of file