mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-10-29 17:22:42 +00:00
Compare commits
1472 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c744a97d83 | ||
|
|
09221504d7 | ||
|
|
f2039fbe1c | ||
|
|
78227e65da | ||
|
|
e27e6d5c7b | ||
|
|
e3445e1066 | ||
|
|
a0758d0da5 | ||
|
|
0bc1fb3bf8 | ||
|
|
cd9d4c55b2 | ||
|
|
62889bf6af | ||
|
|
61787d5052 | ||
|
|
6612a46a9e | ||
|
|
f30515ba9d | ||
|
|
6f9897fe40 | ||
|
|
56e615c713 | ||
|
|
f447c908bc | ||
|
|
4df6cc6b23 | ||
|
|
6c5d11d86c | ||
|
|
1a795639c7 | ||
|
|
ee5e6f9b9e | ||
|
|
ea4ab1d61b | ||
|
|
d43fee5945 | ||
|
|
6603a50e78 | ||
|
|
b76c529c0c | ||
|
|
7a1b15a916 | ||
|
|
7bc9461547 | ||
|
|
b0ac41e2d5 | ||
|
|
bce42331c4 | ||
|
|
d5491c9ace | ||
|
|
689c2fb038 | ||
|
|
15c912bd72 | ||
|
|
d0c10e8537 | ||
|
|
93186b26fb | ||
|
|
49aee5a4e8 | ||
|
|
1c4da4794d | ||
|
|
de42dd4a93 | ||
|
|
57a5e9732b | ||
|
|
101eb8f969 | ||
|
|
7ce6650109 | ||
|
|
252e67a71e | ||
|
|
f83869392b | ||
|
|
94a3714aba | ||
|
|
ccab4835fc | ||
|
|
e55f7a5d4c | ||
|
|
4fda8c6002 | ||
|
|
8717156712 | ||
|
|
d2c0836164 | ||
|
|
eac4ba80ea | ||
|
|
4ef01d54a5 | ||
|
|
4b50ee0c2d | ||
|
|
33a289e22b | ||
|
|
e593b8c9ec | ||
|
|
94a6f922cd | ||
|
|
fbe387915b | ||
|
|
fce9d1d293 | ||
|
|
a59db8fd12 | ||
|
|
de509139b3 | ||
|
|
bb77b3f4a8 | ||
|
|
34c7fd1b60 | ||
|
|
89a962ffaf | ||
|
|
1722fbec13 | ||
|
|
e48aa57c35 | ||
|
|
e3e37b1986 | ||
|
|
abf42afaf8 | ||
|
|
310995045e | ||
|
|
c840bb1a44 | ||
|
|
4b6f4af3a5 | ||
|
|
dc68d38293 | ||
|
|
defe3bee5c | ||
|
|
32adc0fc53 | ||
|
|
4796266657 | ||
|
|
c35104c184 | ||
|
|
7b1354ee24 | ||
|
|
39d3f0f483 | ||
|
|
bbe9ef7356 | ||
|
|
42a8f018cd | ||
|
|
29f5dd1dc4 | ||
|
|
03da959724 | ||
|
|
f621ca6fe7 | ||
|
|
24f4503020 | ||
|
|
520c3615e4 | ||
|
|
548626a9f2 | ||
|
|
7a26833a5a | ||
|
|
c2f6f9c6a0 | ||
|
|
64a91256fc | ||
|
|
bdcffc2a5e | ||
|
|
c384af8062 | ||
|
|
0813332adc | ||
|
|
22fe9ead55 | ||
|
|
920ac30aa5 | ||
|
|
ac8fd770ab | ||
|
|
5277ae2005 | ||
|
|
30ead40e76 | ||
|
|
ae858b911a | ||
|
|
0d236fd31e | ||
|
|
9a84e29433 | ||
|
|
143f63170e | ||
|
|
b2d7f883a1 | ||
|
|
73dbdf3042 | ||
|
|
4a071c53d7 | ||
|
|
dcde64a8db | ||
|
|
38cc0e3cc5 | ||
|
|
fb70413784 | ||
|
|
87e10c240e | ||
|
|
43c1085be6 | ||
|
|
4ace60bea2 | ||
|
|
f950a6aee8 | ||
|
|
fb4195c775 | ||
|
|
29f42666e5 | ||
|
|
9bf7f336e3 | ||
|
|
eed6564f11 | ||
|
|
fbb2f2c587 | ||
|
|
44040c4d06 | ||
|
|
ee9af69558 | ||
|
|
ce21609fec | ||
|
|
a1289e6a9b | ||
|
|
138115e1d7 | ||
|
|
ed41305f55 | ||
|
|
9736f7c032 | ||
|
|
be7ae35db3 | ||
|
|
2b4a4ab72c | ||
|
|
426c88432d | ||
|
|
2a800b781f | ||
|
|
8d1d3677ed | ||
|
|
5b6f8c60cf | ||
|
|
3a733b1fd5 | ||
|
|
2d68b94a46 | ||
|
|
bc71823bd0 | ||
|
|
5481b93728 | ||
|
|
05e301182d | ||
|
|
47c89626e3 | ||
|
|
7a032a63b5 | ||
|
|
f195d5f496 | ||
|
|
56569f866f | ||
|
|
bf1f293043 | ||
|
|
28871c6f2d | ||
|
|
d7c1a6b75e | ||
|
|
c69c2a3af2 | ||
|
|
fb29d72906 | ||
|
|
30a06da6b1 | ||
|
|
139c8cc1e7 | ||
|
|
7034d4c686 | ||
|
|
10164495b9 | ||
|
|
87211b35e9 | ||
|
|
e9f9ddb4d6 | ||
|
|
8ea13bb4d6 | ||
|
|
b45829d2df | ||
|
|
6ac3a517cf | ||
|
|
2f2920a716 | ||
|
|
07fd89351b | ||
|
|
7c60b000b5 | ||
|
|
537eb017b5 | ||
|
|
9c514e8086 | ||
|
|
78efb6c650 | ||
|
|
3510d59250 | ||
|
|
41d9d156a6 | ||
|
|
e9d5e748e4 | ||
|
|
5a5bed56c2 | ||
|
|
22de1b1281 | ||
|
|
73e1485b47 | ||
|
|
22ee05ea6f | ||
|
|
31824f318d | ||
|
|
b0cb604e91 | ||
|
|
79102e283a | ||
|
|
db5e63d51b | ||
|
|
af42699133 | ||
|
|
4ba77d0a0a | ||
|
|
064d3af8e0 | ||
|
|
4ab5bac45f | ||
|
|
bbe5fb7821 | ||
|
|
edf1eec072 | ||
|
|
88ac41f721 | ||
|
|
c20e6fb320 | ||
|
|
05500c7047 | ||
|
|
86a39f4b5e | ||
|
|
2b25609255 | ||
|
|
7e0b95bcfd | ||
|
|
f0a52dcc8a | ||
|
|
3bea4b3c9f | ||
|
|
f2cc9f7225 | ||
|
|
e79f9f51b6 | ||
|
|
7fd7f94efe | ||
|
|
0acdf9d9f6 | ||
|
|
a3edb20142 | ||
|
|
33cc11b85c | ||
|
|
5d079ab261 | ||
|
|
a3b1157e38 | ||
|
|
70731b64d6 | ||
|
|
4ea0180caf | ||
|
|
eb2363a3d4 | ||
|
|
41b94cc888 | ||
|
|
1eeb6a0583 | ||
|
|
215c20e245 | ||
|
|
76e9146043 | ||
|
|
2a07eec966 | ||
|
|
cc994bf118 | ||
|
|
37e70e622c | ||
|
|
7d9a508955 | ||
|
|
185adabd77 | ||
|
|
8f9cf8ccc7 | ||
|
|
0c797a254c | ||
|
|
2cdeeabfa6 | ||
|
|
5e874798cb | ||
|
|
ff8f044064 | ||
|
|
d84ee4e76c | ||
|
|
521d27ffac | ||
|
|
35e759212e | ||
|
|
f6dede2b5f | ||
|
|
0d0019f627 | ||
|
|
06fe1c2f63 | ||
|
|
092316a9d7 | ||
|
|
48e3f96967 | ||
|
|
e9e8956caf | ||
|
|
0ae341c2a5 | ||
|
|
0c2f6372f8 | ||
|
|
97e80b4445 | ||
|
|
5e4c9b7d73 | ||
|
|
e96f821cce | ||
|
|
5f7e61e255 | ||
|
|
682b5c5691 | ||
|
|
11e5117505 | ||
|
|
50603420fc | ||
|
|
125264f265 | ||
|
|
b1067a6266 | ||
|
|
50d4ecd700 | ||
|
|
9f37e0371e | ||
|
|
9bd303db05 | ||
|
|
1bcb3ce25c | ||
|
|
e381138320 | ||
|
|
b450677709 | ||
|
|
54a3725e17 | ||
|
|
8889c2437a | ||
|
|
8bf8b2947b | ||
|
|
cb85b8fe2b | ||
|
|
18610fb7a9 | ||
|
|
bd6b278dd1 | ||
|
|
e143d25339 | ||
|
|
ffc7dbc241 | ||
|
|
b842898baf | ||
|
|
7ea9e3b341 | ||
|
|
fcf168b361 | ||
|
|
a7ec7e2ed6 | ||
|
|
00ee102b3a | ||
|
|
ce11524ad9 | ||
|
|
74be14562a | ||
|
|
16694d0a09 | ||
|
|
33c6038921 | ||
|
|
119c9eda90 | ||
|
|
b63e146bf4 | ||
|
|
09dba8a166 | ||
|
|
7f5043622b | ||
|
|
6ad4593f41 | ||
|
|
706661d801 | ||
|
|
a408d28911 | ||
|
|
b86fe96032 | ||
|
|
43926518ad | ||
|
|
128a6e816b | ||
|
|
44db951261 | ||
|
|
3c3d919b77 | ||
|
|
2079d2bc5b | ||
|
|
062e2076ed | ||
|
|
1dd1bad273 | ||
|
|
5b104af296 | ||
|
|
f170574abf | ||
|
|
a68e8ff8d2 | ||
|
|
d5a52d1b2b | ||
|
|
7ac6e058ec | ||
|
|
74ab3c1bcd | ||
|
|
1a2ff2d215 | ||
|
|
aaf0480e9c | ||
|
|
5e50ffbbf6 | ||
|
|
243b701391 | ||
|
|
bdbfe76aed | ||
|
|
541ec04444 | ||
|
|
bf1522b047 | ||
|
|
3f4188a0fd | ||
|
|
8b387ef722 | ||
|
|
cad9a0f18e | ||
|
|
ab84c77363 | ||
|
|
62fa9ab0b0 | ||
|
|
14591c7a11 | ||
|
|
587932290d | ||
|
|
82b148eb87 | ||
|
|
8393daf67d | ||
|
|
be61dfd094 | ||
|
|
77925b218e | ||
|
|
4621ac12bf | ||
|
|
09920c0af2 | ||
|
|
e6a3d9ce5b | ||
|
|
b9645702c8 | ||
|
|
9c2095b138 | ||
|
|
cb42115230 | ||
|
|
5909da4bbf | ||
|
|
2ba1e86b28 | ||
|
|
3358c5eeb5 | ||
|
|
13e4c29bc1 | ||
|
|
4becc9060c | ||
|
|
32d8b2a4d8 | ||
|
|
399eb9700f | ||
|
|
82f83e1462 | ||
|
|
171450fa54 | ||
|
|
9f9f4c78fc | ||
|
|
c469a8d9ba | ||
|
|
99b2a554dc | ||
|
|
57e98d7173 | ||
|
|
78b45a3958 | ||
|
|
64b6b486a9 | ||
|
|
65cb46f479 | ||
|
|
f94d06f124 | ||
|
|
e1f2c55942 | ||
|
|
d28c67143e | ||
|
|
6bb9ae8336 | ||
|
|
0dc7d853ef | ||
|
|
dec9388416 | ||
|
|
017b35fa33 | ||
|
|
cb0a410418 | ||
|
|
f250990a49 | ||
|
|
280443f17f | ||
|
|
6f62251cb4 | ||
|
|
5ad54879b1 | ||
|
|
825d37c05c | ||
|
|
3ac9f90914 | ||
|
|
dbfbf115ff | ||
|
|
ad2590962b | ||
|
|
a9d530c776 | ||
|
|
f255c31f1f | ||
|
|
80ec05f84c | ||
|
|
22541d65e4 | ||
|
|
26fcf0ff6e | ||
|
|
1c32e437a2 | ||
|
|
718007b3de | ||
|
|
4d6c06340f | ||
|
|
bad893bf86 | ||
|
|
75e7fca8e4 | ||
|
|
4e38ba98ab | ||
|
|
fdcdfca589 | ||
|
|
299ca10a47 | ||
|
|
c0b7bf714e | ||
|
|
7f7c568160 | ||
|
|
9bf6ed953a | ||
|
|
e68dc39ddd | ||
|
|
f8007b41d1 | ||
|
|
228125029e | ||
|
|
d185e0c241 | ||
|
|
357bbec257 | ||
|
|
d25e98c567 | ||
|
|
397411690e | ||
|
|
4ab6f8cb1b | ||
|
|
44aff147db | ||
|
|
a36b139065 | ||
|
|
141fc66d47 | ||
|
|
53f29957fd | ||
|
|
9f3995ee20 | ||
|
|
0cf45bd102 | ||
|
|
55932ee3e9 | ||
|
|
797a0856ec | ||
|
|
3fa53adc4d | ||
|
|
bcb5e6bb60 | ||
|
|
6380f8f37a | ||
|
|
93869d6cb5 | ||
|
|
ce51a4d160 | ||
|
|
601e228bb6 | ||
|
|
3f58cbd559 | ||
|
|
2e3274ac78 | ||
|
|
e33144f8cc | ||
|
|
fd1e3f0f61 | ||
|
|
80c41264cf | ||
|
|
a051a5723b | ||
|
|
72f300ab94 | ||
|
|
2c3b0d8c82 | ||
|
|
11dab614a9 | ||
|
|
11d88bf09a | ||
|
|
af3cc4736e | ||
|
|
50cb82ee18 | ||
|
|
c80aca6696 | ||
|
|
dfca35d4ae | ||
|
|
1fbdaef58a | ||
|
|
bd025f3af4 | ||
|
|
c3e546abe3 | ||
|
|
9427d0b139 | ||
|
|
89f5b12f7e | ||
|
|
9d2c10e267 | ||
|
|
305620e5dd | ||
|
|
c91c5d622f | ||
|
|
24e7f4a5a1 | ||
|
|
225cafa8b7 | ||
|
|
ad9cbb8a93 | ||
|
|
581b4a726f | ||
|
|
ce92d4e1b8 | ||
|
|
eb17b74ea4 | ||
|
|
051359ad77 | ||
|
|
912eb712c3 | ||
|
|
ce4ea9d6e3 | ||
|
|
39c894bb6a | ||
|
|
be95496f85 | ||
|
|
d38dabc824 | ||
|
|
5ad6336fda | ||
|
|
8ec9aca559 | ||
|
|
9abec6c9b7 | ||
|
|
e3b904fb06 | ||
|
|
5d13b9bfb6 | ||
|
|
0c26fd24b5 | ||
|
|
08c922a5e5 | ||
|
|
1b2eb9a5a8 | ||
|
|
219204e320 | ||
|
|
38fc1fdc6d | ||
|
|
e25e1fbe50 | ||
|
|
8a96ff563e | ||
|
|
27d4fb0811 | ||
|
|
b5a8ae3f06 | ||
|
|
e45a54c2b5 | ||
|
|
172697a2aa | ||
|
|
9762b6e610 | ||
|
|
4675a74e02 | ||
|
|
a268c219ed | ||
|
|
a47f069d97 | ||
|
|
8fcead4294 | ||
|
|
b6daa15356 | ||
|
|
469c0f5218 | ||
|
|
830ed22690 | ||
|
|
a386262bfd | ||
|
|
ede3c1a943 | ||
|
|
af767dd38a | ||
|
|
6dcc5a8524 | ||
|
|
7b5878e2f2 | ||
|
|
8c0eac1bdc | ||
|
|
d09938c1b8 | ||
|
|
dba4da0169 | ||
|
|
998249be61 | ||
|
|
ebdba47660 | ||
|
|
6072203afb | ||
|
|
b867c57bee | ||
|
|
4396a4efe9 | ||
|
|
afe686c666 | ||
|
|
e0faf6107d | ||
|
|
441f566964 | ||
|
|
2ca92f1aaa | ||
|
|
c4235fa61c | ||
|
|
41c53fbc5a | ||
|
|
44f8cdbf20 | ||
|
|
07ef8e4e10 | ||
|
|
bf0e435542 | ||
|
|
b688493e98 | ||
|
|
1ad01963c8 | ||
|
|
493de58e65 | ||
|
|
7e97547774 | ||
|
|
0f73a8f810 | ||
|
|
fa834338ab | ||
|
|
fc82f43b89 | ||
|
|
3d9d5d7a8d | ||
|
|
eef2cdc81c | ||
|
|
487ca8c2d6 | ||
|
|
ec66d628f0 | ||
|
|
924c56850d | ||
|
|
21385cbf03 | ||
|
|
87c617b602 | ||
|
|
4fce4ea7d8 | ||
|
|
2ddbd961ff | ||
|
|
05a044dc2c | ||
|
|
340840840f | ||
|
|
3ac08f59e2 | ||
|
|
3bcafc2345 | ||
|
|
b58c089945 | ||
|
|
a211e305c3 | ||
|
|
3a72ce84d0 | ||
|
|
de09b4f8ce | ||
|
|
be5519455f | ||
|
|
f98eb2c10c | ||
|
|
60b9256f22 | ||
|
|
94b9c16d67 | ||
|
|
eaccd63739 | ||
|
|
8fcb61f12c | ||
|
|
efd7468d42 | ||
|
|
8e62955bb0 | ||
|
|
561fd76a20 | ||
|
|
ccb6653f50 | ||
|
|
902cfa11a7 | ||
|
|
24c6acc027 | ||
|
|
3a31d458ee | ||
|
|
22d55ae881 | ||
|
|
3324645f78 | ||
|
|
3014a881f5 | ||
|
|
35877022ec | ||
|
|
9b985d1fc5 | ||
|
|
cd95c83bbf | ||
|
|
f9dbf7d132 | ||
|
|
b37248077c | ||
|
|
d2a8d8e887 | ||
|
|
35c4073292 | ||
|
|
b8e72511de | ||
|
|
120c326e77 | ||
|
|
01115f9852 | ||
|
|
b91ea1828f | ||
|
|
d2a294ac5a | ||
|
|
f41acf31f6 | ||
|
|
8cef09158f | ||
|
|
549e04e925 | ||
|
|
918c19b1bc | ||
|
|
6820a3fc36 | ||
|
|
7e8ed590eb | ||
|
|
4218b7ef44 | ||
|
|
87af343b38 | ||
|
|
26cd33b4dc | ||
|
|
861724ef4f | ||
|
|
86492cff60 | ||
|
|
27fd5cdad6 | ||
|
|
2fc444be4b | ||
|
|
d3490ae30c | ||
|
|
59c3895a51 | ||
|
|
11bc41b941 | ||
|
|
9a7f94a391 | ||
|
|
6487b98136 | ||
|
|
15df99510f | ||
|
|
3d5b1fcf64 | ||
|
|
928bc42cb9 | ||
|
|
643680ec47 | ||
|
|
a4a144a319 | ||
|
|
093085fba8 | ||
|
|
c56ea898a6 | ||
|
|
a5398a5c57 | ||
|
|
6dd40935b7 | ||
|
|
e6ee512001 | ||
|
|
e13d27c1f5 | ||
|
|
bb552fbdd6 | ||
|
|
ed8a3dd933 | ||
|
|
3204077a6c | ||
|
|
85d1bf4e1e | ||
|
|
42edb2e6b9 | ||
|
|
21174a4190 | ||
|
|
f6c2da24cd | ||
|
|
9f16aaac61 | ||
|
|
29fc9d7dac | ||
|
|
be3af5c2e5 | ||
|
|
e0e9ebde28 | ||
|
|
5dc16a39c5 | ||
|
|
416da5c60b | ||
|
|
f8047f9afe | ||
|
|
9e91933106 | ||
|
|
7407e6809b | ||
|
|
56f66779f9 | ||
|
|
2704c56e50 | ||
|
|
ba4cc1ceef | ||
|
|
8396cea652 | ||
|
|
2b1029f3b6 | ||
|
|
8e2709490f | ||
|
|
ebf8249154 | ||
|
|
aaddffcb2e | ||
|
|
29d1f8c666 | ||
|
|
0126645c4d | ||
|
|
1d657d6819 | ||
|
|
0b965d931c | ||
|
|
d3eaa4d7ba | ||
|
|
1dbbc6273b | ||
|
|
efa8b83249 | ||
|
|
30599bf63a | ||
|
|
7c14fe02ab | ||
|
|
ee92011b21 | ||
|
|
9861a22ef9 | ||
|
|
59f9f35817 | ||
|
|
1bb475671d | ||
|
|
566dedbdbb | ||
|
|
b44c4cec16 | ||
|
|
93d11ba408 | ||
|
|
637670fcfa | ||
|
|
7836297708 | ||
|
|
1f8b4ab9a2 | ||
|
|
05eb312f4a | ||
|
|
a98e244abd | ||
|
|
c945bc40fe | ||
|
|
749b9287a9 | ||
|
|
202c76bd6e | ||
|
|
eec0943ca2 | ||
|
|
cd0415e523 | ||
|
|
06d59a5834 | ||
|
|
33dcdde422 | ||
|
|
94949d955b | ||
|
|
b74d0a4919 | ||
|
|
c8fa7635e0 | ||
|
|
4c6cfbda5d | ||
|
|
80e9423590 | ||
|
|
78010aaaef | ||
|
|
3857ab1dbb | ||
|
|
dbb09e4108 | ||
|
|
94a8f3568a | ||
|
|
ae7c9321d0 | ||
|
|
648cc3a8e5 | ||
|
|
f9e0d18a9d | ||
|
|
2d57fd9f85 | ||
|
|
f053f32301 | ||
|
|
8e9d715e9f | ||
|
|
9fd55a5289 | ||
|
|
914d0dbecd | ||
|
|
c38fe72ff7 | ||
|
|
80f63d32ed | ||
|
|
9030f8f84f | ||
|
|
0d5f1c7d80 | ||
|
|
5bc42332cd | ||
|
|
093b85d4a3 | ||
|
|
0efa0d310d | ||
|
|
8eb5980ca9 | ||
|
|
754be7ca08 | ||
|
|
c5c5b693f2 | ||
|
|
7f816eb6e7 | ||
|
|
1009b44d2a | ||
|
|
3b61c6ca4c | ||
|
|
cc11bd186c | ||
|
|
0d1225824e | ||
|
|
a2ecfd924c | ||
|
|
95c3c9c488 | ||
|
|
11033a284f | ||
|
|
357e6cbf18 | ||
|
|
bfa6d29908 | ||
|
|
21e0589e7f | ||
|
|
4d836246ec | ||
|
|
566943a099 | ||
|
|
a4c1ea1f55 | ||
|
|
6b10ed15f8 | ||
|
|
c8daa5ed8c | ||
|
|
0b03725295 | ||
|
|
ee5e64408d | ||
|
|
b96ffe6c7b | ||
|
|
3b981853d4 | ||
|
|
6fa3ef8df1 | ||
|
|
1b2b048b47 | ||
|
|
94c5281260 | ||
|
|
7da4ec08d8 | ||
|
|
2b473d26d3 | ||
|
|
9e74e8b0a0 | ||
|
|
648039521e | ||
|
|
24bc023a07 | ||
|
|
19c2ae7f7a | ||
|
|
9f6894a176 | ||
|
|
a094568d6e | ||
|
|
f728d96d07 | ||
|
|
6b1fb7061f | ||
|
|
7ef505f259 | ||
|
|
c8d394348d | ||
|
|
0daa1c3e8c | ||
|
|
60bafd114d | ||
|
|
11509f5686 | ||
|
|
785c823fa2 | ||
|
|
9faf6430a5 | ||
|
|
01c566a325 | ||
|
|
baa9171315 | ||
|
|
2e50337f38 | ||
|
|
8daa298699 | ||
|
|
76cdd5dc71 | ||
|
|
07eb2dd13a | ||
|
|
04e764d024 | ||
|
|
05ccb14e5d | ||
|
|
f60d035e66 | ||
|
|
0823f8de46 | ||
|
|
a453c57996 | ||
|
|
2f84bb5286 | ||
|
|
7b8e68aea9 | ||
|
|
8d553a255f | ||
|
|
2766e37438 | ||
|
|
f56e64410b | ||
|
|
15ea7218e9 | ||
|
|
db28011c61 | ||
|
|
faccc23018 | ||
|
|
49514c0c70 | ||
|
|
0b1557fdf1 | ||
|
|
46f89aa770 | ||
|
|
3548ed74e2 | ||
|
|
145653df6e | ||
|
|
c7589e0bca | ||
|
|
531810cc85 | ||
|
|
63a6256b5e | ||
|
|
c3febb6db4 | ||
|
|
8b1d8b3479 | ||
|
|
3168603908 | ||
|
|
a2128227bd | ||
|
|
376826b3ae | ||
|
|
4b258cdf2e | ||
|
|
fbdd132a3d | ||
|
|
eebcebb33d | ||
|
|
20152036ff | ||
|
|
2a477071a0 | ||
|
|
f02d11e8bc | ||
|
|
0d542f22a7 | ||
|
|
5af195bd2b | ||
|
|
7ab93e7cd9 | ||
|
|
0aec47ddeb | ||
|
|
9a54dbab43 | ||
|
|
fc03be8bbe | ||
|
|
32f10a4507 | ||
|
|
04544d41f6 | ||
|
|
c87be89e07 | ||
|
|
efa05f0653 | ||
|
|
4cf4db9bc2 | ||
|
|
16434c5737 | ||
|
|
14ee9c9a91 | ||
|
|
7cfc4bd1ec | ||
|
|
9d55cde50d | ||
|
|
72183c24da | ||
|
|
4d1a628488 | ||
|
|
fdeaf75361 | ||
|
|
5695fafac6 | ||
|
|
0fe1d195a3 | ||
|
|
ed1aa0aa03 | ||
|
|
3fc024f5ba | ||
|
|
4f8177908f | ||
|
|
ad64595d75 | ||
|
|
80133e9521 | ||
|
|
de58d7d7c2 | ||
|
|
491a05c5a7 | ||
|
|
1d791aa295 | ||
|
|
58921bc346 | ||
|
|
ab6a91692b | ||
|
|
3b45968799 | ||
|
|
c7d69b9a99 | ||
|
|
1eeed78430 | ||
|
|
1cdafbae0f | ||
|
|
47b4f87bc5 | ||
|
|
e24b766cdc | ||
|
|
51fb6bd68e | ||
|
|
7e405a0514 | ||
|
|
194a13e607 | ||
|
|
856f07e707 | ||
|
|
4582aed895 | ||
|
|
734b6dfef4 | ||
|
|
da6e4f33a4 | ||
|
|
5a1e3f30b3 | ||
|
|
094af16792 | ||
|
|
9474ff17de | ||
|
|
c675f5bd38 | ||
|
|
2556658e68 | ||
|
|
4d5d10935a | ||
|
|
eb87e36781 | ||
|
|
14d8d793f3 | ||
|
|
bc4b6642a0 | ||
|
|
fe2b39ee3b | ||
|
|
d56c91ca7f | ||
|
|
25819fadf5 | ||
|
|
0cacb8851d | ||
|
|
14f98836ed | ||
|
|
82ce3384ba | ||
|
|
1f1877f7a9 | ||
|
|
db26ce07db | ||
|
|
e08ae9c959 | ||
|
|
2de1b5567a | ||
|
|
639b379a5b | ||
|
|
0465397b1d | ||
|
|
d3ec39d506 | ||
|
|
bfe68a5948 | ||
|
|
2ea3363613 | ||
|
|
89cce6e6a3 | ||
|
|
0f10ac706c | ||
|
|
66d26f0ffa | ||
|
|
3c96914482 | ||
|
|
61b1e73362 | ||
|
|
03435079cc | ||
|
|
6661907c1d | ||
|
|
fe811f725c | ||
|
|
80eced85ec | ||
|
|
2960d307fa | ||
|
|
c41cddfff5 | ||
|
|
8598e6591f | ||
|
|
5e2259062c | ||
|
|
d483802a86 | ||
|
|
9a0eece69c | ||
|
|
1657bfd05f | ||
|
|
49bf558916 | ||
|
|
99f44a597b | ||
|
|
a21f3fe6ee | ||
|
|
0ccbb2960c | ||
|
|
c577a75725 | ||
|
|
8827e0cf6f | ||
|
|
b0012fe399 | ||
|
|
31e634615b | ||
|
|
8300a55e39 | ||
|
|
5b939bc57a | ||
|
|
2f1ab9cc50 | ||
|
|
42ba3eb98d | ||
|
|
9eb87fc8e1 | ||
|
|
8fab9bb945 | ||
|
|
1ead232a78 | ||
|
|
b15c8c60ab | ||
|
|
66bdeb0e4d | ||
|
|
1a2e090104 | ||
|
|
a8e280e29b | ||
|
|
edb54b02ac | ||
|
|
83d3f32fe0 | ||
|
|
085a379592 | ||
|
|
37bd5d0404 | ||
|
|
f788b81d21 | ||
|
|
2ff1ce6b34 | ||
|
|
41a1e40d14 | ||
|
|
921e8d2d3c | ||
|
|
c009d28f7d | ||
|
|
898eada097 | ||
|
|
bdfc55e801 | ||
|
|
57f264bedb | ||
|
|
fbe4fa3cf0 | ||
|
|
b2ef345f35 | ||
|
|
471ea7dfba | ||
|
|
1b52f638ff | ||
|
|
84ab38a75f | ||
|
|
916e5377f8 | ||
|
|
534bfd881e | ||
|
|
7c4015324d | ||
|
|
8499ee52f4 | ||
|
|
cc1123863c | ||
|
|
ca382806f6 | ||
|
|
3559fc61c2 | ||
|
|
33581cdcc9 | ||
|
|
991eb02964 | ||
|
|
286e321a2d | ||
|
|
56f158113d | ||
|
|
024f6ff963 | ||
|
|
8118a0f4f4 | ||
|
|
eb89d8fd86 | ||
|
|
a938c1738b | ||
|
|
4f88882513 | ||
|
|
4e8d8b7ddd | ||
|
|
afb7d75749 | ||
|
|
488d0e1fe8 | ||
|
|
708442e4cd | ||
|
|
a2d905dfb1 | ||
|
|
d564fe3e2a | ||
|
|
ea21cce1c0 | ||
|
|
aa9b4aefbe | ||
|
|
8655030e59 | ||
|
|
8107ddeb79 | ||
|
|
76c8e55f06 | ||
|
|
a7b1ab47d8 | ||
|
|
879f587ab9 | ||
|
|
8af2d80219 | ||
|
|
315eea1f55 | ||
|
|
b61e541e15 | ||
|
|
81f88e78c7 | ||
|
|
87cc3dac00 | ||
|
|
89e28cc7be | ||
|
|
2ba29a78c5 | ||
|
|
f990a6c1be | ||
|
|
424e5a4786 | ||
|
|
6a7a04ebb1 | ||
|
|
0366fc2956 | ||
|
|
48b7d71f02 | ||
|
|
715baf2a1c | ||
|
|
e55cea776e | ||
|
|
b388d143fd | ||
|
|
c592c572d8 | ||
|
|
dfa0a26a28 | ||
|
|
609cd94798 | ||
|
|
022f743db1 | ||
|
|
1957beb1b6 | ||
|
|
9ca72d6105 | ||
|
|
e8e126a6ce | ||
|
|
7849782173 | ||
|
|
149a0da8c9 | ||
|
|
1e7c70a59b | ||
|
|
c9d8282e7f | ||
|
|
e7084a2c29 | ||
|
|
d79d2e0724 | ||
|
|
402155c225 | ||
|
|
e5ec669419 | ||
|
|
8f424e8c9d | ||
|
|
fea2b84bb9 | ||
|
|
0c918940c4 | ||
|
|
a63a6ac0ec | ||
|
|
9f58b914d2 | ||
|
|
029bac4b03 | ||
|
|
a27ad57220 | ||
|
|
8d31d924f2 | ||
|
|
8c3b514f90 | ||
|
|
3df27fe315 | ||
|
|
a6087ce354 | ||
|
|
aae0382523 | ||
|
|
b0c2acb1b5 | ||
|
|
a52c96ae2e | ||
|
|
bf28821b5b | ||
|
|
328bd6ea71 | ||
|
|
ec9eb8d054 | ||
|
|
f8c8526045 | ||
|
|
d8c236bb44 | ||
|
|
33ff0910b8 | ||
|
|
faa69917d9 | ||
|
|
d9f5ca9827 | ||
|
|
c817ef7335 | ||
|
|
07de489d6b | ||
|
|
acafc78456 | ||
|
|
325721545e | ||
|
|
dbe2bf560c | ||
|
|
7872cc2203 | ||
|
|
25b4d0e755 | ||
|
|
9af1c90664 | ||
|
|
6b4d44a3f1 | ||
|
|
2faf8d2cdd | ||
|
|
676c94ddf2 | ||
|
|
6f93b64f84 | ||
|
|
54bf426472 | ||
|
|
1862ce9104 | ||
|
|
3771c13d32 | ||
|
|
f1d0230dad | ||
|
|
182929cc96 | ||
|
|
81585c5a86 | ||
|
|
2f52c11589 | ||
|
|
0f4d8573cf | ||
|
|
660b8b3c6e | ||
|
|
71d6a1138c | ||
|
|
a6e741d8fe | ||
|
|
58bcf65cf6 | ||
|
|
27ce55de38 | ||
|
|
36ca22db9b | ||
|
|
33a8de9b39 | ||
|
|
22b76e36db | ||
|
|
528ff31590 | ||
|
|
4d6966cbd3 | ||
|
|
9c9e3be967 | ||
|
|
2dd4745ef7 | ||
|
|
4e786a32b5 | ||
|
|
6ecb2c85e2 | ||
|
|
cd234a909b | ||
|
|
c249f44ea1 | ||
|
|
ed1f51393a | ||
|
|
8bd43130ab | ||
|
|
6c975a53a1 | ||
|
|
8a1001cd40 | ||
|
|
beb2b576aa | ||
|
|
8f3923046b | ||
|
|
88c68d2065 | ||
|
|
8bcde72a10 | ||
|
|
4653dbcf4b | ||
|
|
cde08b32a4 | ||
|
|
2eed891f8d | ||
|
|
c0b84e84c8 | ||
|
|
2c20fd3f9f | ||
|
|
f4db56ca29 | ||
|
|
5b6d58ac7d | ||
|
|
ecb8bd9fbe | ||
|
|
2f9385451f | ||
|
|
1a1346461b | ||
|
|
27dcd29074 | ||
|
|
93986f36c3 | ||
|
|
a6ab8055b1 | ||
|
|
31ea479d7f | ||
|
|
89fb2e047b | ||
|
|
8f705e6173 | ||
|
|
8f735316f5 | ||
|
|
0d7a1871a1 | ||
|
|
33832b3d25 | ||
|
|
4da7f0cc38 | ||
|
|
e29f8485ea | ||
|
|
2da344a563 | ||
|
|
2a0cb8e14f | ||
|
|
e1dc3dc357 | ||
|
|
8259124f73 | ||
|
|
0422956ac6 | ||
|
|
ff82c5171b | ||
|
|
f9bd6310f1 | ||
|
|
471eab126e | ||
|
|
6ad011d12d | ||
|
|
561c8aff85 | ||
|
|
5cf5dd2234 | ||
|
|
fb9915d301 | ||
|
|
7ab67194d6 | ||
|
|
603ac9d8c5 | ||
|
|
a3c7811e9d | ||
|
|
a3778dfe8b | ||
|
|
2dff934612 | ||
|
|
89d666948e | ||
|
|
c3499142b0 | ||
|
|
d8feccc715 | ||
|
|
16173355f3 | ||
|
|
f46134fda5 | ||
|
|
bfecff0412 | ||
|
|
168f1891cf | ||
|
|
862845b4ac | ||
|
|
b7a5dbff49 | ||
|
|
5be30d89a7 | ||
|
|
d94dc51d88 | ||
|
|
22acd88d44 | ||
|
|
fd406c106b | ||
|
|
16134b5caf | ||
|
|
2c485efced | ||
|
|
279d08a0e8 | ||
|
|
1d4a8998e1 | ||
|
|
47a41e7980 | ||
|
|
ecfc4a8cb2 | ||
|
|
2d66b6266b | ||
|
|
b7afb5f9d2 | ||
|
|
58c16a59ac | ||
|
|
f09789f5ef | ||
|
|
b2e12cd3e0 | ||
|
|
71b157a8ba | ||
|
|
cb8affe9b2 | ||
|
|
3f7180c706 | ||
|
|
f0bc2dc62f | ||
|
|
9c95fd6b69 | ||
|
|
c0fda8c3a2 | ||
|
|
bac20af381 | ||
|
|
626211a320 | ||
|
|
783aaa8cb4 | ||
|
|
768bd8af19 | ||
|
|
3894f52194 | ||
|
|
dcfa9edb1c | ||
|
|
4ebdb5629c | ||
|
|
75b0668fc2 | ||
|
|
5fe94ed463 | ||
|
|
db21b97603 | ||
|
|
8074d0c548 | ||
|
|
2d611afbb0 | ||
|
|
bc42507724 | ||
|
|
ff82ab5718 | ||
|
|
62fe374e15 | ||
|
|
e519a3bc39 | ||
|
|
4f146d12ee | ||
|
|
46d6074ad5 | ||
|
|
cbb61f1240 | ||
|
|
0e9f3c3576 | ||
|
|
92f11dc075 | ||
|
|
3aa0a0999b | ||
|
|
e86fbcfa5b | ||
|
|
0b2ee6fdaf | ||
|
|
35f3866882 | ||
|
|
d86bea80d3 | ||
|
|
13b4b5072f | ||
|
|
efae43f122 | ||
|
|
45e8c8692b | ||
|
|
f8fc2a5050 | ||
|
|
3c20d57cc4 | ||
|
|
2cb3858330 | ||
|
|
925d36a561 | ||
|
|
0ffaca91cc | ||
|
|
d3a0f1d969 | ||
|
|
37704db583 | ||
|
|
aadd038bbe | ||
|
|
6d601b4267 | ||
|
|
194798d881 | ||
|
|
1a10495645 | ||
|
|
0e2316513e | ||
|
|
72ce4e2fad | ||
|
|
4ad7311e18 | ||
|
|
fa2b0e8fad | ||
|
|
78eb926693 | ||
|
|
3613efbaab | ||
|
|
2e732854b3 | ||
|
|
f9560d6b1d | ||
|
|
51b0826398 | ||
|
|
af0adb454d | ||
|
|
cdd4c571b0 | ||
|
|
9c440764c7 | ||
|
|
6e94834033 | ||
|
|
1720ed23c9 | ||
|
|
137fab1d92 | ||
|
|
0fee63fa81 | ||
|
|
d5f0d80eed | ||
|
|
b7d4d43f56 | ||
|
|
c0379a1981 | ||
|
|
e5db8e42d1 | ||
|
|
27cf9806f0 | ||
|
|
5dbb5cd112 | ||
|
|
af75569eb8 | ||
|
|
aebf2ff270 | ||
|
|
3bcdeda3e9 | ||
|
|
7433667243 | ||
|
|
d7c009167f | ||
|
|
79f198d6fe | ||
|
|
315a12b9df | ||
|
|
e14d145f2c | ||
|
|
f839da39f0 | ||
|
|
45ca7a63ed | ||
|
|
5d187255ae | ||
|
|
7adf6aed59 | ||
|
|
b22a7a0234 | ||
|
|
8805723114 | ||
|
|
88db4358f5 | ||
|
|
a5d9685caf | ||
|
|
94ff8e6beb | ||
|
|
f3400d9bc1 | ||
|
|
6a6591e41d | ||
|
|
a3a53f3b06 | ||
|
|
2f39abfdb8 | ||
|
|
92239d66fc | ||
|
|
178813806f | ||
|
|
265dbffc53 | ||
|
|
a67a08a4d0 | ||
|
|
6d15f55304 | ||
|
|
0dbcd1f265 | ||
|
|
a0f6380f90 | ||
|
|
ab69cf5bf4 | ||
|
|
3e55a5526a | ||
|
|
b6216bb701 | ||
|
|
fa3ea3aaa7 | ||
|
|
7b56e3a6c3 | ||
|
|
00ad542a11 | ||
|
|
c3e00eea2c | ||
|
|
5c8dd911e3 | ||
|
|
407fd62da5 | ||
|
|
c92f7ca0d8 | ||
|
|
676901e113 | ||
|
|
c099b53a03 | ||
|
|
fd065e4e7c | ||
|
|
fd97527561 | ||
|
|
7b9647a063 | ||
|
|
bf943f1347 | ||
|
|
dbff610d77 | ||
|
|
46aae9486e | ||
|
|
70066de390 | ||
|
|
106af9d444 | ||
|
|
f0be267f9f | ||
|
|
edbaec7265 | ||
|
|
f4537a538b | ||
|
|
d6eb6f33d2 | ||
|
|
7a139c261a | ||
|
|
2e7aa213ed | ||
|
|
d9344287e4 | ||
|
|
b9768a81e9 | ||
|
|
3418c07512 | ||
|
|
5f8621c224 | ||
|
|
c05f3555a3 | ||
|
|
f21827395b | ||
|
|
894c7bb17a | ||
|
|
2028cfae4d | ||
|
|
2064f65c04 | ||
|
|
1de4a4eaa2 | ||
|
|
06ff45d0c2 | ||
|
|
81474e252e | ||
|
|
0069265905 | ||
|
|
dec15f6797 | ||
|
|
f6041cd844 | ||
|
|
ec20d3981b | ||
|
|
08a867ef5a | ||
|
|
76c8296a5d | ||
|
|
f65059dd7f | ||
|
|
e23fef3f64 | ||
|
|
30234f913c | ||
|
|
2dd017bddc | ||
|
|
b25a298087 | ||
|
|
8635a7c182 | ||
|
|
46d25df241 | ||
|
|
0338ccb08f | ||
|
|
8899a575b8 | ||
|
|
b4407b1ff3 | ||
|
|
75f0aebe8f | ||
|
|
5a2dd53636 | ||
|
|
3555154c3e | ||
|
|
6c92c282e7 | ||
|
|
bd1847e5ba | ||
|
|
38727d6203 | ||
|
|
7e6d557d01 | ||
|
|
5d3ce91839 | ||
|
|
1f34e3005e | ||
|
|
8e27437086 | ||
|
|
b4cbe8029e | ||
|
|
92f3fd2063 | ||
|
|
1112b331ef | ||
|
|
ec34e84a3a | ||
|
|
bc9eee326a | ||
|
|
c9106c3a6f | ||
|
|
fa949f977a | ||
|
|
4c2d61bb9b | ||
|
|
ec7b14da8c | ||
|
|
771af4991c | ||
|
|
a08ce9ecb7 | ||
|
|
4d84a4f528 | ||
|
|
5d92baf35e | ||
|
|
ac5171e95e | ||
|
|
697ac311fe | ||
|
|
c22d1173af | ||
|
|
c0cc5fa9fd | ||
|
|
4bd9a9cdda | ||
|
|
63f8139dbc | ||
|
|
be731a5977 | ||
|
|
dd4ce4cea4 | ||
|
|
2548a2eee8 | ||
|
|
03948d6785 | ||
|
|
4c1c17eea6 | ||
|
|
b258d22d25 | ||
|
|
aef43e6bca | ||
|
|
3d7362743d | ||
|
|
96f3d5a805 | ||
|
|
2df500e027 | ||
|
|
346f24022a | ||
|
|
cb45c7ef16 | ||
|
|
9cfb57dc4b | ||
|
|
020d852758 | ||
|
|
8d97fcd735 | ||
|
|
097fe3114e | ||
|
|
5e0fd265ff | ||
|
|
6af137a085 | ||
|
|
3cdc8511a8 | ||
|
|
2d515eea4c | ||
|
|
61289119cb | ||
|
|
b6bc995e40 | ||
|
|
b0bb41bac6 | ||
|
|
0927a92652 | ||
|
|
f51061d650 | ||
|
|
74314f00ca | ||
|
|
81c5ef4a23 | ||
|
|
72e329b08e | ||
|
|
50f884663f | ||
|
|
0d81eb4b29 | ||
|
|
978a9407fa | ||
|
|
2c3b74cdc1 | ||
|
|
448e0f54be | ||
|
|
17f638e991 | ||
|
|
b78d3d8eda | ||
|
|
02a7e467e2 | ||
|
|
15304890f5 | ||
|
|
9ea96e431c | ||
|
|
7b3bfea614 | ||
|
|
d68637c2c8 | ||
|
|
f009306030 | ||
|
|
ca97cba18b | ||
|
|
a46c8c5398 | ||
|
|
88c2e2bd70 | ||
|
|
1bbcee8715 | ||
|
|
39a8fa3335 | ||
|
|
fe067e5367 | ||
|
|
5efbd17829 | ||
|
|
fa3e54a747 | ||
|
|
603beccb01 | ||
|
|
4b20afd599 | ||
|
|
adbe283c83 | ||
|
|
1908d7e29a | ||
|
|
7c6e16cfbc | ||
|
|
1480d23088 | ||
|
|
4be3522209 | ||
|
|
5381e0300f | ||
|
|
cde822ebf8 | ||
|
|
72d3525da1 | ||
|
|
dc867fa051 | ||
|
|
eaf3fcade8 | ||
|
|
3df270e4ac | ||
|
|
7937392dfc | ||
|
|
9c1c0f8d1f | ||
|
|
ad2ab0d164 | ||
|
|
c4bed94eb0 | ||
|
|
edc8eb55de | ||
|
|
f4f9868381 | ||
|
|
f103bebe05 | ||
|
|
c168af46bc | ||
|
|
7d82248903 | ||
|
|
e6cb269754 | ||
|
|
ac8a96398a | ||
|
|
86c79c7c60 | ||
|
|
0c47b3f3ea | ||
|
|
b2b500c5dc | ||
|
|
efc8468268 | ||
|
|
205baebd48 | ||
|
|
af9ba2750d | ||
|
|
e04afdbe4c | ||
|
|
e94fd9590e | ||
|
|
4f4f05abdf | ||
|
|
bcf93e1d9f | ||
|
|
48198bdd89 | ||
|
|
fbb4f3e5dd | ||
|
|
cefd1cf030 | ||
|
|
f8fa544e31 | ||
|
|
27885a4cbc | ||
|
|
185a62958f | ||
|
|
1ba748f2a4 | ||
|
|
90a75a9b3d | ||
|
|
215295efb1 | ||
|
|
2413bd9e0d | ||
|
|
356ae650fd | ||
|
|
2444c24545 | ||
|
|
7727708a3a | ||
|
|
0bfacd84f4 | ||
|
|
b271c1ca3c | ||
|
|
75660febc1 | ||
|
|
13aaa174e1 | ||
|
|
d112c728fc | ||
|
|
826af4a9fd | ||
|
|
c9693d355f | ||
|
|
9f37cb8ce6 | ||
|
|
d99e8ca565 | ||
|
|
44312125ab | ||
|
|
7558721642 | ||
|
|
fb49f7fb5d | ||
|
|
ee7f2c2f47 | ||
|
|
833fe006af | ||
|
|
9be0607b2e | ||
|
|
6dc3f2ffa6 | ||
|
|
df7cbf0b76 | ||
|
|
19b6378b1a | ||
|
|
29cb2b50a8 | ||
|
|
5932c014a0 | ||
|
|
a3f75e9af0 | ||
|
|
9ed31e2c4e | ||
|
|
8599f63fbf | ||
|
|
07de78cb05 | ||
|
|
f764bbe080 | ||
|
|
7aa343b767 | ||
|
|
69198779a7 | ||
|
|
3088032ad8 | ||
|
|
dfaa12598d | ||
|
|
1c724cdc6c | ||
|
|
b59423fb01 | ||
|
|
96bceed102 | ||
|
|
f8e146b9b9 | ||
|
|
c54ddb644a | ||
|
|
2be616411f | ||
|
|
7415744807 | ||
|
|
23905a90f4 | ||
|
|
83444b329e | ||
|
|
9898dc85a9 | ||
|
|
661287f600 | ||
|
|
353c6a77e9 | ||
|
|
8c006fec3f | ||
|
|
5896b7ce6a | ||
|
|
f831f6cb2c | ||
|
|
b505a1ae01 | ||
|
|
a0fac17c0e | ||
|
|
851f606fc0 | ||
|
|
8940430ee0 | ||
|
|
06d3927275 | ||
|
|
7cea13e90d | ||
|
|
de2a504078 | ||
|
|
df14b441a3 | ||
|
|
ab1391440f | ||
|
|
310d32dcea | ||
|
|
f8cd822c92 | ||
|
|
3ade885e41 | ||
|
|
008a88192c | ||
|
|
639e7f012c | ||
|
|
c8ecc16648 | ||
|
|
225fb1ec0c | ||
|
|
c943e0e9b4 | ||
|
|
3d8ac83fcc | ||
|
|
06399ca8af | ||
|
|
8f8fc13ded | ||
|
|
2b018cb9a5 | ||
|
|
9577f4c9a3 | ||
|
|
771d98cc10 | ||
|
|
91e875d54c | ||
|
|
da39f1489f | ||
|
|
2940576681 | ||
|
|
a49c137b78 | ||
|
|
87e748cd83 | ||
|
|
94c2e332bb | ||
|
|
1437b6010e | ||
|
|
5fc203482d | ||
|
|
ff6d81b749 | ||
|
|
167e644bd0 | ||
|
|
d1c7489768 | ||
|
|
a783e165dd | ||
|
|
45bdd82864 | ||
|
|
79c5cb6b78 | ||
|
|
63ade5fdef | ||
|
|
853b8c7aa3 | ||
|
|
0655fb60de | ||
|
|
69b28e3508 | ||
|
|
5c16d9539f | ||
|
|
e3acf02bde | ||
|
|
10268e82d4 | ||
|
|
bc44bf726a | ||
|
|
9839681bc0 | ||
|
|
beb292cb07 | ||
|
|
29c4134f60 | ||
|
|
a6157f328d | ||
|
|
c6432e2c28 | ||
|
|
4a756bf2a9 | ||
|
|
b77cc5cd40 | ||
|
|
9f94af6ff7 | ||
|
|
7aba40cd5b | ||
|
|
fb6c17c5ff | ||
|
|
4504d80c80 | ||
|
|
8a8c8989cb | ||
|
|
20731dbe4b | ||
|
|
55393ca9eb | ||
|
|
e9aa4d5601 | ||
|
|
6d49769df9 | ||
|
|
0333e9d094 | ||
|
|
53bedca50a | ||
|
|
b9518ca987 | ||
|
|
794e713d6d | ||
|
|
5e1fd7501e | ||
|
|
c86ea206d9 | ||
|
|
b810cf84c2 | ||
|
|
15bc5db2ed | ||
|
|
4845d9005e | ||
|
|
bed4e9f1e1 | ||
|
|
7b20db10cc | ||
|
|
d59b3e8c46 | ||
|
|
8fccbb0ac2 | ||
|
|
f36a610e52 | ||
|
|
479a2f358e | ||
|
|
8795c357ae | ||
|
|
d8cb7526bb | ||
|
|
6ead8e391b | ||
|
|
362f45083d | ||
|
|
36218037ec | ||
|
|
584b56bc83 | ||
|
|
d33602e131 | ||
|
|
4304b49bf0 | ||
|
|
4f5325acac | ||
|
|
f8a40bfaf0 | ||
|
|
52dfb20a2b | ||
|
|
34b20cdfe0 | ||
|
|
f462201499 | ||
|
|
5106bdf634 | ||
|
|
b93c6dbcbd | ||
|
|
2ca141baba | ||
|
|
01fe5d2147 | ||
|
|
74830cede4 | ||
|
|
2f21cc29f7 | ||
|
|
05f8d97d68 | ||
|
|
04c4795192 | ||
|
|
ff6e379b6f | ||
|
|
25cfc375bc | ||
|
|
627184ef2d | ||
|
|
180e1178ef | ||
|
|
1c33454ce3 | ||
|
|
c7abe11dd8 | ||
|
|
7a6feccc8b | ||
|
|
f05e578f51 | ||
|
|
277ebea2b5 | ||
|
|
4982c5e147 | ||
|
|
726e217205 | ||
|
|
695c538ee5 | ||
|
|
e9b287ceac | ||
|
|
ecdae68b62 | ||
|
|
e737564b32 | ||
|
|
75c4a8d96d | ||
|
|
28dc1b050f | ||
|
|
4a9a7e31ba | ||
|
|
92da31f905 | ||
|
|
afd264c816 | ||
|
|
d676e3e217 | ||
|
|
4af117aacf | ||
|
|
b27e567a5e | ||
|
|
8ec9a5bf99 | ||
|
|
f129f92cfd | ||
|
|
ef87373d4b | ||
|
|
ff938d4ced | ||
|
|
ae555e0ce1 | ||
|
|
44db6093f5 | ||
|
|
d4bf6ce201 | ||
|
|
0b1c7bfa30 | ||
|
|
80f8a345b5 | ||
|
|
c929ce0257 | ||
|
|
7d3ab357d0 | ||
|
|
84d87602b8 | ||
|
|
14938ea7dd | ||
|
|
be0c052e5e | ||
|
|
af90a6658e | ||
|
|
9720c979b3 | ||
|
|
7c86186416 | ||
|
|
404dbfe725 | ||
|
|
02eac208dd | ||
|
|
bc9a0432cd | ||
|
|
dba7846d6c | ||
|
|
238d7723bb | ||
|
|
d2724bb1a5 | ||
|
|
8e046a9b50 | ||
|
|
1b808afd5d | ||
|
|
8d6f69eb05 | ||
|
|
c4562df955 | ||
|
|
8e1e8a8be3 | ||
|
|
363e92e072 | ||
|
|
c5a52fdb6d | ||
|
|
2dd096cfab | ||
|
|
80e1ce12ce | ||
|
|
2777d957e4 | ||
|
|
898aa4f41a | ||
|
|
c9ece6ad7c | ||
|
|
a6265c1b8d | ||
|
|
5646714c13 | ||
|
|
8ab13537a9 | ||
|
|
25e14e4846 | ||
|
|
55d67f890d | ||
|
|
9b3d7614f5 | ||
|
|
a3273d24b5 | ||
|
|
ffd7bec485 | ||
|
|
0aef76407d | ||
|
|
f2ad236863 | ||
|
|
487237638e | ||
|
|
3a78ccafce |
9
.codecov.yml
Normal file
9
.codecov.yml
Normal file
@@ -0,0 +1,9 @@
|
||||
comment: off
|
||||
coverage:
|
||||
status:
|
||||
project:
|
||||
default:
|
||||
threshold: 5%
|
||||
patch:
|
||||
default:
|
||||
only_pulls: true
|
||||
3
.docker-entry.sh
Executable file
3
.docker-entry.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/bin/bash
|
||||
cp -nr /oopt-gnpy/gnpy/example-data /shared
|
||||
exec "$@"
|
||||
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Environment:**
|
||||
- OS: [e.g. Windows]
|
||||
- Python Version [e.g, 3.7]
|
||||
- Anaconda Version [e.g. 3.7]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
7
.github/pull_request_template.md
vendored
Normal file
7
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
# Thanks for contributing to GNPy
|
||||
|
||||
If it isn't much trouble, please send your contribution as patches to our Gerrit.
|
||||
Here's [how to submit patches](https://review.gerrithub.io/Documentation/intro-gerrit-walkthrough-github.html), and here's a [list of stuff we are currently working on](https://review.gerrithub.io/q/project:Telecominfraproject/oopt-gnpy+status:open).
|
||||
Just sign in via your existing GitHub account.
|
||||
|
||||
However, if you feel more comfortable with filing GitHub PRs, we can work with that too.
|
||||
147
.github/workflows/main.yml
vendored
Normal file
147
.github/workflows/main.yml
vendored
Normal file
@@ -0,0 +1,147 @@
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
|
||||
name: CI
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Tox test
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: fedora-python/tox-github-action@v37.0
|
||||
with:
|
||||
tox_env: ${{ matrix.tox_env }}
|
||||
dnf_install: ${{ matrix.dnf_install }}
|
||||
- uses: codecov/codecov-action@v3.1.1
|
||||
if: ${{ endswith(matrix.tox_env, '-cover') }}
|
||||
with:
|
||||
files: ${{ github.workspace }}/cover/coverage.xml
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
tox_env:
|
||||
- py38
|
||||
- py39
|
||||
- py310
|
||||
- py311
|
||||
- py312-cover
|
||||
include:
|
||||
- tox_env: docs
|
||||
dnf_install: graphviz
|
||||
|
||||
pypi:
|
||||
needs: build
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') && github.repository_owner == 'Telecominfraproject' }}
|
||||
name: PyPI packaging
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4
|
||||
name: Install Python
|
||||
with:
|
||||
python-version: '3.12'
|
||||
- uses: casperdcl/deploy-pypi@bb869aafd89f657ceaafe9561d3b5584766c0f95
|
||||
with:
|
||||
password: ${{ secrets.PYPI_API_TOKEN }}
|
||||
pip: wheel -w dist/ --no-deps .
|
||||
upload: true
|
||||
|
||||
docker:
|
||||
needs: build
|
||||
if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v')) && github.repository_owner == 'Telecominfraproject' }}
|
||||
name: Docker image
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: jktjkt
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Extract tag name
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
id: extract_pretty_git
|
||||
run: echo ::set-output name=GIT_DESC::$(git describe --tags)
|
||||
- name: Build and push a container
|
||||
uses: docker/build-push-action@v2
|
||||
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }}
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
telecominfraproject/oopt-gnpy:${{ steps.extract_pretty_git.outputs.GIT_DESC }}
|
||||
telecominfraproject/oopt-gnpy:master
|
||||
- name: Extract tag name
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
||||
id: extract_tag_name
|
||||
run: echo ::set-output name=GIT_DESC::${GITHUB_REF/refs\/tags\//}
|
||||
- name: Build and push a container
|
||||
uses: docker/build-push-action@v2
|
||||
if: ${{ github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v') }}
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: |
|
||||
telecominfraproject/oopt-gnpy:${{ steps.extract_tag_name.outputs.GIT_DESC }}
|
||||
telecominfraproject/oopt-gnpy:latest
|
||||
|
||||
other-platforms:
|
||||
name: Tests on other platforms
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python_version }}
|
||||
- run: |
|
||||
pip install --editable .[tests]
|
||||
pytest -vv
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2022
|
||||
python_version: "3.11"
|
||||
- os: windows-2022
|
||||
python_version: "3.12"
|
||||
- os: windows-2025
|
||||
python_version: "3.11"
|
||||
- os: windows-2025
|
||||
python_version: "3.12"
|
||||
- os: macos-13
|
||||
python_version: "3.12"
|
||||
- os: macos-14
|
||||
python_version: "3.12"
|
||||
|
||||
paywalled-platforms:
|
||||
name: Tests on paywalled platforms
|
||||
if: github.repository_owner == 'Telecominfraproject'
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: ${{ matrix.python_version }}
|
||||
- run: |
|
||||
pip install --editable .[tests]
|
||||
pytest -vv
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: macos-13-xlarge # Apple M1 CPU
|
||||
python_version: "3.12"
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,6 +2,8 @@
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
.ipynb_checkpoints
|
||||
.idea
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
4
.gitreview
Normal file
4
.gitreview
Normal file
@@ -0,0 +1,4 @@
|
||||
[gerrit]
|
||||
host=review.gerrithub.io
|
||||
project=Telecominfraproject/oopt-gnpy
|
||||
defaultrebase=0
|
||||
3
.lgtm.yml
Normal file
3
.lgtm.yml
Normal file
@@ -0,0 +1,3 @@
|
||||
queries:
|
||||
- exclude: py/clear-text-logging-sensitive-data
|
||||
- exclude: py/clear-text-storage-sensitive-data
|
||||
17
.readthedocs.yml
Normal file
17
.readthedocs.yml
Normal file
@@ -0,0 +1,17 @@
|
||||
version: 2
|
||||
build:
|
||||
os: ubuntu-22.04
|
||||
tools:
|
||||
python: "3.12"
|
||||
apt_packages:
|
||||
- graphviz
|
||||
|
||||
python:
|
||||
install:
|
||||
- method: pip
|
||||
path: .
|
||||
extra_requirements:
|
||||
- docs
|
||||
|
||||
sphinx:
|
||||
configuration: docs/conf.py
|
||||
@@ -1,9 +0,0 @@
|
||||
language: python
|
||||
python:
|
||||
- "3.6"
|
||||
# command to install dependencies
|
||||
install:
|
||||
- pip install -r requirements.txt
|
||||
# command to run tests
|
||||
script:
|
||||
- pytest
|
||||
54
.zuul.yaml
Normal file
54
.zuul.yaml
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
- project:
|
||||
check:
|
||||
jobs:
|
||||
- tox-py38:
|
||||
vars:
|
||||
ensure_tox_version: '<4'
|
||||
- tox-py39:
|
||||
vars:
|
||||
ensure_tox_version: '<4'
|
||||
- tox-py310-cover:
|
||||
vars:
|
||||
ensure_tox_version: '<4'
|
||||
- tox-docs-f36:
|
||||
vars:
|
||||
ensure_tox_version: '<4'
|
||||
- coverage-diff:
|
||||
voting: false
|
||||
dependencies:
|
||||
- tox-py310-cover-previous
|
||||
- tox-py310-cover
|
||||
vars:
|
||||
coverage_job_name_previous: tox-py310-cover-previous
|
||||
coverage_job_name_current: tox-py310-cover
|
||||
- tox-linters-diff-n-report:
|
||||
voting: false
|
||||
vars:
|
||||
ensure_tox_version: '<4'
|
||||
- tox-py310-cover-previous:
|
||||
vars:
|
||||
ensure_tox_version: '<4'
|
||||
tag:
|
||||
jobs:
|
||||
- oopt-release-python:
|
||||
secrets:
|
||||
- secret: pypi-oopt-gnpy
|
||||
name: pypi_info
|
||||
pass-to-parent: true
|
||||
|
||||
- secret:
|
||||
name: pypi-oopt-gnpy
|
||||
data:
|
||||
username: __token__
|
||||
password: !encrypted/pkcs1-oaep
|
||||
- Taod9JmSMtVAvC5ShSbB3UWuccktQvutdySrj0G7a1Nk4tKFQIdwDXEnBuLpHsZVvsU9Q
|
||||
6uk4wRVQABDSdNNI/+M/1FwmZfoxuOXa02U5S1deuxW/rBHTxzYcuB8xriwhArBvTiDMk
|
||||
zyWHVysgDsjlR+85h/DkEhvsaMRDLYWqFwYgXizMoGNKVkwDVIH+qkhBmbggQfDpcYPKT
|
||||
1gq0d6fw0eKVJtO8+vonMEcE0sWZvHmZvSSu0H++gxoe1W/JtzbCteH3Ak0zktwBHI8Qt
|
||||
WBqFvY3laad335tpkFJN5b949N+DP8svCWwRwXmkZlHplPYZWF6QpYbEEXL/6Q0H6VwL+
|
||||
om4f7ybYpKe9Gl939uv2INnXaKe5EU6CMsSw40r2XZCjnSTjWOTgh9pUn2PsoHnqUlALW
|
||||
VR4Z+ipnCrEbu8aTmX3ROcnwYNS7OXkq4uhwDU1u9QjzyMHet6NQQhwhGtimsTo9KhL4E
|
||||
TEUNiRlbAgow9WOwM5r3vRzddO8T2HZZSGaWj75qNRX46XPQWRWgB7ItAwyXgwLZ8UzWl
|
||||
HdztjS3D7Hlsqno3zxNOVlhA5/vl9uVnhFbJnMtUOJAB07YoTJOeR+LjQ0avx/VzopxXc
|
||||
RA/WvJXVZSBrlAHY0+ip4wPZvdi4Ph90gpmvHJvoH82KVfp2j5jxzUhsage94I=
|
||||
37
AUTHORS.rst
Normal file
37
AUTHORS.rst
Normal file
@@ -0,0 +1,37 @@
|
||||
gnpy is written and maintained by the Telecom Infra Project with work
|
||||
contributed by the following TIP members.
|
||||
|
||||
To learn how to contribute, please see CONTRIBUTING.md
|
||||
|
||||
(*in alphabetical order*)
|
||||
|
||||
- Alessio Ferrari (Politecnico di Torino) <alessio.ferrari@polito.it>
|
||||
- Anders Lindgren (Telia Company) <Anders.X.Lindgren@teliacompany.com>
|
||||
- Andrea D'Amico (NEC) <adamico@nec-labs.com>
|
||||
- Arturo Mayoral (Telecom Infra Project) <amayoral@telecominfraproject.com>
|
||||
- Brian Taylor (Facebook) <briantaylor@fb.com>
|
||||
- David Boertjes (Ciena) <dboertje@ciena.com>
|
||||
- Diego Landa (Facebook) <dlanda@fb.com>
|
||||
- Emmanuelle Delfour (Orange) <WEDE7391@orange.com>
|
||||
- Esther Le Rouzic (Orange) <esther.lerouzic@orange.com>
|
||||
- Florian Frank (Orange) <florian1.frank@orange.com>
|
||||
- Gabriele Galimberti (Cisco) <ggalimbe@cisco.com>
|
||||
- Gert Grammel (Juniper Networks) <ggrammel@juniper.net>
|
||||
- Giacomo Borraccini (NEC Laboratories America) <gborraccini@nec-labs.com>
|
||||
- Gilad Goldfarb (Facebook) <giladg@fb.com>
|
||||
- James Powell (Telecom Infra Project) <james.powell@telecominfraproject.com>
|
||||
- Jan Kundrát (Telecom Infra Project) <jkt@jankundrat.com>
|
||||
- Jeanluc Augé (Orange) <jeanluc.auge@orange.com>
|
||||
- Jenny L'Escop (Orange) <jenny.lescop@orange.com>
|
||||
- Jonas Mårtensson (RISE) <jonas.martensson@ri.se>
|
||||
- Mattia Cantono (Politecnico di Torino) <mattia.cantono@polito.it>
|
||||
- Miguel Garrich (University Catalunya) <miquel.garrich@upct.es>
|
||||
- Raj Nagarajan (Lumentum) <raj.nagarajan@lumentum.com>
|
||||
- Renato Ambrosone (Politecnico di Torino) <renato.ambrosone@polito.it>
|
||||
- Roberts Miculens (Lattelecom) <roberts.miculens@lattelecom.lv>
|
||||
- Rodrigo Sasse David (Orange) <rodrigo.sassedavid@orange.com>
|
||||
- Sami Alavi (NUST) <sami.mansooralavi1999@gmail.com>
|
||||
- Shengxiang Zhu (University of Arizona) <szhu@email.arizona.edu>
|
||||
- Stefan Melin (Telia Company) <Stefan.Melin@teliacompany.com>
|
||||
- Vittorio Curri (Politecnico di Torino) <vittorio.curri@polito.it>
|
||||
- Xufeng Liu (Jabil) <xufeng_liu@jabil.com>
|
||||
@@ -1,17 +0,0 @@
|
||||
Contributors in alphabetical order
|
||||
==================================
|
||||
|
||||
Name | Surname | Affiliation | Contact
|
||||
-----|---------|-------------|--------
|
||||
Alessio | Ferrari | Politecnico di Torino | alessio.ferrari@polito.it
|
||||
Brian | Taylor | Facebook | briantaylor@fb.com
|
||||
David | Boertjes | Ciena | dboertje@ciena.com
|
||||
Esther | Le Rouzic | Orange | esther.lerouzic@orange.com
|
||||
Gabriele | Galimberti | Cisco | ggalimbe@cisco.com
|
||||
Gert | Grammel | Juniper Networks | ggrammel@juniper.net
|
||||
Gilad | Goldfarb | Facebook | giladg@fb.com
|
||||
James | Powell | Consultant | james@dontusethiscode.com
|
||||
Jeanluc | Auge | Orange | jeanluc.auge@orange.com
|
||||
Liu | Xufeng | Jabil | Xufeng_Liu@jabil.com
|
||||
Mattia | Cantono | Politecnico di Torino | mattia.cantono@polito.it
|
||||
Vittorio | Curri | Politecnico di Torino | vittorio.curri@polito.it
|
||||
8
Dockerfile
Normal file
8
Dockerfile
Normal file
@@ -0,0 +1,8 @@
|
||||
FROM python:3.9-slim
|
||||
COPY . /oopt-gnpy
|
||||
WORKDIR /oopt-gnpy
|
||||
RUN apt update; apt install -y git
|
||||
RUN pip install .
|
||||
WORKDIR /shared/example-data
|
||||
ENTRYPOINT ["/oopt-gnpy/.docker-entry.sh"]
|
||||
CMD ["/bin/bash"]
|
||||
35
README.md
Normal file
35
README.md
Normal file
@@ -0,0 +1,35 @@
|
||||
# GNPy: Optical Route Planning and DWDM Network Optimization
|
||||
|
||||
[](https://pypi.org/project/gnpy/)
|
||||
[](https://pypi.org/project/gnpy/)
|
||||
[](http://gnpy.readthedocs.io/en/master/?badge=master)
|
||||
[](https://github.com/Telecominfraproject/oopt-gnpy/actions/workflows/main.yml)
|
||||
[](https://review.gerrithub.io/q/project:Telecominfraproject/oopt-gnpy+is:open)
|
||||
[](https://github.com/Telecominfraproject/oopt-gnpy/graphs/contributors)
|
||||
[](https://codecov.io/gh/Telecominfraproject/oopt-gnpy)
|
||||
[](https://doi.org/10.5281/zenodo.3458319)
|
||||
[](https://matrix.to/#/%23oopt-gnpy%3Amatrix.org?via=matrix.org)
|
||||
|
||||
GNPy is an open-source, community-developed library for building route planning and optimization tools in real-world mesh optical networks.
|
||||
We are a consortium of operators, vendors, and academic researchers sponsored via the [Telecom Infra Project](http://telecominfraproject.com)'s [OOPT/PSE](https://telecominfraproject.com/open-optical-packet-transport) working group.
|
||||
Together, we are building this tool for rapid development of production-grade route planning tools which is easily extensible to include custom network elements and performant to the scale of real-world mesh optical networks.
|
||||
|
||||

|
||||
|
||||
## Quick Start
|
||||
|
||||
Install either via [Docker](https://gnpy.readthedocs.io/en/master/install.html#using-prebuilt-docker-images), or as a [Python package](https://gnpy.readthedocs.io/en/master/install.html#using-python-on-your-computer).
|
||||
Read our [documentation](https://gnpy.readthedocs.io/), learn from the demos, and [get in touch with us](https://github.com/Telecominfraproject/oopt-gnpy/discussions).
|
||||
|
||||
This example demonstrates how GNPy can be used to check the expected SNR at the end of the line by varying the channel input power:
|
||||
|
||||

|
||||
|
||||
GNPy can do much more, including acting as a Path Computation Engine, tracking bandwidth requests, or advising the SDN controller about a best possible path through a large DWDM network.
|
||||
Learn more about this [in the documentation](https://gnpy.readthedocs.io/), or give it a [try online at `gnpy.app`](https://gnpy.app/):
|
||||
|
||||
[](https://gnpy.app/)
|
||||
|
||||
## Project Calendar
|
||||
|
||||
See upcoming meetings on the [Project Calendar](https://telecominfraproject.github.io/oopt-gnpy/calendar.html). The calendar is embedded from Google Calendar and updates automatically.
|
||||
191
README.rst
191
README.rst
@@ -1,191 +0,0 @@
|
||||
====
|
||||
`gnpy`: mesh optical network route planning and optimization library
|
||||
====
|
||||
|
||||
|docs| |build|
|
||||
|
||||
**gnpy is an open-source, community-developed library for building route planning
|
||||
and optimization tools in real-world mesh optical networks.**
|
||||
|
||||
`gnpy <http://github.com/telecominfraproject/gnpy>`_ is:
|
||||
|
||||
- a sponsored project of the `OOPT/PSE <http://telecominfraproject.com/project-groups-2/backhaul-projects/open-optical-packet-transport/>`_ working group of the `Telecom Infra Project <http://telecominfraproject.com>`_.
|
||||
- fully community-driven, fully open source library
|
||||
- driven by a consortium of operators, vendors, and academic researchers
|
||||
- intended for rapid development of production-grade route planning tools
|
||||
- easily extensible to include custom network elements
|
||||
- performant to the scale of real-world mesh optical networks
|
||||
|
||||
Documentation: https://gnpy.readthedocs.io
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
``gnpy`` is hosted in the `Python Package Index <http://pypi.org/>`_ (`gnpy <https://pypi.org/project/gnpy/>`_). It can be installed via:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ pip install gnpy
|
||||
|
||||
It can also be installed directly from the repo.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ git clone https://github.com/telecominfraproject/gnpy
|
||||
$ cd gnpy
|
||||
$ python setup.py install
|
||||
|
||||
Both approaches above will handle installing any additional software dependencies.
|
||||
|
||||
**Note**: *We recommend the use of the Anaconda Python distribution
|
||||
(https://www.anaconda.com/download) which comes with many scientific
|
||||
computing dependencies pre-installed.*
|
||||
|
||||
Instructions for Use
|
||||
--------------------
|
||||
|
||||
``gnpy`` is a library for building route planning and optimization tools.
|
||||
|
||||
It ships with a number of example programs. Release versions will ship with
|
||||
fully-functional programs.
|
||||
|
||||
|
||||
**Note**: *If you are a network operator or involved in route planning and
|
||||
optimization for your organization, please contact project maintainer James
|
||||
Powell <james.powell@telecominfraproject>. gnpy is looking for users with
|
||||
specific, delineated use cases to drive requirements for future
|
||||
development.*
|
||||
|
||||
|
||||
**To get started, run the transmission example:**
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ python examples/transmission_main_example.py
|
||||
|
||||
By default, this script operates on a single span network defined in `examples/edfa/edfa_example_network.json <examples/edfa/edfa_example_network.json>`_
|
||||
|
||||
You can specify a different network at the command line as follows. For
|
||||
example, to use the CORONET Continental US (CONUS) network defined in `examples/coronet_conus_example.json <examples/coronet_conus_example.json>`_:
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ python examples/transmission_main_example.py examples/coronet_conus_example.json
|
||||
|
||||
This script will calculate the average signal osnr and snr across 93 network
|
||||
elements (transceiver, ROADMs, fibers, and amplifiers) between Abilene, Texas
|
||||
and Albany, New York.
|
||||
|
||||
This script calculates the average signal OSNR = |OSNR| and SNR = |SNR|.
|
||||
|
||||
.. |OSNR| replace:: P\ :sub:`ch`\ /P\ :sub:`ase`
|
||||
.. |SNR| replace:: P\ :sub:`ch`\ /(P\ :sub:`nli`\ +\ P\ :sub:`ase`)
|
||||
|
||||
|Pase| is the amplified spontaneous emission noise, and |Pnli| the non-linear
|
||||
interference noise.
|
||||
|
||||
.. |Pase| replace:: P\ :sub:`ase`
|
||||
.. |Pnli| replace:: P\ :sub:`nli`
|
||||
|
||||
The `transmission_main_example.py <examples/transmission_main_example.py>`_
|
||||
script propagates a specrum of 96 channels at 32 Gbaud, 50 GHz spacing and 0
|
||||
dBm/channel. These are not yet parametrized but can be modified directly in the
|
||||
script (via the SpectralInformation tuple) to accomodate any baud rate,
|
||||
spacing, power or channel count demand.
|
||||
|
||||
The amplifier's gain is set to exactly compsenate for the loss in each network
|
||||
element. The amplifier is currently defined with gain range of 15 dB to 25 dB
|
||||
and 21 dBm max output power. Ripple and NF models are defined in
|
||||
`examples/edfa_config.json <examples/edfa_config.json>`_
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
``gnpy`` is looking for additional contributors, especially those with experience
|
||||
planning and maintaining large-scale, real-world mesh optical networks.
|
||||
|
||||
To get involved, please contact James Powell
|
||||
<james.powell@telecominfraproject.com> or Gert Grammel <ggrammel@juniper.net>.
|
||||
|
||||
``gnpy`` contributions are currently limited to members of `TIP
|
||||
<http://telecominfraproject.com>`_. Membership is free and open to all.
|
||||
|
||||
See the `Onboarding Guide
|
||||
<https://github.com/Telecominfraproject/gnpy/wiki/Onboarding-Guide>`_ for
|
||||
specific details on code contribtions.
|
||||
|
||||
See `AUTHORS.Md <AUTHORS.Md>`_ for past and present contributors.
|
||||
|
||||
Project Background
|
||||
------------------
|
||||
|
||||
Data Centers are built upon interchangeable, highly standardized node and
|
||||
network architectures rather than a sum of isolated solutions. This also
|
||||
translates to optical networking. It leads to a push in enabling multi-vendor
|
||||
optical network by disaggregating HW and SW functions and focussing on
|
||||
interoperability. In this paradigm, the burden of responsibility for ensuring
|
||||
the performance of such disaggregated open optical systems falls on the
|
||||
operators. Consequently, operators and vendors are collaborating in defining
|
||||
control models that can be readily used by off-the-shelf controllers. However,
|
||||
node and network models are only part of the answer. To take reasonable
|
||||
decisions, controllers need to incorporate logic to simulate and assess optical
|
||||
performance. Hence, a vendor-independent optical quality estimator is required.
|
||||
Given its vendor-agnostic nature, such an estimator needs to be driven by a
|
||||
consortium of operators, system and component suppliers.
|
||||
|
||||
Founded in February 2016, the Telecom Infra Project (TIP) is an
|
||||
engineering-focused initiative which is operator driven, but features
|
||||
collaboration across operators, suppliers, developers, integrators, and
|
||||
startups with the goal of disaggregating the traditional network deployment
|
||||
approach. The group’s ultimate goal is to help provide better connectivity for
|
||||
communities all over the world as more people come on-line and demand more
|
||||
bandwidth- intensive experiences like video, virtual reality and augmented
|
||||
reality.
|
||||
|
||||
Within TIP, the Open Optical Packet Transport (OOPT) project group is chartered
|
||||
with unbundling monolithic packet-optical network technologies in order to
|
||||
unlock innovation and support new, more flexible connectivity paradigms.
|
||||
|
||||
The key to unbundling is the ability to accurately plan and predict the
|
||||
performance of optical line systems based on an accurate simulation of optical
|
||||
parameters. Under that OOPT umbrella, the Physical Simulation Environment (PSE)
|
||||
working group set out to disrupt the planning landscape by providing an open
|
||||
source simulation model which can be used freely across multiple vendor
|
||||
implementations.
|
||||
|
||||
.. |docs| image:: https://readthedocs.org/projects/gnpy/badge/?version=develop
|
||||
:target: http://gnpy.readthedocs.io/en/develop/?badge=develop
|
||||
:alt: Documentation Status
|
||||
:scale: 100%
|
||||
|
||||
.. |build| image:: https://travis-ci.org/mcantono/gnpy.svg?branch=develop
|
||||
:target: https://travis-ci.org/mcantono/gnpy
|
||||
:alt: Build Status
|
||||
:scale: 100%
|
||||
|
||||
TIP OOPT/PSE & PSE WG Charter
|
||||
-----------------------------
|
||||
|
||||
We believe that openly sharing ideas, specifications, and other intellectual
|
||||
property is the key to maximizing innovation and reducing complexity
|
||||
|
||||
TIP OOPT/PSE's goal is to build an end-to-end simulation environment which
|
||||
defines the network models of the optical device transfer functions and their
|
||||
parameters. This environment will provide validation of the optical
|
||||
performance requirements for the TIP OLS building blocks.
|
||||
|
||||
- The model may be approximate or complete depending on the network complexity.
|
||||
Each model shall be validated against the proposed network scenario.
|
||||
- The environment must be able to process network models from multiple vendors,
|
||||
and also allow users to pick any implementation in an open source framework.
|
||||
- The PSE will influence and benefit from the innovation of the DTC, API, and
|
||||
OLS working groups.
|
||||
- The PSE represents a step along the journey towards multi-layer optimization.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
``gnpy`` is distributed under a standard BSD 3-Clause License.
|
||||
|
||||
See `LICENSE <LICENSE>`_ for more details.
|
||||
|
||||
1
bindep.txt
Normal file
1
bindep.txt
Normal file
@@ -0,0 +1 @@
|
||||
graphviz
|
||||
@@ -1,17 +0,0 @@
|
||||
Contributors in alphabetical order
|
||||
==================================
|
||||
|
||||
Name | Surname | Affiliation | Contact
|
||||
-----|---------|-------------|--------
|
||||
Alessio | Ferrari | Politecnico di Torino | alessio.ferrari@polito.it
|
||||
Brian | Taylor | Facebook | briantaylor@fb.com
|
||||
David | Boertjes | Ciena | dboertje@ciena.com
|
||||
Esther | Le Rouzic | Orange | esther.lerouzic@orange.com
|
||||
Gabriele | Galimberti | Cisco | ggalimbe@cisco.com
|
||||
Gert | Grammel | Juniper Networks | ggrammel@juniper.net
|
||||
Gilad | Goldfarb | Facebook | giladg@fb.com
|
||||
James | Powell | Consultant | james@dontusethiscode.com
|
||||
Jeanluc | Auge | Orange | jeanluc.auge@orange.com
|
||||
Liu | Xufeng | Jabil | Xufeng_Liu@jabil.com
|
||||
Mattia | Cantono | Politecnico di Torino | mattia.cantono@polito.it
|
||||
Vittorio | Curri | Politecnico di Torino | vittorio.curri@polito.it
|
||||
4
docs/_static/custom.css
vendored
Normal file
4
docs/_static/custom.css
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
.wy-table-responsive table td, .wy-table-responsive table th {
|
||||
white-space: normal;
|
||||
}
|
||||
60
docs/about-project.md
Normal file
60
docs/about-project.md
Normal file
@@ -0,0 +1,60 @@
|
||||
(about-gnpy)=
|
||||
# About the project
|
||||
|
||||
GNPy is a sponsored project of the [OOPT/PSE](https://telecominfraproject.com/open-optical-packet-transport/) working group of the [Telecom Infra Project](http://telecominfraproject.com).
|
||||
|
||||
There are weekly calls about our progress.
|
||||
Newcomers, users and telecom operators are especially welcome there.
|
||||
We encourage all interested people outside the TIP to [join the project](https://telecominfraproject.com/apply-for-membership/) and especially to [get in touch with us](https://github.com/Telecominfraproject/oopt-gnpy/discussions).
|
||||
|
||||
(contributing)=
|
||||
## Contributing
|
||||
|
||||
`gnpy` is looking for additional contributors, especially those with experience planning and maintaining large-scale, real-world mesh optical networks.
|
||||
|
||||
To get involved, please contact [Esther Le Rouzic](mailto:esther.lerouzic@orange.com) or
|
||||
[Andrea d'Amico](mailto:adamico@nec-labs.com) or [Gert Grammel](mailto:ggrammel@juniper.net).
|
||||
|
||||
`gnpy` contributions are currently limited to members of [TIP](http://telecominfraproject.com).
|
||||
Membership is free and open to all.
|
||||
|
||||
See the [Onboarding Guide](https://github.com/Telecominfraproject/gnpy/wiki/Onboarding-Guide) for specific details on code contributions, or just [upload patches to our Gerrit](https://review.gerrithub.io/Documentation/intro-gerrit-walkthrough-github.html).
|
||||
Here is [what we are currently working on](https://review.gerrithub.io/q/project:Telecominfraproject/oopt-gnpy+status:open).
|
||||
|
||||
## Project Background
|
||||
|
||||
Data Centers are built upon interchangeable, highly standardized node and network architectures rather than a sum of isolated solutions.
|
||||
This also translates to optical networking.
|
||||
It leads to a push in enabling multi-vendor optical network by disaggregating HW and SW functions and focusing on interoperability.
|
||||
In this paradigm, the burden of responsibility for ensuring the performance of such disaggregated open optical systems falls on the operators.
|
||||
Consequently, operators and vendors are collaborating in defining control models that can be readily used by off-the-shelf controllers.
|
||||
However, node and network models are only part of the answer.
|
||||
To take reasonable decisions, controllers need to incorporate logic to simulate and assess optical performance.
|
||||
Hence, a vendor-independent optical quality estimator is required.
|
||||
Given its vendor-agnostic nature, such an estimator needs to be driven by a consortium of operators, system and component suppliers.
|
||||
|
||||
Founded in February 2016, the Telecom Infra Project (TIP) is an engineering-focused initiative which is operator driven, but features collaboration across operators, suppliers, developers, integrators, and startups with the goal of disaggregating the traditional network deployment approach.
|
||||
The group’s ultimate goal is to help provide better connectivity for communities all over the world as more people come on-line and demand more bandwidth-intensive experiences like video, virtual reality and augmented reality.
|
||||
|
||||
Within TIP, the Open Optical Packet Transport (OOPT) project group is chartered with unbundling monolithic packet-optical network technologies in order to unlock innovation and support new, more flexible connectivity paradigms.
|
||||
|
||||
The key to unbundling is the ability to accurately plan and predict the performance of optical line systems based on an accurate simulation of optical parameters.
|
||||
Under that OOPT umbrella, the Physical Simulation Environment (PSE) working group set out to disrupt the planning landscape by providing an open source simulation model which can be used freely across multiple vendor implementations.
|
||||
|
||||
## TIP OOPT/PSE & PSE WG Charter
|
||||
|
||||
We believe that openly sharing ideas, specifications, and other intellectual property is the key to maximizing innovation and reducing complexity
|
||||
|
||||
TIP OOPT/PSE's goal is to build an end-to-end simulation environment which defines the network models of the optical device transfer functions and their parameters.
|
||||
This environment will provide validation of the optical performance requirements for the TIP OLS building blocks.
|
||||
|
||||
- The model may be approximate or complete depending on the network complexity.
|
||||
Each model shall be validated against the proposed network scenario.
|
||||
- The environment must be able to process network models from multiple vendors, and also allow users to pick any implementation in an open source framework.
|
||||
- The PSE will influence and benefit from the innovation of the DTC, API, and OLS working groups.
|
||||
- The PSE represents a step along the journey towards multi-layer optimization.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
GNPy is distributed under a standard BSD 3-Clause License.
|
||||
318
docs/amplifier_models_description.rst
Normal file
318
docs/amplifier_models_description.rst
Normal file
@@ -0,0 +1,318 @@
|
||||
.. _amp_models:
|
||||
|
||||
**********************************
|
||||
Amplifier models and Configuration
|
||||
**********************************
|
||||
|
||||
|
||||
1. Equipment configuration description
|
||||
======================================
|
||||
|
||||
Equipment description defines equipment types and parameters.
|
||||
It takes place in the equipment library such as **eqpt_config.json** file defined in example-data folder.
|
||||
By default **gnpy-transmission-example** uses **eqpt_config.json** file and that
|
||||
can be changed with **-e** or **--equipment** command line parameter.
|
||||
|
||||
2. Amplifier parameters and subtypes
|
||||
====================================
|
||||
|
||||
Several amplifiers can be used by GNpy, so they are defined as an array of equipment parameters in **eqpt_config.json** file.
|
||||
|
||||
- *"type_variety"*:
|
||||
Each amplifier is identified by its unique *"type_variety"*, which is used in the topology files input to reference a specific amplifier. It is a user free defined id.
|
||||
|
||||
For each amplifier *type_variety*, specific parameters are describing its attributes and performance:
|
||||
|
||||
- *"type_def"*:
|
||||
Sets the amplifier model that the simulation will use to calculate the ase noise contribution. 5 models are defined with reserved words:
|
||||
|
||||
- *"advanced_model"*
|
||||
- *"variable_gain"*
|
||||
- *"fixed_gain"*
|
||||
- *"dual_stage"*
|
||||
- *"multi_band"*
|
||||
- *"openroadm"*
|
||||
*see next section for a full description of these models*
|
||||
|
||||
|
||||
- *"default_config_from_json"*:
|
||||
Use a custom per frequency dynamic gain tilt, gain and noise ripple arrays defined in the file specified with
|
||||
this option, instead of the default values from GNPy.
|
||||
|
||||
|
||||
- *"advanced_config_from_json"*:
|
||||
**This parameter is only applicable to the _"advanced_model"_ model**
|
||||
|
||||
json file name describing:
|
||||
|
||||
- nf_fit_coeff
|
||||
- f_min/max
|
||||
- gain_ripple
|
||||
- nf_ripple
|
||||
- dgt
|
||||
|
||||
*see next section for a full description*
|
||||
|
||||
- *"gain_flatmax"*:
|
||||
amplifier maximum gain in dB before its extended gain range: flat or nominal tilt output.
|
||||
|
||||
If gain > gain_flatmax, the amplifier will tilt, based on its dgt function
|
||||
|
||||
If gain > gain_flatmax + target_extended_gain, the amplifier output power is reduced to not exceed the extended gain range.
|
||||
|
||||
- *"gain_min"*:
|
||||
amplifier minimum gain in dB.
|
||||
|
||||
If gain < gain_min, the amplifier input is automatically padded, which results in
|
||||
|
||||
NF += gain_min - gain
|
||||
|
||||
- *"p_max"*:
|
||||
amplifier max output power, full load
|
||||
|
||||
Total signal output power will not be allowed beyond this value
|
||||
|
||||
- *"nf_min/max"*:
|
||||
**These parameters are only applicable to the _"variable_gain"_ model**
|
||||
|
||||
min & max NF values in dB
|
||||
|
||||
NF_min is the amplifier NF @ gain_max
|
||||
|
||||
NF_max is the amplifier NF @ gain_min
|
||||
|
||||
- *"nf_coef"*:
|
||||
**This parameter is only applicable to the *"openroadm"* model**
|
||||
|
||||
[a, b, c, d] 3rd order polynomial coefficients list to define the incremental OSNR vs Pin
|
||||
|
||||
Incremental OSNR is the amplifier OSNR contribution
|
||||
|
||||
Pin is the amplifier channel input power defined in a 50GHz bandwidth
|
||||
|
||||
Incremental OSNR = a*Pin³ + b*Pin² + c*Pin + d
|
||||
|
||||
- *"preamp_variety"*:
|
||||
**This parameter is only applicable to the _"dual_stage"_ model**
|
||||
|
||||
1st stage type_variety
|
||||
|
||||
- *"booster_variety"*:
|
||||
**This parameter is only applicable to the *"dual_stage"* model**
|
||||
|
||||
2nd stage type_variety
|
||||
|
||||
- *"out_voa_auto"*: true/false
|
||||
**power_mode only**
|
||||
|
||||
**This parameter is only applicable to the *"advanced_model"* and *"variable_gain"* models**
|
||||
|
||||
If "out_voa_auto": true, auto_design will chose the output_VOA value that maximizes the amplifier gain within its power capability and therefore minimizes its NF.
|
||||
|
||||
- *"allowed_for_design"*: true/false
|
||||
**auto_design only**
|
||||
|
||||
Tells auto_design if this amplifier can be picked for the design (deactivates unwanted amplifiers)
|
||||
|
||||
It does not prevent the use of an amplifier if it is placed in the topology input.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{"Edfa": [{
|
||||
"type_variety": "std_medium_gain",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 23,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 23,
|
||||
"nf_min": 6.5,
|
||||
"nf_max": 11,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
}
|
||||
]}
|
||||
|
||||
|
||||
3. Amplifier models
|
||||
===================
|
||||
|
||||
In an opensource and multi-vendor environnement, it is needed to support different use cases and context. Therefore several models are supported for amplifiers.
|
||||
|
||||
5 types of EDFA definition are possible and referenced by the *"type_def"* parameter with the following reserved words:
|
||||
|
||||
- *"advanced_model"*
|
||||
This model is refered as a whitebox model because of the detailed level of knowledge that is required. The amplifier NF model and ripple definition are described by a json file referenced with *"advanced_config_from_json"*: json filename. This json file contains:
|
||||
|
||||
- nf_fit_coeff: [a,b,c,d]
|
||||
|
||||
3rd order polynomial NF = f(-dg) coeficients list
|
||||
|
||||
dg = gain - gain_max
|
||||
|
||||
- f_min/max: amplifier frequency range in Hz
|
||||
- gain_ripple : [...]
|
||||
|
||||
amplifier gain ripple excursion comb list in dB across the frequency range.
|
||||
- nf_ripple : [...]
|
||||
|
||||
amplifier nf ripple excursion comb list in dB across the frequency range.
|
||||
- dgt : [...]
|
||||
amplifier dynamic gain tilt comb list across the frequency range.
|
||||
|
||||
*See next section for the generation of this json file*
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"Edfa":[{
|
||||
"type_variety": "high_detail_model_example",
|
||||
"type_def": "advanced_model",
|
||||
"gain_flatmax": 25,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
}
|
||||
]
|
||||
|
||||
- *"variable_gain"*
|
||||
This model is refered as an operator model because a lower level of knowledge is required. A full polynomial description of the NF cross the gain range is not required. Instead, NF_min and NF_max values are required and used by the code to model a dual stage amplifier with an internal mid stage VOA. NF_min and NF_max values are typically available from equipment suppliers data-sheet.
|
||||
|
||||
There is a default configuration to enforce 0 tilt and ripple values because GNPy core algorithm is a multi-carrier propagation.
|
||||
- gain_ripple =[0,...,0]
|
||||
- nf_ripple = [0,...,0]
|
||||
- dgt = [...] generic dgt comb
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"Edfa":[{
|
||||
"type_variety": "std_medium_gain",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 23,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
}
|
||||
]
|
||||
|
||||
- *"fixed_gain"*
|
||||
This model is also an operator model with a single NF value that emulates basic single coil amplifiers without internal VOA.
|
||||
|
||||
if gain_min < gain < gain_max, NF == nf0
|
||||
|
||||
if gain < gain_min, the amplifier input is automatically padded, which results in
|
||||
|
||||
NF += gain_min - gain
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"Edfa":[{
|
||||
"type_variety": "std_fixed_gain",
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 21,
|
||||
"gain_min": 20,
|
||||
"p_max": 21,
|
||||
"nf0": 5.5,
|
||||
"allowed_for_design": false
|
||||
}
|
||||
]
|
||||
|
||||
- *"openroadm"*
|
||||
This model is a black box model replicating OpenRoadm MSA spec for ILA.
|
||||
|
||||
.. code-block:: json-object
|
||||
|
||||
"Edfa":[{
|
||||
"type_variety": "openroadm_ila_low_noise",
|
||||
"type_def": "openroadm",
|
||||
"gain_flatmax": 27,
|
||||
"gain_min": 12,
|
||||
"p_max": 22,
|
||||
"nf_coef": [-8.104e-4,-6.221e-2,-5.889e-1,37.62],
|
||||
"allowed_for_design": false
|
||||
}
|
||||
]
|
||||
|
||||
- *"dual_stage"*
|
||||
This model allows the cascade (pre-defined combination) of any 2 amplifiers already described in the eqpt_config.json library.
|
||||
|
||||
- preamp_variety defines the 1st stge type variety
|
||||
|
||||
- booster variety defines the 2nd stage type variety
|
||||
|
||||
Both preamp and booster variety must exist in the eqpt libray
|
||||
The resulting NF is the sum of the 2 amplifiers
|
||||
The preamp is operated to its maximum gain
|
||||
|
||||
- gain_min indicates to auto_design when this dual_stage should be used
|
||||
|
||||
But unlike other models the 1st stage input will not be padded: it is always operated to its maximum gain and min NF. Therefore if gain adaptation and padding is needed it will be performed by the 2nd stage.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"type_variety": "medium+low_gain",
|
||||
"type_def": "dual_stage",
|
||||
"gain_min": 25,
|
||||
"preamp_variety": "std_medium_gain",
|
||||
"booster_variety": "std_low_gain",
|
||||
"allowed_for_design": true
|
||||
}
|
||||
|
||||
|
||||
- *"multiband"*
|
||||
This model enables the definition of multiband amplifiers that consist of multiple single-band
|
||||
amplifier elements, with each amplifier responsible for amplifying a different portion of the spectrum.
|
||||
The types of single-band amplifiers that can be included in these multiband amplifiers are specified,
|
||||
allowing for multiple options to be available for the same spectrum band (for instance, providing
|
||||
several permitted type varieties for both the C-band and the L-band). The actual element utilizing the
|
||||
type_variety must implement only one option for each band.
|
||||
|
||||
|
||||
4. advanced_config_from_json
|
||||
============================
|
||||
|
||||
The build_oa_json.py library in ``gnpy/example-data/edfa_model/`` can be used to build the json file required for the amplifier advanced_model type_def:
|
||||
|
||||
Update an existing json file with all the 96ch txt files for a given amplifier type
|
||||
amplifier type 'OA_type1' is hard coded but can be modified and other types added
|
||||
returns an updated amplifier json file: output_json_file_name = 'edfa_config.json'
|
||||
amplifier file names
|
||||
|
||||
Convert a set of amplifier files + input json definiton file into a valid edfa_json_file:
|
||||
|
||||
nf_fit_coeff: NF 3rd order polynomial coefficients txt file
|
||||
|
||||
nf = f(dg) with dg = gain_operational - gain_max
|
||||
|
||||
nf_ripple: NF ripple excursion txt file
|
||||
|
||||
gain_ripple: gain ripple txt file
|
||||
|
||||
dgt: dynamic gain txt file
|
||||
|
||||
input json file in argument (defult = 'OA.json')
|
||||
|
||||
the json input file should have the following fields:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"nf_fit_coeff": "nf_filename.txt",
|
||||
"nf_ripple": "nf_ripple_filename.txt",
|
||||
"gain_ripple": "DFG_filename.txt",
|
||||
"dgt": "DGT_filename.txt"
|
||||
}
|
||||
178
docs/biblio.bib
178
docs/biblio.bib
@@ -874,7 +874,7 @@ month={Sept},}
|
||||
number = {7},
|
||||
journal = {Optics Express},
|
||||
urlyear = {2017-11-14},
|
||||
year = {2012-03-26},
|
||||
date = {2012-03-26},
|
||||
year = {2012},
|
||||
pages = {7777},
|
||||
author = {Bononi, A. and Serena, P. and Rossi, N. and Grellier, E. and Vacondio, F.}
|
||||
@@ -1114,7 +1114,7 @@ month={Sept},}
|
||||
number = {26},
|
||||
journal = {Optics Express},
|
||||
urlyear = {2017-11-16},
|
||||
year = {2013-12-30},
|
||||
date = {2013-12-30},
|
||||
year = {2013},
|
||||
pages = {32254},
|
||||
author = {Bononi, Alberto and Beucher, Ottmar and Serena, Paolo}
|
||||
@@ -1848,3 +1848,177 @@ month={Sept},}
|
||||
title = {Telecom Infra Project},
|
||||
url = {https://www.telecominfraproject.com},
|
||||
}
|
||||
|
||||
@ARTICLE{DAmicoJLT2022,
|
||||
author={D’Amico, Andrea and Correia, Bruno and London, Elliot and Virgillito,
|
||||
Emanuele and Borraccini, Giacomo and Napoli, Antonio and Curri, Vittorio},
|
||||
journal={Journal of Lightwave Technology},
|
||||
title={Scalable and Disaggregated GGN Approximation Applied to a C+L+S Optical Network},
|
||||
year={2022},
|
||||
volume={40},
|
||||
number={11},
|
||||
pages={3499-3511},
|
||||
doi={10.1109/JLT.2022.3162134}
|
||||
}
|
||||
|
||||
@inproceedings{grammel2018physical,
|
||||
title={Physical simulation environment of the telecommunications infrastructure project (TIP)},
|
||||
author={Grammel, Gert and Curri, Vittorio and Auge, Jean-Luc},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={M1D--3},
|
||||
year={2018},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{taylor2018towards,
|
||||
title={Towards a route planning tool for open optical networks in the telecom infrastructure project},
|
||||
author={Taylor, Brian D and Goldfarb, Gilad and Bandyopadhyay, Saumil and Curri, Vittorio and Schmidtke, Hans-Juergen},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={Tu3E--4},
|
||||
year={2018},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@article{filer2018multi,
|
||||
title={Multi-vendor experimental validation of an open source QoT estimator for optical networks},
|
||||
author={Filer, Mark and Cantono, Mattia and Ferrari, Alessio and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
journal={Journal of Lightwave Technology},
|
||||
volume={36},
|
||||
number={15},
|
||||
pages={3073--3082},
|
||||
year={2018},
|
||||
publisher={IEEE}
|
||||
}
|
||||
|
||||
@inproceedings{auge2019open,
|
||||
title={Open optical network planning demonstration},
|
||||
author={Auge, Jean-Luc and Grammel, Gert and Le Rouzic, Esther and Curri, Vittorio and Galimberti, Gabriele and Powell, James},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={M3Z--9},
|
||||
year={2019},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{kundrat2020physical,
|
||||
title={Physical-layer awareness: GNPy and ONOS for end-to-end circuits in disaggregated networks},
|
||||
author={Kundr{\'a}t, Jan and Campanella, Andrea and Le Rouzic, Esther and Ferrari, Alessio and Havli{\v{s}}, Ond{\v{r}}ej and Ha{\v{z}}linsk{\`y}, Michal and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
booktitle={2020 Optical Fiber Communications Conference and Exhibition (OFC)},
|
||||
pages={1--3},
|
||||
year={2020},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
@inproceedings{ferrari2020experimental,
|
||||
title={Experimental validation of an open source quality of transmission estimator for open optical networks},
|
||||
author={Ferrari, Alessio and Filer, Mark and Balasubramanian, Karthikeyan and Yin, Yawei and Le Rouzic, Esther and Kundr{\'a}t, Jan and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
booktitle={2020 Optical Fiber Communications Conference and Exhibition (OFC)},
|
||||
pages={1--3},
|
||||
year={2020},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
@article{ferrari2020gnpy,
|
||||
title={GNPy: an open source application for physical layer aware open optical networks},
|
||||
author={Ferrari, Alessio and Filer, Mark and Balasubramanian, Karthikeyan and Yin, Yawei and Le Rouzic, Esther and Kundr{\'a}t, Jan and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
journal={Journal of Optical Communications and Networking},
|
||||
volume={12},
|
||||
number={6},
|
||||
pages={C31--C40},
|
||||
year={2020},
|
||||
publisher={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{ferrari2020softwarized,
|
||||
title={Softwarized optical transport QoT in production optical network: a Brownfield validation},
|
||||
author={Ferrari, Alessio and Balasubramanian, Karthikeyan and Filer, Mark and Yin, Yawei and Le Rouzic, Esther and Kundr{\'a}t, Jan and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
booktitle={2020 European Conference on Optical Communications (ECOC)},
|
||||
pages={1--4},
|
||||
year={2020},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
@article{ferrari2021assessment,
|
||||
title={Assessment on the in-field lightpath QoT computation including connector loss uncertainties},
|
||||
author={Ferrari, Alessio and Balasubramanian, Karthikeyan and Filer, Mark and Yin, Yawei and Le Rouzic, Esther and Kundr{\'a}t, Jan and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
journal={Journal of Optical Communications and Networking},
|
||||
volume={13},
|
||||
number={2},
|
||||
pages={A156--A164},
|
||||
year={2021},
|
||||
publisher={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{kundrat2021gnpy,
|
||||
title={GNPy \& YANG: open APIs for end-to-end service provisioning in optical networks},
|
||||
author={Kundr{\'a}t, Jan and Le Rouzic, Esther and M{\aa}rtensson, Jonas and Campanella, Andrea and Havli{\v{s}}, Ond{\v{r}}ej and D’Amico, Andrea and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio and Vojt{\v{e}}ch, Josef},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={M1B--6},
|
||||
year={2021},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{d2021gnpy,
|
||||
title={GNPy experimental validation on flex-grid, flex-rate WDM optical transport scenarios},
|
||||
author={D’Amico, Andrea and London, Elliot and Le Guyader, Bertrand and Frank, Florian and Le Rouzic, Esther and Pincemin, Erwan and Brochier, Nicolas and Curri, Vittorio},
|
||||
booktitle={Optical fiber communication conference},
|
||||
pages={W1G--2},
|
||||
year={2021},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{virgillito2021testing,
|
||||
title={Testing TIP open source solutions in deployed optical networks},
|
||||
author={Virgillito, Emanuele and Braun, Ralf-Peter and Breuer, Dirk and Gladisch, Andreas and Curri, Vittorio and Grammel, Gert},
|
||||
booktitle={Optical Fiber Communication Conference},
|
||||
pages={F1C--3},
|
||||
year={2021},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@article{d2022experimental,
|
||||
title={Experimental validation of GNPy in a multi-vendor flex-grid flex-rate WDM optical transport scenario},
|
||||
author={D’Amico, Andrea and London, Elliot and Le Guyader, Bertrand and Frank, Florian and Le Rouzic, Esther and Pincemin, Erwan and Brochier, Nicolas and Curri, Vittorio},
|
||||
journal={Journal of Optical Communications and Networking},
|
||||
volume={14},
|
||||
number={3},
|
||||
pages={79--88},
|
||||
year={2022},
|
||||
publisher={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{mano2022accuracy,
|
||||
title={Accuracy of nonlinear interference estimation on launch power optimization in short-reach systems with field trial},
|
||||
author={Mano, Toru and D’Amico, Andrea and Virgillito, Emanuele and Borraccini, Giacomo and Huang, Yue-Kai and Kitamura, Kei and Anazawa, Kazuya and Masuda, Akira and Nishizawa, Hideki and Wang, Ting and others},
|
||||
booktitle={European Conference and Exhibition on Optical Communication},
|
||||
pages={We3B--1},
|
||||
year={2022},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{kundrat2022gnpy,
|
||||
title={GNPy: Lessons learned and future plans},
|
||||
author={Kundr{\'a}t, Jan and Le Rouzic, Esther and M{\aa}rtensson, Jonas and Melin, Stefan and D’Amico, Andrea and Grammel, Gert and Galimberti, Gabriele and Curri, Vittorio},
|
||||
booktitle={European Conference and Exhibition on Optical Communication},
|
||||
pages={We3B--6},
|
||||
year={2022},
|
||||
organization={Optica Publishing Group}
|
||||
}
|
||||
|
||||
@inproceedings{grammel2023open,
|
||||
title={Open Optical Networks: the good, the bad and the ugly},
|
||||
author={Grammel, Gert and Kundrat, Jan and Le Rouzic, Esther and Melin, Stefan and Curri, Vittorio and d'Amico, Andrea and Manzotti, Roberto},
|
||||
booktitle={49th European Conference on Optical Communications (ECOC 2023)},
|
||||
volume={2023},
|
||||
pages={1585--1588},
|
||||
year={2023},
|
||||
organization={IET}
|
||||
}
|
||||
|
||||
@inproceedings{d2024gnpy,
|
||||
title={GNPy Experimental Validation in a C+ L Multiband Optical Multiplex Section},
|
||||
author={D’Amico, Andrea and Gatto, Vittorio and Nespola, Antonino and Borraccini, Giacomo and Jiang, Yanchao and Poggiolini, Pierluigi and Le Rouzic, Esther and de Lerma, Arturo Mayoral L{\'o}pez and Grammel, Gert and Manzotti, Roberto and others},
|
||||
booktitle={2024 24th International Conference on Transparent Optical Networks (ICTON)},
|
||||
pages={1--4},
|
||||
year={2024},
|
||||
organization={IEEE}
|
||||
}
|
||||
|
||||
29
docs/calendar.html
Normal file
29
docs/calendar.html
Normal file
@@ -0,0 +1,29 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>Project Calendar</title>
|
||||
<style>
|
||||
body { font-family: system-ui, -apple-system, Segoe UI, Roboto, Helvetica, Arial, sans-serif; margin: 20px; }
|
||||
.container { max-width: 1000px; margin: 0 auto; }
|
||||
h1 { font-size: 1.8rem; margin-bottom: 1rem; }
|
||||
iframe { border: 0; width: 100%; height: 800px; }
|
||||
.note { color: #555; margin-top: 1rem; font-size: 0.9rem; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Project Calendar</h1>
|
||||
<p>This page embeds the public project calendar. It updates automatically when events change in Google Calendar.</p>
|
||||
<iframe
|
||||
src="https://calendar.google.com/calendar/embed?src=c_0895d13d880537c3e54db61ba95e9df167db19a49b96d41e42e2c6d842f30a6a%40group.calendar.google.com&ctz=Europe%2FMadrid"
|
||||
frameborder="0"
|
||||
scrolling="no"
|
||||
></iframe>
|
||||
<p class="note">Timezone: Europe/Madrid. If you prefer your local timezone, add <code>&ctz=Your%2FTimezone</code> to the URL.</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
||||
297
docs/cli_options.rst
Normal file
297
docs/cli_options.rst
Normal file
@@ -0,0 +1,297 @@
|
||||
.. _cli-options:
|
||||
|
||||
***********************************************************
|
||||
`gnpy-path-request` and `gnpy-transmission-example` scripts
|
||||
***********************************************************
|
||||
|
||||
Common options
|
||||
==============
|
||||
|
||||
**Option**: `--no-insert-edfas`
|
||||
-------------------------------
|
||||
|
||||
**Purpose**: Disables the automatic insertion of EDFAs after ROADMs and fibers, as well as the splitting
|
||||
of fibers during the auto-design process.
|
||||
|
||||
The `--no-insert-edfas` option is a command-line argument available in GNPy that allows users to control the
|
||||
automatic insertion of amplifiers during the network design process. This option provides flexibility for
|
||||
users who may want to manually manage amplifier placements or who have specific design requirements that
|
||||
do not necessitate automatic amplification.
|
||||
|
||||
To use the `--no-insert-edfas` option, simply include it in the command line when running your GNPy program. For example:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --no-insert-edfas
|
||||
|
||||
When the `--no-insert-edfas` option is specified:
|
||||
|
||||
1. **No Automatic Amplifiers**: The program will not automatically add EDFAs to the network topology after
|
||||
ROADMs or fiber elements. This means that if the network design requires amplification, users must ensure
|
||||
that amplifiers are manually defined in the network topology file. Users should be aware that disabling
|
||||
automatic amplifier insertion may lead to insufficient amplification in the network if not managed properly.
|
||||
It is essential to ensure that the network topology includes the necessary amplifiers to meet performance requirements.
|
||||
|
||||
2. **No Fiber Splitting**: The option also prevents the automatic splitting of fibers during the design process.
|
||||
This is particularly useful for users who want to maintain specific fiber lengths or configurations without
|
||||
the program altering them.
|
||||
|
||||
|
||||
**Option**: `--equipment`, `-e`
|
||||
-------------------------------
|
||||
|
||||
**Description**: Specifies the equipment library file.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --equipment <FILE.json>
|
||||
|
||||
**Default**: Uses the default equipment configuration in the example-data folder if not specified.
|
||||
|
||||
**Functionality**: This option allows users to load a specific equipment configuration that defines the characteristics of the network elements.
|
||||
|
||||
**Option**: `--extra-equipment` and `--extra-config`
|
||||
----------------------------------------------------
|
||||
|
||||
The `--extra-equipment` and `--extra-config` options allow users to extend the default equipment library and configuration
|
||||
settings used by the GNPy program. This feature is particularly useful for users who need to incorporate additional
|
||||
equipment types or specific configurations that are not included in the standard equipment library (such as third party pluggables).
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
--extra-equipment <file1.json> [<file2.json> ...]
|
||||
|
||||
**Parameters**:
|
||||
|
||||
- `<file1.json>`: Path to the first additional equipment file.
|
||||
- `<file2.json>`: Path to any subsequent additional equipment files (optional).
|
||||
|
||||
**Functionality**:
|
||||
|
||||
- The program will merge the equipment definitions from the specified files into the main equipment library.
|
||||
- If an equipment type defined in the additional files has the same name as one in the main library, the program
|
||||
will issue a warning about the duplicate entry and will include ony the last definition.
|
||||
- This allows for flexibility in defining equipment that may be specific to certain use cases or vendor-specific models.
|
||||
|
||||
**`--extra-config`**:
|
||||
|
||||
**Description**: This option allows users to specify additional configuration files that can override
|
||||
or extend the default configuration settings used by the program. This is useful for customizing simulation
|
||||
parameters or equipment settings. To set an amplifier with a specific such config, it must be defined in the
|
||||
library with the keyword "default_config_from_json" filled with the file name containing the config in the case of
|
||||
"variable_gain" amplifier or with the "advanced_config_from_json" for the "advanced_model" amplifier.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
--extra-config <file1.json> [<file2.json> ...]
|
||||
|
||||
**Parameters**:
|
||||
- `<file1.json>`: Path to the first additional configuration file.
|
||||
- `<file2.json>`: Path to any subsequent additional configuration files (optional).
|
||||
|
||||
**Functionality**:
|
||||
The program will load the configurations from the specified files and consider them instead of the
|
||||
default configurations for the amplifiers that use the "default_config_from_json" or "advanced_config_from_json" keywords.
|
||||
|
||||
To run the program with additional equipment and configuration files, you can use the following command:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example --equipment main_equipment.json \
|
||||
--extra-equipment additional_equipment1.json additional_equipment2.json \
|
||||
--extra-config additional_config1.json
|
||||
|
||||
|
||||
In this example:
|
||||
- `main_equipment.json` is the primary equipment file.
|
||||
- `additional_equipment1.json` and `additional_equipment2.json` are additional equipment files that will be merged into the main library.
|
||||
- `additional_config1.json` is an additional configuration file that will override the default settings for the amplifiers pointing to it.
|
||||
|
||||
|
||||
**Option**: `--save-network`
|
||||
----------------------------
|
||||
|
||||
**Description**: Saves the final network configuration to a specified JSON file.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
--save-network <FILE.json>
|
||||
|
||||
**Functionality**: This option allows users to save the network state after the simulation, which can be useful for future reference or analysis.
|
||||
|
||||
|
||||
**Option**: `--save-network-before-autodesign`
|
||||
----------------------------------------------
|
||||
|
||||
**Description**: Dumps the network into a JSON file prior to autodesign.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-path-request my_network.json my_services.json --save-network-before-autodesign <FILE.json>
|
||||
|
||||
**Functionality**: This option is useful for users who want to inspect the network configuration before any automatic design adjustments are made.
|
||||
|
||||
|
||||
**Option**: `--sim-params`
|
||||
--------------------------
|
||||
|
||||
**Description**: Path to the JSON file containing simulation parameters.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --sim-params <FILE.json>
|
||||
|
||||
**Functionality**: The `--sim-params` option is a command-line argument available in GNPy that allows users to specify a
|
||||
JSON file containing simulation parameters. This option is crucial for customizing the behavior of the simulation:
|
||||
the file ``sim_params.json`` contains the tuning parameters used within both the ``gnpy.science_utils.RamanSolver`` and
|
||||
the ``gnpy.science_utils.NliSolver`` for the evaluation of the Raman profile and the NLI generation, respectively.
|
||||
|
||||
The tuning of the parameters is detailed here: :ref:`json input sim-params<sim-params>`.
|
||||
|
||||
|
||||
`gnpy-transmission-example` options
|
||||
===================================
|
||||
|
||||
**Option**: `--show-channels`
|
||||
-----------------------------
|
||||
|
||||
**Description**: Displays the final per-channel OSNR and GSNR summary.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --show-channels
|
||||
|
||||
**Functionality**: This option provides a summary of the optical signal-to-noise ratio (OSNR)
|
||||
and generalized signal-to-noise ratio (GSNR) for each channel after the simulation.
|
||||
|
||||
|
||||
**Option**: `-pl`, `--plot`
|
||||
---------------------------
|
||||
|
||||
**Description**: Generates plots of the results.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json -pl
|
||||
|
||||
**Functionality**: This option allows users to visualize the results of the simulation through graphical plots.
|
||||
|
||||
|
||||
**Option**: `-l`, `--list-nodes`
|
||||
--------------------------------
|
||||
|
||||
**Description**: Lists all transceiver nodes in the network.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json -l
|
||||
|
||||
**Functionality**: This option provides a quick way to view all transceiver nodes present in the network topology.
|
||||
|
||||
**Option**: `-po`, `--power`
|
||||
----------------------------
|
||||
|
||||
**Description**: Specifies the reference channel power in span in dBm.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json -po <value>
|
||||
|
||||
**Functionality**: This option allows users to set the input power level for the reference channel used in the simulation.
|
||||
It replaces the value specified in the `SI` section of the equipment library (:ref:`power_dbm<spectral_info>`).
|
||||
|
||||
|
||||
**Option**: `--spectrum`
|
||||
------------------------
|
||||
|
||||
**Description**: Specifies a user-defined mixed rate spectrum JSON file for propagation.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-transmission-example my_network.json --spectrum <FILE.json>
|
||||
|
||||
**Functionality**: This option allows users to define a custom spectrum for the simulation, which can
|
||||
include varying channel rates and configurations. More details here: :ref:`mixed-rate<mixed-rate>`.
|
||||
|
||||
|
||||
Options for `path_requests_run`
|
||||
===============================
|
||||
|
||||
The `gnpy-path-request` script provides a simple path computation function that supports routing, transceiver mode selection, and spectrum assignment.
|
||||
|
||||
It supports include and disjoint constraints for the path computation, but does not provide any optimisation.
|
||||
It requires two mandatory arguments: network file and service file (see :ref:`XLS files<excel-service-sheet>` or :ref:`JSON files<legacy-json>`).
|
||||
|
||||
The `gnpy-path-request` computes:
|
||||
|
||||
- design network once and propagate the service requests on this design
|
||||
- computes performance of each request defined in the service file independently from each other, considering full load (based on the request settings),
|
||||
- assigns spectrum for each request according to the remaining spectrum, on a first arrived first served basis.
|
||||
Lack of spectrum leads to blocking, but performance estimation is still returned for information.
|
||||
|
||||
|
||||
**Option**: `-bi`, `--bidir`
|
||||
----------------------------
|
||||
|
||||
**Description**: Indicates that all demands are bidirectional.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-path-request my_network.json my_service.json -e my_equipment.json -bi
|
||||
|
||||
**Functionality**: This option allows users to specify that the performance of the service requests should be
|
||||
computed in both directions (source to destination and destination to source). This forces the 'bidirectional'
|
||||
attribute to true in the service file, possibly affecting feasibility if one direction is not feasible.
|
||||
|
||||
|
||||
**Option**: `-o`, `--output`
|
||||
----------------------------
|
||||
|
||||
**Description**: Stores computation results requests into a JSON or CSV file.
|
||||
|
||||
**Usage**:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-path-request my_network.json my_service.json -o <FILE.json|FILE.csv>
|
||||
|
||||
**Functionality**: This option allows users to save the results of the path requests into a specified output file
|
||||
for further analysis.
|
||||
|
||||
|
||||
**Option**: `--redesign-per-request`
|
||||
------------------------------------
|
||||
|
||||
**Description**: Redesigns the network for each request using the request as the reference channel
|
||||
(replaces the `SI` section of the equipment library with the request specifications).
|
||||
|
||||
**Usage**:
|
||||
.. code-block:: shell-session
|
||||
|
||||
gnpy-path-request my_network.json my_services.json --redesign-per-request
|
||||
|
||||
**Functionality**: This option enables checking different scenarios for design.
|
||||
271
docs/concepts.rst
Normal file
271
docs/concepts.rst
Normal file
@@ -0,0 +1,271 @@
|
||||
.. _concepts:
|
||||
|
||||
*****************************
|
||||
Simulating networks with GNPy
|
||||
*****************************
|
||||
|
||||
Running simulations with GNPy requires three pieces of information:
|
||||
|
||||
- the :ref:`network topology<concepts-topology>`, which describes how the network looks like, what are the fiber lengths, what amplifiers are used, etc.,
|
||||
- the :ref:`equipment library<concepts-equipment>`, which holds machine-readable datasheets of the equipment used in the network,
|
||||
- the :ref:`simulation options<concepts-simulation>` holding instructions about what to simulate, and under which conditions.
|
||||
|
||||
.. _concepts-topology:
|
||||
|
||||
Network Topology
|
||||
================
|
||||
|
||||
The *topology* acts as a "digital self" of the simulated network.
|
||||
When given a network topology, GNPy can either run a specific simulation as-is, or it can *optimize* the topology before performing the simulation.
|
||||
|
||||
A network topology for GNPy is often a generic, mesh network.
|
||||
This enables GNPy to take into consideration the current spectrum allocation as well as availability and resiliency considerations.
|
||||
When the time comes to run a particular *propagation* of a signal and its impairments are computed, though, a linear path through the network is used.
|
||||
For this purpose, the *path* through the network refers to an ordered, acyclic sequence of *nodes* that are processed.
|
||||
This path is directional, and all "GNPy elements" along the path match the unidirectional part of a real-world network equipment.
|
||||
|
||||
.. note::
|
||||
In practical terms, an amplifier in GNPy refers to an entity with a single input port and a single output port.
|
||||
A real-world inline EDFA enclosed in a single chassis will be therefore represented as two GNPy-level amplifiers.
|
||||
|
||||
The network topology contains not just the physical topology of the network, but also references to the :ref:`equipment library<concepts-equipment>` and a set of *operating parameters* for each entity.
|
||||
These parameters include the **fiber length** of each fiber, the connector **attenutation losses**, or an amplifier's specific **gain setting**.
|
||||
The topology is specified via :ref:`XLS files<excel>` or via :ref:`JSON<legacy-json>`.
|
||||
|
||||
.. _complete-vs-incomplete:
|
||||
|
||||
Fully Specified vs. Partially Designed Networks
|
||||
-----------------------------------------------
|
||||
|
||||
Let's consider a simple triangle topology with three :abbr:`PoPs (Points of Presence)` covering three cities:
|
||||
|
||||
.. graphviz::
|
||||
:layout: neato
|
||||
:align: center
|
||||
|
||||
graph "High-level topology with three PoPs" {
|
||||
A -- B
|
||||
B -- C
|
||||
C -- A
|
||||
}
|
||||
|
||||
In the real world, each city would probably host a ROADM and some transponders:
|
||||
|
||||
.. graphviz::
|
||||
:layout: neato
|
||||
:align: center
|
||||
|
||||
graph "Simplified topology with transponders" {
|
||||
"ROADM A" [pos="2,2!"]
|
||||
"ROADM B" [pos="4,2!"]
|
||||
"ROADM C" [pos="3,1!"]
|
||||
"Transponder A" [shape=box, pos="0,2!"]
|
||||
"Transponder B" [shape=box, pos="6,2!"]
|
||||
"Transponder C" [shape=box, pos="3,0!"]
|
||||
|
||||
"ROADM A" -- "ROADM B"
|
||||
"ROADM B" -- "ROADM C"
|
||||
"ROADM C" -- "ROADM A"
|
||||
|
||||
"Transponder A" -- "ROADM A"
|
||||
"Transponder B" -- "ROADM B"
|
||||
"Transponder C" -- "ROADM C"
|
||||
}
|
||||
|
||||
GNPy simulation works by propagating the optical signal over a sequence of elements, which means that one has to add some preamplifiers and boosters.
|
||||
The amplifiers are, by definition, unidirectional, so the graph becomes quite complex:
|
||||
|
||||
.. _topo-roadm-preamp-booster:
|
||||
|
||||
.. graphviz::
|
||||
:layout: neato
|
||||
:align: center
|
||||
|
||||
digraph "Preamps and boosters are explicitly modeled in GNPy" {
|
||||
"ROADM A" [pos="2,4!"]
|
||||
"ROADM B" [pos="6,4!"]
|
||||
"ROADM C" [pos="4,0!"]
|
||||
"Transponder A" [shape=box, pos="1,5!"]
|
||||
"Transponder B" [shape=box, pos="7,5!"]
|
||||
"Transponder C" [shape=box, pos="4,-1!"]
|
||||
|
||||
"Transponder A" -> "ROADM A"
|
||||
"Transponder B" -> "ROADM B"
|
||||
"Transponder C" -> "ROADM C"
|
||||
"ROADM A" -> "Transponder A"
|
||||
"ROADM B" -> "Transponder B"
|
||||
"ROADM C" -> "Transponder C"
|
||||
|
||||
"Booster A C" [shape=triangle, orientation=-150, fixedsize=true, width=0.5, height=0.5, pos="2.2,3.2!", color=red, label=""]
|
||||
"Preamp A C" [shape=triangle, orientation=0, fixedsize=true, width=0.5, height=0.5, pos="1.5,3.0!", color=red, label=""]
|
||||
"ROADM A" -> "Booster A C"
|
||||
"Preamp A C" -> "ROADM A"
|
||||
|
||||
"Booster A B" [shape=triangle, orientation=-90, fixedsize=true, width=0.5, height=0.5, pos="3,4.3!", color=red, fontcolor=red, labelloc=b, label="\N\n\n"]
|
||||
"Preamp A B" [shape=triangle, orientation=90, fixedsize=true, width=0.5, height=0.5, pos="3,3.6!", color=red, fontcolor=red, labelloc=t, label="\n \N"]
|
||||
"ROADM A" -> "Booster A B"
|
||||
"Preamp A B" -> "ROADM A"
|
||||
|
||||
"Booster C B" [shape=triangle, orientation=-30, fixedsize=true, width=0.5, height=0.5, pos="4.7,0.9!", color=red, label=""]
|
||||
"Preamp C B" [shape=triangle, orientation=120, fixedsize=true, width=0.5, height=0.5, pos="5.4,0.7!", color=red, label=""]
|
||||
"ROADM C" -> "Booster C B"
|
||||
"Preamp C B" -> "ROADM C"
|
||||
|
||||
"Booster C A" [shape=triangle, orientation=30, fixedsize=true, width=0.5, height=0.5, pos="2.6,0.7!", color=red, label=""]
|
||||
"Preamp C A" [shape=triangle, orientation=-30, fixedsize=true, width=0.5, height=0.5, pos="3.3,0.9!", color=red, label=""]
|
||||
"ROADM C" -> "Booster C A"
|
||||
"Preamp C A" -> "ROADM C"
|
||||
|
||||
"Booster B A" [shape=triangle, orientation=90, fixedsize=true, width=0.5, height=0.5, pos="5,3.6!", labelloc=t, color=red, fontcolor=red, label="\n\N "]
|
||||
"Preamp B A" [shape=triangle, orientation=-90, fixedsize=true, width=0.5, height=0.5, pos="5,4.3!", labelloc=b, color=red, fontcolor=red, label="\N\n\n"]
|
||||
"ROADM B" -> "Booster B A"
|
||||
"Preamp B A" -> "ROADM B"
|
||||
|
||||
"Booster B C" [shape=triangle, orientation=-180, fixedsize=true, width=0.5, height=0.5, pos="6.5,3.0!", color=red, label=""]
|
||||
"Preamp B C" [shape=triangle, orientation=-20, fixedsize=true, width=0.5, height=0.5, pos="5.8,3.2!", color=red, label=""]
|
||||
"ROADM B" -> "Booster B C"
|
||||
"Preamp B C" -> "ROADM B"
|
||||
|
||||
"Booster A C" -> "Preamp C A"
|
||||
"Booster A B" -> "Preamp B A"
|
||||
"Booster C A" -> "Preamp A C"
|
||||
"Booster C B" -> "Preamp B C"
|
||||
"Booster B C" -> "Preamp C B"
|
||||
"Booster B A" -> "Preamp A B"
|
||||
}
|
||||
|
||||
In many regions, the ROADMs are not placed physically close to each other, so the long-haul fiber links (:abbr:`OMS (Optical Multiplex Section)`) are split into individual spans (:abbr:`OTS (Optical Transport Section)`) by in-line amplifiers, resulting in an even more complicated topology graphs:
|
||||
|
||||
.. graphviz::
|
||||
:layout: neato
|
||||
:align: center
|
||||
|
||||
digraph "A subset of a real topology with inline amplifiers" {
|
||||
"ROADM A" [pos="2,4!"]
|
||||
"ROADM B" [pos="6,4!"]
|
||||
"ROADM C" [pos="4,-3!"]
|
||||
"Transponder A" [shape=box, pos="1,5!"]
|
||||
"Transponder B" [shape=box, pos="7,5!"]
|
||||
"Transponder C" [shape=box, pos="4,-4!"]
|
||||
|
||||
"Transponder A" -> "ROADM A"
|
||||
"Transponder B" -> "ROADM B"
|
||||
"Transponder C" -> "ROADM C"
|
||||
"ROADM A" -> "Transponder A"
|
||||
"ROADM B" -> "Transponder B"
|
||||
"ROADM C" -> "Transponder C"
|
||||
|
||||
"Booster A C" [shape=triangle, orientation=-166, fixedsize=true, width=0.5, height=0.5, pos="2.2,3.2!", label=""]
|
||||
"Preamp A C" [shape=triangle, orientation=0, fixedsize=true, width=0.5, height=0.5, pos="1.5,3.0!", label=""]
|
||||
"ROADM A" -> "Booster A C"
|
||||
"Preamp A C" -> "ROADM A"
|
||||
|
||||
"Booster A B" [shape=triangle, orientation=-90, fixedsize=true, width=0.5, height=0.5, pos="3,4.3!", label=""]
|
||||
"Preamp A B" [shape=triangle, orientation=90, fixedsize=true, width=0.5, height=0.5, pos="3,3.6!", label=""]
|
||||
"ROADM A" -> "Booster A B"
|
||||
"Preamp A B" -> "ROADM A"
|
||||
|
||||
"Booster C B" [shape=triangle, orientation=-30, fixedsize=true, width=0.5, height=0.5, pos="4.7,-2.1!", label=""]
|
||||
"Preamp C B" [shape=triangle, orientation=10, fixedsize=true, width=0.5, height=0.5, pos="5.4,-2.3!", label=""]
|
||||
"ROADM C" -> "Booster C B"
|
||||
"Preamp C B" -> "ROADM C"
|
||||
|
||||
"Booster C A" [shape=triangle, orientation=20, fixedsize=true, width=0.5, height=0.5, pos="2.6,-2.3!", label=""]
|
||||
"Preamp C A" [shape=triangle, orientation=-30, fixedsize=true, width=0.5, height=0.5, pos="3.3,-2.1!", label=""]
|
||||
"ROADM C" -> "Booster C A"
|
||||
"Preamp C A" -> "ROADM C"
|
||||
|
||||
"Booster B A" [shape=triangle, orientation=90, fixedsize=true, width=0.5, height=0.5, pos="5,3.6!", label=""]
|
||||
"Preamp B A" [shape=triangle, orientation=-90, fixedsize=true, width=0.5, height=0.5, pos="5,4.3!", label=""]
|
||||
"ROADM B" -> "Booster B A"
|
||||
"Preamp B A" -> "ROADM B"
|
||||
|
||||
"Booster B C" [shape=triangle, orientation=-180, fixedsize=true, width=0.5, height=0.5, pos="6.5,3.0!", label=""]
|
||||
"Preamp B C" [shape=triangle, orientation=-20, fixedsize=true, width=0.5, height=0.5, pos="5.8,3.2!", label=""]
|
||||
"ROADM B" -> "Booster B C"
|
||||
"Preamp B C" -> "ROADM B"
|
||||
|
||||
"Inline A C 1" [shape=triangle, orientation=-166, fixedsize=true, width=0.5, pos="2.4,2.2!", label=" \N", color=red, fontcolor=red]
|
||||
"Inline A C 2" [shape=triangle, orientation=-166, fixedsize=true, width=0.5, pos="2.6,1.2!", label=" \N", color=red, fontcolor=red]
|
||||
"Inline A C 3" [shape=triangle, orientation=-166, fixedsize=true, width=0.5, pos="2.8,0.2!", label=" \N", color=red, fontcolor=red]
|
||||
"Inline A C n" [shape=triangle, orientation=-166, fixedsize=true, width=0.5, pos="3.0,-1.1!", label=" \N", color=red, fontcolor=red]
|
||||
|
||||
"Booster A C" -> "Inline A C 1"
|
||||
"Inline A C 1" -> "Inline A C 2"
|
||||
"Inline A C 2" -> "Inline A C 3"
|
||||
"Inline A C 3" -> "Inline A C n" [style=dotted]
|
||||
"Inline A C n" -> "Preamp C A"
|
||||
"Booster A B" -> "Preamp B A" [style=dotted]
|
||||
"Booster C A" -> "Preamp A C" [style=dotted]
|
||||
"Booster C B" -> "Preamp B C" [style=dotted]
|
||||
"Booster B C" -> "Preamp C B" [style=dotted]
|
||||
"Booster B A" -> "Preamp A B" [style=dotted]
|
||||
}
|
||||
|
||||
In such networks, GNPy's autodesign features becomes very useful.
|
||||
It is possible to connect ROADMs via "tentative links" which will be replaced by a sequence of actual fibers and specific amplifiers.
|
||||
In other cases where the location of amplifier huts is already known, but the specific EDFA models have not yet been decided, one can put in amplifier placeholders and let GNPy assign the best amplifier.
|
||||
|
||||
.. _concepts-equipment:
|
||||
|
||||
The Equipment Library
|
||||
=====================
|
||||
|
||||
In order to produce an accurate simulation, GNPy needs to know the physical properties of each entity which affects the optical signal.
|
||||
Entries in the equipment library correspond to actual real-world, tangible entities.
|
||||
Unlike a typical :abbr:`NMS (Network Management System)`, GNPy considers not just the active :abbr:`NEs (Network Elements)` such as amplifiers and :abbr:`ROADMs (Reconfigurable Optical Add/Drop Multiplexers)`, but also the passive ones, such as the optical fiber.
|
||||
|
||||
As the signal propagates through the network, the largest source of optical impairments is the noise introduced from amplifiers.
|
||||
An accurate description of the :abbr:`EDFA (Erbium-Doped Fiber Amplifier)` and especially its noise characteristics is required.
|
||||
GNPy describes this property in terms of the **Noise Figure (NF)** of an amplifier model as a function of its operating point.
|
||||
|
||||
The amplifiers compensate power losses induced on the signal in the optical fiber.
|
||||
The linear losses, however, are just one phenomenon of a multitude of effects that affect the signals in a long fiber run.
|
||||
While a more detailed description is available :ref:`in the literature<physical-model>`, for the purpose of the equipment library, the description of the *optical fiber* comprises its **linear attenutation coefficient**, a set of parameters for the **Raman effect**, optical **dispersion**, etc.
|
||||
|
||||
Signals are introduced into the network via *transponders*.
|
||||
The set of parameters that are required describe the physical properties of each supported *mode* of the transponder, including its **symbol rate**, spectral **width**, etc.
|
||||
|
||||
In the junctions of the network, *ROADMs* are used for spectrum routing.
|
||||
GNPy currently does not take into consideration the spectrum filtering penalties of the :abbr:`WSSes (Wavelength Selective Switches)`, but the equipment library nonetheless contains a list of required parameters, such as the attenuation options, so that the network can be properly simulated.
|
||||
|
||||
.. _concepts-nf-model:
|
||||
|
||||
Amplifier Noise Figure Models
|
||||
-----------------------------
|
||||
|
||||
One of the key parameters of an amplifier is the method to use for computing the Noise Figure (NF).
|
||||
GNPy supports several different noise models with varying level of accuracy.
|
||||
When in doubt, contact your vendor's technical support and ask them to :ref:`contribute their equipment descriptions<extending-edfa>` to GNPy.
|
||||
|
||||
The most accurate noise models describe the resulting NF of an EDFA as a third-degree polynomial.
|
||||
GNPy understands polynomials as a NF-yielding function of the :ref:`gain difference from the optimal gain<ext-nf-model-polynomial-NF>`, or as a function of the input power resulting in an incremental OSNR as used in :ref:`OpenROADM inline amplifiers<ext-nf-model-polynomial-OSNR-OpenROADM>` and :ref:`OpenROADM booster/preamps in the ROADMs<ext-nf-model-noise-mask-OpenROADM>`.
|
||||
For scenarios where the vendor has not yet contributed an accurate EDFA NF description to GNPy, it is possible to approximate the characteristics via an operator-focused, min-max NF model.
|
||||
|
||||
.. _nf-model-min-max-NF:
|
||||
|
||||
Min-max NF
|
||||
^^^^^^^^^^
|
||||
|
||||
This is an operator-focused model where performance is defined by the *minimal* and *maximal NF*.
|
||||
These are especially suited to model a dual-coil EDFA with a VOA in between.
|
||||
In these amplifiers, the minimal NF is achieved when the EDFA operates at its maximal (and usually optimal, in terms of flatness) gain.
|
||||
The worst (maximal) NF applies when the EDFA operates at its minimal gain.
|
||||
|
||||
This model is suitable for use when the vendor has not provided a more accurate performance description of the EDFA.
|
||||
|
||||
Raman Approximation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
While GNPy is fully Raman-aware, under certain scenarios it is useful to be able to run a simulation without an accurate Raman description.
|
||||
For these purposes the :ref:`polynomial NF<ext-nf-model-polynomial-NF>` model with :math:`\text{a} = \text{b} = \text{c} = 0`, and :math:`\text{d} = NF` can be used.
|
||||
|
||||
.. _concepts-simulation:
|
||||
|
||||
Simulation
|
||||
==========
|
||||
|
||||
When the network model has been instantiated and the physical properties and operational settings of the actual physical devices are known, GNPy can start simulating how the signal propagate through the optical fiber.
|
||||
|
||||
This set of input parameters include options such as the *spectrum allocation*, i.e., the number of channels and their spacing.
|
||||
Various strategies for network optimization can be provided as well.
|
||||
82
docs/conf.py
82
docs/conf.py
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# GNpy documentation build configuration file, created by
|
||||
# gnpy documentation build configuration file, created by
|
||||
# sphinx-quickstart on Mon Dec 18 14:41:01 2017.
|
||||
#
|
||||
# This file is execfile()d with the current directory set to its
|
||||
@@ -19,6 +19,8 @@
|
||||
#
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
||||
sys.path.insert(0, os.path.abspath('../'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
@@ -31,8 +33,18 @@ sys.path.insert(0, os.path.abspath('../'))
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = ['sphinx.ext.autodoc',
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.githubpages','sphinxcontrib.bibtex']
|
||||
'sphinx.ext.mathjax',
|
||||
'sphinx.ext.githubpages',
|
||||
'sphinxcontrib.bibtex',
|
||||
'sphinx.ext.graphviz',
|
||||
'myst_parser',
|
||||
'sphinx_rtd_theme',
|
||||
]
|
||||
|
||||
myst_enable_extensions = [
|
||||
"deflist",
|
||||
"dollarmath",
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
@@ -47,25 +59,16 @@ source_suffix = ['.rst', '.md']
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = 'GNpy'
|
||||
copyright = '2017, Telecom InfraProject - OOPT PSE Group'
|
||||
author = 'Telecom InfraProject - OOPT PSE Group'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '0.1'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.1'
|
||||
project = 'gnpy'
|
||||
copyright = '2018 - 2021, Telecom Infra Project - OOPT PSE Group'
|
||||
author = 'Telecom Infra Project - OOPT PSE Group'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#
|
||||
# This is also used if you do content translation via gettext catalogs.
|
||||
# Usually you set "language" from the command line for these cases.
|
||||
language = None
|
||||
language = 'en'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
@@ -84,11 +87,24 @@ todo_include_todos = False
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
#
|
||||
on_rtd = os.environ.get('READTHEDOCS') == 'True'
|
||||
if on_rtd:
|
||||
html_theme = 'default'
|
||||
else:
|
||||
html_theme = 'alabaster'
|
||||
html_theme = "sphinx_rtd_theme"
|
||||
html_theme_options = {
|
||||
'logo': 'images/GNPy-logo.png',
|
||||
'logo_name': False,
|
||||
'prev_next_buttons_location': 'bottom',
|
||||
# Toc options
|
||||
'collapse_navigation': True,
|
||||
'sticky_navigation': True,
|
||||
'navigation_depth': 4,
|
||||
'includehidden': True,
|
||||
'titles_only': False
|
||||
}
|
||||
html_theme_options = {
|
||||
'navigation_depth': 4,
|
||||
}
|
||||
html_favicon = 'images/GNPy-logo.png'
|
||||
|
||||
html_logo = 'images/GNPy-logo.png'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
@@ -100,6 +116,9 @@ else:
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
html_css_files = [
|
||||
'custom.css', # Inclure votre fichier CSS personnalisé
|
||||
]
|
||||
|
||||
# Custom sidebar templates, must be a dictionary that maps document names
|
||||
# to template names.
|
||||
@@ -116,11 +135,12 @@ html_sidebars = {
|
||||
]
|
||||
}
|
||||
|
||||
html_secnum_depth = 4
|
||||
|
||||
# -- Options for HTMLHelp output ------------------------------------------
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'GNpydoc'
|
||||
htmlhelp_basename = 'gnpydoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
@@ -147,8 +167,8 @@ latex_elements = {
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
(master_doc, 'GNpy.tex', 'GNpy Documentation',
|
||||
'Telecom InfraProject - OOPT PSE Group', 'manual'),
|
||||
(master_doc, 'gnpy.tex', 'gnpy Documentation',
|
||||
'Telecom Infra Project - OOPT PSE Group', 'manual'),
|
||||
]
|
||||
|
||||
|
||||
@@ -157,7 +177,7 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
(master_doc, 'gnpy', 'GNpy Documentation',
|
||||
(master_doc, 'gnpy', 'gnpy Documentation',
|
||||
[author], 1)
|
||||
]
|
||||
|
||||
@@ -168,10 +188,18 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
(master_doc, 'GNpy', 'GNpy Documentation',
|
||||
author, 'GNpy', 'One line description of project.',
|
||||
(master_doc, 'gnpy', 'gnpy Documentation',
|
||||
author, 'gnpy', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
autodoc_default_options = {
|
||||
'members': True,
|
||||
'undoc-members': True,
|
||||
'private-members': True,
|
||||
'show-inheritance': True,
|
||||
}
|
||||
|
||||
graphviz_output_format = 'svg'
|
||||
|
||||
bibtex_bibfiles = ['biblio.bib']
|
||||
|
||||
269
docs/excel.rst
Normal file
269
docs/excel.rst
Normal file
@@ -0,0 +1,269 @@
|
||||
.. _excel:
|
||||
|
||||
*****************************
|
||||
Excel (XLS, XLSX) input files
|
||||
*****************************
|
||||
|
||||
``gnpy-transmission-example`` gives the possibility to use an excel input file instead of a json file. The program then will generate the corresponding json file for you.
|
||||
|
||||
The file named 'meshTopologyExampleV2.xls' is an example.
|
||||
|
||||
In order to work the excel file MUST contain at least 2 sheets:
|
||||
|
||||
- `Nodes`
|
||||
- `Links`
|
||||
|
||||
(In progress) The File MAY contain additional sheets:
|
||||
|
||||
- `Eqpt`
|
||||
- `Service`
|
||||
- `Roadms`
|
||||
|
||||
.. _excel-nodes-sheet:
|
||||
|
||||
`Nodes` sheet
|
||||
=============
|
||||
|
||||
`Nodes` sheet contains nine columns.
|
||||
Each line represents a 'node' (`ROADM` site or an in line amplifier site `ILA` or a `Fused`)::
|
||||
|
||||
City (Mandatory) ; State ; Country ; Region ; Latitude ; Longitude ; Type
|
||||
|
||||
- **City** is used for the name of a node of the graph. It accepts letters, numbers,underscore,dash, blank... (not exhaustive). The user may want to avoid commas for future CSV exports.
|
||||
|
||||
**City name MUST be unique**
|
||||
|
||||
- **Type** is not mandatory.
|
||||
|
||||
- If not filled, it will be interpreted as an 'ILA' site if node degree is 2 and as a ROADM otherwise.
|
||||
- If filled, it can take "ROADM", "FUSED" or "ILA" values. If another string is used, it will be considered as not filled. FUSED means that ingress and egress spans will be fused together.
|
||||
|
||||
- *State*, *Country*, *Region* are not mandatory.
|
||||
"Region" is a holdover from the CORONET topology reference file `CORONET_Global_Topology.xlsx <gnpy/example-data/CORONET_Global_Topology.xlsx>`_. CORONET separates its network into geographical regions (Europe, Asia, Continental US.) This information is not used by gnpy.
|
||||
|
||||
- *Longitude*, *Latitude* are not mandatory. If filled they should contain numbers.
|
||||
|
||||
- **Booster_restriction** and **Preamp_restriction** are not mandatory.
|
||||
If used, they must contain one or several amplifier type_variety names separated by ' | '. This information is used to restrict types of amplifiers used in a ROADM node during autodesign. If a ROADM booster or preamp is already specified in the Eqpt sheet , the field is ignored. The field is also ignored if the node is not a ROADM node.
|
||||
|
||||
**There MUST NOT be empty line(s) between two nodes lines**
|
||||
|
||||
|
||||
.. _excel-links-sheet:
|
||||
|
||||
Links sheet
|
||||
===========
|
||||
|
||||
Links sheet must contain sixteen columns::
|
||||
|
||||
<-- east cable from a to z --> <-- west from z to a -->
|
||||
NodeA ; NodeZ ; Distance km ; Fiber type ; Lineic att ; Con_in ; Con_out ; PMD ; Cable Id ; Distance km ; Fiber type ; Lineic att ; Con_in ; Con_out ; PMD ; Cable Id
|
||||
|
||||
|
||||
`Links` sheet MUST contain all links between nodes defined in Nodes sheet.
|
||||
Each line represents a 'bidir link' between two nodes. The two directions are represented on a single line with "east cable from a to z" fields and "west from z to a" fields. Values for 'a to z' may be different from values from 'z to a'.
|
||||
Since both direction of a bidir 'a-z' link are described on the same line (east and west), 'z to a' direction MUST NOT be repeated in a different line. If repeated, it will generate another parrallel bidir link between the same end nodes.
|
||||
|
||||
|
||||
Parameters for "east cable from a to z" and "west from z to a" are detailed in 2x7 columns. If not filled, "west from z to a" is copied from "east cable from a to z".
|
||||
|
||||
For example, a line filled with::
|
||||
|
||||
node6 ; node3 ; 80 ; SSMF ; 0.2 ; 0.5 ; 0.5 ; 0.1 ; cableB ; ; ; 0.21 ; 0.2 ; ; ;
|
||||
|
||||
will generate a unidir fiber span from node6 to node3 with::
|
||||
|
||||
[node6 node3 80 SSMF 0.2 0.5 0.5 0.1 cableB]
|
||||
|
||||
and a fiber span from node3 to node6::
|
||||
|
||||
[node6 node3 80 SSMF 0.21 0.2 0.5 0.1 cableB] attributes.
|
||||
|
||||
- **NodeA** and **NodeZ** are Mandatory.
|
||||
They are the two endpoints of the link. They MUST contain a node name from the **City** names listed in Nodes sheet.
|
||||
|
||||
- **Distance km** is not mandatory.
|
||||
It is the link length.
|
||||
|
||||
- If filled it MUST contain numbers. If empty it is replaced by a default "80" km value.
|
||||
- If value is below 150 km, it is considered as a single (bidirectional) fiber span.
|
||||
- If value is over 150 km or if the loss is greater than 28 dB, the autodesign program
|
||||
will automatically split the span with "_1","_2", ... trailing strings in names.
|
||||
Splitting threshold can be tuned in ["Span"]["max_length"] and ["Span"]["max_loss"] in
|
||||
equipment library.
|
||||
|
||||
- **Fiber type** is not mandatory.
|
||||
|
||||
If filled it must contain types listed in `eqpt_config.json <gnpy/example-data/eqpt_config.json>`_ in "Fiber" list "type_variety".
|
||||
If not filled it takes "SSMF" as default value.
|
||||
|
||||
- **Lineic att** is not mandatory.
|
||||
|
||||
It is the lineic attenuation expressed in dB/km.
|
||||
If filled it must contain positive numbers.
|
||||
If not filled it takes "0.2" dB/km value
|
||||
|
||||
- **Con_in**, **Con_out** are not mandatory.
|
||||
|
||||
They are the connector loss in dB at ingress and egress of the fiber spans.
|
||||
If filled they must contain positive numbers.
|
||||
If not filled they take "0.5" dB default value.
|
||||
|
||||
- **PMD** is not mandatory.
|
||||
|
||||
It is the PMD value of the link in ps.
|
||||
If filled they must contain positive numbers.
|
||||
If not filled, it takes "0.1" ps value.
|
||||
|
||||
- **Cable Id** is not mandatory.
|
||||
If filled they must contain strings with the same constraint as "City" names. Its value is used to differenate links having the same end points. In this case different Id should be used. Cable Ids are not meant to be unique in general.
|
||||
|
||||
|
||||
.. _excel-equipment-sheet:
|
||||
|
||||
Eqpt sheet
|
||||
==========
|
||||
|
||||
The equipment sheet (named "Eqpt") is optional.
|
||||
If provided, it specifies types of boosters and preamplifiers for all ROADM degrees of all ROADM nodes, and for all ILA nodes.
|
||||
|
||||
This sheet contains twelve columns::
|
||||
|
||||
<-- east cable from a to z --> <-- west from z to a -->
|
||||
Node A ; Node Z ; amp type ; att_in ; amp gain ; tilt ; att_out ; delta_p ; amp type ; att_in ; amp gain ; tilt ; att_out ; delta_p
|
||||
|
||||
If the sheet is present, it MUST have as many lines as there are egress directions of ROADMs defined in Links Sheet, and all ILAs.
|
||||
|
||||
For example, consider the following list of links (A, B and C being a ROADM and amp# ILAs):
|
||||
|
||||
::
|
||||
|
||||
A - amp1
|
||||
amp1 - amp2
|
||||
Amp2 - B
|
||||
A - amp3
|
||||
amp3 - C
|
||||
|
||||
then Eqpt sheet should contain:
|
||||
- one line for each ILAs: amp1, amp2, amp3
|
||||
- one line for each one-degree ROADM (B and C in this example)
|
||||
- two lines for each two-degree ROADM (just the ROADM A)
|
||||
|
||||
::
|
||||
|
||||
A - amp1
|
||||
amp1 - amp2
|
||||
Amp2 - B
|
||||
A - amp3
|
||||
amp3 - C
|
||||
B - amp2
|
||||
C - amp3
|
||||
|
||||
|
||||
In case you already have filled Nodes and Links sheets `create_eqpt_sheet.py <gnpy/example-data/create_eqpt_sheet.py>`_ can be used to automatically create a template for the mandatory entries of the list.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ cd $(gnpy-example-data)
|
||||
$ python create_eqpt_sheet.py meshTopologyExampleV2.xls
|
||||
|
||||
This generates a text file meshTopologyExampleV2_eqt_sheet.txt whose content can be directly copied into the Eqt sheet of the excel file. The user then can fill the values in the rest of the columns.
|
||||
|
||||
|
||||
- **Node A** is mandatory. It is the name of the node (as listed in Nodes sheet).
|
||||
If Node A is a 'ROADM' (Type attribute in sheet Node), its number of occurence must be equal to its degree.
|
||||
If Node A is an 'ILA' it should appear only once.
|
||||
|
||||
- **Node Z** is mandatory. It is the egress direction from the *Node A* site. Multiple Links between the same Node A and NodeZ is not supported.
|
||||
|
||||
- **amp type** is not mandatory.
|
||||
If filled it must contain types listed in the equipment librairie like in the example `eqpt_config.json <gnpy/example-data/eqpt_config.json>`_ in "Edfa" list "type_variety".
|
||||
If not filled it takes "std_medium_gain" as default value.
|
||||
If filled with fused, a fused element with 0.0 dB loss will be placed instead of an amplifier. This might be used to avoid booster amplifier on a ROADM direction.
|
||||
|
||||
- **amp_gain** is not mandatory. It is the value to be set on the amplifier (in dB).
|
||||
If not filled, it will be determined with design rules in the convert.py file.
|
||||
If filled, it must contain positive numbers.
|
||||
|
||||
- **att_in** and **att_out** are not mandatory. They are the value of the attenuator at input and output of amplifier (in dB).
|
||||
If filled they must contain positive numbers.
|
||||
|
||||
- **tilt**, in dB, is not mandatory. It is the target gain tilt over the full amplfifier bandwidth and is defined with regard to wavelength, i.e. negative tilt means lower gain
|
||||
for higher wavelengths (lower frequencies). If not filled, the default value is 0.
|
||||
|
||||
- **delta_p**, in dB, is not mandatory. If filled it is used to set the output target power per channel at the output of the amplifier, if power_mode is True. The output power is then set to power_dbm + delta_power.
|
||||
|
||||
|
||||
.. _excel-roadms-sheet:
|
||||
|
||||
Roadms sheet
|
||||
============
|
||||
|
||||
The ROADM sheet (named "Roadms") is optional.
|
||||
If provided, it can be used to specify:
|
||||
|
||||
- per channel power target on a specific ROADM degree (*per_degree_pch_out_db*),
|
||||
- ROADM type variety,
|
||||
- impairment ID (identifier) on a particular ROADM path (from degree - to degree).
|
||||
|
||||
This sheet contains six columns:
|
||||
|
||||
Node A ; Node Z ; per degree target power (dBm) ; type_variety ; from degrees ; from degree to degree impairment id
|
||||
|
||||
- **Node A** is mandatory. Name of the ROADM node (as listed in Nodes sheet).
|
||||
Must be a 'ROADM' (Type attribute in Node sheet), its number of occurence may be equal to its degree.
|
||||
|
||||
- **Node Z** is mandatory. Egress direction from the *Node A* ROADM site. Multiple Links between the same Node A
|
||||
and NodeZ is not supported.
|
||||
|
||||
- **per degree target power (dBm)** (optional).
|
||||
If filled it must contain a value in dBm corresponding to :ref:`per_degree_pch_out_db<roadm_json_instance>` on the **Node Z** degree.
|
||||
Defaults to equipment library value if not filled.
|
||||
|
||||
- **type_variety** (optional). Must be the same for all ROADM entries if filled,
|
||||
and defined in the :ref:`equipment library<roadm>`. Defaults to 'default' if not filled.
|
||||
|
||||
- **from degrees** (optional): List of Node names separated by ' | '. Names must be present in Node sheet.
|
||||
Together with Node Z, they define a list of internal path in ROADM for which the impairment ID applies
|
||||
|
||||
- **from degree to degree impairment id** (optional):List of impairment IDs separated by ' | '. Must be filled
|
||||
if **from degrees** is defined.
|
||||
The impairment ID must be defined in the equipment library and be of "express" type.
|
||||
|
||||
(in progress)
|
||||
|
||||
.. _excel-service-sheet:
|
||||
|
||||
Service sheet
|
||||
=============
|
||||
|
||||
Service sheet is optional. It lists the services for which path and feasibility must be computed with ``gnpy-path-request``.
|
||||
|
||||
Service sheet must contain 11 columns::
|
||||
|
||||
route id ; Source ; Destination ; TRX type ; Mode ; System: spacing ; System: input power (dBm) ; System: nb of channels ; routing: disjoint from ; routing: path ; routing: is loose?
|
||||
|
||||
- **route id** is mandatory. It must be unique. It is the identifier of the request. It can be an integer or a string (do not use blank or dash or coma)
|
||||
|
||||
- **Source** is mandatory. It is the name of the source node (as listed in Nodes sheet). Source MUST be a ROADM node. (TODO: relax this and accept trx entries)
|
||||
|
||||
- **Destination** is mandatory. It is the name of the destination node (as listed in Nodes sheet). Source MUST be a ROADM node. (TODO: relax this and accept trx entries)
|
||||
|
||||
- **TRX type** is mandatory. It is the variety type of the transceiver to be used for the propagation simulation. These modes MUST be defined in the equipment library. The format of the mode is used as the name of the mode. (TODO: maybe add another mode id on Transceiver library ?). In particular the mode selection defines the channel baudrate to be used for the propagation simulation.
|
||||
|
||||
- **mode** is optional. If not specified, the program will search for the mode of the defined transponder with the highest baudrate fitting within the spacing value.
|
||||
|
||||
- **System: spacing** is mandatory. Spacing is the channel spacing defined in GHz difined for the feasibility propagation simulation, assuming system full load.
|
||||
|
||||
- **System: input power (dBm) ; System: nb of channels** are optional input defining the system parameters for the propagation simulation.
|
||||
|
||||
- input power is the channel optical input power in dBm
|
||||
- nb of channels is the number of channels to be used for the simulation.
|
||||
|
||||
- **routing: disjoint from ; routing: path ; routing: is loose?** are optional.
|
||||
|
||||
- disjoint from: identifies the requests from which this request must be disjoint. If filled it must contain request ids separated by ' | '
|
||||
- path: is the set of ROADM nodes that must be used by the path. It must contain the list of ROADM names that the path must cross. TODO : only ROADM nodes are accepted in this release. Relax this with any type of nodes. If filled it must contain ROADM ids separated by ' | '. Exact names are required.
|
||||
- is loose? 'no' value means that the list of nodes should be strictly followed, while any other value means that the constraint may be relaxed if the node is not reachable.
|
||||
|
||||
- **path bandwidth** is mandatory. It is the amount of capacity required between source and destination in Gbit/s. Value should be positive (non zero). It is used to compute the amount of required spectrum for the service.
|
||||
173
docs/extending.rst
Normal file
173
docs/extending.rst
Normal file
@@ -0,0 +1,173 @@
|
||||
.. _extending:
|
||||
|
||||
****************************************
|
||||
Extending GNPy with vendor-specific data
|
||||
****************************************
|
||||
|
||||
GNPy ships with an :ref:`equipment library<concepts-equipment>` containing machine-readable datasheets of networking equipment.
|
||||
Vendors who are willing to contribute descriptions of their supported products are encouraged to `submit a patch <https://review.gerrithub.io/Documentation/intro-gerrit-walkthrough-github.html>`__ -- or just :ref:`get in touch with us directly<contributing>`.
|
||||
|
||||
This chapter discusses option for modeling performance of :ref:`EDFA amplifiers<extending-edfa>`, :ref:`Raman amplifiers<extending-raman>`, :ref:`transponders<extending-transponder>` and :ref:`ROADMs<extending-roadm>`.
|
||||
|
||||
.. _extending-edfa:
|
||||
|
||||
EDFAs
|
||||
=====
|
||||
|
||||
An accurate description of the :abbr:`EDFA (Erbium-Doped Fiber Amplifier)` and especially its noise characteristics is required.
|
||||
GNPy describes this property in terms of the **Noise Figure (NF)** of an amplifier model as a function of its operating point.
|
||||
GNPy supports several different :ref:`noise models<concepts-nf-model>`, and vendors are encouraged to pick one which describes performance of their equipment most accurately.
|
||||
|
||||
.. _ext-nf-model-polynomial-NF:
|
||||
|
||||
Polynomial NF
|
||||
-------------
|
||||
|
||||
This model computes the NF as a function of the difference between the optimal gain and the current gain.
|
||||
The NF is expressed as a third-degree polynomial:
|
||||
|
||||
.. math::
|
||||
|
||||
f(x) &= \text{a}x^3 + \text{b}x^2 + \text{c}x + \text{d}
|
||||
|
||||
\text{NF} &= f(G - G_\text{max})
|
||||
|
||||
This model can be also used for fixed-gain fixed-NF amplifiers.
|
||||
In that case, use:
|
||||
|
||||
.. math::
|
||||
|
||||
a = b = c &= 0
|
||||
|
||||
d &= \text{NF}
|
||||
|
||||
.. _ext-nf-model-polynomial-OSNR-OpenROADM:
|
||||
|
||||
Polynomial OSNR (OpenROADM-style for inline amplifier)
|
||||
------------------------------------------------------
|
||||
|
||||
This model is useful for amplifiers compliant to the OpenROADM specification for ILA (an in-line amplifier).
|
||||
The amplifier performance is evaluated via its incremental OSNR, which is a function of the input power.
|
||||
|
||||
.. math::
|
||||
|
||||
\text{OSNR}_\text{inc}(P_\text{in}) = \text{a}P_\text{in}^3 + \text{b}P_\text{in}^2 + \text{c}P_\text{in} + \text{d}
|
||||
|
||||
.. _ext-nf-model-noise-mask-OpenROADM:
|
||||
|
||||
Noise mask (OpenROADM-style for combined preamp and booster)
|
||||
------------------------------------------------------------
|
||||
|
||||
Unlike GNPy which simluates the preamplifier and the booster separately as two amplifiers for best accuracy, the OpenROADM specification mandates a certain performance level for a combination of these two amplifiers.
|
||||
For the express path, the effective noise mask comprises the preamplifier and the booster.
|
||||
When terminating a channel, the same effective noise mask is mandated for a combination of the preamplifier and the drop stage.
|
||||
|
||||
GNPy emulates this specification via two special NF models:
|
||||
|
||||
- The ``openroadm_preamp`` NF model for preamplifiers.
|
||||
This NF model provides all of the linear impairments to the signal, including those which are incured by the booster in a real network.
|
||||
- The ``openroadm_booster`` NF model is a special "zero noise" faux amplifier in place of the booster.
|
||||
|
||||
.. _ext-nf-model-min-max-NF:
|
||||
|
||||
Min-max NF
|
||||
----------
|
||||
|
||||
When the vendor prefers not to share the amplifier description in full detail, GNPy also supports describing the NF characteristics via the *minimal* and *maximal NF*.
|
||||
This approximates a more accurate polynomial description reasonably well for some models of a dual-coil EDFA with a VOA in between.
|
||||
In these amplifiers, the minimal NF is achieved when the EDFA operates at its maximal (and usually optimal, in terms of flatness) gain.
|
||||
The worst (maximal) NF applies when the EDFA operates at the minimal gain.
|
||||
|
||||
.. _ext-nf-model-dual-stage-amplifier:
|
||||
|
||||
Dual-stage
|
||||
----------
|
||||
|
||||
Dual-stage amplifier combines two distinct amplifiers.
|
||||
Vendors which provide an accurate description of their preamp and booster stages separately can use the dual-stage model for an aggregate description of the whole amplifier.
|
||||
|
||||
.. _ext-nf-model-advanced:
|
||||
|
||||
Advanced Specification
|
||||
----------------------
|
||||
|
||||
The amplifier performance can be further described in terms of gain ripple, NF ripple, and the dynamic gain tilt.
|
||||
When provided, the amplifier characteristic is fine-tuned as a function of carrier frequency. Note that in this advanced
|
||||
specification tilt is defined vs frequency while tilt_target specified in EDFA instances is defined vs wavelength.
|
||||
|
||||
.. _extending-raman:
|
||||
|
||||
Raman Amplifiers
|
||||
================
|
||||
|
||||
An accurate simulation of Raman amplification requires knowledge of:
|
||||
|
||||
* the *power* and *wavelength* of all Raman pumping lasers,
|
||||
* the *direction*, whether it is co-propagating or counter-propagating,
|
||||
* the Raman efficiency of the fiber,
|
||||
* the fiber temperature.
|
||||
|
||||
Under certain scenarios it is useful to be able to run a simulation without an accurate Raman description.
|
||||
For these purposes, it is possible to approximate a Raman amplifier via a fixed-gain EDFA with the :ref:`polynomial NF<ext-nf-model-polynomial-NF>` model using :math:`\text{a} = \text{b} = \text{c} = 0`, and a desired effective :math:`\text{d} = NF`.
|
||||
This is also useful to quickly approximate a hybrid EDFA+Raman amplifier.
|
||||
|
||||
.. _extending-transponder:
|
||||
|
||||
Transponders
|
||||
============
|
||||
|
||||
Since transponders are usually capable of operating in a variety of modes, these are described separately.
|
||||
A *mode* usually refers to a particular performance point that is defined by a combination of the symbol rate, modulation format, and :abbr:`FEC (Forward Error Correction)`.
|
||||
|
||||
The following data are required for each mode:
|
||||
|
||||
``bit_rate``
|
||||
Data bit rate, in :math:`\text{bits}\times s^{-1}`.
|
||||
``baud_rate``
|
||||
Symbol modulation rate, in :math:`\text{baud}`.
|
||||
``OSNR``
|
||||
Minimal required OSNR for the receiver. In :math:`\text{dB}`
|
||||
``tx-osnr``
|
||||
Initial OSNR at the transmitter's output. In :math:`\text{dB}`
|
||||
``min-spacing``
|
||||
Minimal grid spacing, i.e., an effective channel spectral bandwidth.
|
||||
In :math:`\text{Hz}`.
|
||||
``roll-off``
|
||||
Roll-off parameter (:math:`\beta`) of the TX pulse shaping filter.
|
||||
This assumes a raised-cosine filter.
|
||||
``rx-power-min`` and ``rx-power-max``
|
||||
(work in progress) The allowed range of power at the receiver.
|
||||
In :math:`\text{dBm}`.
|
||||
``penalties``
|
||||
Impairments such as Chromatic Dispersion (CD), Polarization Mode Dispersion (PMD), and Polarization Dispersion Loss (PDL)
|
||||
result in penalties at the receiver. The receiver's ability to handle these impairments can be defined for each mode as
|
||||
a list of {impairment: in defined units, 'penalty_value' in dB} (see `transceiver section here <json.rst#_transceiver>`).
|
||||
Maximum allowed CD, maximum allowed PMD, and maximum allowed PDL should be listed there with corresponding penalties.
|
||||
Impairments experienced during propagation are linearly interpolated between given points to obtain the corresponding penalty.
|
||||
The accumulated penalties are subtracted from the path GSNR before comparing with the minimum required OSNR.
|
||||
Impairments: PMD in :math:`\text{ps}`, CD in :math:`\text{ps/nm}`, PDL in :math:`\text{dB}`, penalty_value in :math:`\text{dB}`
|
||||
|
||||
|
||||
GNPy does not directly track the FEC performance, so the type of chosen FEC is likely indicated in the *name* of the selected transponder mode alone.
|
||||
|
||||
.. _extending-roadm:
|
||||
|
||||
ROADMs
|
||||
======
|
||||
|
||||
In a :abbr:`ROADM (Reconfigurable Add/Drop Multiplexer)`, GNPy simulates the impairments of the preamplifiers and boosters of line degrees :ref:`separately<topo-roadm-preamp-booster>`.
|
||||
The set of parameters for each ROADM model therefore includes:
|
||||
|
||||
``add-drop-osnr``
|
||||
OSNR penalty introduced by the Add and Drop stages of this ROADM type.
|
||||
``target-channel-out-power``
|
||||
Per-channel target TX power towards the egress amplifier.
|
||||
Within GNPy, a ROADM is expected to attenuate any signal that enters the ROADM node to this level.
|
||||
This can be overridden on a per-link in the network topology.
|
||||
Targets can be set using power or power spectral density (see `roadm section here <json.rst#__roadm>`)
|
||||
``pmd``
|
||||
Polarization mode dispersion (PMD) penalty of the express path.
|
||||
In :math:`\text{ps}`.
|
||||
|
||||
Provisions are in place to define the list of all allowed booster and preamplifier types.
|
||||
This is useful for specifying constraints on what amplifier modules fit into ROADM chassis, and when using fully disaggregated ROADM topologies as well.
|
||||
@@ -1,124 +0,0 @@
|
||||
The QoT estimation in the PSE framework of TIP-OOPT
|
||||
=======================================================
|
||||
|
||||
QoT-E including ASE noise and NLI accumulation
|
||||
----------------------------------------------
|
||||
|
||||
The operations of PSE simulative framework are based on the capability to estimate the QoT of one
|
||||
or more channels operating lightpaths over a given network route. For
|
||||
backbone transport networks, we can suppose that transceivers are
|
||||
operating polarization-division-multiplexed multilevel modulation
|
||||
formats with DSP-based coherent receivers, including equalization. For
|
||||
the optical links, we focus on state-of-the-art amplified and
|
||||
uncompensated fiber links, connecting network nodes including ROADMs,
|
||||
where add and drop operations on data traffic are performed. In such a
|
||||
transmission scenario, it is well accepted
|
||||
:cite:`vacondio_nonlinear_2012,bononi_modeling_2012,carena_modeling_2012,mecozzi_nonlinear_2012,secondini_analytical_2012,johannisson_perturbation_2013,dar_properties_2013,serena_alternative_2013,secondini_achievable_2013,poggiolini_gn-model_2014,dar_accumulation_2014,poggiolini_analytical_2011,savory_approximations_2013,bononi_single-_2013,johannisson_modeling_2014`
|
||||
to assume that transmission performances are limited by the amplified
|
||||
spontaneous emission (ASE) noise generated by optical amplifiers and and
|
||||
by nonlinear propagation effects: accumulation of a Gaussian disturbance
|
||||
defined as nonlinear interference (NLI) and generation of phase noise.
|
||||
State-of-the-art DSP in commercial transceivers are typically able to
|
||||
compensate for most of the phase noise through carrier-phase estimator
|
||||
(CPE) algorithms, for modulation formats with cardinality up to 16, per
|
||||
polarization state
|
||||
:cite:`poggiolini_recent_2017,schmidt_experimental_2015,fehenberger_experimental_2016`.
|
||||
So, for backbone networks covering medium-to-wide geographical areas, we
|
||||
can suppose that propagation is limited by the accumulation of two
|
||||
Gaussian disturbances: the ASE noise and the NLI. Additional impairments
|
||||
such as filtering effects introduced by ROADMs can be considered as
|
||||
additional equivalent power penalties depending on the ratio between the
|
||||
channel bandwidth and the ROADMs filters and the number of traversed
|
||||
ROADMs (hops) of the route under analysis. Modeling the two major
|
||||
sources of impairments as Gaussian disturbances, and being the receivers
|
||||
*coherent*, the unique QoT parameter determining the bit error rate
|
||||
(BER) for the considered transmission scenario is the generalized
|
||||
signal-to-noise ratio (SNR) defined as
|
||||
|
||||
.. math::
|
||||
|
||||
{\text{SNR}}= L_F \frac{P_{\text{ch}}}{P_{\text{ASE}}+P_{\text{NLI}}} = L_F \left(\frac{1}{{\text{SNR}}_{\text{LIN}}}+\frac{1}{{\text{SNR}}_{\text{NL}}}\right)^{-1}
|
||||
|
||||
|
||||
where :math:`P_{\text{ch}}` is the channel power,
|
||||
:math:`P_{\text{ASE}}` and :math:`P_{\text{NLI}}` are the power levels of the disturbances
|
||||
in the channel bandwidth for ASE noise and NLI, respectively.
|
||||
:math:`L_F` is a parameter assuming values smaller or equal than one
|
||||
that summarizes the equivalent power penalty loss such as
|
||||
filtering effects. Note that for state-of-the art equipment, filtering
|
||||
effects can be typically neglected over routes with few hops
|
||||
:cite:`rahman_mitigation_2014,foggi_overcoming_2015`.
|
||||
|
||||
|
||||
To properly estimate :math:`P_{\text{ch}}` and :math:`P_{\text{ASE}}`
|
||||
the transmitted power at the beginning of the considered route must be
|
||||
known, and losses and amplifiers gain and noise figure, including their
|
||||
variation with frequency, must be characterized. So, the evaluation of
|
||||
:math:`{\text{SNR}}_{\text{LIN}}` *just* requires an accurate
|
||||
knowledge of equipment, which is not a trivial aspect, but it is not
|
||||
related to physical-model issues. For the evaluation of the NLI, several
|
||||
models have been proposed and validated in the technical literature
|
||||
:cite:`vacondio_nonlinear_2012,bononi_modeling_2012,carena_modeling_2012,mecozzi_nonlinear_2012,secondini_analytical_2012,johannisson_perturbation_2013,dar_properties_2013,serena_alternative_2013,secondini_achievable_2013,poggiolini_gn-model_2014,dar_accumulation_2014,poggiolini_analytical_2011,savory_approximations_2013,bononi_single-_2013,johannisson_modeling_2014`.
|
||||
The decision about which model to test within the PSE activities was
|
||||
driven by requirements of the entire PSE framework:
|
||||
|
||||
i. the model must be *local*, i.e., related individually to each network element (i.e. fiber span) generating NLI, independently of preceding and subsequent elements; and
|
||||
ii. the related computational time must be compatible with interactive operations.
|
||||
|
||||
So, the choice fell on the Gaussian Noise
|
||||
(GN) model with incoherent accumulation of NLI over fiber spans
|
||||
:cite:`poggiolini_gn-model_2014`. We implemented both the
|
||||
exact GN-model evaluation of NLI based on a double integral (Eq. (11) of
|
||||
:cite:`poggiolini_gn-model_2014`) and its analytical
|
||||
approximation (Eq. (120-121) of
|
||||
:cite:`poggiolini_analytical_2011`). We performed several
|
||||
validation analyses comparing results of the two implementations with
|
||||
split-step simulations over wide bandwidths
|
||||
:cite:`pilori_ffss_2017`, and results clearly showed that
|
||||
for fiber types with chromatic dispersion roughly larger than 4
|
||||
ps/nm/km, the analytical approximation ensures an excellent accuracy
|
||||
with a computational time compatible with real-time operations.
|
||||
|
||||
|
||||
|
||||
The Gaussian Noise Model to evaluate the NLI
|
||||
--------------------------------------------
|
||||
As previously stated, fiber propagation of multilevel modulation formats relying on the polarization-division-multiplexing
|
||||
generates impairments that can be summarized as a disturbance called nonlinear interference (NLI),
|
||||
when exploiting a DSP-based coherent receiver, as in all state-of-the-art equipment.
|
||||
From a practical point of view, the NLI can be modeled as an additive
|
||||
Gaussian random process added by each fiber span, and whose strength depends on the cube of the input power spectral density and
|
||||
on the fiber-span parameters.
|
||||
|
||||
Since the introduction in the market in 2007 of the first transponder based on such a transmission technique, the scientific
|
||||
community has intensively worked to define the propagation behavior of such a trasnmission technique.
|
||||
First, the role of in-line chromatic dispersion compensation has been investigated, deducing that besides being
|
||||
not essential, it is indeed detrimental for performances :cite:`curri_dispersion_2008`.
|
||||
Then, it has been observed that the fiber propagation impairments are practically summarized by the sole NLI, being all the other
|
||||
phenomena compensated for by the blind equalizer implemented in the receiver DSP :cite:`carena_statistical_2010`.
|
||||
Once these assessments have been accepted by the community, several prestigious research groups have started to work
|
||||
on deriving analytical models able to estimating the NLI accumulation, and consequentially the generalized SNR that sets the BER,
|
||||
according to the transponder BER vs. SNR performance.
|
||||
Many models delivering different levels of accuracy have been developed and validated. As previously clarified, for the purposes
|
||||
of the PSE framework, the GN-model with incoherent accumulation of NLI over fiber spans has been selected as adequate.
|
||||
The reason for such a choice is first such a model being a "local" model, so related to each fiber spans, independently of
|
||||
the preceding and succeeding network elements. The other model characteristic driving the choice is
|
||||
the availability of a closed form for the model, so permitting a real-time evaluation, as required by the PSE framework.
|
||||
For a detailed derivation of the model, please refer to :cite:`poggiolini_analytical_2011`, while a qualitative description
|
||||
can be summarized as in the following.
|
||||
The GN-model assumes that the channel comb propagating in the fiber is well approximated by unpolarized spectrally shaped
|
||||
Gaussian noise. In such a scenario, supposing to rely - as in state-of-the-art equipment - on a receiver entirely compensating for linear propagation effects, propagation in the fiber only excites the four-wave mixing (FWM) process among the continuity of
|
||||
the tones occupying the bandwidth. Such a FWM generates an unpolarized complex Gaussian disturbance in each spectral slot
|
||||
that can be easily evaluated extending the FWM theory from a set of discrete tones - the standard FWM theory introduced back in the 90s by Inoue :cite:`Innoue-FWM`- to a continuity of tones, possibly spectrally shaped.
|
||||
Signals propagating in the fiber are not equivalent to Gaussian noise, but thanks to the absence of in-line compensation for choromatic dispersion,
|
||||
the become so, over short distances.
|
||||
So, the Gaussian noise model with incoherent accumulation of NLI has estensively proved to be a quick yet accurate and conservative tool
|
||||
to estimate propagation impairments of fiber propagation.
|
||||
Note that the GN-model has not been derived with the aim of an *exact* performance estimation, but to pursue a conservative performance prediction. So, considering these characteristics, and the fact that the NLI is always a secondary effect with respect to the ASE noise accumulation, and - most importantly - that typically linear propagation parameters (losses, gains and noise figures) are known within
|
||||
a variation range, a QoT estimator based on the GN model is adequate to deliver performance predictions in terms of a reasonable SNR range, rather than an exact value.
|
||||
As final remark, it must be clarified that the GN-model is adequate to be used when relying on a relatively narrow bandwidth up to few THz. When exceeding such a bandwidth occupation, the GN-model must be generalized introducing the interaction with the Stimulated
|
||||
Raman Scattering in order to give a proper estimation for all channels :cite:`cantono2018modeling`.
|
||||
This will be the main upgrade required within the PSE framework.
|
||||
|
||||
|
||||
.. bibliography:: biblio.bib
|
||||
13
docs/gnpy-api-core.rst
Normal file
13
docs/gnpy-api-core.rst
Normal file
@@ -0,0 +1,13 @@
|
||||
``gnpy.core``
|
||||
-------------
|
||||
|
||||
.. automodule:: gnpy.core
|
||||
.. automodule:: gnpy.core.ansi_escapes
|
||||
.. automodule:: gnpy.core.elements
|
||||
.. automodule:: gnpy.core.equipment
|
||||
.. automodule:: gnpy.core.exceptions
|
||||
.. automodule:: gnpy.core.info
|
||||
.. automodule:: gnpy.core.network
|
||||
.. automodule:: gnpy.core.parameters
|
||||
.. automodule:: gnpy.core.science_utils
|
||||
.. automodule:: gnpy.core.utils
|
||||
10
docs/gnpy-api-tools.rst
Normal file
10
docs/gnpy-api-tools.rst
Normal file
@@ -0,0 +1,10 @@
|
||||
``gnpy.tools``
|
||||
--------------
|
||||
|
||||
.. automodule:: gnpy.tools
|
||||
.. automodule:: gnpy.tools.cli_examples
|
||||
.. automodule:: gnpy.tools.convert
|
||||
.. automodule:: gnpy.tools.json_io
|
||||
.. automodule:: gnpy.tools.plots
|
||||
.. automodule:: gnpy.tools.service_sheet
|
||||
.. automodule:: gnpy.tools.worker_utils
|
||||
6
docs/gnpy-api-topology.rst
Normal file
6
docs/gnpy-api-topology.rst
Normal file
@@ -0,0 +1,6 @@
|
||||
``gnpy.topology``
|
||||
-----------------
|
||||
|
||||
.. automodule:: gnpy.topology
|
||||
.. automodule:: gnpy.topology.request
|
||||
.. automodule:: gnpy.topology.spectrum_assignment
|
||||
14
docs/gnpy-api.rst
Normal file
14
docs/gnpy-api.rst
Normal file
@@ -0,0 +1,14 @@
|
||||
***************************
|
||||
API Reference Documentation
|
||||
***************************
|
||||
|
||||
GNPy package
|
||||
============
|
||||
|
||||
.. automodule:: gnpy
|
||||
|
||||
.. toctree::
|
||||
|
||||
gnpy-api-core
|
||||
gnpy-api-topology
|
||||
gnpy-api-tools
|
||||
BIN
docs/images/2022-04-12-gnpy-app.png
Normal file
BIN
docs/images/2022-04-12-gnpy-app.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 288 KiB |
BIN
docs/images/GNPy-banner.png
Normal file
BIN
docs/images/GNPy-banner.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 518 KiB |
BIN
docs/images/GNPy-logo.png
Normal file
BIN
docs/images/GNPy-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 20 KiB |
1
docs/images/gnpy-transmission-example.svg
Normal file
1
docs/images/gnpy-transmission-example.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 478 KiB |
@@ -1,70 +1,36 @@
|
||||
.. GNpy documentation master file, created by
|
||||
sphinx-quickstart on Mon Dec 18 14:41:01 2017.
|
||||
You can adapt this file completely to your liking, but it should at least
|
||||
contain the root `toctree` directive.
|
||||
************************************
|
||||
GNPy: Optical Route Planning Library
|
||||
************************************
|
||||
|
||||
Welcome to GNpy's documentation!
|
||||
================================
|
||||
|
||||
Gaussian Noise (GN) based modeling library for physical layer impairment evaluation in optical networks.
|
||||
|
||||
Summary
|
||||
--------
|
||||
|
||||
We believe that openly sharing ideas, specifications, and other intellectual property is the key to maximizing innovation and reducing complexity
|
||||
|
||||
PSE WG Charter
|
||||
--------------
|
||||
|
||||
- Goal is to build an end-to-end simulation environment which defines the network models of the optical device transfer functions and their parameters. This environment will provide validation of the optical performance requirements for the TIP OLS building blocks.
|
||||
- The model may be approximate or complete depending on the network complexity. Each model shall be validated against the proposed network scenario.
|
||||
- The environment must be able to process network models from multiple vendors, and also allow users to pick any implementation in an open source framework.
|
||||
- The PSE will influence and benefit from the innovation of the DTC, API, and OLS working groups.
|
||||
- The PSE represents a step along the journey towards multi-layer optimization.
|
||||
|
||||
|
||||
Documentation
|
||||
=============
|
||||
|
||||
The following pages are meant to describe specific implementation details and modeling assumptions behind GNpy.
|
||||
`GNPy <http://github.com/telecominfraproject/gnpy>`_ is an open-source,
|
||||
community-developed library for building route planning and optimization tools
|
||||
in real-world mesh optical networks. It is based on the Gaussian Noise Model.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:maxdepth: 4
|
||||
:caption: Contents
|
||||
|
||||
gn_model
|
||||
intro
|
||||
concepts
|
||||
install
|
||||
cli_options
|
||||
amplifier_models_description
|
||||
json
|
||||
json_instance_examples
|
||||
excel
|
||||
extending
|
||||
about-project
|
||||
model
|
||||
gnpy-api
|
||||
release-notes
|
||||
publications
|
||||
genindex
|
||||
modindex
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
------------------
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
|
||||
Contributors in alphabetical order
|
||||
==================================
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Name | Surname | Affiliation | Contact |
|
||||
+==========+============+=======================+============================+
|
||||
| Alessio | Ferrari | Politecnico di Torino | alessio.ferrari@polito.it |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Brian | Taylor | Facebook | briantaylor@fb.com |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| David | Boertjes | Ciena | dboertje@ciena.com |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Esther | Le Rouzic | Orange | esther.lerouzic@orange.com |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Gabriele | Galimberti | Cisco | ggalimbe@cisco.com |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Gert | Grammel | Juniper Networks | ggrammel@juniper.net |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Gilad | Goldfarb | Facebook | giladg@fb.com |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| James | Powell | Consultant | james@dontusethiscode.com |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Jeanluc | Auge | Orange | jeanluc.auge@orange.com |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Mattia | Cantono | Politecnico di Torino | mattia.cantono@polito.it |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
| Vittorio | Curri | Politecnico di Torino | vittorio.curri@polito.it |
|
||||
+----------+------------+-----------------------+----------------------------+
|
||||
|
||||
|
||||
112
docs/install.rst
Normal file
112
docs/install.rst
Normal file
@@ -0,0 +1,112 @@
|
||||
***************
|
||||
Installing GNPy
|
||||
***************
|
||||
|
||||
There are several methods on how to obtain GNPy.
|
||||
The easiest option for a non-developer is probably going via our :ref:`Docker images<install-docker>`.
|
||||
Developers are encouraged to install the :ref:`Python package in the same way as any other Python package<install-pip>`.
|
||||
Note that this needs a :ref:`working installation of Python<install-python>`, for example :ref:`via Anaconda<install-anaconda>`.
|
||||
|
||||
.. _install-docker:
|
||||
|
||||
Using prebuilt Docker images
|
||||
============================
|
||||
|
||||
Our `Docker images <https://hub.docker.com/r/telecominfraproject/oopt-gnpy>`_ contain everything needed to run all examples from this guide.
|
||||
Docker transparently fetches the image over the network upon first use.
|
||||
On Linux and Mac, run:
|
||||
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ docker run -it --rm --volume $(pwd):/shared telecominfraproject/oopt-gnpy
|
||||
root@bea050f186f7:/shared/example-data#
|
||||
|
||||
On Windows, launch from Powershell as:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
PS C:\> docker run -it --rm --volume ${PWD}:/shared telecominfraproject/oopt-gnpy
|
||||
root@89784e577d44:/shared/example-data#
|
||||
|
||||
In both cases, a directory named ``example-data/`` will appear in your current working directory.
|
||||
GNPy automaticallly populates it with example files from the current release.
|
||||
Remove that directory if you want to start from scratch.
|
||||
|
||||
.. _install-python:
|
||||
|
||||
Using Python on your computer
|
||||
=============================
|
||||
|
||||
**Note**: `gnpy` supports Python 3 only. Python 2 is not supported.
|
||||
`gnpy` requires Python ≥3.8
|
||||
|
||||
**Note**: the `gnpy` maintainers strongly recommend the use of Anaconda for
|
||||
managing dependencies.
|
||||
|
||||
It is recommended that you use a "virtual environment" when installing `gnpy`.
|
||||
Do not install `gnpy` on your system Python.
|
||||
|
||||
.. _install-anaconda:
|
||||
|
||||
We recommend the use of the `Anaconda Python distribution <https://www.anaconda.com/download>`_ which comes with many scientific computing
|
||||
dependencies pre-installed. Anaconda creates a base "virtual environment" for
|
||||
you automatically. You can also create and manage your ``conda`` "virtual
|
||||
environments" yourself (see:
|
||||
https://conda.io/docs/user-guide/tasks/manage-environments.html)
|
||||
|
||||
To activate your Anaconda virtual environment, you may need to do the
|
||||
following:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ source /path/to/anaconda/bin/activate # activate Anaconda base environment
|
||||
(base) $ # note the change to the prompt
|
||||
|
||||
You can check which Anaconda environment you are using with:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
(base) $ conda env list # list all environments
|
||||
# conda environments:
|
||||
#
|
||||
base * /src/install/anaconda3
|
||||
|
||||
(base) $ echo $CONDA_DEFAULT_ENV # show default environment
|
||||
base
|
||||
|
||||
You can check your version of Python with the following. If you are using
|
||||
Anaconda's Python 3, you should see similar output as below. Your results may
|
||||
be slightly different depending on your Anaconda installation path and the
|
||||
exact version of Python you are using.
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ which python # check which Python executable is used
|
||||
/path/to/anaconda/bin/python
|
||||
$ python -V # check your Python version
|
||||
Python 3.8.0 :: Anaconda, Inc.
|
||||
|
||||
.. _install-pip:
|
||||
|
||||
Installing the Python package
|
||||
-----------------------------
|
||||
|
||||
From within your Anaconda Python 3 environment, you can clone the master branch
|
||||
of the `gnpy` repo and install it with:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ git clone https://github.com/Telecominfraproject/oopt-gnpy # clone the repo
|
||||
$ cd oopt-gnpy
|
||||
$ pip install --editable . # note the trailing dot
|
||||
|
||||
To test that `gnpy` was successfully installed, you can run this command. If it
|
||||
executes without a ``ModuleNotFoundError``, you have successfully installed
|
||||
`gnpy`.
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ python -c 'import gnpy' # attempt to import gnpy
|
||||
|
||||
$ pytest # run tests
|
||||
97
docs/intro.rst
Normal file
97
docs/intro.rst
Normal file
@@ -0,0 +1,97 @@
|
||||
.. _intro:
|
||||
|
||||
************
|
||||
Introduction
|
||||
************
|
||||
|
||||
``gnpy`` is a library for building route planning and optimization tools.
|
||||
|
||||
It ships with a number of example programs. Release versions will ship with
|
||||
fully-functional programs.
|
||||
|
||||
**Note**: *If you are a network operator or involved in route planning and
|
||||
optimization for your organization, please contact project maintainers
|
||||
esther Le Rouzic <esther.lerouzic@orange.com>, Andrea D'Amico <adamico@nec-labs.com>.
|
||||
gnpy is looking for users with
|
||||
specific, delineated use cases to drive requirements for future
|
||||
development.*
|
||||
|
||||
This example demonstrates how GNPy can be used to check the expected SNR at the end of the line by varying the channel input power,
|
||||
or to run a planning script to check SNR of several services:
|
||||
|
||||
.. image:: images/gnpy-transmission-example.svg
|
||||
:width: 100%
|
||||
:align: left
|
||||
:alt: Running a simple simulation example
|
||||
|
||||
By default, the gnpy-transmission-example script operates on a single span network defined in
|
||||
`gnpy/example-data/edfa_example_network.json <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/edfa_example_network.json>`_
|
||||
|
||||
You can specify a different network at the command line as follows. For
|
||||
example, to use the CORONET Global network defined in
|
||||
`gnpy/example-data/CORONET_Global_Topology.json <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/CORONET_Global_Topology.json>`_:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ gnpy-transmission-example $(gnpy-example-data)/CORONET_Global_Topology.json
|
||||
|
||||
It is also possible to use an Excel file input (for example
|
||||
`gnpy/example-data/CORONET_Global_Topology.xls <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/CORONET_Global_Topology.xls>`_).
|
||||
The Excel file will be processed into a JSON file with the same prefix.
|
||||
Further details about the Excel data structure are available `in the documentation <excel.rst>`__.
|
||||
|
||||
The main transmission example will calculate the average signal OSNR and SNR
|
||||
across network elements (transceiver, ROADMs, fibers, and amplifiers)
|
||||
between two transceivers selected by the user. Additional details are provided by doing ``gnpy-transmission-example -h``. (By default, for the CORONET Global
|
||||
network, it will show the transmission of spectral information between Abilene and Albany)
|
||||
|
||||
This script calculates the average signal OSNR = |OSNR| and SNR = |SNR|.
|
||||
|
||||
.. |OSNR| replace:: P\ :sub:`ch`\ /P\ :sub:`ase`
|
||||
.. |SNR| replace:: P\ :sub:`ch`\ /(P\ :sub:`nli`\ +\ P\ :sub:`ase`)
|
||||
|
||||
|Pase| is the amplified spontaneous emission noise, and |Pnli| the non-linear
|
||||
interference noise.
|
||||
|
||||
.. |Pase| replace:: P\ :sub:`ase`
|
||||
.. |Pnli| replace:: P\ :sub:`nli`
|
||||
|
||||
Further Instructions for Use
|
||||
============================
|
||||
|
||||
Simulations are driven by a set of `JSON <json.rst>`__ or `XLS <excel.rst>`__ files.
|
||||
|
||||
The ``gnpy-transmission-example`` script propagates a spectrum of channels at 32 Gbaud, 50 GHz spacing and 0 dBm/channel.
|
||||
Launch power in fiber spans can be overridden by using the ``--power`` argument.
|
||||
Spectrum information is not yet parametrized but can be modified directly in the ``eqpt_config.json`` (via the ``SpectralInformation`` -SI- structure) to accommodate any baud rate or spacing.
|
||||
The number of channel is computed based on ``spacing`` and ``f_min``, ``f_max`` values.
|
||||
|
||||
An experimental support for Raman amplification is available:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ gnpy-transmission-example \
|
||||
$(gnpy-example-data)/raman_edfa_example_network.json \
|
||||
--sim $(gnpy-example-data)/sim_params.json --show-channels
|
||||
|
||||
Configuration of Raman pumps (their frequencies, power and pumping direction) is done via the `RamanFiber element in the network topology <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/raman_edfa_example_network.json>`_.
|
||||
General numeric parameters for simulation control are provided in the `gnpy/example-data/sim_params.json <https://github.com/Telecominfraproject/oopt-gnpy/blob/master/gnpy/example-data/sim_params.json>`_.
|
||||
|
||||
Use ``gnpy-path-request`` to request several paths at once:
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ cd $(gnpy-example-data)
|
||||
$ gnpy-path-request -o output_file.json \
|
||||
meshTopologyExampleV2.xls meshTopologyExampleV2_services.json
|
||||
|
||||
This program operates on a network topology (`JSON <json.rst>`__ or `Excel <excel.rst>`__ format), processing the list of service requests (JSON or XLS again).
|
||||
The service requests and reply formats are based on the `draft-ietf-teas-yang-path-computation-01 <https://tools.ietf.org/html/draft-ietf-teas-yang-path-computation-01>`__ with custom extensions (e.g., for transponder modes).
|
||||
An example of the JSON input is provided in file `service-template.json`, while results are shown in `path_result_template.json`.
|
||||
|
||||
Important note: ``gnpy-path-request`` is not a network dimensionning tool: each service does not reserve spectrum, or occupy ressources such as transponders. It only computes path feasibility assuming the spectrum (between defined frequencies) is loaded with "nb of channels" spaced by "spacing" values as specified in the system parameters input in the service file, each cannel having the same characteristics in terms of baudrate, format,... as the service transponder. The transceiver element acts as a "logical starting/stopping point" for the spectral information propagation. At that point it is not meant to represent the capacity of add drop ports.
|
||||
As a result transponder type is not part of the network info. it is related to the list of services requests.
|
||||
|
||||
The current version includes a spectrum assigment features that enables to compute a candidate spectrum assignment for each service based on a first fit policy. Spectrum is assigned based on service specified spacing value, path_bandwidth value and selected mode for the transceiver. This spectrum assignment includes a basic capacity planning capability so that the spectrum resource is limited by the frequency min and max values defined for the links. If the requested services reach the link spectrum capacity, additional services feasibility are computed but marked as blocked due to spectrum reason.
|
||||
|
||||
OpenROADM networks can be simulated via ``gnpy/example-data/eqpt_config_openroadm_*.json`` -- see ``gnpy/example-data/Sweden_OpenROADM*_example_network.json`` as an example.
|
||||
1604
docs/json.rst
Normal file
1604
docs/json.rst
Normal file
File diff suppressed because it is too large
Load Diff
1034
docs/json_instance_examples.rst
Normal file
1034
docs/json_instance_examples.rst
Normal file
File diff suppressed because it is too large
Load Diff
149
docs/model.rst
Normal file
149
docs/model.rst
Normal file
@@ -0,0 +1,149 @@
|
||||
.. _physical-model:
|
||||
|
||||
***************************
|
||||
Physical Model used in GNPy
|
||||
***************************
|
||||
|
||||
QoT-E including ASE noise and NLI accumulation
|
||||
==============================================
|
||||
|
||||
The operations of PSE simulative framework are based on the capability to
|
||||
estimate the QoT of one or more channels operating lightpaths over a given
|
||||
network route. For backbone transport networks, we can suppose that
|
||||
transceivers are operating polarization-division-multiplexed multilevel
|
||||
modulation formats with DSP-based coherent receivers, including equalization.
|
||||
For the optical links, we focus on state-of-the-art amplified and uncompensated
|
||||
fiber links, connecting network nodes including ROADMs, where add and drop
|
||||
operations on data traffic are performed. In such a transmission scenario, it
|
||||
is well accepted
|
||||
:cite:`vacondio_nonlinear_2012,bononi_modeling_2012,carena_modeling_2012,mecozzi_nonlinear_2012,secondini_analytical_2012,johannisson_perturbation_2013,dar_properties_2013,serena_alternative_2013,secondini_achievable_2013,poggiolini_gn-model_2014,dar_accumulation_2014,poggiolini_analytical_2011,savory_approximations_2013,bononi_single-_2013,johannisson_modeling_2014`
|
||||
to assume that transmission performances are limited by the amplified
|
||||
spontaneous emission (ASE) noise generated by optical amplifiers and and
|
||||
by nonlinear propagation effects: accumulation of a Gaussian disturbance
|
||||
defined as nonlinear interference (NLI) and generation of phase noise.
|
||||
State-of-the-art DSP in commercial transceivers are typically able to
|
||||
compensate for most of the phase noise through carrier-phase estimator
|
||||
(CPE) algorithms, for modulation formats with cardinality up to 16, per
|
||||
polarization state
|
||||
:cite:`poggiolini_recent_2017,schmidt_experimental_2015,fehenberger_experimental_2016`.
|
||||
So, for backbone networks covering medium-to-wide geographical areas, we
|
||||
can suppose that propagation is limited by the accumulation of two
|
||||
Gaussian disturbances: the ASE noise and the NLI. Additional impairments
|
||||
such as filtering effects introduced by ROADMs can be considered as
|
||||
additional equivalent power penalties depending on the ratio between the
|
||||
channel bandwidth and the ROADMs filters and the number of traversed
|
||||
ROADMs (hops) of the route under analysis. Modeling the two major
|
||||
sources of impairments as Gaussian disturbances, and being the receivers
|
||||
*coherent*, the unique QoT parameter determining the bit error rate
|
||||
(BER) for the considered transmission scenario is the generalized
|
||||
signal-to-noise ratio (SNR) defined as
|
||||
|
||||
.. math::
|
||||
|
||||
{\text{SNR}}= L_F \frac{P_{\text{ch}}}{P_{\text{ASE}}+P_{\text{NLI}}} = L_F \left(\frac{1}{{\text{SNR}}_{\text{LIN}}}+\frac{1}{{\text{SNR}}_{\text{NL}}}\right)^{-1}
|
||||
|
||||
|
||||
where :math:`P_{\text{ch}}` is the channel power,
|
||||
:math:`P_{\text{ASE}}` and :math:`P_{\text{NLI}}` are the power levels of the disturbances
|
||||
in the channel bandwidth for ASE noise and NLI, respectively.
|
||||
:math:`L_F` is a parameter assuming values smaller or equal than one
|
||||
that summarizes the equivalent power penalty loss such as
|
||||
filtering effects. Note that for state-of-the art equipment, filtering
|
||||
effects can be typically neglected over routes with few hops
|
||||
:cite:`rahman_mitigation_2014,foggi_overcoming_2015`.
|
||||
|
||||
To properly estimate :math:`P_{\text{ch}}` and :math:`P_{\text{ASE}}`
|
||||
the transmitted power at the beginning of the considered route must be
|
||||
known, and losses and amplifiers gain and noise figure, including their
|
||||
variation with frequency, must be characterized. So, the evaluation of
|
||||
:math:`{\text{SNR}}_{\text{LIN}}` *just* requires an accurate
|
||||
knowledge of equipment, which is not a trivial aspect, but it is not
|
||||
related to physical-model issues. For the evaluation of the NLI, several
|
||||
models have been proposed and validated in the technical literature
|
||||
:cite:`vacondio_nonlinear_2012,bononi_modeling_2012,carena_modeling_2012,mecozzi_nonlinear_2012,secondini_analytical_2012,johannisson_perturbation_2013,dar_properties_2013,serena_alternative_2013,secondini_achievable_2013,poggiolini_gn-model_2014,dar_accumulation_2014,poggiolini_analytical_2011,savory_approximations_2013,bononi_single-_2013,johannisson_modeling_2014`.
|
||||
The decision about which model to test within the PSE activities was
|
||||
driven by requirements of the entire PSE framework:
|
||||
|
||||
i. the model must be *local*, i.e., related individually to each network
|
||||
element (i.e. fiber span) generating NLI, independently of preceding and
|
||||
subsequent elements; and ii. the related computational time must be compatible
|
||||
with interactive operations.
|
||||
|
||||
So, the choice fell on the Gaussian Noise
|
||||
(GN) model with incoherent accumulation of NLI over fiber spans
|
||||
:cite:`poggiolini_gn-model_2014`. We implemented both the
|
||||
exact GN-model evaluation of NLI based on a double integral (Eq. (11) of
|
||||
:cite:`poggiolini_gn-model_2014`) and its analytical
|
||||
approximation (Eq. (120-121) of
|
||||
:cite:`poggiolini_analytical_2011`). We performed several
|
||||
validation analyses comparing results of the two implementations with
|
||||
split-step simulations over wide bandwidths
|
||||
:cite:`pilori_ffss_2017`, and results clearly showed that
|
||||
for fiber types with chromatic dispersion roughly larger than 4
|
||||
ps/nm/km, the analytical approximation ensures an excellent accuracy
|
||||
with a computational time compatible with real-time operations.
|
||||
|
||||
The Gaussian Noise Model to evaluate the NLI
|
||||
============================================
|
||||
|
||||
As previously stated, fiber propagation of multilevel modulation formats
|
||||
relying on the polarization-division-multiplexing generates impairments that
|
||||
can be summarized as a disturbance called nonlinear interference (NLI), when
|
||||
exploiting a DSP-based coherent receiver, as in all state-of-the-art equipment.
|
||||
From a practical point of view, the NLI can be modeled as an additive Gaussian
|
||||
random process added by each fiber span, and whose strength depends on the cube
|
||||
of the input power spectral density and on the fiber-span parameters.
|
||||
|
||||
Since the introduction in the market in 2007 of the first transponder based on
|
||||
such a transmission technique, the scientific community has intensively worked
|
||||
to define the propagation behavior of such a trasnmission technique. First,
|
||||
the role of in-line chromatic dispersion compensation has been investigated,
|
||||
deducing that besides being not essential, it is indeed detrimental for
|
||||
performances :cite:`curri_dispersion_2008`. Then, it has been observed that
|
||||
the fiber propagation impairments are practically summarized by the sole NLI,
|
||||
being all the other phenomena compensated for by the blind equalizer
|
||||
implemented in the receiver DSP :cite:`carena_statistical_2010`. Once these
|
||||
assessments have been accepted by the community, several prestigious research
|
||||
groups have started to work on deriving analytical models able to estimating
|
||||
the NLI accumulation, and consequentially the generalized SNR that sets the
|
||||
BER, according to the transponder BER vs. SNR performance. Many models
|
||||
delivering different levels of accuracy have been developed and validated. As
|
||||
previously clarified, for the purposes of the PSE framework, the GN-model with
|
||||
incoherent accumulation of NLI over fiber spans has been selected as adequate.
|
||||
The reason for such a choice is first such a model being a "local" model, so
|
||||
related to each fiber spans, independently of the preceding and succeeding
|
||||
network elements. The other model characteristic driving the choice is the
|
||||
availability of a closed form for the model, so permitting a real-time
|
||||
evaluation, as required by the PSE framework. For a detailed derivation of the
|
||||
model, please refer to :cite:`poggiolini_analytical_2011`, while a qualitative
|
||||
description can be summarized as in the following. The GN-model assumes that
|
||||
the channel comb propagating in the fiber is well approximated by unpolarized
|
||||
spectrally shaped Gaussian noise. In such a scenario, supposing to rely - as in
|
||||
state-of-the-art equipment - on a receiver entirely compensating for linear
|
||||
propagation effects, propagation in the fiber only excites the four-wave mixing
|
||||
(FWM) process among the continuity of the tones occupying the bandwidth. Such a
|
||||
FWM generates an unpolarized complex Gaussian disturbance in each spectral slot
|
||||
that can be easily evaluated extending the FWM theory from a set of discrete
|
||||
tones - the standard FWM theory introduced back in the 90s by Inoue
|
||||
:cite:`Innoue-FWM`- to a continuity of tones, possibly spectrally shaped.
|
||||
Signals propagating in the fiber are not equivalent to Gaussian noise, but
|
||||
thanks to the absence of in-line compensation for chromatic dispersion, the
|
||||
become so, over short distances. So, the Gaussian noise model with incoherent
|
||||
accumulation of NLI has extensively proved to be a quick yet accurate and
|
||||
conservative tool to estimate propagation impairments of fiber propagation.
|
||||
Note that the GN-model has not been derived with the aim of an *exact*
|
||||
performance estimation, but to pursue a conservative performance prediction.
|
||||
So, considering these characteristics, and the fact that the NLI is always a
|
||||
secondary effect with respect to the ASE noise accumulation, and - most
|
||||
importantly - that typically linear propagation parameters (losses, gains and
|
||||
noise figures) are known within a variation range, a QoT estimator based on the
|
||||
GN model is adequate to deliver performance predictions in terms of a
|
||||
reasonable SNR range, rather than an exact value. As final remark, it must be
|
||||
clarified that the GN-model is adequate to be used when relying on a relatively
|
||||
narrow bandwidth up to few THz. When exceeding such a bandwidth occupation, the
|
||||
GN-model must be generalized introducing the interaction with the Stimulated
|
||||
Raman Scattering in order to give a proper estimation for all channels
|
||||
:cite:`cantono2018modeling`. This will be the main upgrade required within the
|
||||
PSE framework.
|
||||
|
||||
.. bibliography::
|
||||
25
docs/publications.rst
Normal file
25
docs/publications.rst
Normal file
@@ -0,0 +1,25 @@
|
||||
.. _publications:
|
||||
|
||||
************
|
||||
Publications
|
||||
************
|
||||
|
||||
Below is a chronological list of notable publications that emerged from the PSE group's collaborative work.
|
||||
These articles detail the evolution of GNPy and confirm its performance through experimental trials:
|
||||
|
||||
- `G. Grammel, V. Curri, and J. Auge, "Physical Simulation Environment of The Telecommunications Infrastructure Project (TIP)," in Optical Fiber Communication Conference, OSA Technical Digest (online) (Optica Publishing Group, 2018), paper M1D.3. <https://opg.optica.org/abstract.cfm?uri=OFC-2018-M1D.3>`_
|
||||
- `B. D. Taylor, G. Goldfarb, S. Bandyopadhyay, V. Curri, and H. Schmidtke, "Towards a Route Planning Tool for Open Optical Networks in the Telecom Infrastructure Project," in Optical Fiber Communication Conference, OSA Technical Digest (online) (Optica Publishing Group, 2018), paper Tu3E.4. <https://opg.optica.org/abstract.cfm?uri=OFC-2018-Tu3E.4>`_
|
||||
- `M. Filer, M. Cantono, A. Ferrari, G. Grammel, G. Galimberti, and V. Curri, "Multi-Vendor Experimental Validation of an Open Source QoT Estimator for Optical Networks," J. Lightwave Technol. 36, 3073-3082 (2018). <https://opg.optica.org/jlt/abstract.cfm?uri=jlt-36-15-3073>`_
|
||||
- `J. Auge, G. Grammel, E. le Rouzic, V. Curri, G. Galimberti, and J. Powell, "Open optical network planning demonstration," in Optical Fiber Communication Conference (OFC) 2019, OSA Technical Digest (Optica Publishing Group, 2019), paper M3Z.9. <https://opg.optica.org/abstract.cfm?uri=OFC-2019-M3Z.9>`_
|
||||
- `J. Kundrát, A. Campanella, E. Le Rouzic, A. Ferrari, O. Havliš, M. Hažlinský, G. Grammel, G. Galimberti, and V. Curri, "Physical-Layer Awareness: GNPy and ONOS for End-to-End Circuits in Disaggregated Networks," in Optical Fiber Communication Conference (OFC) 2020, OSA Technical Digest (Optica Publishing Group, 2020), paper M3Z.17. <https://opg.optica.org/abstract.cfm?uri=ofc-2020-m3z.17>`_
|
||||
- `A. Ferrari, M. Filer, K. Balasubramanian, Y. Yin, E. Le Rouzic, J. Kundrát, G. Grammel, G. Galimberti, and V. Curri, "Experimental Validation of an Open Source Quality of Transmission Estimator for Open Optical Networks," in Optical Fiber Communication Conference (OFC) 2020, OSA Technical Digest (Optica Publishing Group, 2020), paper W3C.2. <https://opg.optica.org/abstract.cfm?uri=ofc-2020-W3C.2>`_
|
||||
- `A. Ferrari, M. Filer, K. Balasubramanian, Y. Yin, E. Le Rouzic, J. Kundrát, G. Grammel, G. Galimberti, and V. Curri, "GNPy: an open source application for physical layer aware open optical networks," J. Opt. Commun. Netw. 12, C31-C40 (2020). <https://opg.optica.org/jocn/fulltext.cfm?uri=jocn-12-6-C31&id=429003>`_
|
||||
- `A. Ferrari, K. Balasubramanian, M. Filer, Y. Yin, E. Le Rouzic, J. Kundrát, G. Grammel, G. Galimberti, and V. Curri, "Softwarized Optical Transport QoT in Production Optical Network: a Brownfield Validation," 2020 European Conference on Optical Communications (ECOC), Brussels, Belgium, 2020. <https://ieeexplore.ieee.org/document/9333280>`_
|
||||
- `A. Ferrari, K. Balasubramanian, M. Filer, Y. Yin, E. Le Rouzic, J. Kundrát, G. Grammel, G. Galimberti, and V. Curri, "Assessment on the in-field lightpath QoT computation including connector loss uncertainties," in Journal of Optical Communications and Networking, vol. 13, no. 2, pp. A156-A164, February 2021. <https://ieeexplore.ieee.org/document/9308057>`_
|
||||
- `J. Kundrát, E. Le Rouzic, J. Mårtensson, A. Campanella, O. Havliš, A. D’Amico, G. Grammel, G. Galimberti, V. Curri, and J. Vojtěch, "GNPy & YANG: Open APIs for End-to-End Service Provisioning in Optical Networks," in Optical Fiber Communication Conference (OFC) 2021, P. Dong, J. Kani, C. Xie, R. Casellas, C. Cole, and M. Li, eds., OSA Technical Digest (Optica Publishing Group, 2021), paper M1B.6. <https://opg.optica.org/abstract.cfm?uri=ofc-2021-M1B.6>`_
|
||||
- `A. D’Amico, E. London, B. Le Guyader, F. Frank, E. Le Rouzic, E. Pincemin, N. Brochier, and V. Curri, "GNPy experimental validation on flex-grid, flex-rate WDM optical transport scenarios," in Optical Fiber Communication Conference (OFC) 2021, P. Dong, J. Kani, C. Xie, R. Casellas, C. Cole, and M. Li, eds., OSA Technical Digest (Optica Publishing Group, 2021), paper W1G.2. <https://opg.optica.org/abstract.cfm?uri=ofc-2021-W1G.2>`_
|
||||
- `E. Virgillito, R. Braun, D. Breuer, A. Gladisch, V. Curri, and G. Grammel, "Testing TIP Open Source Solutions in Deployed Optical Networks," in Optical Fiber Communication Conference (OFC) 2021, P. Dong, J. Kani, C. Xie, R. Casellas, C. Cole, and M. Li, eds., OSA Technical Digest (Optica Publishing Group, 2021), paper F1C.3. <https://opg.optica.org/abstract.cfm?uri=ofc-2021-F1C.3>`_
|
||||
- `A. D’Amico, E. London, B. Le Guyader, F. Frank, E. Le Rouzic, E. Pincemin, N. Brochier, and V. Curri, "Experimental validation of GNPy in a multi-vendor flex-grid flex-rate WDM optical transport scenario," J. Opt. Commun. Netw. 14, 79-88 (2022). <https://opg.optica.org/jocn/fulltext.cfm?uri=jocn-14-3-79&id=466355>`_
|
||||
- `J. Kundrát, E. Le Rouzic, J. Mårtensson, S. Melin, A. D’Amico, G. Grammel, G. Galimberti, and V. Curri, "GNPy: Lessons Learned and Future Plans [Invited]," in European Conference on Optical Communication (ECOC) 2022, J. Leuthold, C. Harder, B. Offrein, and H. Limberger, eds., Technical Digest Series (Optica Publishing Group, 2022), paper We3B.6. <https://opg.optica.org/abstract.cfm?uri=ECEOC-2022-We3B.6>`_
|
||||
- `G. Grammel, J. Kundrat, E. Le Rouzic, S. Melin, V. Curri, A. D'Amico, R. Manzotti, "Open Optical Networks: the good, the bad and the ugly," 49th European Conference on Optical Communications (ECOC 2023), Hybrid Conference, Glasgow, UK, 2023. <https://ieeexplore.ieee.org/document/10484723>`_
|
||||
- `A. D’Amico, V. Gatto, A. Nespola, G. Borraccini, Y. Jiang, P. Poggiolini, E. Le Rouzic, A. M. L. de Lerma, G. Grammel, R. Manzotti, V. Curri, "GNPy Experimental Validation in a C+L Multiband Optical Multiplex Section," 2024 24th International Conference on Transparent Optical Networks (ICTON), Bari, Italy, 2024. <https://ieeexplore.ieee.org/document/10648172>`_
|
||||
527
docs/release-notes.rst
Normal file
527
docs/release-notes.rst
Normal file
@@ -0,0 +1,527 @@
|
||||
.. _release-notes:
|
||||
|
||||
******************
|
||||
Release change log
|
||||
******************
|
||||
|
||||
Each release introduces some changes and new features.
|
||||
|
||||
(prepare text for next release)
|
||||
|
||||
v2.13
|
||||
=====
|
||||
|
||||
**Environment**
|
||||
|
||||
The windows-2019 environment is no more supported.
|
||||
|
||||
**Yang Conversion Utilities**
|
||||
|
||||
This release introduces new conversion utilities to facilitate conversion between YANG and legacy formats,
|
||||
ensuring full compatibility with GNPy. The "legacy" format also benefit from the YANG validation for
|
||||
a stricter verification of input files.
|
||||
Console Script for Yang Conversion: Added a new command-line script to perform Yang format conversions easily.
|
||||
|
||||
**Design Enhancements**
|
||||
|
||||
This release adds the ability to parametrize power target calculations, allowing customization of reference
|
||||
span loss and deviation ratios. It implements the use of a reference channel per OMS (Optical Multiplex Section)
|
||||
instead of total power for design calculations, improving accuracy and performance.
|
||||
It also includes spacing information in design band data to assist in maximum power computation for EDFA
|
||||
targets compution during autodesign.
|
||||
|
||||
**Excel handling**
|
||||
|
||||
XLSX files are now read with openpyxl library (while XLS files are still read with xlrd library). Latest release of
|
||||
xlrd is supported, which solves compatibility issues with anaconda install.
|
||||
|
||||
v2.12
|
||||
=====
|
||||
|
||||
**Important Changes:**
|
||||
|
||||
The default values for EDFA configuration, including frequency range, gain ripple, noise figure ripple, or dynamic gain tilt
|
||||
are now hardcoded in parameters.py and are no longer read from the default_edfa_config.json file (the file has been removed).
|
||||
However, users can define their own custom parameters using the default_config_from_json variable, which should be populated with a file name containing the desired parameter description. This applies to both variable_gain and fixed_gain amplifier types.
|
||||
|
||||
This change streamlines the configuration process but requires users to explicitly set parameters through the new
|
||||
model if the default values do not suit their needs via the --extra-config option.
|
||||
|
||||
v2.11.1
|
||||
-------
|
||||
|
||||
**Environment**
|
||||
|
||||
The macOS-12 environment is no more supported.
|
||||
|
||||
**per degree impairment enabled in xls input**
|
||||
|
||||
This release now read per degre roadm-path impairment from roadm sheet
|
||||
Several optional columns are added: 'type_variety' and 'from degrees'
|
||||
and 'from degree to degree impairment id'.
|
||||
|
||||
- 'from degrees' can contain a list of degrees separated with ' | ', then the
|
||||
'from degree to degree impairment id' must contain a list of ids of the same
|
||||
length.
|
||||
|
||||
Impairment ids are expected to be defined in the ROADM equipment library and
|
||||
from degree must be among the previous node from this ROADM.
|
||||
|
||||
**optimizing computation speed**
|
||||
The computation of path is skipped if the provided include nodes provides
|
||||
a complete explicit path (speeds simulation time).
|
||||
|
||||
v2.11
|
||||
=====
|
||||
|
||||
**New feature**
|
||||
|
||||
A new type_def for amplifiers has been introduced: multi_band. This allows the definition of a
|
||||
multiband amplifier site composed of several amplifiers per band (a typical application is C+L transmission). The
|
||||
release also includes autodesign for links (Optical Multiplex Section, OMS) composed of multi_band amplifiers.
|
||||
Multi_band autodesign includes basic tilt and tilt_target calculation when the Raman flag is enabled with the
|
||||
--sim-params option. The spectrum is demultiplexed before propagation in the amplifier and multiplexed in the output
|
||||
fiber at the amplifier output.
|
||||
|
||||
|
||||
In the library:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"type_variety": "std_medium_gain_C",
|
||||
"f_min": 191.225e12,
|
||||
"f_max": 196.125e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain_L",
|
||||
"f_min": 186.5e12,
|
||||
"f_max": 190.1e12,
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain_multiband",
|
||||
"type_def": "multi_band",
|
||||
"amplifiers": [
|
||||
"std_medium_gain_C",
|
||||
"std_medium_gain_L"
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
|
||||
In the network topology:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"uid": "east edfa in Site_A to Site_B",
|
||||
"type": "Multiband_amplifier",
|
||||
"type_variety": "std_medium_gain_multiband",
|
||||
"amplifiers": [{
|
||||
"type_variety": "std_medium_gain_C",
|
||||
"operational": {
|
||||
"gain_target": 22.55,
|
||||
"delta_p": 0.9,
|
||||
"out_voa": 3.0,
|
||||
"tilt_target": 0.0
|
||||
}
|
||||
}, {
|
||||
"type_variety": "std_medium_gain_L",
|
||||
"operational": {
|
||||
"gain_target": 21,
|
||||
"delta_p": 3.0,
|
||||
"out_voa": 3.0,
|
||||
"tilt_target": 0.0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
**Network design**
|
||||
|
||||
Optionally, users can define a design target per OMS (single or multi-band), with specific frequency ranges.
|
||||
Default design bands are defined in the SI.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"uid": "roadm Site_A",
|
||||
"type": "Roadm",
|
||||
"params": {
|
||||
"target_pch_out_db": -20,
|
||||
"design_bands": [{"f_min": 191.3e12, "f_max": 195.1e12}]
|
||||
}
|
||||
}
|
||||
|
||||
It is possible to define a set of bands in the SI block instead of a single Spectrum Information.
|
||||
In this case type_variety must be used.
|
||||
Each set defines a reference channel used for design functions and autodesign.
|
||||
|
||||
The default design settings for the path-request-run script have been modified.
|
||||
Now, design is performed once for the reference channel defined in the SI block of the eqpt_config,
|
||||
and requests are propagated based on this design.
|
||||
The --redesign-per-request option can be used to restore previous behaviour
|
||||
(design using request channel types).
|
||||
|
||||
The autodesign function has been updated to insert multiband booster, preamp or inline amplifiers based on the OMS
|
||||
nature. If nothing is stated (no amplifier defined in the OMS, no design_bands attribute in the ROADM), then
|
||||
it uses single band Edfas.
|
||||
|
||||
**Propagation**
|
||||
|
||||
Only carriers within the amplifier bandwidth are propagated, improving system coherence. This more rigorous checking
|
||||
of the spectrum to be propagated and the amplifier bandwidth may lead to changes in the total number of channels
|
||||
compared to previous releases. The range can be adjusted by changing the values of ``f_min`` and ``f_max``
|
||||
in the amplifier library.
|
||||
|
||||
|
||||
``f_min`` and ``f_max`` represent the boundary frequencies of the amplification bandwidth (the entire channel must fit
|
||||
within this range).
|
||||
In the example below, a signal center frequency of 190.05THz with a 50GHz width cannot fit within the amplifier band.
|
||||
Note that this has a different meaning in the SI or Transceiver blocks, where ``f_min`` and ``f_max`` refers to the
|
||||
minimum / maximum values of the carrier center frequency.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"type_variety": "std_booster_L",
|
||||
"f_min": 186.55e12,
|
||||
"f_max": 190.05e12,
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 21,
|
||||
"gain_min": 20,
|
||||
"p_max": 21,
|
||||
"nf0": 5,
|
||||
"allowed_for_design": false
|
||||
}
|
||||
|
||||
|
||||
**Display**
|
||||
|
||||
The CLI output for the transmission_main_example now displays the channels used for design and simulation,
|
||||
as well as the tilt target of amplifiers.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Reference used for design: (Input optical power reference in span = 0.00dBm,
|
||||
spacing = 50.00GHz
|
||||
nb_channels = 76)
|
||||
|
||||
Channels propagating: (Input optical power deviation in span = 0.00dB,
|
||||
spacing = 50.00GHz,
|
||||
transceiver output power = 0.00dBm,
|
||||
nb_channels = 76)
|
||||
|
||||
The CLI output displays the settings of each amplifier:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Multiband_amplifier east edfa in Site_A to Site_B
|
||||
type_variety: std_medium_gain_multiband
|
||||
type_variety: std_medium_gain_C type_variety: std_medium_gain_L
|
||||
effective gain(dB): 20.90 effective gain(dB): 22.19
|
||||
(before att_in and before output VOA) (before att_in and before output VOA)
|
||||
tilt-target(dB) 0.00 tilt-target(dB) 0.00
|
||||
noise figure (dB): 6.38 noise figure (dB): 6.19
|
||||
(including att_in) (including att_in)
|
||||
pad att_in (dB): 0.00 pad att_in (dB): 0.00
|
||||
Power In (dBm): -1.08 Power In (dBm): -1.49
|
||||
Power Out (dBm): 19.83 Power Out (dBm): 20.71
|
||||
Delta_P (dB): 0.90 Delta_P (dB): 2.19
|
||||
target pch (dBm): 0.90 target pch (dBm): 3.00
|
||||
actual pch out (dBm): -2.09 actual pch out (dBm): -0.80
|
||||
output VOA (dB): 3.00 output VOA (dB): 3.00
|
||||
|
||||
|
||||
**New feature**
|
||||
|
||||
The preturbative Raman and the approximated GGN models are introduced for a faster evaluation of the Raman and
|
||||
Kerr effects, respectively.
|
||||
These implementation are intended to reduce the computational effort required by multiband transmission scenarios.
|
||||
|
||||
Both the novel models have been validated with exstensive simulations
|
||||
(see `arXiv:2304.11756 <https://arxiv.org/abs/2304.11756>`_ for the new Raman model and
|
||||
`jlt:9741324 <https://eeexplore.ieee.org/document/9741324>`_ for the new NLI model).
|
||||
Additionally, they have been experimentally validated in a laboratory setup composed of commertial equipment
|
||||
(see `icton:10648172 <https://eeexplore.ieee.org/document/10648172>`_).
|
||||
|
||||
|
||||
v2.10
|
||||
=====
|
||||
|
||||
ROADM impairments can be defined per degree and roadm-path type (add, drop or express).
|
||||
Minimum loss when crossing a ROADM is no more 0 dB. It can be set per ROADM degree with roadm-path-impairments.
|
||||
|
||||
The transceiver output power, which was previously set using the same parameter as the input span power (power_dbm),
|
||||
can now be set using a different parameter. It can be set as:
|
||||
|
||||
- for all channels, with tx_power_dbm using SI similarly to tx_osnr (gnpy-transmission-example script)
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
"SI": [{
|
||||
"f_min": 191.35e12,
|
||||
"baud_rate": 32e9,
|
||||
"f_max": 196.1e12,
|
||||
"spacing": 50e9,
|
||||
"power_dbm": 3,
|
||||
"power_range_db": [0, 0, 1],
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"tx_power_dbm": -10,
|
||||
"sys_margins": 2
|
||||
}
|
||||
]
|
||||
|
||||
- for certain channels, using -spectrum option and tx_channel_power_dbm option (gnpy-transmission-example script).
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"spectrum": [
|
||||
{
|
||||
"f_min": 191.35e12,
|
||||
"f_max":193.1e12,
|
||||
"baud_rate": 32e9,
|
||||
"slot_width": 50e9,
|
||||
"power_dbm": 0,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40
|
||||
},
|
||||
{
|
||||
"f_min": 193.15e12,
|
||||
"f_max":193.15e12,
|
||||
"baud_rate": 32e9,
|
||||
"slot_width": 50e9,
|
||||
"power_dbm": 0,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"tx_power_dbm": -10
|
||||
},
|
||||
{
|
||||
"f_min": 193.2e12,
|
||||
"f_max":195.1e12,
|
||||
"baud_rate": 32e9,
|
||||
"slot_width": 50e9,
|
||||
"power_dbm": 0,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
- per service using the additional parameter ``tx_power`` which similarly to ``power`` should be defined in Watt (gnpy-path-request script)
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"path-request": [
|
||||
{
|
||||
"request-id": "0",
|
||||
"source": "trx SITE1",
|
||||
"destination": "trx SITE2",
|
||||
"src-tp-id": "trx SITE1",
|
||||
"dst-tp-id": "trx SITE2",
|
||||
"bidirectional": false,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Voyager",
|
||||
"trx_mode": "mode 1",
|
||||
"spacing": 50000000000.0,
|
||||
"path_bandwidth": 100000000000.0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"request-id": "0 with tx_power",
|
||||
"source": "trx SITE1",
|
||||
"destination": "trx SITE2",
|
||||
"src-tp-id": "trx SITE1",
|
||||
"dst-tp-id": "trx SITE2",
|
||||
"bidirectional": false,
|
||||
"path-constraints": {
|
||||
"te-bandwidth": {
|
||||
"technology": "flexi-grid",
|
||||
"trx_type": "Voyager",
|
||||
"trx_mode": "mode 1",
|
||||
"tx_power": 0.0001,
|
||||
"spacing": 50000000000.0,
|
||||
"path_bandwidth": 100000000000.0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
v2.9
|
||||
====
|
||||
|
||||
The revision introduces a major refactor that separates design and propagation. Most of these changes have no impact
|
||||
on the user experience, except the following ones:
|
||||
|
||||
**Network design - amplifiers**: amplifier saturation is checked during design in all cases, even if type_variety is
|
||||
set; amplifier gain is no more computed on the fly but only at design phase.
|
||||
|
||||
Before, the design did not consider amplifier power saturation during design if amplifier type_variety was stated.
|
||||
With this revision, the saturation is always applied:
|
||||
If design is made for a per channel power that leads to saturation, the target are properly reduced and the design
|
||||
is freezed. So that when a new simulation is performed on the same network for lower levels of power per channel
|
||||
the same gain target is applied. Before these were recomputed, changing the gain targets, so the simulation was
|
||||
not considering the exact same working points for amplifiers in case of saturation.
|
||||
|
||||
Note that this case (working with saturation settings) is not recommended.
|
||||
|
||||
The gain of amplifiers was estimated on the fly also in case of RamanFiber preceding elements. The refactor now
|
||||
requires that an estimation of Raman gain of the RamanFiber is done during design to properly compute a gain target.
|
||||
The Raman gain is estimated at design for every RamanFiber span and also during propagation instead of being only
|
||||
estimated at propagation stage for those Raman Fiber spans concerned with the transmission. The auto-design is more
|
||||
accurate for unpropagated spans, but this results in an increase overall computation time.
|
||||
This will be improved in the future.
|
||||
|
||||
**Network design - ROADMs**: ROADM target power settings are verified during design.
|
||||
|
||||
Design checks that expected power coming from every directions ingress from a ROADM are consistent with output power
|
||||
targets. The checks only considers the adjacent previous hop. If the expected power at the input of this ROADM is
|
||||
lower than the target power on the out-degree of the ROADM, a warning is displayed, and user is asked to review the
|
||||
input network to avoid this situation. This does not change the design or propagation behaviour.
|
||||
|
||||
**Propagation**: amplifier gain target is no more recomputed during propagation. It is now possible to freeze
|
||||
the design and propagate without automatic changes.
|
||||
|
||||
In previous release, gain was recomputed during propagation based on an hypothetical reference noiseless channel
|
||||
propagation. It was not possible to «freeze» the autodesign, and propagate without recomputing the gain target
|
||||
of amplifiers.
|
||||
With this new release, the design is freezed, so that it is possible to compare performances on same basis.
|
||||
|
||||
**Display**: "effective pch (dbm)" is removed. Display contains the target pch which is the target power per channel
|
||||
in dBm, computed based on reference channel used for design and the amplifier delta_p in dB (and before out VOA
|
||||
contribution). Note that "actual pch out (dBm)" is the actual propagated total power per channel averaged per spectrum
|
||||
band definition at the output of the amplifier element, including noises and out VOA contribution.
|
||||
|
||||
v2.8
|
||||
====
|
||||
|
||||
**Spectrum assignment**: requests can now support multiple slots.
|
||||
The definition in service file supports multiple assignments (unchanged syntax):
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
"effective-freq-slot": [
|
||||
{
|
||||
"N": 0,
|
||||
"M": 4
|
||||
}, {
|
||||
"N": 50,
|
||||
"M": 4
|
||||
}
|
||||
],
|
||||
|
||||
But in results, label-hop is now a list of slots and center frequency index:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"path-route-object": {
|
||||
"index": 4,
|
||||
"label-hop": [
|
||||
{
|
||||
"N": 0,
|
||||
"M": 4
|
||||
}, {
|
||||
"N": 50,
|
||||
"M": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
instead of
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"path-route-object": {
|
||||
"index": 4,
|
||||
"label-hop": {
|
||||
"N": 0,
|
||||
"M": 4
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
||||
**change in display**: only warnings are displayed ; information are disabled and needs the -v (verbose)
|
||||
option to be displayed on standard output.
|
||||
|
||||
**frequency scaling**: A more accurate description of fiber parameters is implemented, including frequency scaling of
|
||||
chromatic dispersion, effective area, Raman gain coefficient, and nonlinear coefficient.
|
||||
|
||||
In particular:
|
||||
|
||||
1. Chromatic dispersion can be defined with ``'dispersion'`` and ``'dispersion_slope'``, as in previous versions, or
|
||||
with ``'dispersion_per_frequency'``; the latter must be defined as a dictionary with two keys, ``'value'`` and
|
||||
``'frequency'`` and it has higher priority than the entries ``'dispersion'`` and ``'dispersion_slope'``.
|
||||
Essential change: In previous versions, when it was not provided the ``'dispersion_slope'`` was calculated in an
|
||||
involute manner to get a vanishing beta3 , and this was a mere artifact for NLI evaluation purposes (namely to evaluate
|
||||
beta2 and beta3, not for total dispersion accumulation). Now, the evaluation of beta2 and beta3 is performed explicitly
|
||||
in the element.py module.
|
||||
|
||||
1. The effective area is provided as a scalar value evaluated at the Fiber reference frequency and properly scaled
|
||||
considering the Fiber refractive indices n1 and n2, and the core radius. These quantities are assumed to be fixed and
|
||||
are hard coded in the parameters.py module. Essential change: The effective area is always scaled along the frequency.
|
||||
|
||||
1. The Raman gain coefficient is properly scaled considering the overlapping of fiber effective area values scaled at
|
||||
the interacting frequencies. Essential change: In previous version the Raman gain coefficient depends only on
|
||||
the frequency offset.
|
||||
|
||||
1. The nonlinear coefficient ``'gamma'`` is properly scaled considering the refractive index n2 and the scaling
|
||||
effective area. Essential change: As the effective area, the nonlinear coefficient is always scaled along the
|
||||
frequency.
|
||||
|
||||
**power offset**: Power equalization now enables defining a power offset in transceiver library to represent
|
||||
the deviation from the general equalisation strategy defined in ROADMs.
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
"mode": [{
|
||||
"format": "100G",
|
||||
"baud_rate": 32.0e9,
|
||||
"tx_osnr": 35.0,
|
||||
"min_spacing": 50.0e9,
|
||||
"cost": 1,
|
||||
"OSNR": 10.0,
|
||||
"bit_rate": 100.0e9,
|
||||
"roll_off": 0.2,
|
||||
"equalization_offset_db": 0.0
|
||||
}, {
|
||||
"format": "200G",
|
||||
"baud_rate": 64.0e9,
|
||||
"tx_osnr": 35.0,
|
||||
"min_spacing": 75.0e9,
|
||||
"cost": 1,
|
||||
"OSNR": 13.0,
|
||||
"bit_rate": 200.0e9,
|
||||
"roll_off": 0.2,
|
||||
"equalization_offset_db": 1.76
|
||||
}
|
||||
]
|
||||
|
||||
v2.7
|
||||
====
|
||||
@@ -1,70 +0,0 @@
|
||||
gnpy\.core package
|
||||
==================
|
||||
|
||||
Submodules
|
||||
----------
|
||||
|
||||
gnpy\.core\.elements module
|
||||
---------------------------
|
||||
|
||||
.. automodule:: gnpy.core.elements
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
gnpy\.core\.execute module
|
||||
--------------------------
|
||||
|
||||
.. automodule:: gnpy.core.execute
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
gnpy\.core\.info module
|
||||
-----------------------
|
||||
|
||||
.. automodule:: gnpy.core.info
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
gnpy\.core\.network module
|
||||
--------------------------
|
||||
|
||||
.. automodule:: gnpy.core.network
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
gnpy\.core\.node module
|
||||
-----------------------
|
||||
|
||||
.. automodule:: gnpy.core.node
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
gnpy\.core\.units module
|
||||
------------------------
|
||||
|
||||
.. automodule:: gnpy.core.units
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
gnpy\.core\.utils module
|
||||
------------------------
|
||||
|
||||
.. automodule:: gnpy.core.utils
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: gnpy.core
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -1,17 +0,0 @@
|
||||
gnpy package
|
||||
============
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
|
||||
.. toctree::
|
||||
|
||||
gnpy.core
|
||||
|
||||
Module contents
|
||||
---------------
|
||||
|
||||
.. automodule:: gnpy
|
||||
:members:
|
||||
:undoc-members:
|
||||
:show-inheritance:
|
||||
@@ -1,7 +0,0 @@
|
||||
gnpy
|
||||
====
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 4
|
||||
|
||||
gnpy
|
||||
Binary file not shown.
@@ -1,11 +0,0 @@
|
||||
REGIONS = europe asia conus
|
||||
TARGETS = $(foreach region,$(REGIONS),coronet.$(region).json)
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
$(TARGETS): convert.py CORONET_Global_Topology.xls
|
||||
python $< -f $(subst .json,,$(subst coronet.,,$@)) > $@
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
-rm $(TARGETS) -f
|
||||
@@ -1,143 +0,0 @@
|
||||
{
|
||||
"networks": {
|
||||
"network": [
|
||||
{
|
||||
"network-types": {
|
||||
"tip-oopt-pse": {}
|
||||
},
|
||||
"network-id": "pt-to-pt",
|
||||
"node": [
|
||||
{
|
||||
"node-id": "M_KMA",
|
||||
"type":"roadm",
|
||||
"termination-point": [
|
||||
{
|
||||
"tp-id": "1-2-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"node-id": "T_CAS",
|
||||
"type":"roadm",
|
||||
"termination-point": [
|
||||
{
|
||||
"tp-id": "2-1-1"
|
||||
},
|
||||
{
|
||||
"tp-id": "2-3-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"node-id": "LA",
|
||||
"type":"ila",
|
||||
"termination-point": [
|
||||
{
|
||||
"tp-id": "3-2-1"
|
||||
},
|
||||
{
|
||||
"tp-id": "3-4-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"node-id": "SR",
|
||||
"type":"fused",
|
||||
"termination-point": [
|
||||
{
|
||||
"tp-id": "4-3-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"node-id": "C",
|
||||
"type":"ila",
|
||||
"termination-point": [
|
||||
{
|
||||
"tp-id": "5-6-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"node-id": "N_KBE",
|
||||
"type":"roadm",
|
||||
"termination-point": [
|
||||
{
|
||||
"tp-id": "6-5-1"
|
||||
},
|
||||
{
|
||||
"tp-id": "6-7-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"node-id": "N_KBA",
|
||||
"type":"roadm",
|
||||
"termination-point": [
|
||||
{
|
||||
"tp-id": "7-6-1"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"link": [
|
||||
{
|
||||
"link-id": "M_KMA,1-2-1,T_CAS,2-1-1",
|
||||
"source": {
|
||||
"source-node": "M_KMA",
|
||||
"source-tp": "1-2-1"
|
||||
}
|
||||
"destination": {
|
||||
"dest-node": "T_CAS",
|
||||
"dest-tp": "2-1-1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"link-id": "T_CAS,2-3-1,LA,3-2-1",
|
||||
"source": {
|
||||
"source-node": "T_CAS",
|
||||
"source-tp": "2-3-1"
|
||||
}
|
||||
"destination": {
|
||||
"dest-node": "LA",
|
||||
"dest-tp": "3-2-1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"link-id": "LA,3-4-1,SR,4-3-1",
|
||||
"source": {
|
||||
"source-node": "LA",
|
||||
"source-tp": "3-4-1"
|
||||
}
|
||||
"destination": {
|
||||
"dest-node": "SR",
|
||||
"dest-tp": "4-3-1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"link-id": "C,5-6-1,N_KBE,6-5-1",
|
||||
"source": {
|
||||
"source-node": "C",
|
||||
"source-tp": "5-6-1"
|
||||
}
|
||||
"destination": {
|
||||
"dest-node": "N_KBE",
|
||||
"dest-tp": "6-5-1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"link-id": "N_KBE,6-7-1,N_KBA,7-6-1",
|
||||
"source": {
|
||||
"source-node": "N_KBE",
|
||||
"source-tp": "6-7-1"
|
||||
}
|
||||
"destination": {
|
||||
"dest-node": "N_KBA",
|
||||
"dest-tp": "7-6-1"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
{
|
||||
"network_name": "pt to pt",
|
||||
"nodes_elements":
|
||||
[
|
||||
{
|
||||
"id":"M_KMA",
|
||||
"type":"ROADM",
|
||||
"metadata": {
|
||||
"city":"M",
|
||||
"region":"RLD",
|
||||
"latitude":0,
|
||||
"longitude":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":"T_CAS",
|
||||
"type":"ROADM",
|
||||
"metadata": {
|
||||
"city":"T",
|
||||
"region":"RLD",
|
||||
"latitude":0,
|
||||
"longitude":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":"LA",
|
||||
"type":"ILA",
|
||||
"metadata": {
|
||||
"city":"LA",
|
||||
"region":"RLD",
|
||||
"latitude":0,
|
||||
"longitude":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":"SR",
|
||||
"type":"fused",
|
||||
"metadata": {
|
||||
"city":"SR",
|
||||
"region":"RLD",
|
||||
"latitude":0,
|
||||
"longitude":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":"C",
|
||||
"type":"ILA",
|
||||
"metadata": {
|
||||
"city":"C",
|
||||
"region":"RLD",
|
||||
"latitude":0,
|
||||
"longitude":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":"N_KBE",
|
||||
"type":"ROADM",
|
||||
"metadata": {
|
||||
"city":"N",
|
||||
"region":"RLD",
|
||||
"latitude":0,
|
||||
"longitude":0
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":"N_KBA",
|
||||
"type":"ROADM",
|
||||
"metadata": {
|
||||
"city":"N",
|
||||
"region":"RLD",
|
||||
"latitude":0,
|
||||
"longitude":0
|
||||
}
|
||||
},
|
||||
],
|
||||
"OTS_elements":[
|
||||
{
|
||||
"id":1,
|
||||
"source_id":"M_KMA",
|
||||
"dest_id":"T_CAS",
|
||||
"parameters_cable":{
|
||||
"units":"km",
|
||||
"length":60,
|
||||
"id":"F060",
|
||||
"type":"G652"
|
||||
},
|
||||
"parameters_east":{
|
||||
"con_in":0.5,
|
||||
"con_out":0.5,
|
||||
"loss":16,
|
||||
"pmd":2,
|
||||
"fo_id":5
|
||||
},
|
||||
"parameters_west":{
|
||||
"con_in":0.5,
|
||||
"con_out":0.5,
|
||||
"loss":15,
|
||||
"pmd":2,
|
||||
"fo_id":6
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":2,
|
||||
"source_id":"T_CAS",
|
||||
"dest_id":"LA",
|
||||
"parameters_cable":{
|
||||
},
|
||||
"parameters_east":{
|
||||
},
|
||||
"parameters_west":{
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"source_id":"LA",
|
||||
"dest_id":"SR",
|
||||
"parameters_cable":{
|
||||
},
|
||||
"parameters_east":{
|
||||
},
|
||||
"parameters_west":{
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":3,
|
||||
"source_id":"SR",
|
||||
"dest_id":"C",
|
||||
"parameters_cable":{
|
||||
},
|
||||
"parameters_east":{
|
||||
},
|
||||
"parameters_west":{
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":5,
|
||||
"source_id":"C",
|
||||
"dest_id":"N_KBE",
|
||||
"parameters_cable":{
|
||||
},
|
||||
"parameters_east":{
|
||||
},
|
||||
"parameters_west":{
|
||||
}
|
||||
},
|
||||
{
|
||||
"id":6,
|
||||
"source_id":"N_KBE",
|
||||
"dest_id":"N_KBA",
|
||||
"parameters_cable":{
|
||||
},
|
||||
"parameters_east":{
|
||||
},
|
||||
"parameters_west":{
|
||||
}
|
||||
},
|
||||
]}
|
||||
@@ -1,162 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from sys import exit
|
||||
try:
|
||||
from xlrd import open_workbook
|
||||
except ModuleNotFoundError:
|
||||
exit('Required: `pip install xlrd`')
|
||||
from argparse import ArgumentParser
|
||||
from collections import namedtuple, Counter
|
||||
from itertools import chain
|
||||
from json import dumps
|
||||
from uuid import uuid4
|
||||
import math
|
||||
import numpy as np
|
||||
|
||||
output_json_file_name = 'coronet_conus_example.json'
|
||||
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')
|
||||
links_sheet = wb.sheet_by_name('Links')
|
||||
|
||||
# sanity check
|
||||
header = [x.value.strip() for x in nodes_sheet.row(4)]
|
||||
expected = ['City', 'State', 'Country', 'Region', 'Latitude', 'Longitude']
|
||||
if header != expected:
|
||||
raise ValueError(f'Malformed header on Nodes sheet: {header} != {expected}')
|
||||
|
||||
nodes = []
|
||||
for row in all_rows(nodes_sheet, start=5):
|
||||
nodes.append(Node(*(x.value for x in row)))
|
||||
|
||||
# sanity check
|
||||
header = [x.value.strip() for x in links_sheet.row(4)]
|
||||
expected = ['Node A', 'Node Z', 'Distance (km)']
|
||||
if header != expected:
|
||||
raise ValueError(f'Malformed header on Nodes sheet: {header} != {expected}')
|
||||
|
||||
links = []
|
||||
for row in all_rows(links_sheet, start=5):
|
||||
links.append(Link(*(x.value for x in row)))
|
||||
|
||||
# sanity check
|
||||
all_cities = Counter(n.city for n in nodes)
|
||||
if len(all_cities) != len(nodes):
|
||||
ValueError(f'Duplicate city: {all_cities}')
|
||||
if any(ln.from_city not in all_cities or
|
||||
ln.to_city not in all_cities for ln in links):
|
||||
ValueError(f'Bad link.')
|
||||
|
||||
return nodes, links
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('workbook', nargs='?', default='CORONET_Global_Topology.xls')
|
||||
parser.add_argument('-f', '--filter-region', action='append', default=[])
|
||||
|
||||
all_rows = lambda sh, start=0: (sh.row(x) for x in range(start, sh.nrows))
|
||||
|
||||
def midpoint(city_a, city_b):
|
||||
lats = city_a.latitude, city_b.latitude
|
||||
longs = city_a.longitude, city_b.longitude
|
||||
return {
|
||||
'latitude': sum(lats) / 2,
|
||||
'longitude': sum(longs) / 2,
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = parser.parse_args()
|
||||
nodes, links = parse_excel(args)
|
||||
|
||||
if args.filter_region:
|
||||
nodes = [n for n in nodes if n.region.lower() in args.filter_region]
|
||||
cities = {n.city for n in nodes}
|
||||
links = [lnk for lnk in links if lnk.from_city in cities and
|
||||
lnk.to_city in cities]
|
||||
cities = {lnk.from_city for lnk in links} | {lnk.to_city for lnk in links}
|
||||
nodes = [n for n in nodes if n.city in cities]
|
||||
|
||||
nodes_by_city = {n.city: n for n in nodes}
|
||||
|
||||
data = {
|
||||
'elements':
|
||||
[{'uid': f'trx {x.city}',
|
||||
'metadata': {'location': {'city': x.city,
|
||||
'region': x.region,
|
||||
'latitude': x.latitude,
|
||||
'longitude': x.longitude}},
|
||||
'type': 'Transceiver'}
|
||||
for x in nodes] +
|
||||
[{'uid': f'roadm {x.city}',
|
||||
'metadata': {'location': {'city': x.city,
|
||||
'region': x.region,
|
||||
'latitude': x.latitude,
|
||||
'longitude': x.longitude}},
|
||||
'type': 'Roadm'}
|
||||
for x in nodes] +
|
||||
[{'uid': f'fiber ({x.from_city} → {x.to_city})',
|
||||
'metadata': {'location': midpoint(nodes_by_city[x.from_city],
|
||||
nodes_by_city[x.to_city])},
|
||||
'type': 'Fiber',
|
||||
'params': {'length': round(x.distance, 3),
|
||||
'length_units': x.distance_units,
|
||||
'loss_coef': 0.2,
|
||||
'dispersion': 16.7E-6,
|
||||
'gamma': 1.27E-3}
|
||||
}
|
||||
for x in links],
|
||||
'connections':
|
||||
list(chain.from_iterable(zip( # put bidi next to each other
|
||||
[{'from_node': f'roadm {x.from_city}',
|
||||
'to_node': f'fiber ({x.from_city} → {x.to_city})'}
|
||||
for x in links],
|
||||
[{'from_node': f'fiber ({x.from_city} → {x.to_city})',
|
||||
'to_node': f'roadm {x.from_city}'}
|
||||
for x in links])))
|
||||
+
|
||||
list(chain.from_iterable(zip(
|
||||
[{'from_node': f'fiber ({x.from_city} → {x.to_city})',
|
||||
'to_node': f'roadm {x.to_city}'}
|
||||
for x in links],
|
||||
[{'from_node': f'roadm {x.to_city}',
|
||||
'to_node': f'fiber ({x.from_city} → {x.to_city})'}
|
||||
for x in links])))
|
||||
+
|
||||
list(chain.from_iterable(zip(
|
||||
[{'from_node': f'trx {x.city}',
|
||||
'to_node': f'roadm {x.city}'}
|
||||
for x in nodes],
|
||||
[{'from_node': f'roadm {x.city}',
|
||||
'to_node': f'trx {x.city}'}
|
||||
for x in nodes])))
|
||||
}
|
||||
|
||||
print(dumps(data, indent=2))
|
||||
with open(output_json_file_name,'w') as edfa_json_file:
|
||||
edfa_json_file.write(dumps(data, indent=2))
|
||||
@@ -1,542 +0,0 @@
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"uid": "Bangkok",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Bangkok",
|
||||
"region": "Asia",
|
||||
"latitude": 13.73,
|
||||
"longitude": 100.5
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Beijing",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Beijing",
|
||||
"region": "Asia",
|
||||
"latitude": 39.92999979,
|
||||
"longitude": 116.4000013
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Delhi",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Delhi",
|
||||
"region": "Asia",
|
||||
"latitude": 28.6700003,
|
||||
"longitude": 77.2099989
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Hong_Kong",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Hong_Kong",
|
||||
"region": "Asia",
|
||||
"latitude": 22.267,
|
||||
"longitude": 114.14
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Honolulu",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Honolulu",
|
||||
"region": "Asia",
|
||||
"latitude": 21.3199996,
|
||||
"longitude": -157.800003
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Mumbai",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Mumbai",
|
||||
"region": "Asia",
|
||||
"latitude": 18.9599987,
|
||||
"longitude": 72.8199999
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Seoul",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Seoul",
|
||||
"region": "Asia",
|
||||
"latitude": 37.56000108,
|
||||
"longitude": 126.9899988
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Shanghai",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Shanghai",
|
||||
"region": "Asia",
|
||||
"latitude": 31.23,
|
||||
"longitude": 121.47
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Singapore",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Singapore",
|
||||
"region": "Asia",
|
||||
"latitude": 1.299999907,
|
||||
"longitude": 103.8499992
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Sydney",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Sydney",
|
||||
"region": "Asia",
|
||||
"latitude": -33.86999896,
|
||||
"longitude": 151.2100066
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Taipei",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Taipei",
|
||||
"region": "Asia",
|
||||
"latitude": 25.0200005,
|
||||
"longitude": 121.449997
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Tokyo",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Tokyo",
|
||||
"region": "Asia",
|
||||
"latitude": 35.6699986,
|
||||
"longitude": 139.770004
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Bangkok \u2192 Delhi)",
|
||||
"metadata": {
|
||||
"length": 3505.95,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 21.20000015,
|
||||
"longitude": 88.85499945000001
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Bangkok \u2192 Hong_Kong)",
|
||||
"metadata": {
|
||||
"length": 2070.724,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 17.9985,
|
||||
"longitude": 107.32
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Beijing \u2192 Seoul)",
|
||||
"metadata": {
|
||||
"length": 1146.124,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 38.745000434999994,
|
||||
"longitude": 121.69500005
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Beijing \u2192 Shanghai)",
|
||||
"metadata": {
|
||||
"length": 1284.465,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 35.579999895,
|
||||
"longitude": 118.93500065
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Delhi \u2192 Mumbai)",
|
||||
"metadata": {
|
||||
"length": 1402.141,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 23.8149995,
|
||||
"longitude": 75.0149994
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Hong_Kong \u2192 Shanghai)",
|
||||
"metadata": {
|
||||
"length": 1480.406,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 26.7485,
|
||||
"longitude": 117.805
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Hong_Kong \u2192 Sydney)",
|
||||
"metadata": {
|
||||
"length": 8856.6,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": -5.801499479999999,
|
||||
"longitude": 132.67500330000001
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Hong_Kong \u2192 Taipei)",
|
||||
"metadata": {
|
||||
"length": 966.177,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 23.64350025,
|
||||
"longitude": 117.79499849999999
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Honolulu \u2192 Sydney)",
|
||||
"metadata": {
|
||||
"length": 9808.616,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": -6.274999679999999,
|
||||
"longitude": -3.294998199999995
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Honolulu \u2192 Taipei)",
|
||||
"metadata": {
|
||||
"length": 9767.013,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 23.17000005,
|
||||
"longitude": -18.175003000000004
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Mumbai \u2192 Singapore)",
|
||||
"metadata": {
|
||||
"length": 4692.708,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 10.1299993035,
|
||||
"longitude": 88.33499954999999
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Seoul \u2192 Tokyo)",
|
||||
"metadata": {
|
||||
"length": 1391.085,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 36.614999839999996,
|
||||
"longitude": 133.3800014
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Singapore \u2192 Sydney)",
|
||||
"metadata": {
|
||||
"length": 7562.331,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": -16.2849995265,
|
||||
"longitude": 127.5300029
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Taipei \u2192 Tokyo)",
|
||||
"metadata": {
|
||||
"length": 2537.345,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 30.344999549999997,
|
||||
"longitude": 130.6100005
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"from_node": "Bangkok",
|
||||
"to_node": "fiber (Bangkok \u2192 Delhi)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Bangkok \u2192 Delhi)",
|
||||
"to_node": "Bangkok"
|
||||
},
|
||||
{
|
||||
"from_node": "Bangkok",
|
||||
"to_node": "fiber (Bangkok \u2192 Hong_Kong)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Bangkok \u2192 Hong_Kong)",
|
||||
"to_node": "Bangkok"
|
||||
},
|
||||
{
|
||||
"from_node": "Beijing",
|
||||
"to_node": "fiber (Beijing \u2192 Seoul)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Beijing \u2192 Seoul)",
|
||||
"to_node": "Beijing"
|
||||
},
|
||||
{
|
||||
"from_node": "Beijing",
|
||||
"to_node": "fiber (Beijing \u2192 Shanghai)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Beijing \u2192 Shanghai)",
|
||||
"to_node": "Beijing"
|
||||
},
|
||||
{
|
||||
"from_node": "Delhi",
|
||||
"to_node": "fiber (Delhi \u2192 Mumbai)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Delhi \u2192 Mumbai)",
|
||||
"to_node": "Delhi"
|
||||
},
|
||||
{
|
||||
"from_node": "Hong_Kong",
|
||||
"to_node": "fiber (Hong_Kong \u2192 Shanghai)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Hong_Kong \u2192 Shanghai)",
|
||||
"to_node": "Hong_Kong"
|
||||
},
|
||||
{
|
||||
"from_node": "Hong_Kong",
|
||||
"to_node": "fiber (Hong_Kong \u2192 Sydney)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Hong_Kong \u2192 Sydney)",
|
||||
"to_node": "Hong_Kong"
|
||||
},
|
||||
{
|
||||
"from_node": "Hong_Kong",
|
||||
"to_node": "fiber (Hong_Kong \u2192 Taipei)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Hong_Kong \u2192 Taipei)",
|
||||
"to_node": "Hong_Kong"
|
||||
},
|
||||
{
|
||||
"from_node": "Honolulu",
|
||||
"to_node": "fiber (Honolulu \u2192 Sydney)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Honolulu \u2192 Sydney)",
|
||||
"to_node": "Honolulu"
|
||||
},
|
||||
{
|
||||
"from_node": "Honolulu",
|
||||
"to_node": "fiber (Honolulu \u2192 Taipei)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Honolulu \u2192 Taipei)",
|
||||
"to_node": "Honolulu"
|
||||
},
|
||||
{
|
||||
"from_node": "Mumbai",
|
||||
"to_node": "fiber (Mumbai \u2192 Singapore)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Mumbai \u2192 Singapore)",
|
||||
"to_node": "Mumbai"
|
||||
},
|
||||
{
|
||||
"from_node": "Seoul",
|
||||
"to_node": "fiber (Seoul \u2192 Tokyo)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Seoul \u2192 Tokyo)",
|
||||
"to_node": "Seoul"
|
||||
},
|
||||
{
|
||||
"from_node": "Singapore",
|
||||
"to_node": "fiber (Singapore \u2192 Sydney)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Singapore \u2192 Sydney)",
|
||||
"to_node": "Singapore"
|
||||
},
|
||||
{
|
||||
"from_node": "Taipei",
|
||||
"to_node": "fiber (Taipei \u2192 Tokyo)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Taipei \u2192 Tokyo)",
|
||||
"to_node": "Taipei"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Bangkok \u2192 Delhi)",
|
||||
"to_node": "Delhi"
|
||||
},
|
||||
{
|
||||
"from_node": "Delhi",
|
||||
"to_node": "fiber (Bangkok \u2192 Delhi)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Bangkok \u2192 Hong_Kong)",
|
||||
"to_node": "Hong_Kong"
|
||||
},
|
||||
{
|
||||
"from_node": "Hong_Kong",
|
||||
"to_node": "fiber (Bangkok \u2192 Hong_Kong)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Beijing \u2192 Seoul)",
|
||||
"to_node": "Seoul"
|
||||
},
|
||||
{
|
||||
"from_node": "Seoul",
|
||||
"to_node": "fiber (Beijing \u2192 Seoul)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Beijing \u2192 Shanghai)",
|
||||
"to_node": "Shanghai"
|
||||
},
|
||||
{
|
||||
"from_node": "Shanghai",
|
||||
"to_node": "fiber (Beijing \u2192 Shanghai)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Delhi \u2192 Mumbai)",
|
||||
"to_node": "Mumbai"
|
||||
},
|
||||
{
|
||||
"from_node": "Mumbai",
|
||||
"to_node": "fiber (Delhi \u2192 Mumbai)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Hong_Kong \u2192 Shanghai)",
|
||||
"to_node": "Shanghai"
|
||||
},
|
||||
{
|
||||
"from_node": "Shanghai",
|
||||
"to_node": "fiber (Hong_Kong \u2192 Shanghai)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Hong_Kong \u2192 Sydney)",
|
||||
"to_node": "Sydney"
|
||||
},
|
||||
{
|
||||
"from_node": "Sydney",
|
||||
"to_node": "fiber (Hong_Kong \u2192 Sydney)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Hong_Kong \u2192 Taipei)",
|
||||
"to_node": "Taipei"
|
||||
},
|
||||
{
|
||||
"from_node": "Taipei",
|
||||
"to_node": "fiber (Hong_Kong \u2192 Taipei)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Honolulu \u2192 Sydney)",
|
||||
"to_node": "Sydney"
|
||||
},
|
||||
{
|
||||
"from_node": "Sydney",
|
||||
"to_node": "fiber (Honolulu \u2192 Sydney)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Honolulu \u2192 Taipei)",
|
||||
"to_node": "Taipei"
|
||||
},
|
||||
{
|
||||
"from_node": "Taipei",
|
||||
"to_node": "fiber (Honolulu \u2192 Taipei)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Mumbai \u2192 Singapore)",
|
||||
"to_node": "Singapore"
|
||||
},
|
||||
{
|
||||
"from_node": "Singapore",
|
||||
"to_node": "fiber (Mumbai \u2192 Singapore)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Seoul \u2192 Tokyo)",
|
||||
"to_node": "Tokyo"
|
||||
},
|
||||
{
|
||||
"from_node": "Tokyo",
|
||||
"to_node": "fiber (Seoul \u2192 Tokyo)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Singapore \u2192 Sydney)",
|
||||
"to_node": "Sydney"
|
||||
},
|
||||
{
|
||||
"from_node": "Sydney",
|
||||
"to_node": "fiber (Singapore \u2192 Sydney)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Taipei \u2192 Tokyo)",
|
||||
"to_node": "Tokyo"
|
||||
},
|
||||
{
|
||||
"from_node": "Tokyo",
|
||||
"to_node": "fiber (Taipei \u2192 Tokyo)"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,582 +0,0 @@
|
||||
{
|
||||
"elements": [
|
||||
{
|
||||
"uid": "Amsterdam",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Amsterdam",
|
||||
"region": "Europe",
|
||||
"latitude": 52.3699996,
|
||||
"longitude": 4.88999915
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Berlin",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Berlin",
|
||||
"region": "Europe",
|
||||
"latitude": 52.520002,
|
||||
"longitude": 13.379995
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Brussels",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Brussels",
|
||||
"region": "Europe",
|
||||
"latitude": 50.830002,
|
||||
"longitude": 4.330002
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Bucharest",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Bucharest",
|
||||
"region": "Europe",
|
||||
"latitude": 44.44,
|
||||
"longitude": 26.1
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Frankfurt",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Frankfurt",
|
||||
"region": "Europe",
|
||||
"latitude": 50.1199992,
|
||||
"longitude": 8.68000104
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Istanbul",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Istanbul",
|
||||
"region": "Europe",
|
||||
"latitude": 41.1,
|
||||
"longitude": 29.0
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "London",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "London",
|
||||
"region": "Europe",
|
||||
"latitude": 51.5200005,
|
||||
"longitude": -0.100000296
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Madrid",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Madrid",
|
||||
"region": "Europe",
|
||||
"latitude": 40.419998,
|
||||
"longitude": -3.7100002
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Paris",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Paris",
|
||||
"region": "Europe",
|
||||
"latitude": 48.86,
|
||||
"longitude": 2.3399995
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Rome",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Rome",
|
||||
"region": "Europe",
|
||||
"latitude": 41.8899996,
|
||||
"longitude": 12.5000004
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Vienna",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Vienna",
|
||||
"region": "Europe",
|
||||
"latitude": 48.2200024,
|
||||
"longitude": 16.3700005
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Warsaw",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Warsaw",
|
||||
"region": "Europe",
|
||||
"latitude": 52.2599987,
|
||||
"longitude": 21.0200005
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "Zurich",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Zurich",
|
||||
"region": "Europe",
|
||||
"latitude": 47.3800015,
|
||||
"longitude": 8.5399996
|
||||
}
|
||||
},
|
||||
"type": "Transceiver"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Amsterdam \u2192 Berlin)",
|
||||
"metadata": {
|
||||
"length": 690.608,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 52.4450008,
|
||||
"longitude": 9.134997075
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Amsterdam \u2192 Brussels)",
|
||||
"metadata": {
|
||||
"length": 210.729,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 51.600000800000004,
|
||||
"longitude": 4.610000575000001
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Amsterdam \u2192 Frankfurt)",
|
||||
"metadata": {
|
||||
"length": 436.324,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 51.2449994,
|
||||
"longitude": 6.785000095000001
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Berlin \u2192 Warsaw)",
|
||||
"metadata": {
|
||||
"length": 623.015,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 52.390000349999994,
|
||||
"longitude": 17.199997749999998
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Brussels \u2192 London)",
|
||||
"metadata": {
|
||||
"length": 381.913,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 51.17500125,
|
||||
"longitude": 2.115000852
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Bucharest \u2192 Istanbul)",
|
||||
"metadata": {
|
||||
"length": 528.58,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 42.769999999999996,
|
||||
"longitude": 27.55
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Bucharest \u2192 Warsaw)",
|
||||
"metadata": {
|
||||
"length": 1136.2,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 48.34999935,
|
||||
"longitude": 23.56000025
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Frankfurt \u2192 Vienna)",
|
||||
"metadata": {
|
||||
"length": 717.001,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 49.1700008,
|
||||
"longitude": 12.52500077
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Istanbul \u2192 Rome)",
|
||||
"metadata": {
|
||||
"length": 1650.406,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 41.4949998,
|
||||
"longitude": 20.7500002
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (London \u2192 Paris)",
|
||||
"metadata": {
|
||||
"length": 411.692,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 50.19000025,
|
||||
"longitude": 1.1199996019999998
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Madrid \u2192 Paris)",
|
||||
"metadata": {
|
||||
"length": 1263.619,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 44.639999,
|
||||
"longitude": -0.6850003500000001
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Madrid \u2192 Zurich)",
|
||||
"metadata": {
|
||||
"length": 1497.358,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 43.89999975,
|
||||
"longitude": 2.4149997
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Rome \u2192 Vienna)",
|
||||
"metadata": {
|
||||
"length": 920.026,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 45.055001000000004,
|
||||
"longitude": 14.43500045
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Rome \u2192 Zurich)",
|
||||
"metadata": {
|
||||
"length": 823.4,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 44.63500055,
|
||||
"longitude": 10.52
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
},
|
||||
{
|
||||
"uid": "fiber (Vienna \u2192 Warsaw)",
|
||||
"metadata": {
|
||||
"length": 669.297,
|
||||
"units": "km",
|
||||
"location": {
|
||||
"latitude": 50.24000055,
|
||||
"longitude": 18.6950005
|
||||
}
|
||||
},
|
||||
"type": "Fiber"
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"from_node": "Amsterdam",
|
||||
"to_node": "fiber (Amsterdam \u2192 Berlin)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Amsterdam \u2192 Berlin)",
|
||||
"to_node": "Amsterdam"
|
||||
},
|
||||
{
|
||||
"from_node": "Amsterdam",
|
||||
"to_node": "fiber (Amsterdam \u2192 Brussels)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Amsterdam \u2192 Brussels)",
|
||||
"to_node": "Amsterdam"
|
||||
},
|
||||
{
|
||||
"from_node": "Amsterdam",
|
||||
"to_node": "fiber (Amsterdam \u2192 Frankfurt)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Amsterdam \u2192 Frankfurt)",
|
||||
"to_node": "Amsterdam"
|
||||
},
|
||||
{
|
||||
"from_node": "Berlin",
|
||||
"to_node": "fiber (Berlin \u2192 Warsaw)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Berlin \u2192 Warsaw)",
|
||||
"to_node": "Berlin"
|
||||
},
|
||||
{
|
||||
"from_node": "Brussels",
|
||||
"to_node": "fiber (Brussels \u2192 London)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Brussels \u2192 London)",
|
||||
"to_node": "Brussels"
|
||||
},
|
||||
{
|
||||
"from_node": "Bucharest",
|
||||
"to_node": "fiber (Bucharest \u2192 Istanbul)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Bucharest \u2192 Istanbul)",
|
||||
"to_node": "Bucharest"
|
||||
},
|
||||
{
|
||||
"from_node": "Bucharest",
|
||||
"to_node": "fiber (Bucharest \u2192 Warsaw)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Bucharest \u2192 Warsaw)",
|
||||
"to_node": "Bucharest"
|
||||
},
|
||||
{
|
||||
"from_node": "Frankfurt",
|
||||
"to_node": "fiber (Frankfurt \u2192 Vienna)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Frankfurt \u2192 Vienna)",
|
||||
"to_node": "Frankfurt"
|
||||
},
|
||||
{
|
||||
"from_node": "Istanbul",
|
||||
"to_node": "fiber (Istanbul \u2192 Rome)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Istanbul \u2192 Rome)",
|
||||
"to_node": "Istanbul"
|
||||
},
|
||||
{
|
||||
"from_node": "London",
|
||||
"to_node": "fiber (London \u2192 Paris)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (London \u2192 Paris)",
|
||||
"to_node": "London"
|
||||
},
|
||||
{
|
||||
"from_node": "Madrid",
|
||||
"to_node": "fiber (Madrid \u2192 Paris)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Madrid \u2192 Paris)",
|
||||
"to_node": "Madrid"
|
||||
},
|
||||
{
|
||||
"from_node": "Madrid",
|
||||
"to_node": "fiber (Madrid \u2192 Zurich)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Madrid \u2192 Zurich)",
|
||||
"to_node": "Madrid"
|
||||
},
|
||||
{
|
||||
"from_node": "Rome",
|
||||
"to_node": "fiber (Rome \u2192 Vienna)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Rome \u2192 Vienna)",
|
||||
"to_node": "Rome"
|
||||
},
|
||||
{
|
||||
"from_node": "Rome",
|
||||
"to_node": "fiber (Rome \u2192 Zurich)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Rome \u2192 Zurich)",
|
||||
"to_node": "Rome"
|
||||
},
|
||||
{
|
||||
"from_node": "Vienna",
|
||||
"to_node": "fiber (Vienna \u2192 Warsaw)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Vienna \u2192 Warsaw)",
|
||||
"to_node": "Vienna"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Amsterdam \u2192 Berlin)",
|
||||
"to_node": "Berlin"
|
||||
},
|
||||
{
|
||||
"from_node": "Berlin",
|
||||
"to_node": "fiber (Amsterdam \u2192 Berlin)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Amsterdam \u2192 Brussels)",
|
||||
"to_node": "Brussels"
|
||||
},
|
||||
{
|
||||
"from_node": "Brussels",
|
||||
"to_node": "fiber (Amsterdam \u2192 Brussels)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Amsterdam \u2192 Frankfurt)",
|
||||
"to_node": "Frankfurt"
|
||||
},
|
||||
{
|
||||
"from_node": "Frankfurt",
|
||||
"to_node": "fiber (Amsterdam \u2192 Frankfurt)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Berlin \u2192 Warsaw)",
|
||||
"to_node": "Warsaw"
|
||||
},
|
||||
{
|
||||
"from_node": "Warsaw",
|
||||
"to_node": "fiber (Berlin \u2192 Warsaw)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Brussels \u2192 London)",
|
||||
"to_node": "London"
|
||||
},
|
||||
{
|
||||
"from_node": "London",
|
||||
"to_node": "fiber (Brussels \u2192 London)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Bucharest \u2192 Istanbul)",
|
||||
"to_node": "Istanbul"
|
||||
},
|
||||
{
|
||||
"from_node": "Istanbul",
|
||||
"to_node": "fiber (Bucharest \u2192 Istanbul)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Bucharest \u2192 Warsaw)",
|
||||
"to_node": "Warsaw"
|
||||
},
|
||||
{
|
||||
"from_node": "Warsaw",
|
||||
"to_node": "fiber (Bucharest \u2192 Warsaw)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Frankfurt \u2192 Vienna)",
|
||||
"to_node": "Vienna"
|
||||
},
|
||||
{
|
||||
"from_node": "Vienna",
|
||||
"to_node": "fiber (Frankfurt \u2192 Vienna)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Istanbul \u2192 Rome)",
|
||||
"to_node": "Rome"
|
||||
},
|
||||
{
|
||||
"from_node": "Rome",
|
||||
"to_node": "fiber (Istanbul \u2192 Rome)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (London \u2192 Paris)",
|
||||
"to_node": "Paris"
|
||||
},
|
||||
{
|
||||
"from_node": "Paris",
|
||||
"to_node": "fiber (London \u2192 Paris)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Madrid \u2192 Paris)",
|
||||
"to_node": "Paris"
|
||||
},
|
||||
{
|
||||
"from_node": "Paris",
|
||||
"to_node": "fiber (Madrid \u2192 Paris)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Madrid \u2192 Zurich)",
|
||||
"to_node": "Zurich"
|
||||
},
|
||||
{
|
||||
"from_node": "Zurich",
|
||||
"to_node": "fiber (Madrid \u2192 Zurich)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Rome \u2192 Vienna)",
|
||||
"to_node": "Vienna"
|
||||
},
|
||||
{
|
||||
"from_node": "Vienna",
|
||||
"to_node": "fiber (Rome \u2192 Vienna)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Rome \u2192 Zurich)",
|
||||
"to_node": "Zurich"
|
||||
},
|
||||
{
|
||||
"from_node": "Zurich",
|
||||
"to_node": "fiber (Rome \u2192 Zurich)"
|
||||
},
|
||||
{
|
||||
"from_node": "fiber (Vienna \u2192 Warsaw)",
|
||||
"to_node": "Warsaw"
|
||||
},
|
||||
{
|
||||
"from_node": "Warsaw",
|
||||
"to_node": "fiber (Vienna \u2192 Warsaw)"
|
||||
}
|
||||
]
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,8 +0,0 @@
|
||||
-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
|
||||
@@ -1,8 +0,0 @@
|
||||
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
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"params": {
|
||||
"dfg": [25.13596985, 25.11822814, 25.09542133, 25.06245771, 25.02602765, 24.99637953, 24.98167255, 24.97530668, 24.98320726, 24.99718565, 25.01757247, 25.03832781, 25.05495585, 25.0670719, 25.07091411, 25.07094365, 25.07114324, 25.07533627, 25.08731018, 25.10313936, 25.12276204, 25.14239479, 25.15945633, 25.17392704, 25.17673767, 25.17037141, 25.15216254, 25.1311431, 25.10802335, 25.08548777, 25.06916675, 25.05848176, 25.05447313, 25.05154441, 25.04946059, 25.04717849, 25.04551656, 25.04467649, 25.0407292, 25.03285408, 25.0234883, 25.01659234, 25.01332136, 25.01123434, 25.01030015, 25.00936548, 25.00873964, 25.00842535, 25.00696466, 25.0040431, 25.00070998, 24.9984232, 24.99306332, 24.98352421, 24.97125103, 24.96038108, 24.94888721, 24.93531489, 24.92131927, 24.90898697, 24.89896514, 24.88958463, 24.8808387, 24.87210092, 24.86462026, 24.85839773, 24.85445838, 24.85155443, 24.85176601, 24.85408014, 24.85909624, 24.86474458, 24.87203486, 24.8803652, 24.88910669, 24.89721313, 24.90282604, 24.9065669, 24.9086508, 24.91093944, 24.91343079, 24.91592344, 24.92155351, 24.93031861, 24.94052812, 24.94904669, 24.95757123, 24.96781845, 24.98180093, 24.99782686, 25.01393183, 25.02809846, 25.04032575, 25.05256981, 25.06479701, 25.07704697],
|
||||
"dgt": [2.714526681131686, 2.705443819238505, 2.6947834587664494, 2.6841217449620203, 2.6681935771243177, 2.6521732021128046, 2.630396440815385, 2.602860350286428, 2.5696460593920065, 2.5364027376452056, 2.499446286796604, 2.4587748041127506, 2.414398437185221, 2.3699990328716107, 2.322373696229342, 2.271520771371253, 2.2174389328192197, 2.16337565384239, 2.1183028432496016, 2.082225099873648, 2.055100772005235, 2.0279625371819305, 2.0008103857988204, 1.9736443063300082, 1.9482128147680253, 1.9245345552113182, 1.9026104247588487, 1.8806927939516411, 1.862235672444246, 1.847275503201129, 1.835814081380705, 1.824381436842932, 1.8139629377087627, 1.8045606557581335, 1.7961751115773796, 1.7877868031023945, 1.7793941781790852, 1.7709972329654864, 1.7625959636196327, 1.7541903672600494, 1.7459181197626403, 1.737780757913635, 1.7297783508684146, 1.7217732861435076, 1.7137640932265894, 1.7057507692361864, 1.6918150918099673, 1.6719047669939942, 1.6460167077689267, 1.6201194134191075, 1.5986915141218316, 1.5817353179379183, 1.569199764184379, 1.5566577309558969, 1.545374152761467, 1.5353620432989845, 1.5266220576235803, 1.5178910621476225, 1.5097346239790443, 1.502153039909686, 1.495145456062699, 1.488134243479226, 1.48111939735681, 1.474100442252211, 1.4670307626366115, 1.4599103316162523, 1.45273959485914, 1.445565137158368, 1.4340878115214444, 1.418273806730323, 1.3981208704326855, 1.3779439775587023, 1.3598972673004606, 1.3439818461440451, 1.3301807335621048, 1.316383926863083, 1.3040618749785347, 1.2932153453410835, 1.2838336236692311, 1.2744470198196236, 1.2650555289898042, 1.2556591482982988, 1.2428104897182262, 1.2264996957264114, 1.2067249615595257, 1.1869318618366975, 1.1672278304018044, 1.1476135933863398, 1.1280891949729075, 1.108555289615659, 1.0895983485572227, 1.0712204022764056, 1.0534217504465226, 1.0356155337864215, 1.017807767853702, 1.0],
|
||||
"nf_fit_coeff": [0.000168241, 0.0469961, 0.0359549, 5.82851],
|
||||
"nf_ripple": [-0.315374332, -0.315374332, -0.3154009157100272, -0.3184914611751095, -0.32158358425400546, -0.3246772861549999, -0.32762368641496226, -0.3205413846123276, -0.31345546385118733, -0.3063659213569748, -0.29920267890990127, -0.27061972852631744, -0.24202215770774693, -0.21340995523361256, -0.18478227130158695, -0.14809761118389625, -0.11139416731807622, -0.07467192527357988, -0.038026748965679924, -0.019958469399422092, -0.0018809287980157928, 0.01620587996057356, 0.03430196400570967, 0.05240733047405406, 0.07052198650959736, 0.079578036683472, 0.08854664736190952, 0.0975198632319653, 0.10649768784154924, 0.0977413804499074, 0.08880343717266004, 0.07986089973284587, 0.0709137645874038, 0.06333589274056531, 0.055756212252058776, 0.04817263174786321, 0.04058514821716236, 0.03338159167571013, 0.026178308595650738, 0.018971315351761126, 0.011760609076833628, 0.01695029492275999, 0.02227499135770144, 0.02760243318910433, 0.03293262254079026, 0.038265561538776145, 0.04360125231127117, 0.03485699074348155, 0.025991055149117932, 0.017120541224980364, 0.008275758735920322, 0.0019423214065246042, -0.004394389017104359, -0.010734375072893196, -0.017077639301414434, -0.02467970289957285, -0.03229797040382168, -0.03992018009047725, -0.04753456632753024, -0.049234003141433724, -0.05093432003654719, -0.05263551769669225, -0.05433759680640246, -0.0560405580509193, -0.057718452237076875, -0.056840590379175944, -0.055962273198734966, -0.05508350034141658, -0.054204271452516814, -0.05839608872695511, -0.06262733016971533, -0.0668607690892037, -0.07090173625606945, -0.05209609730905224, -0.03328068412141294, -0.014455489070928059, 0.004315038757905716, 0.014839202394482527, 0.025368841662503576, 0.03590396083646565, 0.0464445641953214, 0.05699065602246746, 0.06754224060577406, 0.10002709623672751, 0.13258013095133617, 0.1651501336277331, 0.1977371175359939, 0.23194802687829724, 0.26618779883837107, 0.3004454365808535, 0.33472095409250663, 0.35929034770587287, 0.38384389188855605, 0.40841026111391787, 0.43298946543290784, 0.43298946543290784],
|
||||
"frequencies": []
|
||||
}
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
{
|
||||
"network_name": "EDFA Example Network - P2P",
|
||||
"elements": [{
|
||||
"uid": "Site A",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site A",
|
||||
"region": "",
|
||||
"latitude": 0,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1",
|
||||
"type": "Fiber",
|
||||
"params": {
|
||||
"length": 80,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"dispersion": 16.7E-6,
|
||||
"gamma": 1.27E-3
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": 1,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Edfa1",
|
||||
"type": "Edfa",
|
||||
"operational": {
|
||||
"gain_target": 16,
|
||||
"tilt_target": 0
|
||||
},
|
||||
"config_from_json": "edfa_config.json",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": 2,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Site B",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site B",
|
||||
"region": "",
|
||||
"latitude": 3,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
],
|
||||
"connections": [{
|
||||
"from_node": "Site A",
|
||||
"to_node": "Span1"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1",
|
||||
"to_node": "Edfa1"
|
||||
},
|
||||
{
|
||||
"from_node": "Edfa1",
|
||||
"to_node": "Site B"
|
||||
}
|
||||
|
||||
]
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
from gnpy.core.utils import (load_json,
|
||||
itufs,
|
||||
freq2wavelength,
|
||||
lin2db,
|
||||
db2lin)
|
||||
from gnpy.core import network
|
||||
|
||||
topology = load_json('edfa_example_network.json')
|
||||
nw = network.network_from_json(topology)
|
||||
pch2d_legend_data = np.loadtxt('Pchan2DLegend.txt')
|
||||
pch2d = np.loadtxt('Pchan2D.txt')
|
||||
|
||||
ch_spacing = 0.05
|
||||
fc = itufs(ch_spacing)
|
||||
lc = freq2wavelength(fc) / 1000
|
||||
nchan = np.arange(len(lc))
|
||||
df = np.ones(len(lc)) * ch_spacing
|
||||
|
||||
edfa1 = [n for n in nw.nodes() if n.uid == 'Edfa1'][0]
|
||||
edfa1.gain_target = 20.0
|
||||
edfa1.tilt_target = -0.7
|
||||
edfa1.calc_nf()
|
||||
|
||||
results = []
|
||||
for Pin in pch2d:
|
||||
chgain = edfa1.gain_profile(Pin)
|
||||
pase = edfa1.noise_profile(chgain, fc, df)
|
||||
pout = lin2db(db2lin(Pin + chgain) + db2lin(pase))
|
||||
results.append(pout)
|
||||
|
||||
# Generate legend text
|
||||
|
||||
pch2d_legend = []
|
||||
for ea in pch2d_legend_data:
|
||||
s = ''.join([chr(xx) for xx in ea.astype(dtype=int)]).strip()
|
||||
pch2d_legend.append(s)
|
||||
|
||||
# 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()
|
||||
for result in results:
|
||||
plt.plot(nchan, result, '.-', lw=2)
|
||||
plt.title('Output Power w/ 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)
|
||||
plt.show()
|
||||
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"gain_flatmax": 25,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_fit_coeff": "pNFfit3.txt",
|
||||
"nf_ripple": "NFR_96.txt",
|
||||
"dfg": "DFG_96.txt",
|
||||
"dgt": "DGT_96.txt",
|
||||
"nf_model":
|
||||
{
|
||||
"enabled": true,
|
||||
"nf_min": 5.8,
|
||||
"nf_max": 10
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
-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
|
||||
@@ -1,8 +0,0 @@
|
||||
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
|
||||
@@ -1,301 +0,0 @@
|
||||
#!/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)
|
||||
plt.show()
|
||||
@@ -1,164 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Created on Tue Jan 30 12:32:00 2018
|
||||
|
||||
@author: jeanluc-auge
|
||||
@comments about amplifier input files from Brian Taylor & Dave Boertjes
|
||||
|
||||
update an existing json file with all the 96ch txt files for a given amplifier type
|
||||
amplifier type 'OA_type1' is hard coded but can be modified and other types added
|
||||
returns an updated amplifier json file: output_json_file_name = 'edfa_config.json'
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import numpy as np
|
||||
from gnpy.core.utils import lin2db, db2lin
|
||||
|
||||
"""amplifier file names
|
||||
convert a set of amplifier files + input json definiton file into a valid edfa_json_file:
|
||||
nf_fit_coeff: NF polynomial coefficients txt file (optional)
|
||||
nf_ripple: NF ripple excursion txt file
|
||||
dfg: gain txt file
|
||||
dgt: dynamic gain txt file
|
||||
input json file in argument (defult = 'OA.json')
|
||||
the json input file should have the following fields:
|
||||
{
|
||||
"gain_flatmax": 25,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_fit_coeff": "pNFfit3.txt",
|
||||
"nf_ripple": "NFR_96.txt",
|
||||
"dfg": "DFG_96.txt",
|
||||
"dgt": "DGT_96.txt",
|
||||
"nf_model":
|
||||
{
|
||||
"enabled": true,
|
||||
"nf_min": 5.8,
|
||||
"nf_max": 10
|
||||
}
|
||||
}
|
||||
gain_flat = max flat gain (dB)
|
||||
gain_min = min gain (dB) : will consider an input VOA if below (TBD vs throwing an exception)
|
||||
p_max = max power (dBm)
|
||||
nf_fit = boolean (True, False) :
|
||||
if False nf_fit_coeff are ignored and nf_model fields are used
|
||||
"""
|
||||
|
||||
input_json_file_name = "OA.json" #default path
|
||||
output_json_file_name = "edfa_config.json"
|
||||
param_field ="params"
|
||||
gain_min_field = "gain_min"
|
||||
gain_max_field = "gain_flatmax"
|
||||
gain_ripple_field = "dfg"
|
||||
nf_ripple_field = "nf_ripple"
|
||||
nf_fit_coeff = "nf_fit_coeff"
|
||||
nf_model_field = "nf_model"
|
||||
nf_model_enabled_field = "enabled"
|
||||
nf_min_field ="nf_min"
|
||||
nf_max_field = "nf_max"
|
||||
|
||||
def read_file(field, file_name):
|
||||
"""read and format the 96 channels txt files describing the amplifier NF and ripple
|
||||
convert dfg into gain ripple by removing the mean component
|
||||
"""
|
||||
|
||||
#with open(path + file_name,'r') as this_file:
|
||||
# data = this_file.read()
|
||||
#data.strip()
|
||||
#data = re.sub(r"([0-9])([ ]{1,3})([0-9-+])",r"\1,\3",data)
|
||||
#data = list(data.split(","))
|
||||
#data = [float(x) for x in data]
|
||||
data = np.loadtxt(file_name)
|
||||
if field == gain_ripple_field or field == nf_ripple_field:
|
||||
#consider ripple excursion only to avoid redundant information
|
||||
#because the max flat_gain is already given by the 'gain_flat' field in json
|
||||
#remove the mean component
|
||||
data = data - data.mean()
|
||||
data = data.tolist()
|
||||
return data
|
||||
|
||||
def nf_model(amp_dict):
|
||||
if amp_dict[nf_model_field][nf_model_enabled_field] == True:
|
||||
gain_min = amp_dict[gain_min_field]
|
||||
gain_max = amp_dict[gain_max_field]
|
||||
nf_min = amp_dict[nf_model_field][nf_min_field]
|
||||
nf_max = amp_dict[nf_model_field][nf_max_field]
|
||||
#use NF estimation model based on NFmin and NFmax in json OA file
|
||||
delta_p = 5 #max power dB difference between 1st and 2nd stage coils
|
||||
#dB g1a = (1st stage gain) - (internal voa attenuation)
|
||||
g1a_min = gain_min - (gain_max-gain_min) - delta_p
|
||||
g1a_max = gain_max - delta_p
|
||||
#nf1 and nf2 are the nf of the 1st and 2nd stage coils
|
||||
#calculate nf1 and nf2 values that solve nf_[min/max] = nf1 + nf2 / g1a[min/max]
|
||||
nf2 = lin2db((db2lin(nf_min) - db2lin(nf_max)) / (1/db2lin(g1a_max)-1/db2lin(g1a_min)))
|
||||
nf1 = lin2db(db2lin(nf_min)- db2lin(nf2)/db2lin(g1a_max)) #expression (1)
|
||||
|
||||
""" now checking and recalculating the results:
|
||||
recalculate delta_p to check it is within [1-6] boundaries
|
||||
This is to check that the nf_min and nf_max values from the json file
|
||||
make sense. If not a warning is printed """
|
||||
if nf1 < 4:
|
||||
print('1st coil nf calculated value {} is too low: revise inputs'.format(nf1))
|
||||
if nf2 < nf1 + 0.3 or nf2 > nf1 + 2:
|
||||
"""nf2 should be with [nf1+0.5 - nf1 +2] boundaries
|
||||
there shouldn't be very high nf differences between 2 coils
|
||||
=> recalculate delta_p
|
||||
"""
|
||||
nf2 = max(nf2, nf1+0.3)
|
||||
nf2 = min(nf2, nf1+2)
|
||||
g1a_max = lin2db(db2lin(nf2) / (db2lin(nf_min) - db2lin(nf1))) #use expression (1)
|
||||
delta_p = gain_max - g1a_max
|
||||
g1a_min = gain_min - (gain_max-gain_min) - delta_p
|
||||
if delta_p < 1 or delta_p > 6:
|
||||
#delta_p should be > 1dB and < 6dB => consider user warning if not
|
||||
print('1st coil vs 2nd coil calculated DeltaP {} is not valid: revise inputs'
|
||||
.format(delta_p))
|
||||
#check the calculated values for nf1 & nf2:
|
||||
nf_min_calc = lin2db(db2lin(nf1) + db2lin(nf2)/db2lin(g1a_max))
|
||||
nf_max_calc = lin2db(db2lin(nf1) + db2lin(nf2)/db2lin(g1a_min))
|
||||
if (abs(nf_min_calc-nf_min) > 0.01) or (abs(nf_max_calc-nf_max) > 0.01):
|
||||
print('nf model calculation failed with nf_min {} and nf_max {} calculated'
|
||||
.format(nf_min_calc, nf_max_calc))
|
||||
print('do not use the generated edfa_config.json file')
|
||||
else :
|
||||
(nf1, nf2, delta_p) = (0, 0, 0)
|
||||
|
||||
return (nf1, nf2, delta_p)
|
||||
|
||||
def input_json(path):
|
||||
"""read the json input file and add all the 96 channels txt files
|
||||
create the output json file with output_json_file_name"""
|
||||
with open(path,'r') as edfa_json_file:
|
||||
amp_text = edfa_json_file.read()
|
||||
amp_dict = json.loads(amp_text)
|
||||
|
||||
for k, v in amp_dict.items():
|
||||
if re.search(r'.txt$',str(v)) :
|
||||
amp_dict[k] = read_file(k, v)
|
||||
|
||||
#calculate nf of 1st and 2nd coil for the nf_model if 'enabled'==true
|
||||
(nf1, nf2, delta_p) = nf_model(amp_dict)
|
||||
#rename nf_min and nf_max in nf1 and nf2 after the nf model calculation:
|
||||
del amp_dict[nf_model_field][nf_min_field]
|
||||
del amp_dict[nf_model_field][nf_max_field]
|
||||
amp_dict[nf_model_field]['nf1'] = nf1
|
||||
amp_dict[nf_model_field]['nf2'] = nf2
|
||||
amp_dict[nf_model_field]['delta_p'] = delta_p
|
||||
#rename dfg into gain_ripple after removing the average part:
|
||||
amp_dict['gain_ripple'] = amp_dict.pop(gain_ripple_field)
|
||||
|
||||
new_amp_dict = {}
|
||||
new_amp_dict[param_field] = amp_dict
|
||||
amp_text = json.dumps(new_amp_dict, indent=4)
|
||||
#print(amp_text)
|
||||
with open(output_json_file_name,'w') as edfa_json_file:
|
||||
edfa_json_file.write(amp_text)
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) == 2:
|
||||
path = sys.argv[1]
|
||||
else:
|
||||
path = input_json_file_name
|
||||
input_json(path)
|
||||
@@ -1,313 +0,0 @@
|
||||
{
|
||||
"params": {
|
||||
"gain_flatmax": 25,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"nf_fit_coeff": [
|
||||
0.000168241,
|
||||
0.0469961,
|
||||
0.0359549,
|
||||
5.82851
|
||||
],
|
||||
"nf_ripple": [
|
||||
-0.3110761646066259,
|
||||
-0.3110761646066259,
|
||||
-0.31110274831665313,
|
||||
-0.31419329378173544,
|
||||
-0.3172854168606314,
|
||||
-0.32037911876162584,
|
||||
-0.3233255190215882,
|
||||
-0.31624321721895354,
|
||||
-0.30915729645781326,
|
||||
-0.30206775396360075,
|
||||
-0.2949045115165272,
|
||||
-0.26632156113294336,
|
||||
-0.23772399031437283,
|
||||
-0.20911178784023846,
|
||||
-0.18048410390821285,
|
||||
-0.14379944379052215,
|
||||
-0.10709599992470213,
|
||||
-0.07037375788020579,
|
||||
-0.03372858157230583,
|
||||
-0.015660302006048,
|
||||
0.0024172385953583004,
|
||||
0.020504047353947653,
|
||||
0.03860013139908377,
|
||||
0.05670549786742816,
|
||||
0.07482015390297145,
|
||||
0.0838762040768461,
|
||||
0.09284481475528361,
|
||||
0.1018180306253394,
|
||||
0.11079585523492333,
|
||||
0.1020395478432815,
|
||||
0.09310160456603413,
|
||||
0.08415906712621996,
|
||||
0.07521193198077789,
|
||||
0.0676340601339394,
|
||||
0.06005437964543287,
|
||||
0.052470799141237305,
|
||||
0.044883315610536455,
|
||||
0.037679759069084225,
|
||||
0.03047647598902483,
|
||||
0.02326948274513522,
|
||||
0.01605877647020772,
|
||||
0.021248462316134083,
|
||||
0.02657315875107553,
|
||||
0.03190060058247842,
|
||||
0.03723078993416436,
|
||||
0.04256372893215024,
|
||||
0.047899419704645264,
|
||||
0.03915515813685565,
|
||||
0.030289222542492025,
|
||||
0.021418708618354456,
|
||||
0.012573926129294415,
|
||||
0.006240488799898697,
|
||||
-9.622162373026585e-05,
|
||||
-0.006436207679519103,
|
||||
-0.012779471908040341,
|
||||
-0.02038153550619876,
|
||||
-0.027999803010447587,
|
||||
-0.035622012697103154,
|
||||
-0.043236398934156144,
|
||||
-0.04493583574805963,
|
||||
-0.04663615264317309,
|
||||
-0.048337350303318156,
|
||||
-0.050039429413028365,
|
||||
-0.051742390657545205,
|
||||
-0.05342028484370278,
|
||||
-0.05254242298580185,
|
||||
-0.05166410580536087,
|
||||
-0.05078533294804249,
|
||||
-0.04990610405914272,
|
||||
-0.05409792133358102,
|
||||
-0.05832916277634124,
|
||||
-0.06256260169582961,
|
||||
-0.06660356886269536,
|
||||
-0.04779792991567815,
|
||||
-0.028982516728038848,
|
||||
-0.010157321677553965,
|
||||
0.00861320615127981,
|
||||
0.01913736978785662,
|
||||
0.029667009055877668,
|
||||
0.04020212822983975,
|
||||
0.050742731588695494,
|
||||
0.061288823415841555,
|
||||
0.07184040799914815,
|
||||
0.1043252636301016,
|
||||
0.13687829834471027,
|
||||
0.1694483010211072,
|
||||
0.202035284929368,
|
||||
0.23624619427167134,
|
||||
0.27048596623174515,
|
||||
0.30474360397422756,
|
||||
0.3390191214858807,
|
||||
0.36358851509924695,
|
||||
0.38814205928193013,
|
||||
0.41270842850729195,
|
||||
0.4372876328262819,
|
||||
0.4372876328262819
|
||||
],
|
||||
"dgt": [
|
||||
2.714526681131686,
|
||||
2.705443819238505,
|
||||
2.6947834587664494,
|
||||
2.6841217449620203,
|
||||
2.6681935771243177,
|
||||
2.6521732021128046,
|
||||
2.630396440815385,
|
||||
2.602860350286428,
|
||||
2.5696460593920065,
|
||||
2.5364027376452056,
|
||||
2.499446286796604,
|
||||
2.4587748041127506,
|
||||
2.414398437185221,
|
||||
2.3699990328716107,
|
||||
2.322373696229342,
|
||||
2.271520771371253,
|
||||
2.2174389328192197,
|
||||
2.16337565384239,
|
||||
2.1183028432496016,
|
||||
2.082225099873648,
|
||||
2.055100772005235,
|
||||
2.0279625371819305,
|
||||
2.0008103857988204,
|
||||
1.9736443063300082,
|
||||
1.9482128147680253,
|
||||
1.9245345552113182,
|
||||
1.9026104247588487,
|
||||
1.8806927939516411,
|
||||
1.862235672444246,
|
||||
1.847275503201129,
|
||||
1.835814081380705,
|
||||
1.824381436842932,
|
||||
1.8139629377087627,
|
||||
1.8045606557581335,
|
||||
1.7961751115773796,
|
||||
1.7877868031023945,
|
||||
1.7793941781790852,
|
||||
1.7709972329654864,
|
||||
1.7625959636196327,
|
||||
1.7541903672600494,
|
||||
1.7459181197626403,
|
||||
1.737780757913635,
|
||||
1.7297783508684146,
|
||||
1.7217732861435076,
|
||||
1.7137640932265894,
|
||||
1.7057507692361864,
|
||||
1.6918150918099673,
|
||||
1.6719047669939942,
|
||||
1.6460167077689267,
|
||||
1.6201194134191075,
|
||||
1.5986915141218316,
|
||||
1.5817353179379183,
|
||||
1.569199764184379,
|
||||
1.5566577309558969,
|
||||
1.545374152761467,
|
||||
1.5353620432989845,
|
||||
1.5266220576235803,
|
||||
1.5178910621476225,
|
||||
1.5097346239790443,
|
||||
1.502153039909686,
|
||||
1.495145456062699,
|
||||
1.488134243479226,
|
||||
1.48111939735681,
|
||||
1.474100442252211,
|
||||
1.4670307626366115,
|
||||
1.4599103316162523,
|
||||
1.45273959485914,
|
||||
1.445565137158368,
|
||||
1.4340878115214444,
|
||||
1.418273806730323,
|
||||
1.3981208704326855,
|
||||
1.3779439775587023,
|
||||
1.3598972673004606,
|
||||
1.3439818461440451,
|
||||
1.3301807335621048,
|
||||
1.316383926863083,
|
||||
1.3040618749785347,
|
||||
1.2932153453410835,
|
||||
1.2838336236692311,
|
||||
1.2744470198196236,
|
||||
1.2650555289898042,
|
||||
1.2556591482982988,
|
||||
1.2428104897182262,
|
||||
1.2264996957264114,
|
||||
1.2067249615595257,
|
||||
1.1869318618366975,
|
||||
1.1672278304018044,
|
||||
1.1476135933863398,
|
||||
1.1280891949729075,
|
||||
1.108555289615659,
|
||||
1.0895983485572227,
|
||||
1.0712204022764056,
|
||||
1.0534217504465226,
|
||||
1.0356155337864215,
|
||||
1.017807767853702,
|
||||
1.0
|
||||
],
|
||||
"nf_model": {
|
||||
"enabled": true,
|
||||
"nf1": 5.727887800964238,
|
||||
"nf2": 7.727887800964238,
|
||||
"delta_p": 5.238350271545567
|
||||
},
|
||||
"gain_ripple": [
|
||||
0.1359703369791596,
|
||||
0.11822862697916037,
|
||||
0.09542181697916163,
|
||||
0.06245819697916133,
|
||||
0.02602813697916062,
|
||||
-0.0036199830208403228,
|
||||
-0.018326963020840026,
|
||||
-0.0246928330208398,
|
||||
-0.016792253020838643,
|
||||
-0.0028138630208403015,
|
||||
0.017572956979162058,
|
||||
0.038328296979159404,
|
||||
0.054956336979159914,
|
||||
0.0670723869791594,
|
||||
0.07091459697916136,
|
||||
0.07094413697916124,
|
||||
0.07114372697916238,
|
||||
0.07533675697916209,
|
||||
0.08731066697916035,
|
||||
0.10313984697916112,
|
||||
0.12276252697916235,
|
||||
0.14239527697916188,
|
||||
0.15945681697916214,
|
||||
0.1739275269791598,
|
||||
0.1767381569791624,
|
||||
0.17037189697916233,
|
||||
0.15216302697916007,
|
||||
0.13114358697916018,
|
||||
0.10802383697916085,
|
||||
0.08548825697916129,
|
||||
0.06916723697916183,
|
||||
0.05848224697916038,
|
||||
0.05447361697916264,
|
||||
0.05154489697916276,
|
||||
0.04946107697915991,
|
||||
0.04717897697916129,
|
||||
0.04551704697916037,
|
||||
0.04467697697916151,
|
||||
0.04072968697916224,
|
||||
0.03285456697916089,
|
||||
0.023488786979161347,
|
||||
0.01659282697915998,
|
||||
0.013321846979160057,
|
||||
0.011234826979162449,
|
||||
0.01030063697916006,
|
||||
0.00936596697916059,
|
||||
0.00874012697916271,
|
||||
0.00842583697916055,
|
||||
0.006965146979162284,
|
||||
0.0040435869791615175,
|
||||
0.0007104669791608842,
|
||||
-0.0015763130208377163,
|
||||
-0.006936193020838033,
|
||||
-0.016475303020840215,
|
||||
-0.028748483020837767,
|
||||
-0.039618433020837784,
|
||||
-0.051112303020840244,
|
||||
-0.06468462302083822,
|
||||
-0.07868024302083754,
|
||||
-0.09101254302083817,
|
||||
-0.10103437302083762,
|
||||
-0.11041488302083735,
|
||||
-0.11916081302083725,
|
||||
-0.12789859302083784,
|
||||
-0.1353792530208402,
|
||||
-0.14160178302083892,
|
||||
-0.1455411330208385,
|
||||
-0.1484450830208388,
|
||||
-0.14823350302084037,
|
||||
-0.14591937302083835,
|
||||
-0.1409032730208395,
|
||||
-0.13525493302083902,
|
||||
-0.1279646530208396,
|
||||
-0.11963431302083904,
|
||||
-0.11089282302084058,
|
||||
-0.1027863830208382,
|
||||
-0.09717347302083823,
|
||||
-0.09343261302083761,
|
||||
-0.0913487130208388,
|
||||
-0.08906007302083907,
|
||||
-0.0865687230208394,
|
||||
-0.08407607302083875,
|
||||
-0.07844600302084004,
|
||||
-0.06968090302083851,
|
||||
-0.05947139302083926,
|
||||
-0.05095282302083959,
|
||||
-0.042428283020839785,
|
||||
-0.03218106302083967,
|
||||
-0.01819858302084043,
|
||||
-0.0021726530208390216,
|
||||
0.01393231697916164,
|
||||
0.028098946979159933,
|
||||
0.040326236979161934,
|
||||
0.05257029697916238,
|
||||
0.06479749697916048,
|
||||
0.07704745697916238
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
#!/usr/bin/env
|
||||
"""
|
||||
@author: briantaylor
|
||||
@author: giladgoldfarb
|
||||
@author: jeanluc-auge
|
||||
|
||||
Transmission setup example:
|
||||
reads from network json (default = examples/edfa/edfa_example_network.json)
|
||||
propagates a 96 channels comb
|
||||
"""
|
||||
from argparse import ArgumentParser
|
||||
from json import load
|
||||
from sys import exit
|
||||
from pathlib import Path
|
||||
from logging import getLogger, basicConfig, INFO, ERROR, DEBUG
|
||||
|
||||
from matplotlib.pyplot import show, axis, figure, title
|
||||
from networkx import (draw_networkx_nodes, draw_networkx_edges,
|
||||
draw_networkx_labels, dijkstra_path)
|
||||
|
||||
from gnpy.core import network_from_json, build_network
|
||||
from gnpy.core.elements import Transceiver, Fiber, Edfa
|
||||
from gnpy.core.info import SpectralInformation, Channel, Power
|
||||
#from gnpy.core.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')
|
||||
|
||||
def main(args):
|
||||
with open(args.filename) as f:
|
||||
json_data = load(f)
|
||||
|
||||
network = network_from_json(json_data)
|
||||
build_network(network)
|
||||
|
||||
spacing = 0.05 #THz
|
||||
si = SpectralInformation() # !! SI units W, Hz
|
||||
si = si.update(carriers=tuple(Channel(f, (191.3+spacing*f)*1e12,
|
||||
32e9, 0.15, Power(1e-3, 0, 0)) for f in range(1,97)))
|
||||
|
||||
trx = [n for n in network.nodes() if isinstance(n, Transceiver)]
|
||||
source, sink = trx[0], trx[1]
|
||||
|
||||
path = dijkstra_path(network, source, sink)
|
||||
print(f'There are {len(path)} network elements between {source} and {sink}')
|
||||
|
||||
for el in path:
|
||||
si = el(si)
|
||||
print(el)
|
||||
|
||||
nodelist = [n for n in network.nodes() if isinstance(n, (Transceiver, Fiber))]
|
||||
pathnodes = [n for n in path if isinstance(n, (Transceiver, Fiber))]
|
||||
edgelist = [(u, v) for u, v in zip(pathnodes, pathnodes[1:])]
|
||||
node_color = ['#ff0000' if n is source or n is sink else
|
||||
'#900000' if n in path else '#ffdfdf'
|
||||
for n in nodelist]
|
||||
edge_color = ['#ff9090' if u in path and v in path else '#ababab'
|
||||
for u, v in edgelist]
|
||||
labels = {n: n.location.city if isinstance(n, Transceiver) else ''
|
||||
for n in pathnodes}
|
||||
|
||||
fig = figure()
|
||||
pos = {n: (n.lng, n.lat) for n in nodelist}
|
||||
kwargs = {'figure': fig, 'pos': pos}
|
||||
plot = draw_networkx_nodes(network, nodelist=nodelist, node_color=node_color, **kwargs)
|
||||
draw_networkx_edges(network, edgelist=edgelist, edge_color=edge_color, **kwargs)
|
||||
draw_networkx_labels(network, labels=labels, font_size=14, **kwargs)
|
||||
title(f'Propagating from {source.loc.city} to {sink.loc.city}')
|
||||
axis('off')
|
||||
show()
|
||||
|
||||
parser = ArgumentParser()
|
||||
parser.add_argument('filename', nargs='?', type=Path,
|
||||
default= Path(__file__).parent / 'edfa/edfa_example_network.json')
|
||||
parser.add_argument('-v', '--verbose', action='count')
|
||||
|
||||
if __name__ == '__main__':
|
||||
args = parser.parse_args()
|
||||
level = {1: INFO, 2: DEBUG}.get(args.verbose, ERROR)
|
||||
logger.setLevel(level)
|
||||
basicConfig()
|
||||
exit(main(args))
|
||||
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
GNPy is an open-source, community-developed library for building route planning and optimization tools in real-world mesh optical networks. It is based on the Gaussian Noise Model.
|
||||
|
||||
Signal propagation is implemented in :py:mod:`.core`.
|
||||
Path finding and spectrum assignment is in :py:mod:`.topology`.
|
||||
Various tools and auxiliary code, including the JSON I/O handling, is in
|
||||
:py:mod:`.tools`.
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Simulation of signal propagation in the DWDM network
|
||||
|
||||
from . import elements
|
||||
from .execute import *
|
||||
from .network import *
|
||||
from .utils import *
|
||||
Optical signals, as defined via :class:`.info.SpectralInformation`, enter
|
||||
:py:mod:`.elements` which compute how these signals are affected as they travel
|
||||
through the :py:mod:`.network`.
|
||||
The simulation is controlled via :py:mod:`.parameters` and implemented mainly
|
||||
via :py:mod:`.science_utils`.
|
||||
"""
|
||||
|
||||
20
gnpy/core/ansi_escapes.py
Normal file
20
gnpy/core/ansi_escapes.py
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.ansi_escapes: A random subset of ANSI terminal escape codes for colored messages
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.ansi_escapes
|
||||
======================
|
||||
|
||||
A random subset of ANSI terminal escape codes for colored messages
|
||||
"""
|
||||
|
||||
red = '\x1b[1;31;40m'
|
||||
blue = '\x1b[1;34;40m'
|
||||
cyan = '\x1b[1;36;40m'
|
||||
yellow = '\x1b[1;33;40m'
|
||||
reset = '\x1b[0m'
|
||||
File diff suppressed because it is too large
Load Diff
137
gnpy/core/equipment.py
Normal file
137
gnpy/core/equipment.py
Normal file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.equipment: functionality for specifying equipment
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.equipment
|
||||
===================
|
||||
|
||||
This module contains functionality for specifying equipment.
|
||||
"""
|
||||
from collections import defaultdict
|
||||
from functools import reduce
|
||||
from typing import List
|
||||
|
||||
from gnpy.core.exceptions import EquipmentConfigError, ConfigurationError
|
||||
|
||||
|
||||
def trx_mode_params(equipment, trx_type_variety='', trx_mode='', error_message=False):
|
||||
"""return the trx and SI parameters from eqpt_config for a given type_variety and mode (ie format)
|
||||
|
||||
if the type or mode do no match an existing transceiver in the library, then the function
|
||||
raises an error if error_message is True else returns a default mode based on equipment['SI']['default']
|
||||
If trx_mode is None (but type is valid), it returns an undetermined mode whatever the error message:
|
||||
this is a special case for automatic mode selection.
|
||||
"""
|
||||
trx_params = {}
|
||||
default_si_data = equipment['SI']['default']
|
||||
# default transponder characteristics
|
||||
# mainly used with transmission_main_example.py
|
||||
default_trx_params = {
|
||||
'f_min': default_si_data.f_min,
|
||||
'f_max': default_si_data.f_max,
|
||||
'baud_rate': default_si_data.baud_rate,
|
||||
'spacing': default_si_data.spacing,
|
||||
'OSNR': None,
|
||||
'penalties': {},
|
||||
'bit_rate': None,
|
||||
'cost': None,
|
||||
'roll_off': default_si_data.roll_off,
|
||||
'tx_osnr': default_si_data.tx_osnr,
|
||||
'min_spacing': None,
|
||||
'equalization_offset_db': 0
|
||||
}
|
||||
# Undetermined transponder characteristics
|
||||
# mainly used with path_request_run.py for the automatic mode computation case
|
||||
undetermined_trx_params = {
|
||||
"format": "undetermined",
|
||||
"baud_rate": None,
|
||||
"OSNR": None,
|
||||
"penalties": None,
|
||||
"bit_rate": None,
|
||||
"roll_off": None,
|
||||
"tx_osnr": None,
|
||||
"min_spacing": None,
|
||||
"cost": None,
|
||||
"equalization_offset_db": 0
|
||||
}
|
||||
|
||||
trxs = equipment['Transceiver']
|
||||
if trx_type_variety in trxs:
|
||||
modes = {mode['format']: mode for mode in trxs[trx_type_variety].mode}
|
||||
trx_frequencies = {'f_min': trxs[trx_type_variety].frequency['min'],
|
||||
'f_max': trxs[trx_type_variety].frequency['max']}
|
||||
if trx_mode in modes:
|
||||
# if called from transmission_main.py, trx_mode is ''
|
||||
trx_params = {**modes[trx_mode], **trx_frequencies}
|
||||
if trx_params['baud_rate'] > trx_params['min_spacing']:
|
||||
# sanity check: baudrate must be smaller than min spacing
|
||||
raise EquipmentConfigError(f'Inconsistency in equipment library:\n Transponder "{trx_type_variety}" '
|
||||
+ f'mode "{trx_params["format"]}" has baud rate '
|
||||
+ f'{trx_params["baud_rate"] * 1e-9:.2f} GHz greater than min_spacing '
|
||||
+ f'{trx_params["min_spacing"] * 1e-9:.2f}.')
|
||||
trx_params['equalization_offset_db'] = trx_params.get('equalization_offset_db', 0)
|
||||
return trx_params
|
||||
if trx_mode is None:
|
||||
# if called from path_requests_run.py, trx_mode is filled with None when not specified by user
|
||||
trx_params = {**undetermined_trx_params, **trx_frequencies}
|
||||
return trx_params
|
||||
if trx_type_variety in trxs and error_message:
|
||||
raise EquipmentConfigError(f'Could not find transponder "{trx_type_variety}" with mode "{trx_mode}" '
|
||||
+ 'in equipment library')
|
||||
if error_message:
|
||||
raise EquipmentConfigError(f'Could not find transponder "{trx_type_variety}" in equipment library')
|
||||
|
||||
trx_params = {**default_trx_params}
|
||||
return trx_params
|
||||
|
||||
|
||||
def find_type_variety(amps: List[str], equipment: dict) -> List[str]:
|
||||
"""Returns the multiband type_variety associated with a list of single band type_varieties
|
||||
Args:
|
||||
amps (List[str]): A list of single band type_varieties.
|
||||
equipment (dict): A dictionary containing equipment information.
|
||||
|
||||
Returns:
|
||||
str: an amplifier type variety
|
||||
"""
|
||||
listes = find_type_varieties(amps, equipment)
|
||||
|
||||
_found_type = list(reduce(lambda x, y: set(x) & set(y), listes))
|
||||
# Given a list of single band amplifiers, find the multiband amplifier whose multi_band group
|
||||
# matches. For example, if amps list contains ["a1_LBAND", "a2_CBAND"], with a1.multi_band = [a1_LBAND, a1_CBAND]
|
||||
# and a2.multi_band = [a1_LBAND, a2_CBAND], then:
|
||||
# possible_type_varieties = {"a1_LBAND": ["a1", "a2"], "a2_CBAND": ["a2"]}
|
||||
# listes = [["a1", "a2"], ["a2"]]
|
||||
# and _found_type = [a2]
|
||||
if not _found_type:
|
||||
msg = f'{amps} amps do not belong to the same amp type {listes}'
|
||||
raise ConfigurationError(msg)
|
||||
return _found_type
|
||||
|
||||
|
||||
def find_type_varieties(amps: List[str], equipment: dict) -> List[List[str]]:
|
||||
"""Returns the multiband list of type_varieties associated with a list of single band type_varieties
|
||||
Args:
|
||||
amps (List[str]): A list of single band type_varieties.
|
||||
equipment (dict): A dictionary containing equipment information.
|
||||
|
||||
Returns:
|
||||
List[List[str]]: A list of lists containing the multiband type_varieties
|
||||
associated with each single band type_variety.
|
||||
"""
|
||||
possible_type_varieties = defaultdict(list)
|
||||
for amp_name, amp in equipment['Edfa'].items():
|
||||
if amp.multi_band is not None:
|
||||
for elem in amp.multi_band:
|
||||
# possible_type_varieties stores the list of multiband amp names that list this elem as
|
||||
# a possible amplifier of the multiband group. For example, if "std_medium_gain_multiband"
|
||||
# and "std_medium_gain_multiband_new" contain "std_medium_gain_C" in their "multi_band" list, then:
|
||||
# possible_type_varieties["std_medium_gain_C"] =
|
||||
# ["std_medium_gain_multiband", "std_medium_gain_multiband_new"]
|
||||
possible_type_varieties[elem].append(amp_name)
|
||||
return [possible_type_varieties[a] for a in amps]
|
||||
42
gnpy/core/exceptions.py
Normal file
42
gnpy/core/exceptions.py
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.exceptions: Exceptions thrown by other gnpy modules
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.exceptions
|
||||
====================
|
||||
|
||||
Exceptions thrown by other gnpy modules
|
||||
"""
|
||||
|
||||
|
||||
class ConfigurationError(Exception):
|
||||
"""User-provided configuration contains an error"""
|
||||
|
||||
|
||||
class EquipmentConfigError(ConfigurationError):
|
||||
"""Incomplete or wrong configuration within the equipment library"""
|
||||
|
||||
|
||||
class NetworkTopologyError(ConfigurationError):
|
||||
"""Topology of user-provided network is wrong"""
|
||||
|
||||
|
||||
class ServiceError(Exception):
|
||||
"""Service of user-provided request is wrong"""
|
||||
|
||||
|
||||
class DisjunctionError(ServiceError):
|
||||
"""Disjunction of user-provided request can not be satisfied"""
|
||||
|
||||
|
||||
class SpectrumError(Exception):
|
||||
"""Spectrum errors of the program"""
|
||||
|
||||
|
||||
class ParametersError(ConfigurationError):
|
||||
"""Incomplete or wrong configurations within parameters json"""
|
||||
@@ -1,2 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
@@ -1,50 +1,433 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.info: classes for modelling Spectral Information
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.info
|
||||
==============
|
||||
|
||||
This module contains classes for modelling :class:`SpectralInformation`.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
from collections import namedtuple
|
||||
from collections.abc import Iterable
|
||||
from typing import Union, List, Optional
|
||||
from dataclasses import dataclass
|
||||
from numpy import argsort, mean, array, append, ones, ceil, any, zeros, outer, full, ndarray, asarray
|
||||
|
||||
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)))
|
||||
from gnpy.core.utils import automatic_nch, db2lin, watt2dbm
|
||||
from gnpy.core.exceptions import SpectrumError
|
||||
|
||||
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)
|
||||
DEFAULT_SLOT_WIDTH_STEP = 12.5e9 # Hz
|
||||
"""Channels with unspecified slot width will have their slot width evaluated as the baud rate rounded up to the minimum
|
||||
multiple of the DEFAULT_SLOT_WIDTH_STEP (the baud rate is extended including the roll off in this evaluation)"""
|
||||
|
||||
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 baud_rate roll_off power'), ConvenienceAccess):
|
||||
_ABBREVS = {'channel': 'channel_number',
|
||||
'num_chan': 'channel_number',
|
||||
'ffs': 'frequency',
|
||||
'freq': 'frequency',}
|
||||
class Power(namedtuple('Power', 'signal nli ase')):
|
||||
"""carriers power in W"""
|
||||
|
||||
class SpectralInformation(namedtuple('SpectralInformation', 'carriers'), ConvenienceAccess):
|
||||
def __new__(cls, *carriers):
|
||||
return super().__new__(cls, carriers)
|
||||
|
||||
if __name__ == '__main__':
|
||||
si = SpectralInformation(
|
||||
Channel(1, 193.95e12, 32e9, 0.15, # 193.95 THz, 32 Gbaud
|
||||
Power(1e-3, 1e-6, 1e-6)), # 1 mW, 1uW, 1uW
|
||||
Channel(1, 195.95e12, 32e9, 0.15, # 195.95 THz, 32 Gbaud
|
||||
Power(1.2e-3, 1e-6, 1e-6)), # 1.2 mW, 1uW, 1uW
|
||||
)
|
||||
class Channel(
|
||||
namedtuple('Channel',
|
||||
'channel_number frequency baud_rate slot_width roll_off power chromatic_dispersion pmd pdl latency')):
|
||||
"""Class containing the parameters of a WDM signal.
|
||||
|
||||
si = SpectralInformation()
|
||||
spacing = 0.05 #THz
|
||||
|
||||
si = si.update(carriers=tuple(Channel(f+1, 191.3+spacing*(f+1), 32e9, 0.15, Power(1e-3, f, 1)) for f in range(96)))
|
||||
|
||||
print(f'si = {si}')
|
||||
print(f'si = {si.carriers[0].power.nli}')
|
||||
print(f'si = {si.carriers[20].power.nli}')
|
||||
:param channel_number: channel number in the WDM grid
|
||||
:param frequency: central frequency of the signal (Hz)
|
||||
:param baud_rate: the symbol rate of the signal (Baud)
|
||||
:param slot_width: the slot width (Hz)
|
||||
:param roll_off: the roll off of the signal. It is a pure number between 0 and 1
|
||||
:param power (gnpy.core.info.Power): power of signal, ASE noise and NLI (W)
|
||||
:param chromatic_dispersion: chromatic dispersion (s/m)
|
||||
:param pmd: polarization mode dispersion (s)
|
||||
:param pdl: polarization dependent loss (dB)
|
||||
:param latency: propagation latency (s)
|
||||
"""
|
||||
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}')
|
||||
"""
|
||||
|
||||
|
||||
class SpectralInformation(object):
|
||||
"""Class containing the parameters of the entire WDM comb.
|
||||
|
||||
delta_pdb_per_channel: (per frequency) per channel delta power in dbm for the actual mix of channels"""
|
||||
|
||||
def __init__(self, frequency: array, baud_rate: array, slot_width: array, signal: array, nli: array, ase: array,
|
||||
roll_off: array, chromatic_dispersion: array, pmd: array, pdl: array, latency: array,
|
||||
delta_pdb_per_channel: array, tx_osnr: array, tx_power: array, label: array):
|
||||
indices = argsort(frequency)
|
||||
self._frequency = frequency[indices]
|
||||
self._df = outer(ones(frequency.shape), frequency) - outer(frequency, ones(frequency.shape))
|
||||
self._number_of_channels = len(self._frequency)
|
||||
self._channel_number = [*range(1, self._number_of_channels + 1)]
|
||||
self._slot_width = slot_width[indices]
|
||||
self._baud_rate = baud_rate[indices]
|
||||
overlap = self._frequency[:-1] + self._slot_width[:-1] / 2 > self._frequency[1:] - self._slot_width[1:] / 2
|
||||
if any(overlap):
|
||||
overlap = [pair for pair in zip(overlap * self._channel_number[:-1], overlap * self._channel_number[1:])
|
||||
if pair != (0, 0)]
|
||||
raise SpectrumError(f'Spectrum required slot widths larger than the frequency spectral distances '
|
||||
f'between channels: {overlap}.')
|
||||
exceed = self._baud_rate > self._slot_width
|
||||
if any(exceed):
|
||||
raise SpectrumError(f'Spectrum baud rate, including the roll off, larger than the slot width for channels: '
|
||||
f'{[ch for ch in exceed * self._channel_number if ch]}.')
|
||||
self._signal = signal[indices]
|
||||
self._nli = nli[indices]
|
||||
self._ase = ase[indices]
|
||||
self._roll_off = roll_off[indices]
|
||||
self._chromatic_dispersion = chromatic_dispersion[indices]
|
||||
self._pmd = pmd[indices]
|
||||
self._pdl = pdl[indices]
|
||||
self._latency = latency[indices]
|
||||
self._delta_pdb_per_channel = delta_pdb_per_channel[indices]
|
||||
self._tx_osnr = tx_osnr[indices]
|
||||
self._tx_power = tx_power[indices]
|
||||
self._label = label[indices]
|
||||
|
||||
@property
|
||||
def frequency(self):
|
||||
return self._frequency
|
||||
|
||||
@property
|
||||
def df(self):
|
||||
"""Matrix of relative frequency distances between all channels. Positive elements in the upper right side."""
|
||||
return self._df
|
||||
|
||||
@property
|
||||
def slot_width(self):
|
||||
return self._slot_width
|
||||
|
||||
@property
|
||||
def baud_rate(self):
|
||||
return self._baud_rate
|
||||
|
||||
@property
|
||||
def number_of_channels(self):
|
||||
return self._number_of_channels
|
||||
|
||||
@property
|
||||
def powers(self):
|
||||
powers = zip(self.signal, self.nli, self.ase)
|
||||
return [Power(*p) for p in powers]
|
||||
|
||||
@property
|
||||
def signal(self):
|
||||
return self._signal
|
||||
|
||||
@signal.setter
|
||||
def signal(self, signal):
|
||||
self._signal = signal
|
||||
|
||||
@property
|
||||
def nli(self):
|
||||
return self._nli
|
||||
|
||||
@nli.setter
|
||||
def nli(self, nli):
|
||||
self._nli = nli
|
||||
|
||||
@property
|
||||
def ase(self):
|
||||
return self._ase
|
||||
|
||||
@ase.setter
|
||||
def ase(self, ase):
|
||||
self._ase = ase
|
||||
|
||||
@property
|
||||
def roll_off(self):
|
||||
return self._roll_off
|
||||
|
||||
@property
|
||||
def chromatic_dispersion(self):
|
||||
return self._chromatic_dispersion
|
||||
|
||||
@chromatic_dispersion.setter
|
||||
def chromatic_dispersion(self, chromatic_dispersion):
|
||||
self._chromatic_dispersion = chromatic_dispersion
|
||||
|
||||
@property
|
||||
def pmd(self):
|
||||
return self._pmd
|
||||
|
||||
@property
|
||||
def label(self):
|
||||
return self._label
|
||||
|
||||
@pmd.setter
|
||||
def pmd(self, pmd):
|
||||
self._pmd = pmd
|
||||
|
||||
@property
|
||||
def pdl(self):
|
||||
return self._pdl
|
||||
|
||||
@pdl.setter
|
||||
def pdl(self, pdl):
|
||||
self._pdl = pdl
|
||||
|
||||
@property
|
||||
def latency(self):
|
||||
return self._latency
|
||||
|
||||
@latency.setter
|
||||
def latency(self, latency):
|
||||
self._latency = latency
|
||||
|
||||
@property
|
||||
def delta_pdb_per_channel(self):
|
||||
return self._delta_pdb_per_channel
|
||||
|
||||
@delta_pdb_per_channel.setter
|
||||
def delta_pdb_per_channel(self, delta_pdb_per_channel):
|
||||
self._delta_pdb_per_channel = delta_pdb_per_channel
|
||||
|
||||
@property
|
||||
def tx_osnr(self):
|
||||
return self._tx_osnr
|
||||
|
||||
@tx_osnr.setter
|
||||
def tx_osnr(self, tx_osnr):
|
||||
self._tx_osnr = tx_osnr
|
||||
|
||||
@property
|
||||
def tx_power(self):
|
||||
return self._tx_power
|
||||
|
||||
@tx_power.setter
|
||||
def tx_power(self, tx_power):
|
||||
self._tx_power = tx_power
|
||||
|
||||
@property
|
||||
def channel_number(self):
|
||||
return self._channel_number
|
||||
|
||||
@property
|
||||
def carriers(self):
|
||||
entries = zip(self.channel_number, self.frequency, self.baud_rate, self.slot_width,
|
||||
self.roll_off, self.powers, self.chromatic_dispersion, self.pmd, self.pdl, self.latency)
|
||||
return [Channel(*entry) for entry in entries]
|
||||
|
||||
def apply_attenuation_lin(self, attenuation_lin):
|
||||
self.signal *= attenuation_lin
|
||||
self.nli *= attenuation_lin
|
||||
self.ase *= attenuation_lin
|
||||
|
||||
def apply_attenuation_db(self, attenuation_db):
|
||||
attenuation_lin = 1 / db2lin(attenuation_db)
|
||||
self.apply_attenuation_lin(attenuation_lin)
|
||||
|
||||
def apply_gain_lin(self, gain_lin):
|
||||
self.signal *= gain_lin
|
||||
self.nli *= gain_lin
|
||||
self.ase *= gain_lin
|
||||
|
||||
def apply_gain_db(self, gain_db):
|
||||
gain_lin = db2lin(gain_db)
|
||||
self.apply_gain_lin(gain_lin)
|
||||
|
||||
def __add__(self, other: SpectralInformation):
|
||||
try:
|
||||
return SpectralInformation(frequency=append(self.frequency, other.frequency),
|
||||
slot_width=append(self.slot_width, other.slot_width),
|
||||
signal=append(self.signal, other.signal), nli=append(self.nli, other.nli),
|
||||
ase=append(self.ase, other.ase),
|
||||
baud_rate=append(self.baud_rate, other.baud_rate),
|
||||
roll_off=append(self.roll_off, other.roll_off),
|
||||
chromatic_dispersion=append(self.chromatic_dispersion,
|
||||
other.chromatic_dispersion),
|
||||
pmd=append(self.pmd, other.pmd),
|
||||
pdl=append(self.pdl, other.pdl),
|
||||
latency=append(self.latency, other.latency),
|
||||
delta_pdb_per_channel=append(self.delta_pdb_per_channel,
|
||||
other.delta_pdb_per_channel),
|
||||
tx_osnr=append(self.tx_osnr, other.tx_osnr),
|
||||
tx_power=append(self.tx_power, other.tx_power),
|
||||
label=append(self.label, other.label))
|
||||
except SpectrumError:
|
||||
raise SpectrumError('Spectra cannot be summed: channels overlapping.')
|
||||
|
||||
def _replace(self, carriers):
|
||||
self.chromatic_dispersion = array([c.chromatic_dispersion for c in carriers])
|
||||
self.pmd = array([c.pmd for c in carriers])
|
||||
self.pdl = array([c.pdl for c in carriers])
|
||||
self.latency = array([c.latency for c in carriers])
|
||||
self.signal = array([c.power.signal for c in carriers])
|
||||
self.nli = array([c.power.nli for c in carriers])
|
||||
self.ase = array([c.power.ase for c in carriers])
|
||||
return self
|
||||
|
||||
|
||||
def create_arbitrary_spectral_information(frequency: Union[ndarray, Iterable, float],
|
||||
signal: Union[float, ndarray, Iterable],
|
||||
baud_rate: Union[float, ndarray, Iterable],
|
||||
tx_osnr: Union[float, ndarray, Iterable],
|
||||
tx_power: Union[float, ndarray, Iterable] = None,
|
||||
delta_pdb_per_channel: Union[float, ndarray, Iterable] = 0.,
|
||||
slot_width: Union[float, ndarray, Iterable] = None,
|
||||
roll_off: Union[float, ndarray, Iterable] = 0.,
|
||||
chromatic_dispersion: Union[float, ndarray, Iterable] = 0.,
|
||||
pmd: Union[float, ndarray, Iterable] = 0.,
|
||||
pdl: Union[float, ndarray, Iterable] = 0.,
|
||||
latency: Union[float, ndarray, Iterable] = 0.,
|
||||
label: Union[str, ndarray, Iterable] = None):
|
||||
"""This is just a wrapper around the SpectralInformation.__init__() that simplifies the creation of
|
||||
a non-uniform spectral information with NLI and ASE powers set to zero."""
|
||||
frequency = asarray(frequency)
|
||||
number_of_channels = frequency.size
|
||||
try:
|
||||
signal = full(number_of_channels, signal)
|
||||
baud_rate = full(number_of_channels, baud_rate)
|
||||
roll_off = full(number_of_channels, roll_off)
|
||||
slot_width = full(number_of_channels, slot_width) if slot_width is not None else \
|
||||
ceil((1 + roll_off) * baud_rate / DEFAULT_SLOT_WIDTH_STEP) * DEFAULT_SLOT_WIDTH_STEP
|
||||
chromatic_dispersion = full(number_of_channels, chromatic_dispersion)
|
||||
pmd = full(number_of_channels, pmd)
|
||||
pdl = full(number_of_channels, pdl)
|
||||
latency = full(number_of_channels, latency)
|
||||
nli = zeros(number_of_channels)
|
||||
ase = zeros(number_of_channels)
|
||||
delta_pdb_per_channel = full(number_of_channels, delta_pdb_per_channel)
|
||||
tx_osnr = full(number_of_channels, tx_osnr)
|
||||
tx_power = full(number_of_channels, tx_power)
|
||||
label = full(number_of_channels, label)
|
||||
return SpectralInformation(frequency=frequency, slot_width=slot_width,
|
||||
signal=signal, nli=nli, ase=ase,
|
||||
baud_rate=baud_rate, roll_off=roll_off,
|
||||
chromatic_dispersion=chromatic_dispersion,
|
||||
pmd=pmd, pdl=pdl, latency=latency,
|
||||
delta_pdb_per_channel=delta_pdb_per_channel,
|
||||
tx_osnr=tx_osnr, tx_power=tx_power, label=label)
|
||||
except ValueError as e:
|
||||
if 'could not broadcast' in str(e):
|
||||
raise SpectrumError('Dimension mismatch in input fields.')
|
||||
else:
|
||||
raise
|
||||
|
||||
|
||||
def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, spacing, tx_osnr, tx_power,
|
||||
delta_pdb=0):
|
||||
"""Creates a fixed slot width spectral information with flat power.
|
||||
all arguments are scalar values"""
|
||||
number_of_channels = automatic_nch(f_min, f_max, spacing)
|
||||
frequency = [(f_min + spacing * i) for i in range(1, number_of_channels + 1)]
|
||||
delta_pdb_per_channel = delta_pdb * ones(number_of_channels)
|
||||
label = [f'{baud_rate * 1e-9 :.2f}G' for i in range(number_of_channels)]
|
||||
return create_arbitrary_spectral_information(frequency, slot_width=spacing, signal=tx_power, baud_rate=baud_rate,
|
||||
roll_off=roll_off, delta_pdb_per_channel=delta_pdb_per_channel,
|
||||
tx_osnr=tx_osnr, tx_power=tx_power, label=label)
|
||||
|
||||
|
||||
def is_in_band(frequency: float, band: dict) -> bool:
|
||||
"""band has {"f_min": value, "f_max": value} format
|
||||
"""
|
||||
if frequency >= band['f_min'] and frequency <= band['f_max']:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def demuxed_spectral_information(input_si: SpectralInformation, band: dict) -> Optional[SpectralInformation]:
|
||||
"""extract a si based on band
|
||||
"""
|
||||
filtered_indices = [i for i, f in enumerate(input_si.frequency)
|
||||
if is_in_band(f - input_si.slot_width[i] / 2, band)
|
||||
and is_in_band(f + input_si.slot_width[i] / 2, band)]
|
||||
if filtered_indices:
|
||||
frequency = input_si.frequency[filtered_indices]
|
||||
baud_rate = input_si.baud_rate[filtered_indices]
|
||||
slot_width = input_si.slot_width[filtered_indices]
|
||||
signal = input_si.signal[filtered_indices]
|
||||
nli = input_si.nli[filtered_indices]
|
||||
ase = input_si.ase[filtered_indices]
|
||||
roll_off = input_si.roll_off[filtered_indices]
|
||||
chromatic_dispersion = input_si.chromatic_dispersion[filtered_indices]
|
||||
pmd = input_si.pmd[filtered_indices]
|
||||
pdl = input_si.pdl[filtered_indices]
|
||||
latency = input_si.latency[filtered_indices]
|
||||
delta_pdb_per_channel = input_si.delta_pdb_per_channel[filtered_indices]
|
||||
tx_osnr = input_si.tx_osnr[filtered_indices]
|
||||
tx_power = input_si.tx_power[filtered_indices]
|
||||
label = input_si.label[filtered_indices]
|
||||
|
||||
return SpectralInformation(frequency=frequency, baud_rate=baud_rate, slot_width=slot_width, signal=signal,
|
||||
nli=nli, ase=ase, roll_off=roll_off, chromatic_dispersion=chromatic_dispersion,
|
||||
pmd=pmd, pdl=pdl, latency=latency, delta_pdb_per_channel=delta_pdb_per_channel,
|
||||
tx_osnr=tx_osnr, tx_power=tx_power, label=label)
|
||||
return None
|
||||
|
||||
|
||||
def muxed_spectral_information(input_si_list: List[SpectralInformation]) -> SpectralInformation:
|
||||
"""return the assembled spectrum
|
||||
"""
|
||||
if input_si_list and len(input_si_list) > 1:
|
||||
si = input_si_list[0] + muxed_spectral_information(input_si_list[1:])
|
||||
return si
|
||||
elif input_si_list and len(input_si_list) == 1:
|
||||
return input_si_list[0]
|
||||
else:
|
||||
raise ValueError('liste vide')
|
||||
|
||||
|
||||
def carriers_to_spectral_information(initial_spectrum: dict[float, Carrier],
|
||||
power: float) -> 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,
|
||||
tx_osnr, tx_power and roll off.
|
||||
:param power: power of the request
|
||||
"""
|
||||
frequency = list(initial_spectrum.keys())
|
||||
signal = [c.tx_power 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 = [c.delta_pdb for c in initial_spectrum.values()]
|
||||
slot_width = [c.slot_width for c in initial_spectrum.values()]
|
||||
tx_osnr = [c.tx_osnr for c in initial_spectrum.values()]
|
||||
tx_power = [c.tx_power for c in initial_spectrum.values()]
|
||||
label = [c.label for c in initial_spectrum.values()]
|
||||
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, tx_osnr=tx_osnr,
|
||||
tx_power=tx_power, label=label)
|
||||
|
||||
|
||||
@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
|
||||
tx_power, and tx_osnr. delta_pdb offset is applied to target power out of Roadm.
|
||||
Label is used to group carriers which belong to the same partition when printing results.
|
||||
"""
|
||||
delta_pdb: float
|
||||
baud_rate: float
|
||||
slot_width: float
|
||||
roll_off: float
|
||||
tx_osnr: float
|
||||
tx_power: float
|
||||
label: str
|
||||
|
||||
|
||||
@dataclass
|
||||
class ReferenceCarrier:
|
||||
"""Reference channel type is used to determine target power out of ROADM for the reference channel when
|
||||
constant power spectral density (PSD) equalization is set. Reference channel is the type that has been defined
|
||||
in SI block and used for the initial design of the network.
|
||||
Computing the power out of ROADM for the reference channel is required to correctly compute the loss
|
||||
experienced by reference channel in Roadm element.
|
||||
|
||||
Baud rate is required to find the target power in constant PSD: power = PSD_target * baud_rate.
|
||||
For example, if target PSD is 3.125e4mW/GHz and reference carrier type a 32 GBaud channel then
|
||||
output power should be -20 dBm and for a 64 GBaud channel power target would need 3 dB more: -17 dBm.
|
||||
|
||||
Slot width is required to find the target power in constant PSW (constant power per slot width equalization):
|
||||
power = PSW_target * slot_width.
|
||||
For example, if target PSW is 2e4mW/GHz and reference carrier type a 32 GBaud channel in a 50GHz slot width then
|
||||
output power should be -20 dBm and for a 64 GBaud channel in a 75 GHz slot width, power target would be -18.24 dBm.
|
||||
|
||||
Other attributes (like roll-off) may be added there for future equalization purpose.
|
||||
"""
|
||||
baud_rate: float
|
||||
slot_width: float
|
||||
|
||||
2226
gnpy/core/network.py
2226
gnpy/core/network.py
File diff suppressed because it is too large
Load Diff
@@ -1,60 +0,0 @@
|
||||
#! /bin/usr/python3
|
||||
|
||||
from uuid import uuid4
|
||||
from gnpy.core.utils import load_json
|
||||
|
||||
|
||||
class ConfigStruct:
|
||||
|
||||
def __init__(self, **config):
|
||||
if config is None:
|
||||
return None
|
||||
if 'config_from_json' in config:
|
||||
json_config = load_json(config['config_from_json'])
|
||||
self.set_config_attr(json_config)
|
||||
|
||||
self.set_config_attr(config)
|
||||
|
||||
def set_config_attr(self, config):
|
||||
for k, v in config.items():
|
||||
setattr(self, k, ConfigStruct(**v)
|
||||
if isinstance(v, dict) else v)
|
||||
|
||||
def __repr__(self):
|
||||
return f'{self.__dict__}'
|
||||
|
||||
|
||||
class Node:
|
||||
|
||||
def __init__(self, config=None):
|
||||
self.config = ConfigStruct(**config)
|
||||
if self.config is None or not hasattr(self.config, 'uid'):
|
||||
self.uid = uuid4()
|
||||
else:
|
||||
self.uid = self.config.uid
|
||||
if hasattr(self.config, 'params'):
|
||||
self.params = self.config.params
|
||||
if hasattr(self.config, 'metadata'):
|
||||
self.metadata = self.config.metadata
|
||||
if hasattr(self.config, 'operational'):
|
||||
self.operational = self.config.operational
|
||||
|
||||
@property
|
||||
def coords(self):
|
||||
return tuple(self.lng, self.lat)
|
||||
|
||||
@property
|
||||
def location(self):
|
||||
return self.config.metadata.location
|
||||
|
||||
@property
|
||||
def loc(self): # Aliases .location
|
||||
return self.location
|
||||
|
||||
@property
|
||||
def lng(self):
|
||||
return self.config.metadata.location.longitude
|
||||
|
||||
@property
|
||||
def lat(self):
|
||||
return self.config.metadata.location.latitude
|
||||
731
gnpy/core/parameters.py
Normal file
731
gnpy/core/parameters.py
Normal file
@@ -0,0 +1,731 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.parameters: parameters to configure standard network elements
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.parameters
|
||||
====================
|
||||
|
||||
This module contains all parameters to configure standard network elements.
|
||||
"""
|
||||
from collections import namedtuple
|
||||
from copy import deepcopy
|
||||
from dataclasses import dataclass
|
||||
from scipy.constants import c, pi
|
||||
from numpy import asarray, array, exp, sqrt, log, outer, ones, squeeze, append, flip, linspace, full
|
||||
|
||||
from gnpy.core.utils import convert_length
|
||||
from gnpy.core.exceptions import ParametersError
|
||||
|
||||
|
||||
class Parameters:
|
||||
def asdict(self):
|
||||
class_dict = self.__class__.__dict__
|
||||
instance_dict = self.__dict__
|
||||
new_dict = {}
|
||||
for key in class_dict:
|
||||
if isinstance(class_dict[key], property):
|
||||
new_dict[key] = instance_dict['_' + key]
|
||||
return new_dict
|
||||
|
||||
|
||||
class PumpParams(Parameters):
|
||||
def __init__(self, power, frequency, propagation_direction):
|
||||
self.power = power
|
||||
self.frequency = frequency
|
||||
self.propagation_direction = propagation_direction.lower()
|
||||
|
||||
|
||||
class RamanParams(Parameters):
|
||||
def __init__(self, flag=False, method='perturbative', order=2, result_spatial_resolution=10e3,
|
||||
solver_spatial_resolution=10e3):
|
||||
"""Simulation parameters used within the Raman Solver
|
||||
|
||||
:params flag: boolean for enabling/disable the evaluation of the Raman power profile in frequency and position
|
||||
:params method: Raman solver method
|
||||
:params order: solution order for perturbative method
|
||||
:params result_spatial_resolution: spatial resolution of the evaluated Raman power profile
|
||||
:params solver_spatial_resolution: spatial step for the iterative solution of the first order ode
|
||||
"""
|
||||
self.flag = flag
|
||||
self.method = method
|
||||
self.order = order
|
||||
self.result_spatial_resolution = result_spatial_resolution # [m]
|
||||
self.solver_spatial_resolution = solver_spatial_resolution # [m]
|
||||
|
||||
def to_json(self):
|
||||
return {"flag": self.flag,
|
||||
"method": self.method,
|
||||
"order": self.order,
|
||||
"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=4, phase_shift_tolerance=0.1,
|
||||
computed_channels=None, computed_number_of_channels=None):
|
||||
"""Simulation parameters used within the Nli Solver
|
||||
|
||||
:params method: formula for NLI calculation
|
||||
:params dispersion_tolerance: tuning parameter for ggn model solution
|
||||
:params phase_shift_tolerance: tuning parameter for ggn model solution
|
||||
:params computed_channels: the NLI is evaluated for these channels and extrapolated for the others
|
||||
:params computed_number_of_channels: the NLI is evaluated for this number of channels equally distributed
|
||||
in the spectrum and extrapolated for the others
|
||||
"""
|
||||
self.method = method.lower()
|
||||
self.dispersion_tolerance = dispersion_tolerance
|
||||
self.phase_shift_tolerance = phase_shift_tolerance
|
||||
self.computed_channels = computed_channels
|
||||
self.computed_number_of_channels = computed_number_of_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,
|
||||
"computed_number_of_channels": self.computed_number_of_channels}
|
||||
|
||||
|
||||
class SimParams(Parameters):
|
||||
_shared_dict = {'nli_params': NLIParams(), 'raman_params': RamanParams()}
|
||||
|
||||
@classmethod
|
||||
def set_params(cls, sim_params):
|
||||
cls._shared_dict['nli_params'] = NLIParams(**sim_params.get('nli_params', {}))
|
||||
cls._shared_dict['raman_params'] = RamanParams(**sim_params.get('raman_params', {}))
|
||||
|
||||
@property
|
||||
def nli_params(self):
|
||||
return self._shared_dict['nli_params']
|
||||
|
||||
@property
|
||||
def raman_params(self):
|
||||
return self._shared_dict['raman_params']
|
||||
|
||||
|
||||
class RoadmParams(Parameters):
|
||||
def __init__(self, **kwargs):
|
||||
self.target_pch_out_db = kwargs.get('target_pch_out_db')
|
||||
self.target_psd_out_mWperGHz = kwargs.get('target_psd_out_mWperGHz')
|
||||
self.target_out_mWperSlotWidth = kwargs.get('target_out_mWperSlotWidth')
|
||||
equalisation_type = ['target_pch_out_db', 'target_psd_out_mWperGHz', 'target_out_mWperSlotWidth']
|
||||
temp = [kwargs.get(k) is not None for k in equalisation_type]
|
||||
if sum(temp) > 1:
|
||||
raise ParametersError('ROADM config contains more than one equalisation type.'
|
||||
+ 'Please choose only one', kwargs)
|
||||
self.per_degree_pch_out_db = kwargs.get('per_degree_pch_out_db', {})
|
||||
self.per_degree_pch_psd = kwargs.get('per_degree_psd_out_mWperGHz', {})
|
||||
self.per_degree_pch_psw = kwargs.get('per_degree_psd_out_mWperSlotWidth', {})
|
||||
try:
|
||||
self.add_drop_osnr = kwargs['add_drop_osnr']
|
||||
self.pmd = kwargs['pmd']
|
||||
self.pdl = kwargs['pdl']
|
||||
self.restrictions = kwargs['restrictions']
|
||||
self.roadm_path_impairments = self.get_roadm_path_impairments(kwargs['roadm-path-impairments'])
|
||||
except KeyError as e:
|
||||
raise ParametersError(f'ROADM configurations must include {e}. Configuration: {kwargs}')
|
||||
self.per_degree_impairments = kwargs.get('per_degree_impairments', [])
|
||||
self.design_bands = kwargs.get('design_bands', [])
|
||||
self.per_degree_design_bands = kwargs.get('per_degree_design_bands', {})
|
||||
|
||||
def get_roadm_path_impairments(self, path_impairments_list):
|
||||
"""Get the ROADM list of profiles for impairments definition
|
||||
|
||||
transform the ietf model into gnpy internal model: add a path-type in the attributes
|
||||
"""
|
||||
if not path_impairments_list:
|
||||
return {}
|
||||
authorized_path_types = {
|
||||
'roadm-express-path': 'express',
|
||||
'roadm-add-path': 'add',
|
||||
'roadm-drop-path': 'drop',
|
||||
}
|
||||
roadm_path_impairments = {}
|
||||
for path_impairment in path_impairments_list:
|
||||
index = path_impairment['roadm-path-impairments-id']
|
||||
path_type = next(key for key in path_impairment if key in authorized_path_types.keys())
|
||||
impairment_dict = {'path-type': authorized_path_types[path_type], 'impairment': path_impairment[path_type]}
|
||||
roadm_path_impairments[index] = RoadmImpairment(impairment_dict)
|
||||
return roadm_path_impairments
|
||||
|
||||
|
||||
class RoadmPath:
|
||||
def __init__(self, from_degree, to_degree, path_type, impairment_id=None, impairment=None):
|
||||
"""Records roadm internal paths, types and impairment
|
||||
|
||||
path_type must be in "express", "add", "drop"
|
||||
impairment_id must be one of the id detailed in equipement
|
||||
"""
|
||||
self.from_degree = from_degree
|
||||
self.to_degree = to_degree
|
||||
self.path_type = path_type
|
||||
self.impairment_id = impairment_id
|
||||
self.impairment = impairment
|
||||
|
||||
|
||||
class RoadmImpairment:
|
||||
"""Generic definition of impairments for express, add and drop"""
|
||||
default_values = {
|
||||
'roadm-pmd': None,
|
||||
'roadm-cd': None,
|
||||
'roadm-pdl': None,
|
||||
'roadm-inband-crosstalk': None,
|
||||
'roadm-maxloss': 0,
|
||||
'roadm-osnr': None,
|
||||
'roadm-pmax': None,
|
||||
'roadm-noise-figure': None,
|
||||
'minloss': None,
|
||||
'typloss': None,
|
||||
'pmin': None,
|
||||
'ptyp': None
|
||||
}
|
||||
|
||||
def __init__(self, params):
|
||||
self.path_type = params.get('path-type')
|
||||
self.impairments = params['impairment']
|
||||
|
||||
|
||||
class FusedParams(Parameters):
|
||||
def __init__(self, **kwargs):
|
||||
self.loss = kwargs['loss'] if 'loss' in kwargs else 1
|
||||
|
||||
|
||||
DEFAULT_RAMAN_COEFFICIENT = {
|
||||
# SSMF Raman coefficient profile in terms of mode intensity (g0 * A_ff_overlap)
|
||||
'gamma_raman': array(
|
||||
[0.0, 8.524419934705497e-16, 2.643567866245371e-15, 4.410548410941305e-15, 6.153422961291078e-15,
|
||||
7.484924703044943e-15, 8.452060808349209e-15, 9.101549322698156e-15, 9.57837595158966e-15,
|
||||
1.0008642675474562e-14, 1.0865773569905647e-14, 1.1300776305865833e-14, 1.2143238647099625e-14,
|
||||
1.3231065750676068e-14, 1.4624900971525384e-14, 1.6013330554840492e-14, 1.7458119359310242e-14,
|
||||
1.9320241330434762e-14, 2.1720395392873534e-14, 2.4137337406734775e-14, 2.628163218460466e-14,
|
||||
2.8041019963285974e-14, 2.9723155447089933e-14, 3.129353531005888e-14, 3.251796163324624e-14,
|
||||
3.3198839487612773e-14, 3.329527690685666e-14, 3.313155691238456e-14, 3.289013852154548e-14,
|
||||
3.2458917188506916e-14, 3.060684277937575e-14, 3.2660349473783173e-14, 2.957419109657689e-14,
|
||||
2.518894321396672e-14, 1.734560485857344e-14, 9.902860761605233e-15, 7.219176385099358e-15,
|
||||
6.079565990401311e-15, 5.828373065963427e-15, 7.20580801091692e-15, 7.561924351387493e-15,
|
||||
7.621152352332206e-15, 6.8859886780643254e-15, 5.629181047471162e-15, 3.679727598966185e-15,
|
||||
2.7555869742500355e-15, 2.4810133942597675e-15, 2.2160080532403624e-15, 2.1440626024765557e-15,
|
||||
2.33873070799544e-15, 2.557317929858713e-15, 3.039839048226572e-15, 4.8337165515610065e-15,
|
||||
5.4647431818257436e-15, 5.229187813711269e-15, 4.510768525811313e-15, 3.3213473130607794e-15,
|
||||
2.2602577027996455e-15, 1.969576495866441e-15, 1.5179853954188527e-15, 1.2953988551200156e-15,
|
||||
1.1304672156251838e-15, 9.10004390675213e-16, 8.432919922183503e-16, 7.849224069008326e-16,
|
||||
7.827568196032024e-16, 9.000514440646232e-16, 1.3025926460013665e-15, 1.5444108938497558e-15,
|
||||
1.8795594063060786e-15, 1.7796130169921014e-15, 1.5938159865046653e-15, 1.1585522355108287e-15,
|
||||
8.507044444633358e-16, 7.625404663756823e-16, 8.14510750925789e-16, 9.047944693473188e-16,
|
||||
9.636431901702084e-16, 9.298633899602105e-16, 8.349739503637023e-16, 7.482901278066085e-16,
|
||||
6.240794767134268e-16, 5.00652535687506e-16, 3.553373263685851e-16, 2.0344217706119682e-16,
|
||||
1.4267522642294203e-16, 8.980016576743517e-17, 2.9829068181832594e-17, 1.4861959129014824e-17,
|
||||
7.404482113326137e-18]
|
||||
), # m/W
|
||||
# SSMF Raman coefficient profile
|
||||
'g0': array(
|
||||
[0.00000000e+00, 1.12351610e-05, 3.47838074e-05, 5.79356636e-05, 8.06921680e-05, 9.79845709e-05, 1.10454361e-04,
|
||||
1.18735302e-04, 1.24736889e-04, 1.30110053e-04, 1.41001273e-04, 1.46383247e-04, 1.57011792e-04, 1.70765865e-04,
|
||||
1.88408911e-04, 2.05914127e-04, 2.24074028e-04, 2.47508283e-04, 2.77729174e-04, 3.08044243e-04, 3.34764439e-04,
|
||||
3.56481704e-04, 3.77127256e-04, 3.96269124e-04, 4.10955175e-04, 4.18718761e-04, 4.19511263e-04, 4.17025384e-04,
|
||||
4.13565369e-04, 4.07726048e-04, 3.83671291e-04, 4.08564283e-04, 3.69571936e-04, 3.14442090e-04, 2.16074535e-04,
|
||||
1.23097823e-04, 8.95457457e-05, 7.52470400e-05, 7.19806145e-05, 8.87961158e-05, 9.30812065e-05, 9.37058268e-05,
|
||||
8.45719619e-05, 6.90585286e-05, 4.50407159e-05, 3.36521245e-05, 3.02292475e-05, 2.69376939e-05, 2.60020897e-05,
|
||||
2.82958958e-05, 3.08667558e-05, 3.66024657e-05, 5.80610307e-05, 6.54797937e-05, 6.25022715e-05, 5.37806442e-05,
|
||||
3.94996621e-05, 2.68120644e-05, 2.33038554e-05, 1.79140757e-05, 1.52472424e-05, 1.32707565e-05, 1.06541760e-05,
|
||||
9.84649374e-06, 9.13999627e-06, 9.08971012e-06, 1.04227525e-05, 1.50419271e-05, 1.77838232e-05, 2.15810815e-05,
|
||||
2.03744008e-05, 1.81939341e-05, 1.31862121e-05, 9.65352116e-06, 8.62698322e-06, 9.18688016e-06, 1.01737784e-05,
|
||||
1.08017817e-05, 1.03903588e-05, 9.30040333e-06, 8.30809173e-06, 6.90650401e-06, 5.52238029e-06, 3.90648708e-06,
|
||||
2.22908227e-06, 1.55796177e-06, 9.77218716e-07, 3.23477236e-07, 1.60602454e-07, 7.97306386e-08]
|
||||
), # [1 / (W m)]
|
||||
|
||||
# Note the non-uniform spacing of this range; this is required for properly capturing the Raman peak shape.
|
||||
'frequency_offset': array([
|
||||
0., 0.5, 1., 1.5, 2., 2.5, 3., 3.5, 4., 4.5, 5., 5.5, 6., 6.5, 7., 7.5, 8., 8.5, 9., 9.5, 10., 10.5, 11., 11.5,
|
||||
12., 12.5, 12.75, 13., 13.25, 13.5, 14., 14.5, 14.75, 15., 15.5, 16., 16.5, 17., 17.5, 18., 18.25, 18.5, 18.75,
|
||||
19., 19.5, 20., 20.5, 21., 21.5, 22., 22.5, 23., 23.5, 24., 24.5, 25., 25.5, 26., 26.5, 27., 27.5, 28., 28.5,
|
||||
29., 29.5, 30., 30.5, 31., 31.5, 32., 32.5, 33., 33.5, 34., 34.5, 35., 35.5, 36., 36.5, 37., 37.5, 38., 38.5,
|
||||
39., 39.5, 40., 40.5, 41., 41.5, 42.]) * 1e12, # [Hz]
|
||||
|
||||
# Raman profile reference frequency
|
||||
'reference_frequency': 206.184634112792e12, # [Hz] (1454 nm)
|
||||
|
||||
# Raman profile reference effective area
|
||||
'reference_effective_area': 75.74659443542413e-12 # [m^2] (@1454 nm)
|
||||
}
|
||||
|
||||
|
||||
class RamanGainCoefficient(namedtuple('RamanGainCoefficient', 'normalized_gamma_raman frequency_offset')):
|
||||
""" Raman Gain Coefficient Parameters
|
||||
|
||||
Based on:
|
||||
Andrea D’Amico, Bruno Correia, Elliot London, Emanuele Virgillito, Giacomo Borraccini, Antonio Napoli,
|
||||
and Vittorio Curri, "Scalable and Disaggregated GGN Approximation Applied to a C+L+S Optical Network,"
|
||||
J. Lightwave Technol. 40, 3499-3511 (2022)
|
||||
Section III.D
|
||||
"""
|
||||
|
||||
|
||||
class FiberParams(Parameters):
|
||||
def __init__(self, **kwargs):
|
||||
try:
|
||||
self._length = convert_length(kwargs['length'], kwargs['length_units'])
|
||||
# fixed attenuator for padding
|
||||
self._att_in = kwargs.get('att_in', 0)
|
||||
# if not defined in the network json connector loss in/out
|
||||
# the None value will be updated in network.py[build_network]
|
||||
# with default values from eqpt_config.json[Spans]
|
||||
self._con_in = kwargs.get('con_in')
|
||||
self._con_out = kwargs.get('con_out')
|
||||
|
||||
# Reference frequency (unique for all parameters: beta2, beta3, gamma, effective_area)
|
||||
if 'ref_wavelength' in kwargs:
|
||||
self._ref_wavelength = kwargs['ref_wavelength']
|
||||
self._ref_frequency = c / self._ref_wavelength
|
||||
elif 'ref_frequency' in kwargs:
|
||||
self._ref_frequency = kwargs['ref_frequency']
|
||||
self._ref_wavelength = c / self._ref_frequency
|
||||
else:
|
||||
self._ref_wavelength = 1550e-9 # conventional central C band wavelength [m]
|
||||
self._ref_frequency = c / self._ref_wavelength
|
||||
|
||||
# Chromatic Dispersion
|
||||
if 'dispersion_per_frequency' in kwargs:
|
||||
# Frequency-dependent dispersion
|
||||
self._dispersion = asarray(kwargs['dispersion_per_frequency']['value']) # s/m/m
|
||||
self._f_dispersion_ref = asarray(kwargs['dispersion_per_frequency']['frequency']) # Hz
|
||||
self._dispersion_slope = None
|
||||
elif 'dispersion' in kwargs:
|
||||
# Single value dispersion
|
||||
self._dispersion = asarray(kwargs['dispersion']) # s/m/m
|
||||
self._dispersion_slope = kwargs.get('dispersion_slope') # s/m/m/m
|
||||
self._f_dispersion_ref = asarray(self._ref_frequency) # Hz
|
||||
else:
|
||||
# Default single value dispersion
|
||||
self._dispersion = asarray(1.67e-05) # s/m/m
|
||||
self._dispersion_slope = None
|
||||
self._f_dispersion_ref = asarray(self.ref_frequency) # Hz
|
||||
|
||||
# Effective Area and Nonlinear Coefficient
|
||||
self._effective_area = kwargs.get('effective_area') # m^2
|
||||
self._n1 = 1.468
|
||||
self._core_radius = 4.2e-6 # m
|
||||
self._n2 = 2.6e-20 # m^2/W
|
||||
if self._effective_area is not None:
|
||||
default_gamma = 2 * pi * self._n2 / (self._ref_wavelength * self._effective_area)
|
||||
self._gamma = kwargs.get('gamma', default_gamma) # 1/W/m
|
||||
elif 'gamma' in kwargs:
|
||||
self._gamma = kwargs['gamma'] # 1/W/m
|
||||
self._effective_area = 2 * pi * self._n2 / (self._ref_wavelength * self._gamma) # m^2
|
||||
else:
|
||||
self._effective_area = 83e-12 # m^2
|
||||
self._gamma = 2 * pi * self._n2 / (self._ref_wavelength * self._effective_area) # 1/W/m
|
||||
self._contrast = 0.5 * (c / (2 * pi * self._ref_frequency * self._core_radius * self._n1) * exp(
|
||||
pi * self._core_radius ** 2 / self._effective_area)) ** 2
|
||||
|
||||
# Raman Gain Coefficient
|
||||
raman_coefficient = kwargs.get('raman_coefficient')
|
||||
if raman_coefficient is None:
|
||||
self._raman_reference_frequency = DEFAULT_RAMAN_COEFFICIENT['reference_frequency']
|
||||
frequency_offset = asarray(DEFAULT_RAMAN_COEFFICIENT['frequency_offset'])
|
||||
gamma_raman = asarray(DEFAULT_RAMAN_COEFFICIENT['gamma_raman'])
|
||||
stokes_wave = self._raman_reference_frequency - frequency_offset
|
||||
normalized_gamma_raman = gamma_raman / self._raman_reference_frequency # 1 / m / W / Hz
|
||||
self._g0 = gamma_raman / self.effective_area_overlap(stokes_wave, self._raman_reference_frequency)
|
||||
else:
|
||||
self._raman_reference_frequency = raman_coefficient['reference_frequency']
|
||||
frequency_offset = asarray(raman_coefficient['frequency_offset'])
|
||||
stokes_wave = self._raman_reference_frequency - frequency_offset
|
||||
self._g0 = asarray(raman_coefficient['g0'])
|
||||
gamma_raman = self._g0 * self.effective_area_overlap(stokes_wave, self._raman_reference_frequency)
|
||||
normalized_gamma_raman = gamma_raman / self._raman_reference_frequency # 1 / m / W / Hz
|
||||
|
||||
# Raman gain coefficient array of the frequency offset constructed such that positive frequency values
|
||||
# represent a positive power transfer from higher frequency and vice versa
|
||||
frequency_offset = append(-flip(frequency_offset[1:]), frequency_offset)
|
||||
normalized_gamma_raman = append(- flip(normalized_gamma_raman[1:]), normalized_gamma_raman)
|
||||
self._raman_coefficient = RamanGainCoefficient(normalized_gamma_raman, frequency_offset)
|
||||
|
||||
# Polarization Mode Dispersion
|
||||
self._pmd_coef = kwargs['pmd_coef'] # s/sqrt(m)
|
||||
self._pmd_coef_defined = kwargs.get('pmd_coef_defined', kwargs['pmd_coef'] is True)
|
||||
|
||||
# Loss Coefficient
|
||||
if isinstance(kwargs['loss_coef'], dict):
|
||||
self._loss_coef = asarray(kwargs['loss_coef']['value']) * 1e-3 # lineic loss dB/m
|
||||
self._f_loss_ref = asarray(kwargs['loss_coef']['frequency']) # Hz
|
||||
else:
|
||||
self._loss_coef = asarray(kwargs['loss_coef']) * 1e-3 # lineic loss dB/m
|
||||
self._f_loss_ref = asarray(self._ref_frequency) # Hz
|
||||
# Lumped Losses
|
||||
self._lumped_losses = kwargs['lumped_losses'] if 'lumped_losses' in kwargs else array([])
|
||||
self._latency = self._length / (c / self._n1) # s
|
||||
except KeyError as e:
|
||||
raise ParametersError(f'Fiber configurations json must include {e}. Configuration: {kwargs}')
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
return self._length
|
||||
|
||||
@length.setter
|
||||
def length(self, length):
|
||||
"""length must be in m"""
|
||||
self._length = length
|
||||
|
||||
@property
|
||||
def att_in(self):
|
||||
return self._att_in
|
||||
|
||||
@att_in.setter
|
||||
def att_in(self, att_in):
|
||||
self._att_in = att_in
|
||||
|
||||
@property
|
||||
def con_in(self):
|
||||
return self._con_in
|
||||
|
||||
@con_in.setter
|
||||
def con_in(self, con_in):
|
||||
self._con_in = con_in
|
||||
|
||||
@property
|
||||
def con_out(self):
|
||||
return self._con_out
|
||||
|
||||
@property
|
||||
def lumped_losses(self):
|
||||
return self._lumped_losses
|
||||
|
||||
@con_out.setter
|
||||
def con_out(self, con_out):
|
||||
self._con_out = con_out
|
||||
|
||||
@property
|
||||
def dispersion(self):
|
||||
return self._dispersion
|
||||
|
||||
@property
|
||||
def f_dispersion_ref(self):
|
||||
return self._f_dispersion_ref
|
||||
|
||||
@property
|
||||
def dispersion_slope(self):
|
||||
return self._dispersion_slope
|
||||
|
||||
@property
|
||||
def gamma(self):
|
||||
return self._gamma
|
||||
|
||||
def effective_area_scaling(self, frequency):
|
||||
V = 2 * pi * frequency / c * self._core_radius * self._n1 * sqrt(2 * self._contrast)
|
||||
w = self._core_radius / sqrt(log(V))
|
||||
return asarray(pi * w ** 2)
|
||||
|
||||
def effective_area_overlap(self, frequency_stokes_wave, frequency_pump):
|
||||
effective_area_stokes_wave = self.effective_area_scaling(frequency_stokes_wave)
|
||||
effective_area_pump = self.effective_area_scaling(frequency_pump)
|
||||
return squeeze(outer(effective_area_stokes_wave, ones(effective_area_pump.size)) + outer(
|
||||
ones(effective_area_stokes_wave.size), effective_area_pump)) / 2
|
||||
|
||||
def gamma_scaling(self, frequency):
|
||||
return asarray(2 * pi * self._n2 * frequency / (c * self.effective_area_scaling(frequency)))
|
||||
|
||||
@property
|
||||
def pmd_coef(self):
|
||||
return self._pmd_coef
|
||||
|
||||
@property
|
||||
def pmd_coef_defined(self):
|
||||
return self._pmd_coef_defined
|
||||
|
||||
@property
|
||||
def ref_wavelength(self):
|
||||
return self._ref_wavelength
|
||||
|
||||
@property
|
||||
def ref_frequency(self):
|
||||
return self._ref_frequency
|
||||
|
||||
@property
|
||||
def loss_coef(self):
|
||||
return self._loss_coef
|
||||
|
||||
@property
|
||||
def f_loss_ref(self):
|
||||
return self._f_loss_ref
|
||||
|
||||
@property
|
||||
def raman_coefficient(self):
|
||||
return self._raman_coefficient
|
||||
|
||||
@property
|
||||
def latency(self):
|
||||
return self._latency
|
||||
|
||||
def asdict(self):
|
||||
dictionary = super().asdict()
|
||||
dictionary['loss_coef'] = self.loss_coef * 1e3
|
||||
dictionary['length_units'] = 'm'
|
||||
if len(self.lumped_losses) == 0:
|
||||
dictionary.pop('lumped_losses')
|
||||
if not self.raman_coefficient:
|
||||
dictionary.pop('raman_coefficient')
|
||||
else:
|
||||
raman_frequency_offset = \
|
||||
self.raman_coefficient.frequency_offset[self.raman_coefficient.frequency_offset >= 0]
|
||||
dictionary['raman_coefficient'] = {'g0': self._g0.tolist(),
|
||||
'frequency_offset': raman_frequency_offset.tolist(),
|
||||
'reference_frequency': self._raman_reference_frequency}
|
||||
return dictionary
|
||||
|
||||
|
||||
class EdfaParams:
|
||||
default_values = {
|
||||
'f_min': None,
|
||||
'f_max': None,
|
||||
'multi_band': None,
|
||||
'bands': None,
|
||||
'type_variety': '',
|
||||
'type_def': '',
|
||||
'gain_flatmax': None,
|
||||
'gain_min': None,
|
||||
'p_max': None,
|
||||
'nf_model': None,
|
||||
'dual_stage_model': None,
|
||||
'preamp_variety': None,
|
||||
'booster_variety': None,
|
||||
'nf_min': None,
|
||||
'nf_max': None,
|
||||
'nf_coef': None,
|
||||
'nf0': None,
|
||||
'nf_fit_coeff': None,
|
||||
'nf_ripple': 0,
|
||||
'dgt': None,
|
||||
'gain_ripple': 0,
|
||||
'tilt_ripple': 0,
|
||||
'f_ripple_ref': None,
|
||||
'out_voa_auto': False,
|
||||
'allowed_for_design': False,
|
||||
'raman': False,
|
||||
'pmd': 0,
|
||||
'pdl': 0,
|
||||
'advance_configurations_from_json': None
|
||||
}
|
||||
|
||||
def __init__(self, **params):
|
||||
try:
|
||||
self.type_variety = params['type_variety']
|
||||
self.type_def = params['type_def']
|
||||
|
||||
# Bandwidth
|
||||
self.f_min = params['f_min']
|
||||
self.f_max = params['f_max']
|
||||
self.bandwidth = self.f_max - self.f_min if self.f_max and self.f_min else None
|
||||
self.f_cent = (self.f_max + self.f_min) / 2 if self.f_max and self.f_min else None
|
||||
self.f_ripple_ref = params['f_ripple_ref']
|
||||
self.bands = [{'f_min': params['f_min'],
|
||||
'f_max': params['f_max']}]
|
||||
|
||||
# Gain
|
||||
self.gain_flatmax = params['gain_flatmax']
|
||||
self.gain_min = params['gain_min']
|
||||
|
||||
gain_ripple = params['gain_ripple']
|
||||
if gain_ripple == 0:
|
||||
self.gain_ripple = asarray([0, 0])
|
||||
self.f_ripple_ref = asarray([self.f_min, self.f_max])
|
||||
else:
|
||||
self.gain_ripple = asarray(gain_ripple)
|
||||
if self.f_ripple_ref is not None:
|
||||
if (self.f_ripple_ref[0] != self.f_min) or (self.f_ripple_ref[-1] != self.f_max):
|
||||
raise ParametersError("The reference ripple frequency maximum and minimum have to coincide "
|
||||
"with the EDFA frequency maximum and minimum.")
|
||||
elif self.gain_ripple.size != self.f_ripple_ref.size:
|
||||
raise ParametersError("The reference ripple frequency and the gain ripple must have the same "
|
||||
"size.")
|
||||
else:
|
||||
self.f_ripple_ref = linspace(self.f_min, self.f_max, self.gain_ripple.size)
|
||||
|
||||
tilt_ripple = params['tilt_ripple']
|
||||
|
||||
if tilt_ripple == 0:
|
||||
self.tilt_ripple = full(self.gain_ripple.size, 0)
|
||||
else:
|
||||
self.tilt_ripple = asarray(tilt_ripple)
|
||||
if self.tilt_ripple.size != self.gain_ripple.size:
|
||||
raise ParametersError("The tilt ripple and the gain ripple must have the same size.")
|
||||
|
||||
# Power
|
||||
self.p_max = params['p_max']
|
||||
|
||||
# Noise Figure
|
||||
self.nf_model = params['nf_model']
|
||||
self.nf_min = params['nf_min']
|
||||
self.nf_max = params['nf_max']
|
||||
self.nf_coef = params['nf_coef']
|
||||
self.nf0 = params['nf0']
|
||||
self.nf_fit_coeff = params['nf_fit_coeff']
|
||||
|
||||
nf_ripple = params['nf_ripple']
|
||||
if nf_ripple == 0:
|
||||
self.nf_ripple = full(self.gain_ripple.size, 0)
|
||||
else:
|
||||
self.nf_ripple = asarray(nf_ripple)
|
||||
if self.nf_ripple.size != self.gain_ripple.size:
|
||||
raise ParametersError(
|
||||
"The noise figure ripple and the gain ripple must have the same size. %s, %s",
|
||||
self.nf_ripple.size, self.gain_ripple.size)
|
||||
|
||||
# VOA
|
||||
self.out_voa_auto = params['out_voa_auto']
|
||||
|
||||
# Dual Stage
|
||||
self.dual_stage_model = params['dual_stage_model']
|
||||
if self.dual_stage_model is not None:
|
||||
# Preamp
|
||||
self.preamp_variety = params['preamp_variety']
|
||||
self.preamp_type_def = params['preamp_type_def']
|
||||
self.preamp_nf_model = params['preamp_nf_model']
|
||||
self.preamp_nf_fit_coeff = params['preamp_nf_fit_coeff']
|
||||
self.preamp_gain_min = params['preamp_gain_min']
|
||||
self.preamp_gain_flatmax = params['preamp_gain_flatmax']
|
||||
|
||||
# Booster
|
||||
self.booster_variety = params['booster_variety']
|
||||
self.booster_type_def = params['booster_type_def']
|
||||
self.booster_nf_model = params['booster_nf_model']
|
||||
self.booster_nf_fit_coeff = params['booster_nf_fit_coeff']
|
||||
self.booster_gain_min = params['booster_gain_min']
|
||||
self.booster_gain_flatmax = params['booster_gain_flatmax']
|
||||
|
||||
# Others
|
||||
self.pmd = params['pmd']
|
||||
self.pdl = params['pdl']
|
||||
self.raman = params['raman']
|
||||
self.dgt = params['dgt']
|
||||
self.advance_configurations_from_json = params['advance_configurations_from_json']
|
||||
|
||||
# Design
|
||||
self.allowed_for_design = params['allowed_for_design']
|
||||
|
||||
except KeyError as e:
|
||||
raise ParametersError(f'Edfa configurations json must include {e}. Configuration: {params}')
|
||||
|
||||
def update_params(self, kwargs):
|
||||
for k, v in kwargs.items():
|
||||
setattr(self, k, v)
|
||||
|
||||
|
||||
class EdfaOperational:
|
||||
default_values = {
|
||||
'gain_target': None,
|
||||
'delta_p': None,
|
||||
'out_voa': None,
|
||||
'in_voa': 0,
|
||||
'tilt_target': None
|
||||
}
|
||||
|
||||
def __init__(self, **operational):
|
||||
self.update_attr(operational)
|
||||
|
||||
def update_attr(self, kwargs):
|
||||
clean_kwargs = {k: v for k, v in kwargs.items() if v != ''}
|
||||
for k, v in self.default_values.items():
|
||||
setattr(self, k, clean_kwargs.get(k, v))
|
||||
|
||||
def __repr__(self):
|
||||
return (f'{type(self).__name__}('
|
||||
f'gain_target={self.gain_target!r}, '
|
||||
f'tilt_target={self.tilt_target!r})')
|
||||
|
||||
|
||||
DEFAULT_EDFA_CONFIG = {
|
||||
"nf_ripple": [
|
||||
0.0
|
||||
],
|
||||
"gain_ripple": [
|
||||
0.0
|
||||
],
|
||||
"f_min": 191.275e12,
|
||||
"f_max": 196.125e12,
|
||||
"dgt": [
|
||||
1.0, 1.017807767853702, 1.0356155337864215, 1.0534217504465226, 1.0712204022764056, 1.0895983485572227,
|
||||
1.108555289615659, 1.1280891949729075, 1.1476135933863398, 1.1672278304018044, 1.1869318618366975,
|
||||
1.2067249615595257, 1.2264996957264114, 1.2428104897182262, 1.2556591482982988, 1.2650555289898042,
|
||||
1.2744470198196236, 1.2838336236692311, 1.2932153453410835, 1.3040618749785347, 1.316383926863083,
|
||||
1.3301807335621048, 1.3439818461440451, 1.3598972673004606, 1.3779439775587023, 1.3981208704326855,
|
||||
1.418273806730323, 1.4340878115214444, 1.445565137158368, 1.45273959485914, 1.4599103316162523,
|
||||
1.4670307626366115, 1.474100442252211, 1.48111939735681, 1.488134243479226, 1.495145456062699,
|
||||
1.502153039909686, 1.5097346239790443, 1.5178910621476225, 1.5266220576235803, 1.5353620432989845,
|
||||
1.545374152761467, 1.5566577309558969, 1.569199764184379, 1.5817353179379183, 1.5986915141218316,
|
||||
1.6201194134191075, 1.6460167077689267, 1.6719047669939942, 1.6918150918099673, 1.7057507692361864,
|
||||
1.7137640932265894, 1.7217732861435076, 1.7297783508684146, 1.737780757913635, 1.7459181197626403,
|
||||
1.7541903672600494, 1.7625959636196327, 1.7709972329654864, 1.7793941781790852, 1.7877868031023945,
|
||||
1.7961751115773796, 1.8045606557581335, 1.8139629377087627, 1.824381436842932, 1.835814081380705,
|
||||
1.847275503201129, 1.862235672444246, 1.8806927939516411, 1.9026104247588487, 1.9245345552113182,
|
||||
1.9482128147680253, 1.9736443063300082, 2.0008103857988204, 2.0279625371819305, 2.055100772005235,
|
||||
2.082225099873648, 2.1183028432496016, 2.16337565384239, 2.2174389328192197, 2.271520771371253,
|
||||
2.322373696229342, 2.3699990328716107, 2.414398437185221, 2.4587748041127506, 2.499446286796604,
|
||||
2.5364027376452056, 2.5696460593920065, 2.602860350286428, 2.630396440815385, 2.6521732021128046,
|
||||
2.6681935771243177, 2.6841217449620203, 2.6947834587664494, 2.705443819238505, 2.714526681131686
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
class MultiBandParams:
|
||||
default_values = {
|
||||
'bands': [],
|
||||
'type_variety': '',
|
||||
'type_def': None,
|
||||
'allowed_for_design': False
|
||||
}
|
||||
|
||||
def __init__(self, **params):
|
||||
try:
|
||||
self.update_attr(params)
|
||||
except KeyError as e:
|
||||
raise ParametersError(f'Multiband configurations json must include {e}. Configuration: {params}')
|
||||
|
||||
def update_attr(self, kwargs):
|
||||
clean_kwargs = {k: v for k, v in kwargs.items() if v != ''}
|
||||
for k, v in self.default_values.items():
|
||||
# use deepcopy to avoid sharing same object amongst all instance when v is a list or a dict!
|
||||
if isinstance(v, (list, dict)):
|
||||
setattr(self, k, clean_kwargs.get(k, deepcopy(v)))
|
||||
else:
|
||||
setattr(self, k, clean_kwargs.get(k, v))
|
||||
|
||||
|
||||
class TransceiverParams:
|
||||
def __init__(self, **params):
|
||||
self.design_bands = params.get('design_bands', [])
|
||||
self.per_degree_design_bands = params.get('per_degree_design_bands', {})
|
||||
|
||||
|
||||
@dataclass
|
||||
class FrequencyBand:
|
||||
"""Frequency band
|
||||
"""
|
||||
f_min: float
|
||||
f_max: float
|
||||
|
||||
|
||||
DEFAULT_BANDS_DEFINITION = {
|
||||
"LBAND": FrequencyBand(f_min=187e12, f_max=189e12),
|
||||
"CBAND": FrequencyBand(f_min=191.3e12, f_max=196.0e12)
|
||||
}
|
||||
# use this definition to index amplifiers'element of a multiband amplifier.
|
||||
# this is not the design band
|
||||
|
||||
|
||||
def find_band_name(band: FrequencyBand) -> str:
|
||||
"""return the default band name (CBAND, LBAND, ...) that corresponds to the band frequency range
|
||||
Use the band center frequency: if center frequency is inside the band then returns CBAND.
|
||||
This is to flexibly encompass all kind of bands definitions.
|
||||
returns the first matching band name.
|
||||
"""
|
||||
for band_name, frequency_range in DEFAULT_BANDS_DEFINITION.items():
|
||||
center_frequency = (band.f_min + band.f_max) / 2
|
||||
if center_frequency >= frequency_range.f_min and center_frequency <= frequency_range.f_max:
|
||||
return band_name
|
||||
return 'unknown_band'
|
||||
735
gnpy/core/science_utils.py
Normal file
735
gnpy/core/science_utils.py
Normal file
@@ -0,0 +1,735 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.science_utils: Solver definitions to calculate the Raman effect and the nonlinear interference noise
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
gnpy.core.science_utils
|
||||
=======================
|
||||
|
||||
Solver definitions to calculate the Raman effect and the nonlinear interference noise
|
||||
|
||||
The solvers take as input instances of the spectral information, the fiber and the simulation parameters
|
||||
"""
|
||||
|
||||
from numpy import interp, pi, zeros, cos, array, append, ones, exp, arange, sqrt, trapz, arcsinh, clip, abs, sum, \
|
||||
concatenate, flip, outer, inner, transpose, max, format_float_scientific, diag, sort, unique, argsort, cumprod, \
|
||||
polyfit, log, reshape, swapaxes, full, nan, cumsum
|
||||
from logging import getLogger
|
||||
from scipy.constants import k, h
|
||||
from scipy.interpolate import interp1d
|
||||
from math import isclose, factorial
|
||||
|
||||
from gnpy.core.utils import db2lin, lin2db
|
||||
from gnpy.core.exceptions import EquipmentConfigError, ParametersError
|
||||
from gnpy.core.parameters import SimParams
|
||||
from gnpy.core.info import SpectralInformation
|
||||
|
||||
logger = getLogger(__name__)
|
||||
sim_params = SimParams()
|
||||
|
||||
|
||||
def raised_cosine(frequency, channel_frequency, channel_baud_rate, channel_roll_off):
|
||||
"""Returns a unitary raised cosine profile for the given parame
|
||||
|
||||
:param frequency: numpy array of frequencies in Hz for the resulting raised cosine
|
||||
:param channel_frequency: channel frequencies in Hz
|
||||
:param channel_baud_rate: channel baud rate in Hz
|
||||
:param channel_roll_off: channel roll off
|
||||
"""
|
||||
raised_cosine_mask = zeros(frequency.size)
|
||||
base_frequency = frequency - channel_frequency
|
||||
ts = 1 / channel_baud_rate
|
||||
pass_band = (1 - channel_roll_off) * channel_baud_rate / 2
|
||||
stop_band = (1 + channel_roll_off) * channel_baud_rate / 2
|
||||
|
||||
flat_condition = (abs(base_frequency) <= pass_band) == 1
|
||||
cosine_condition = (pass_band < abs(base_frequency)) * (abs(base_frequency) < stop_band) == 1
|
||||
|
||||
raised_cosine_mask[flat_condition] = 1
|
||||
raised_cosine_mask[cosine_condition] = \
|
||||
0.5 * (1 + cos(pi * ts / channel_roll_off * (abs(base_frequency[cosine_condition]) - pass_band)))
|
||||
return raised_cosine_mask
|
||||
|
||||
|
||||
class StimulatedRamanScattering:
|
||||
def __init__(self, power_profile, loss_profile, frequency, z):
|
||||
"""
|
||||
:params power_profile: power profile matrix along frequency and z [W]
|
||||
:params loss_profile: power profile matrix along frequency and z [linear units]
|
||||
:params frequency: channels frequencies array [Hz]
|
||||
:params z: positions array [m]
|
||||
"""
|
||||
self.power_profile = power_profile
|
||||
self.loss_profile = loss_profile
|
||||
# Field loss profile matrix along frequency and z
|
||||
self.rho = sqrt(loss_profile)
|
||||
self.frequency = frequency
|
||||
self.z = z
|
||||
|
||||
|
||||
class RamanSolver:
|
||||
"""This class contains the methods to calculate the Raman scattering effect."""
|
||||
|
||||
@staticmethod
|
||||
def _create_lumped_losses(z, lumped_losses, z_lumped_losses):
|
||||
lumped_losses = concatenate((lumped_losses, ones(z.size)))
|
||||
z, unique_indices = unique(concatenate((z_lumped_losses, z)), return_index=True)
|
||||
order = argsort(z)
|
||||
lumped_losses = (lumped_losses[unique_indices])[order]
|
||||
z = z[order]
|
||||
return z, lumped_losses
|
||||
|
||||
@staticmethod
|
||||
def calculate_attenuation_profile(spectral_info: SpectralInformation, fiber):
|
||||
"""Evaluates the attenuation profile along the z axis for all the frequency propagating in the
|
||||
fiber without considering the stimulated Raman scattering.
|
||||
"""
|
||||
# z array definition
|
||||
z = array([0, fiber.params.length])
|
||||
|
||||
# Lumped losses array definition
|
||||
z, lumped_losses = RamanSolver._create_lumped_losses(z, fiber.lumped_losses, fiber.z_lumped_losses)
|
||||
|
||||
lumped_loss_acc = cumprod(lumped_losses)
|
||||
frequency = spectral_info.frequency
|
||||
alpha = fiber.alpha(frequency)
|
||||
loss_profile = exp(- outer(alpha, z)) * lumped_loss_acc
|
||||
power_profile = outer(spectral_info.signal, ones(z.size)) * loss_profile
|
||||
return StimulatedRamanScattering(power_profile, loss_profile, spectral_info.frequency, z)
|
||||
|
||||
@staticmethod
|
||||
def calculate_stimulated_raman_scattering(spectral_info: SpectralInformation, fiber):
|
||||
"""Evaluates the Raman profile along the z axis for all the frequency propagated in the fiber
|
||||
including the Raman pumps co- and counter-propagating
|
||||
"""
|
||||
logger.debug('Start computing fiber Stimulated Raman Scattering')
|
||||
|
||||
if sim_params.raman_params.flag:
|
||||
# Raman parameters
|
||||
z_resolution = sim_params.raman_params.result_spatial_resolution
|
||||
z_step = sim_params.raman_params.solver_spatial_resolution
|
||||
z = append(arange(0, fiber.params.length, z_step), fiber.params.length)
|
||||
z_final = append(arange(0, fiber.params.length, z_resolution), fiber.params.length)
|
||||
z_final = sort(unique(concatenate((fiber.z_lumped_losses, z_final))))
|
||||
|
||||
# Lumped losses array definition
|
||||
z, lumped_losses = RamanSolver._create_lumped_losses(z, fiber.lumped_losses, fiber.z_lumped_losses)
|
||||
|
||||
if hasattr(fiber, 'raman_pumps'):
|
||||
# TODO: verify co-propagating pumps computation and in general unsorted frequency
|
||||
# Co-propagating spectrum definition
|
||||
co_raman_pump_power = array([pump.power for pump in fiber.raman_pumps
|
||||
if pump.propagation_direction == 'coprop'])
|
||||
co_raman_pump_frequency = array([pump.frequency for pump in fiber.raman_pumps
|
||||
if pump.propagation_direction == 'coprop'])
|
||||
|
||||
co_power = concatenate((spectral_info.signal, co_raman_pump_power))
|
||||
co_frequency = concatenate((spectral_info.frequency, co_raman_pump_frequency))
|
||||
|
||||
# Counter-propagating spectrum definition
|
||||
cnt_power = array([pump.power for pump in fiber.raman_pumps
|
||||
if pump.propagation_direction == 'counterprop'])
|
||||
cnt_frequency = array([pump.frequency for pump in fiber.raman_pumps
|
||||
if pump.propagation_direction == 'counterprop'])
|
||||
# Co-propagating profile initialization
|
||||
co_power_profile = zeros([co_frequency.size, z.size])
|
||||
if co_frequency.size:
|
||||
co_cr = fiber.cr(co_frequency)
|
||||
co_alpha = fiber.alpha(co_frequency)
|
||||
co_power_profile = \
|
||||
RamanSolver.calculate_unidirectional_stimulated_raman_scattering(co_power, co_alpha, co_cr, z,
|
||||
lumped_losses)
|
||||
# Counter-propagating profile initialization
|
||||
cnt_power_profile = zeros([cnt_frequency.size, z.size])
|
||||
if cnt_frequency.size:
|
||||
cnt_cr = fiber.cr(cnt_frequency)
|
||||
cnt_alpha = fiber.alpha(cnt_frequency)
|
||||
cnt_power_profile = flip(
|
||||
RamanSolver.calculate_unidirectional_stimulated_raman_scattering(cnt_power, cnt_alpha, cnt_cr,
|
||||
z[-1] - flip(z),
|
||||
flip(lumped_losses)), axis=1)
|
||||
# Co-propagating and Counter-propagating Profile Computation
|
||||
if co_frequency.size and cnt_frequency.size:
|
||||
co_power_profile, cnt_power_profile = \
|
||||
RamanSolver.iterative_algorithm(co_power_profile, cnt_power_profile,
|
||||
co_frequency, cnt_frequency, z, fiber, lumped_losses)
|
||||
# Complete Power Profile
|
||||
power_profile = concatenate((co_power_profile, cnt_power_profile), axis=0)
|
||||
# Complete Loss Profile
|
||||
co_loss_profile = co_power_profile / outer(co_power, ones(z.size))
|
||||
cnt_loss_profile = cnt_power_profile / outer(cnt_power, ones(z.size))
|
||||
loss_profile = concatenate((co_loss_profile, cnt_loss_profile), axis=0)
|
||||
# Complete frequency
|
||||
frequency = concatenate((co_frequency, cnt_frequency))
|
||||
else:
|
||||
# Without Raman pumps
|
||||
alpha = fiber.alpha(spectral_info.frequency)
|
||||
cr = fiber.cr(spectral_info.frequency)
|
||||
# Power profile
|
||||
power_profile = (
|
||||
RamanSolver.calculate_unidirectional_stimulated_raman_scattering(spectral_info.signal, alpha, cr, z,
|
||||
lumped_losses))
|
||||
# Loss profile
|
||||
loss_profile = power_profile / outer(spectral_info.signal, ones(z.size))
|
||||
frequency = spectral_info.frequency
|
||||
power_profile = interp1d(z, power_profile, axis=1)(z_final)
|
||||
loss_profile = interp1d(z, loss_profile, axis=1)(z_final)
|
||||
stimulated_raman_scattering = StimulatedRamanScattering(power_profile, loss_profile, frequency, z_final)
|
||||
else:
|
||||
stimulated_raman_scattering = \
|
||||
RamanSolver.calculate_attenuation_profile(spectral_info, fiber)
|
||||
return stimulated_raman_scattering
|
||||
|
||||
@staticmethod
|
||||
def calculate_spontaneous_raman_scattering(spectral_info: SpectralInformation, srs: StimulatedRamanScattering,
|
||||
fiber):
|
||||
"""Evaluates the Raman profile along the z axis for all the frequency propagated in the fiber
|
||||
including the Raman pumps co- and counter-propagating.
|
||||
"""
|
||||
logger.debug('Start computing fiber Spontaneous Raman Scattering')
|
||||
z = srs.z
|
||||
baud_rate = spectral_info.baud_rate
|
||||
frequency = spectral_info.frequency
|
||||
channels_loss = srs.loss_profile[:spectral_info.number_of_channels, :]
|
||||
|
||||
# calculate ase power
|
||||
ase = zeros(spectral_info.number_of_channels)
|
||||
cr = fiber.cr(srs.frequency)[:spectral_info.number_of_channels, spectral_info.number_of_channels:]
|
||||
for i, pump in enumerate(fiber.raman_pumps):
|
||||
pump_power = srs.power_profile[spectral_info.number_of_channels + i, :]
|
||||
df = pump.frequency - frequency
|
||||
eta = - 1 / (1 - exp(h * df / (k * fiber.temperature)))
|
||||
integral = trapz(pump_power / channels_loss, z, axis=1)
|
||||
ase += 2 * h * baud_rate * frequency * (1 + eta) * cr[:, i] * (df > 0) * integral # 2 factor for double pol
|
||||
return ase
|
||||
|
||||
@staticmethod
|
||||
def calculate_unidirectional_stimulated_raman_scattering(power_in, alpha, cr, z, lumped_losses):
|
||||
"""Solves the Raman equation
|
||||
|
||||
:param power_in: launch power array
|
||||
:param alpha: loss coefficient array
|
||||
:param cr: Raman efficiency coefficients matrix
|
||||
:param z: z position array
|
||||
:param lumped_losses: concentrated losses array along the fiber span
|
||||
:return: power profile matrix
|
||||
"""
|
||||
if sim_params.raman_params.method == 'perturbative':
|
||||
if sim_params.raman_params.order > 4:
|
||||
raise ValueError(f'Order {sim_params.raman_params.order} not implemented in Raman Solver.')
|
||||
z_lumped_losses = append(z[lumped_losses != 1], z[-1])
|
||||
llumped_losses = append(1, lumped_losses[lumped_losses != 1])
|
||||
power = outer(power_in, ones(z.size))
|
||||
last_position = 0
|
||||
z_indices = arange(0, z.size)
|
||||
|
||||
for z_lumped_loss, lumped_loss in zip(z_lumped_losses, llumped_losses):
|
||||
if last_position < z[-1]:
|
||||
interval = z_indices[(z >= last_position) * (z <= z_lumped_loss) == 1]
|
||||
z_interval = z[interval] - last_position
|
||||
dz = z_interval[1:] - z_interval[:-1]
|
||||
last_position = z[interval][-1]
|
||||
p0 = power_in * lumped_loss
|
||||
power_interval = outer(p0, ones(z_interval.size))
|
||||
alphaz = outer(alpha, z_interval)
|
||||
expz = exp(- alphaz)
|
||||
eff_length = 1 / outer(alpha, ones(z_interval.size)) * (1 - expz)
|
||||
crpz = transpose(ones([z_interval.size, cr.shape[0], cr.shape[1]]) * cr * p0, (1, 2, 0))
|
||||
exponent = - alphaz
|
||||
if sim_params.raman_params.order >= 1:
|
||||
gamma1 = sum(crpz * eff_length, 1)
|
||||
exponent += gamma1
|
||||
if sim_params.raman_params.order >= 2:
|
||||
z_integrand = expz * gamma1
|
||||
z_integral = cumsum((z_integrand[:, :-1] + z_integrand[:, 1:]) / 2 * dz, 1)
|
||||
gamma2 = zeros(gamma1.shape)
|
||||
gamma2[:, 1:] = sum(crpz[:, :, 1:] * z_integral, 1)
|
||||
exponent += gamma2
|
||||
if sim_params.raman_params.order >= 3:
|
||||
z_integrand = expz * (gamma2 + 1/2 * gamma1**2)
|
||||
z_integral = cumsum((z_integrand[:, :-1] + z_integrand[:, 1:]) / 2 * dz, 1)
|
||||
gamma3 = zeros(gamma1.shape)
|
||||
gamma3[:, 1:] = sum(crpz[:, :, 1:] * z_integral, 1)
|
||||
exponent += gamma3
|
||||
if sim_params.raman_params.order >= 4:
|
||||
z_integrand = expz * (gamma3 + gamma1 * gamma2 + 1/factorial(3) * gamma1**3)
|
||||
z_integral = cumsum((z_integrand[:, :-1] + z_integrand[:, 1:]) / 2 * dz, 1)
|
||||
gamma4 = zeros(gamma1.shape)
|
||||
gamma4[:, 1:] = sum(crpz[:, :, 1:] * z_integral, 1)
|
||||
exponent += gamma4
|
||||
power_interval *= exp(exponent)
|
||||
power[:, interval[1:]] = power_interval[:, 1:]
|
||||
power_in = power_interval[:, -1]
|
||||
elif sim_params.raman_params.method == 'numerical':
|
||||
dz = z[1:] - z[:-1]
|
||||
power = outer(power_in, ones(z.size))
|
||||
for i in range(1, z.size):
|
||||
power[:, i] = (power[:, i - 1] * (1 + (- alpha + sum(cr * power[:, i - 1], 1)) * dz[i - 1]) *
|
||||
lumped_losses[i - 1])
|
||||
else:
|
||||
raise ValueError(f'Method {sim_params.raman_params.method} not implemented in Raman Solver.')
|
||||
return power
|
||||
|
||||
@staticmethod
|
||||
def iterative_algorithm(co_initial_guess_power, cnt_initial_guess_power, co_frequency, cnt_frequency, z, fiber,
|
||||
lumped_losses):
|
||||
"""Solves the Raman equation in case of both co- and counter-propagating frequencies
|
||||
|
||||
:param co_initial_guess_power: co-propagationg Raman first order derivative equation solution
|
||||
:param cnt_initial_guess_power: counter-propagationg Raman first order derivative equation solution
|
||||
:param co_frequency: co-propagationg frequencies
|
||||
:param cnt_frequency: counter-propagationg frequencies
|
||||
:param z: z position array
|
||||
:param fiber: instance of gnpy.core.elements.Fiber or gnpy.core.elements.RamanFiber
|
||||
:param lumped_losses: concentrated losses array along the fiber span
|
||||
:return: co- and counter-propagatng power profile matrix
|
||||
"""
|
||||
logger.debug(' Start iterative algorithm')
|
||||
residue = 1
|
||||
residue_tol = 1e-6
|
||||
accuracy = 1
|
||||
accuracy_tol = 1e-3
|
||||
iteration = 0
|
||||
num_max_iter = 1000
|
||||
prev_power = concatenate((co_initial_guess_power, cnt_initial_guess_power))
|
||||
frequency = concatenate((co_frequency, cnt_frequency))
|
||||
dz = z[1:] - z[:-1]
|
||||
cr = fiber.cr(frequency)
|
||||
alpha = fiber.alpha(frequency)
|
||||
next_power = array(prev_power)
|
||||
while residue > residue_tol and accuracy > accuracy_tol and iteration < num_max_iter:
|
||||
iteration += 1
|
||||
for i in range(1, z.size):
|
||||
dpdz = - alpha + sum(cr * next_power[:, i - 1], 1)
|
||||
next_power[:co_frequency.size, i] = \
|
||||
next_power[:co_frequency.size, i - 1] * (1 + dpdz[:co_frequency.size] * dz[i - 1]) * \
|
||||
lumped_losses[i - 1]
|
||||
for i in range(1, z.size):
|
||||
dpdz = - alpha + sum(cr * next_power[:, -i], 1)
|
||||
next_power[co_frequency.size:, -i - 1] = \
|
||||
next_power[co_frequency.size:, -i] * (1 + dpdz[co_frequency.size:] * dz[-i]) * \
|
||||
lumped_losses[-i]
|
||||
|
||||
dpdz_num = (next_power[:co_frequency.size, 1:] - next_power[:co_frequency.size, :-1]) / dz
|
||||
dpdz_exp = next_power[:co_frequency.size, :-1] * \
|
||||
(- outer(alpha, ones(z.size)) + inner(cr, transpose(next_power)))[:co_frequency.size, :-1] * \
|
||||
lumped_losses[:-1]
|
||||
|
||||
residue = max(abs((next_power - prev_power) / next_power))
|
||||
accuracy = max(abs((dpdz_exp - dpdz_num) / dpdz_exp))
|
||||
prev_power = array(next_power)
|
||||
logger.debug(f' Iteration: {iteration} Accuracy: {format_float_scientific(accuracy, precision=3)}')
|
||||
return next_power[:co_frequency.size, :], next_power[co_frequency.size:, :]
|
||||
|
||||
|
||||
class NliSolver:
|
||||
"""This class implements the NLI models.
|
||||
Model and method can be specified in `sim_params.nli_params.method`.
|
||||
List of implemented methods:
|
||||
'gn_model_analytic': eq. 120 from arXiv:1209.0394
|
||||
'ggn_spectrally_separated': eq. 21 from arXiv: 1710.02225
|
||||
'ggn_approx': eq. 24-25 jlt:9741324
|
||||
"""
|
||||
|
||||
SPM_WEIGHT = (16.0 / 27.0)
|
||||
XPM_WEIGHT = 2 * (16.0 / 27.0)
|
||||
|
||||
@staticmethod
|
||||
def effective_length(alpha, length):
|
||||
"""The effective length identify the region in which the NLI has a significant contribution to
|
||||
the signal degradation.
|
||||
"""
|
||||
return (1 - exp(- alpha * length)) / alpha
|
||||
|
||||
@staticmethod
|
||||
def compute_nli(spectral_info: SpectralInformation, srs: StimulatedRamanScattering, fiber):
|
||||
"""Compute NLI power generated by the WDM comb `*carriers` on the channel under test `carrier`
|
||||
at the end of the fiber span.
|
||||
"""
|
||||
logger.debug('Start computing fiber NLI noise')
|
||||
|
||||
if 'gn_model_analytic' == sim_params.nli_params.method:
|
||||
eta = NliSolver._gn_analytic(spectral_info, fiber)
|
||||
|
||||
cut_power = outer(spectral_info.signal, ones(spectral_info.number_of_channels))
|
||||
pump_power = outer(ones(spectral_info.number_of_channels), spectral_info.signal)
|
||||
nli_matrix = cut_power * pump_power ** 2 * eta
|
||||
nli = sum(nli_matrix, 1)
|
||||
elif 'ggn_spectrally_separated' in sim_params.nli_params.method:
|
||||
if sim_params.nli_params.computed_channels is not None:
|
||||
cut_indices = array(sim_params.nli_params.computed_channels) - 1
|
||||
elif sim_params.nli_params.computed_number_of_channels is not None:
|
||||
nb_ch_computed = sim_params.nli_params.computed_number_of_channels
|
||||
nb_ch = len(spectral_info.channel_number)
|
||||
cut_indices = array([round(i * (nb_ch - 1) / (nb_ch_computed - 1)) for i in range(0, nb_ch_computed)])
|
||||
else:
|
||||
cut_indices = array(spectral_info.channel_number) - 1
|
||||
|
||||
eta = NliSolver._ggn_spectrally_separated(cut_indices, spectral_info, fiber, srs)
|
||||
|
||||
# Interpolation over the channels not indicated as compted channels in simulation parameters
|
||||
cut_power = outer(spectral_info.signal[cut_indices], ones(spectral_info.number_of_channels))
|
||||
cut_frequency = spectral_info.frequency[cut_indices]
|
||||
pump_power = outer(ones(cut_indices.size), spectral_info.signal)
|
||||
cut_baud_rate = outer(spectral_info.baud_rate[cut_indices], ones(spectral_info.number_of_channels))
|
||||
|
||||
g_nli = eta * cut_power * pump_power**2 / cut_baud_rate
|
||||
g_nli = sum(g_nli, 1)
|
||||
g_nli = interp(spectral_info.frequency, cut_frequency, g_nli)
|
||||
nli = spectral_info.baud_rate * g_nli # Local white noise
|
||||
elif 'ggn_approx' in sim_params.nli_params.method:
|
||||
if sim_params.nli_params.computed_channels is not None:
|
||||
cut_indices = array(sim_params.nli_params.computed_channels) - 1
|
||||
elif sim_params.nli_params.computed_number_of_channels is not None:
|
||||
nb_ch_computed = sim_params.nli_params.computed_number_of_channels
|
||||
nb_ch = len(spectral_info.channel_number)
|
||||
cut_indices = array([round(i * (nb_ch - 1) / (nb_ch_computed - 1)) for i in range(0, nb_ch_computed)])
|
||||
else:
|
||||
cut_indices = array(spectral_info.channel_number) - 1
|
||||
|
||||
eta = NliSolver._ggn_approx(cut_indices, spectral_info, fiber, srs)
|
||||
|
||||
# Interpolation over the channels not indicated as computed channels in simulation parameters
|
||||
cut_power = outer(spectral_info.signal[cut_indices], ones(spectral_info.number_of_channels))
|
||||
cut_frequency = spectral_info.frequency[cut_indices]
|
||||
pump_power = outer(ones(cut_indices.size), spectral_info.signal)
|
||||
cut_baud_rate = outer(spectral_info.baud_rate[cut_indices], ones(spectral_info.number_of_channels))
|
||||
|
||||
g_nli = eta * cut_power * pump_power ** 2 / cut_baud_rate
|
||||
g_nli = sum(g_nli, 1)
|
||||
g_nli = interp(spectral_info.frequency, cut_frequency, g_nli)
|
||||
nli = spectral_info.baud_rate * g_nli # Local white noise
|
||||
else:
|
||||
raise ValueError(f'Method {sim_params.nli_params.method} not implemented.')
|
||||
|
||||
return nli
|
||||
|
||||
# Methods for computing GN-model eta matrix
|
||||
@staticmethod
|
||||
def _gn_analytic(spectral_info, fiber, spm_weight=SPM_WEIGHT, xpm_weight=XPM_WEIGHT):
|
||||
"""Computes the nonlinear interference power evaluated at the fiber input.
|
||||
The method uses eq. 120 from arXiv:1209.0394
|
||||
"""
|
||||
# Spectral Features
|
||||
nch = spectral_info.number_of_channels
|
||||
frequency = spectral_info.frequency
|
||||
baud_rate = spectral_info.baud_rate
|
||||
delta_frequency = spectral_info.df
|
||||
|
||||
# Physical fiber parameters
|
||||
alpha = fiber.alpha(frequency)
|
||||
beta2 = fiber.beta2(frequency)
|
||||
gamma = outer(fiber.gamma(frequency), ones(nch))
|
||||
length = fiber.params.length
|
||||
|
||||
identity = diag(ones(nch))
|
||||
weight = spm_weight * identity + xpm_weight * (ones([nch, nch]) - identity)
|
||||
|
||||
effective_length = NliSolver.effective_length(alpha, length)
|
||||
asymptotic_length = 1 / alpha
|
||||
|
||||
cut_baud_rate = outer(baud_rate, ones(nch))
|
||||
pump_baud_rate = outer(ones(nch), baud_rate)
|
||||
|
||||
psi = NliSolver._psi(delta_frequency, baud_rate, beta2, effective_length, asymptotic_length)
|
||||
eta_cut_central_frequency = gamma ** 2 * weight * psi / (cut_baud_rate * pump_baud_rate ** 2)
|
||||
eta = cut_baud_rate * eta_cut_central_frequency # Local white noise
|
||||
return eta
|
||||
|
||||
@staticmethod
|
||||
def _psi(df, baud_rate, beta2, effective_length, asymptotic_length):
|
||||
"""Calculates eq. 123 from `arXiv:1209.0394 <https://arxiv.org/abs/1209.0394>`__"""
|
||||
cut_baud_rate = outer(baud_rate, ones(baud_rate.size))
|
||||
cut_beta = outer(beta2, ones(baud_rate.size))
|
||||
pump_baud_rate = baud_rate
|
||||
pump_beta = outer(ones(baud_rate.size), beta2)
|
||||
beta2 = (cut_beta + pump_beta) / 2
|
||||
right_extreme = df + pump_baud_rate / 2
|
||||
left_extreme = df - pump_baud_rate / 2
|
||||
psi = (arcsinh(pi ** 2 * asymptotic_length * abs(beta2) * cut_baud_rate * right_extreme) -
|
||||
arcsinh(pi ** 2 * asymptotic_length * abs(beta2) * cut_baud_rate * left_extreme)) / 2
|
||||
psi *= effective_length ** 2 / (2 * pi * abs(beta2) * asymptotic_length)
|
||||
return psi
|
||||
|
||||
# Methods for computing the GGN-model eta matrix
|
||||
@staticmethod
|
||||
def _ggn_spectrally_separated(cut_indices, spectral_info, fiber, srs, spm_weight=SPM_WEIGHT, xpm_weight=XPM_WEIGHT):
|
||||
"""Computes the nonlinear interference power evaluated at the fiber input.
|
||||
The method uses eq. 21 from arXiv: 1710.02225
|
||||
"""
|
||||
# Spectral Features
|
||||
nch = spectral_info.number_of_channels
|
||||
frequency = spectral_info.frequency
|
||||
baud_rate = spectral_info.baud_rate
|
||||
slot_width = spectral_info.slot_width
|
||||
roll_off = spectral_info.roll_off
|
||||
|
||||
# Physical fiber parameters
|
||||
alpha = fiber.alpha(frequency)
|
||||
beta2 = fiber.beta2(frequency)
|
||||
gamma = outer(fiber.gamma(frequency[cut_indices]), ones(nch))
|
||||
|
||||
identity = diag(ones(nch))
|
||||
weight = spm_weight * identity + xpm_weight * (ones([nch, nch]) - identity)
|
||||
weight = weight[cut_indices, :]
|
||||
|
||||
dispersion_tolerance = sim_params.nli_params.dispersion_tolerance
|
||||
phase_shift_tolerance = sim_params.nli_params.phase_shift_tolerance
|
||||
max_slot_width = max(slot_width)
|
||||
delta_z = sim_params.raman_params.result_spatial_resolution
|
||||
|
||||
psi_cut_central_frequency = zeros([cut_indices.size, nch])
|
||||
for i, cut_index in enumerate(cut_indices):
|
||||
logger.debug(f'Start computing fiber NLI noise of cut: {cut_index + 1}')
|
||||
cut_frequency = frequency[cut_index]
|
||||
cut_baud_rate = baud_rate[cut_index]
|
||||
cut_roll_off = roll_off[cut_index]
|
||||
cut_number = cut_index + 1
|
||||
cut_beta2 = beta2[cut_index]
|
||||
cut_base_frequency = frequency - cut_frequency
|
||||
cut_beta_coefficients = polyfit(cut_base_frequency, beta2, 2)
|
||||
cut_beta3 = cut_beta_coefficients[1] / (2 * pi)
|
||||
|
||||
for pump_index in range(nch):
|
||||
pump_frequency = frequency[pump_index]
|
||||
pump_baud_rate = baud_rate[pump_index]
|
||||
pump_roll_off = roll_off[pump_index]
|
||||
pump_number = pump_index + 1
|
||||
pump_alpha = alpha[pump_index]
|
||||
dn = abs(pump_number - cut_number)
|
||||
delta_f = abs(cut_frequency - pump_frequency)
|
||||
k_tol = dispersion_tolerance * abs(alpha[pump_index])
|
||||
phi_tol = phase_shift_tolerance / delta_z
|
||||
f_cut_resolution = min(k_tol, phi_tol) / abs(cut_beta2) / (4 * pi ** 2 * (1 + dn) * max_slot_width)
|
||||
f_pump_resolution = min(k_tol, phi_tol) / abs(cut_beta2) / (4 * pi ** 2 * max_slot_width)
|
||||
if cut_index == pump_index: # SPM
|
||||
psi_cut_central_frequency[i, pump_index] = \
|
||||
NliSolver._generalized_psi(cut_frequency, cut_frequency, cut_baud_rate, cut_roll_off,
|
||||
pump_frequency, pump_baud_rate, pump_roll_off, f_cut_resolution,
|
||||
f_pump_resolution, srs, pump_alpha, cut_beta2, cut_beta3,
|
||||
cut_frequency)
|
||||
else: # XPM
|
||||
frequency_offset_threshold = NliSolver._frequency_offset_threshold(cut_beta2, pump_baud_rate)
|
||||
if abs(delta_f) <= frequency_offset_threshold:
|
||||
psi_cut_central_frequency[i, pump_index] = \
|
||||
NliSolver._generalized_psi(cut_frequency, cut_frequency, cut_baud_rate, cut_roll_off,
|
||||
pump_frequency, pump_baud_rate, pump_roll_off, f_cut_resolution,
|
||||
f_pump_resolution, srs, pump_alpha, cut_beta2, cut_beta3,
|
||||
cut_frequency)
|
||||
else:
|
||||
psi_cut_central_frequency[i, pump_index] = \
|
||||
NliSolver._fast_generalized_psi(cut_frequency, cut_frequency, cut_baud_rate, cut_roll_off,
|
||||
pump_frequency, pump_baud_rate, pump_roll_off,
|
||||
f_cut_resolution, srs, pump_alpha, cut_beta2, cut_beta3,
|
||||
cut_frequency)
|
||||
|
||||
cut_baud_rate = outer(baud_rate[cut_indices], ones(nch))
|
||||
pump_baud_rate = outer(ones(cut_indices.size), baud_rate)
|
||||
|
||||
eta_cut_central_frequency = \
|
||||
gamma ** 2 * weight * psi_cut_central_frequency / (cut_baud_rate * pump_baud_rate ** 2)
|
||||
eta = cut_baud_rate * eta_cut_central_frequency # Local white noise
|
||||
return eta
|
||||
|
||||
@staticmethod
|
||||
def _fast_generalized_psi(f_eval, cut_frequency, cut_baud_rate, cut_roll_off, pump_frequency, pump_baud_rate,
|
||||
pump_roll_off, f_cut_resolution, srs, alpha, beta2, beta3, f_ref_beta):
|
||||
"""Computes the generalized psi function similarly to the one used in the GN model."""
|
||||
z = srs.z
|
||||
rho_norm = srs.rho * exp(outer(alpha / 2, z))
|
||||
rho_pump = interp1d(srs.frequency, rho_norm, axis=0)(pump_frequency)
|
||||
|
||||
f1_array = array([pump_frequency - (pump_baud_rate * (1 + pump_roll_off) / 2),
|
||||
pump_frequency + (pump_baud_rate * (1 + pump_roll_off) / 2)])
|
||||
f2_array = arange(cut_frequency, cut_frequency + (cut_baud_rate * (1 + cut_roll_off) / 2),
|
||||
f_cut_resolution) # Only positive f2 is used since integrand_f2 is symmetric
|
||||
|
||||
integrand_f1 = zeros(f1_array.size)
|
||||
for f1_index, f1 in enumerate(f1_array):
|
||||
delta_beta = 4 * pi ** 2 * (f1 - f_eval) * (f2_array - f_eval) * (
|
||||
beta2 + pi * beta3 * (f1 + f2_array - 2 * f_ref_beta))
|
||||
integrand_f2 = NliSolver._generalized_rho_nli(delta_beta, rho_pump, z, alpha)
|
||||
integrand_f1[f1_index] = 2 * trapz(integrand_f2, f2_array) # 2x since integrand_f2 is symmetric in f2
|
||||
generalized_psi = 0.5 * sum(integrand_f1) * pump_baud_rate
|
||||
return generalized_psi
|
||||
|
||||
@staticmethod
|
||||
def _generalized_psi(f_eval, cut_frequency, cut_baud_rate, cut_roll_off, pump_frequency, pump_baud_rate,
|
||||
pump_roll_off, f_cut_resolution, f_pump_resolution, srs, alpha, beta2, beta3, f_ref_beta):
|
||||
"""Computes the generalized psi function similarly to the one used in the GN model."""
|
||||
z = srs.z
|
||||
rho_norm = srs.rho * exp(outer(alpha / 2, z))
|
||||
rho_pump = interp1d(srs.frequency, rho_norm, axis=0)(pump_frequency)
|
||||
|
||||
f1_array = arange(pump_frequency - (pump_baud_rate * (1 + pump_roll_off) / 2),
|
||||
pump_frequency + (pump_baud_rate * (1 + pump_roll_off) / 2),
|
||||
f_pump_resolution)
|
||||
f2_array = arange(cut_frequency - (cut_baud_rate * (1 + cut_roll_off) / 2),
|
||||
cut_frequency + (cut_baud_rate * (1 + cut_roll_off) / 2),
|
||||
f_cut_resolution)
|
||||
rc1 = raised_cosine(f1_array, pump_frequency, pump_baud_rate, pump_roll_off)
|
||||
|
||||
integrand_f1 = zeros(f1_array.size)
|
||||
for i in range(f1_array.size):
|
||||
f3_array = f1_array[i] + f2_array - f_eval
|
||||
rc2 = raised_cosine(f2_array, cut_frequency, cut_baud_rate, cut_roll_off)
|
||||
rc3 = raised_cosine(f3_array, pump_frequency, pump_baud_rate, pump_roll_off)
|
||||
delta_beta = 4 * pi ** 2 * (f1_array[i] - f_eval) * (f2_array - f_eval) * (
|
||||
beta2 + pi * beta3 * (f1_array[i] + f2_array - 2 * f_ref_beta))
|
||||
integrand_f2 = rc1[i] * rc2 * rc3 * NliSolver._generalized_rho_nli(delta_beta, rho_pump, z, alpha)
|
||||
integrand_f1[i] = trapz(integrand_f2, f2_array)
|
||||
generalized_psi = trapz(integrand_f1, f1_array)
|
||||
return generalized_psi
|
||||
|
||||
@staticmethod
|
||||
def _generalized_rho_nli(delta_beta, rho_pump, z, alpha):
|
||||
w = 1j * delta_beta - alpha
|
||||
generalized_rho_nli = (rho_pump[-1]**2 * exp(w * z[-1]) - rho_pump[0]**2 * exp(w * z[0])) / w
|
||||
for z_ind in range(0, len(z) - 1):
|
||||
derivative_rho = (rho_pump[z_ind + 1]**2 - rho_pump[z_ind]**2) / (z[z_ind + 1] - z[z_ind])
|
||||
generalized_rho_nli -= derivative_rho * (exp(w * z[z_ind + 1]) - exp(w * z[z_ind])) / (w**2)
|
||||
generalized_rho_nli = abs(generalized_rho_nli)**2
|
||||
return generalized_rho_nli
|
||||
|
||||
@staticmethod
|
||||
def _frequency_offset_threshold(beta2, symbol_rate):
|
||||
k_ref = 5
|
||||
beta2_ref = 21.3e-27
|
||||
delta_f_ref = 50e9
|
||||
rs_ref = 32e9
|
||||
beta2 = abs(beta2)
|
||||
freq_offset_th = ((k_ref * delta_f_ref) * rs_ref * beta2_ref) / (beta2 * symbol_rate)
|
||||
return freq_offset_th
|
||||
|
||||
@staticmethod
|
||||
def _ggn_approx(cut_indices, spectral_info: SpectralInformation, fiber, srs, spm_weight=SPM_WEIGHT,
|
||||
xpm_weight=XPM_WEIGHT):
|
||||
"""Computes the nonlinear interference power evaluated at the fiber input.
|
||||
The method uses eq. 24-25 of https://ieeexplore.ieee.org/document/9741324
|
||||
"""
|
||||
# Spectral Features
|
||||
nch = spectral_info.number_of_channels
|
||||
frequency = spectral_info.frequency
|
||||
baud_rate = spectral_info.baud_rate
|
||||
slot_width = spectral_info.slot_width
|
||||
roll_off = spectral_info.roll_off
|
||||
df = spectral_info.df + diag(full(nch, nan))
|
||||
|
||||
# Physical fiber parameters
|
||||
alpha = fiber.alpha(frequency)
|
||||
beta2 = fiber.beta2(frequency)
|
||||
gamma = outer(fiber.gamma(frequency[cut_indices]), ones(nch))
|
||||
|
||||
identity = diag(ones(nch))
|
||||
weight = spm_weight * identity + xpm_weight * (ones([nch, nch]) - identity)
|
||||
weight = weight[cut_indices, :]
|
||||
|
||||
dispersion_tolerance = sim_params.nli_params.dispersion_tolerance
|
||||
phase_shift_tolerance = sim_params.nli_params.phase_shift_tolerance
|
||||
max_slot_width = max(slot_width)
|
||||
max_beta2 = max(abs(beta2))
|
||||
delta_z = sim_params.raman_params.result_spatial_resolution
|
||||
|
||||
# Approximation psi
|
||||
loss_profile = srs.loss_profile[:nch]
|
||||
z = srs.z
|
||||
psi = NliSolver._approx_psi(df=df, frequency=frequency, beta2=beta2, baud_rate=baud_rate,
|
||||
loss_profile=loss_profile, z=z)
|
||||
|
||||
# GGN for SPM
|
||||
for cut_index in cut_indices:
|
||||
dn = 0
|
||||
cut_frequency = frequency[cut_index]
|
||||
cut_baud_rate = baud_rate[cut_index]
|
||||
cut_roll_off = roll_off[cut_index]
|
||||
cut_beta2 = beta2[cut_index]
|
||||
cut_alpha = alpha[cut_index]
|
||||
k_tol = dispersion_tolerance * abs(cut_alpha)
|
||||
phi_tol = phase_shift_tolerance / delta_z
|
||||
f_cut_resolution = min(k_tol, phi_tol) / abs(max_beta2) / (4 * pi ** 2 * (1 + dn) * max_slot_width)
|
||||
f_pump_resolution = min(k_tol, phi_tol) / abs(max_beta2) / (4 * pi ** 2 * max_slot_width)
|
||||
psi[cut_index, cut_index] = NliSolver._generalized_psi(cut_frequency, cut_frequency, cut_baud_rate,
|
||||
cut_roll_off, cut_frequency, cut_baud_rate,
|
||||
cut_roll_off, f_cut_resolution, f_pump_resolution,
|
||||
srs, cut_alpha, cut_beta2, 0, cut_frequency)
|
||||
psi = psi[cut_indices, :]
|
||||
cut_baud_rate = outer(baud_rate[cut_indices], ones(nch))
|
||||
pump_baud_rate = outer(ones(cut_indices.size), baud_rate)
|
||||
|
||||
eta_cut_central_frequency = \
|
||||
gamma ** 2 * weight * psi / (cut_baud_rate * pump_baud_rate ** 2)
|
||||
eta = cut_baud_rate * eta_cut_central_frequency # Local white noise
|
||||
|
||||
return eta
|
||||
|
||||
@staticmethod
|
||||
def _approx_psi(df, frequency, baud_rate, beta2, loss_profile, z):
|
||||
"""Computes the approximated psi function similarly to the one used in the GN model.
|
||||
The method uses eq. 25 of https://ieeexplore.ieee.org/document/9741324"""
|
||||
pump_baud_rate = outer(ones(frequency.size), baud_rate)
|
||||
cut_beta = outer(beta2, ones(frequency.size))
|
||||
pump_beta = outer(ones(frequency.size), beta2)
|
||||
delta_z = abs(z[:-1] - z[1:])
|
||||
|
||||
loss_lin = log(loss_profile)
|
||||
pump_alpha = (loss_lin[:, 1:] - loss_lin[:, :-1]) / delta_z
|
||||
leff = abs((loss_profile[:, 1:] - loss_profile[:, :-1]) / sqrt(abs(pump_alpha))) * pump_alpha / abs(pump_alpha)
|
||||
leff = reshape(outer(leff, ones(z.size - 1)), newshape=[leff.shape[0], leff.shape[1], leff.shape[1]])
|
||||
leff2 = leff * swapaxes(leff, 2, 1)
|
||||
leff2 = sum(leff2, axis=(1, 2))
|
||||
z_int = outer(ones(frequency.size), leff2)
|
||||
|
||||
delta_beta = (cut_beta + pump_beta) / 2
|
||||
psi = z_int * pump_baud_rate / (4 * pi * abs(delta_beta * df))
|
||||
return psi
|
||||
|
||||
|
||||
|
||||
def estimate_nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
||||
if nf_min < -10:
|
||||
raise EquipmentConfigError(f'Invalid nf_min value {nf_min!r} for amplifier {type_variety}')
|
||||
if nf_max < -10:
|
||||
raise EquipmentConfigError(f'Invalid nf_max value {nf_max!r} for amplifier {type_variety}')
|
||||
|
||||
# NF estimation model based on nf_min and nf_max
|
||||
# delta_p: max power dB difference between first and second stage coils
|
||||
# dB g1a: first stage gain - internal VOA attenuation
|
||||
# nf1, nf2: first and second stage coils
|
||||
# calculated by solving nf_{min,max} = nf1 + nf2 / g1a{min,max}
|
||||
delta_p = 5
|
||||
g1a_min = gain_min - (gain_max - gain_min) - delta_p
|
||||
g1a_max = gain_max - delta_p
|
||||
nf2 = lin2db((db2lin(nf_min) - db2lin(nf_max)) /
|
||||
(1 / db2lin(g1a_max) - 1 / db2lin(g1a_min)))
|
||||
nf1 = lin2db(db2lin(nf_min) - db2lin(nf2) / db2lin(g1a_max))
|
||||
|
||||
if nf1 < 4:
|
||||
raise EquipmentConfigError(f'First coil value too low {nf1} for amplifier {type_variety}')
|
||||
|
||||
# Check 1 dB < delta_p < 6 dB to ensure nf_min and nf_max values make sense.
|
||||
# There shouldn't be high nf differences between the two coils:
|
||||
# nf2 should be nf1 + 0.3 < nf2 < nf1 + 2
|
||||
# If not, recompute and check delta_p
|
||||
if not nf1 + 0.3 < nf2 < nf1 + 2:
|
||||
nf2 = clip(nf2, nf1 + 0.3, nf1 + 2)
|
||||
g1a_max = lin2db(db2lin(nf2) / (db2lin(nf_min) - db2lin(nf1)))
|
||||
delta_p = gain_max - g1a_max
|
||||
g1a_min = gain_min - (gain_max - gain_min) - delta_p
|
||||
if not 1 < delta_p < 11:
|
||||
raise EquipmentConfigError(f'Computed \N{greek capital letter delta}P invalid \
|
||||
\n 1st coil vs 2nd coil calculated DeltaP {delta_p:.2f} for \
|
||||
\n amplifier {type_variety} is not valid: revise inputs \
|
||||
\n calculated 1st coil NF = {nf1:.2f}, 2nd coil NF = {nf2:.2f}')
|
||||
# Check calculated values for nf1 and nf2
|
||||
calc_nf_min = lin2db(db2lin(nf1) + db2lin(nf2) / db2lin(g1a_max))
|
||||
if not isclose(nf_min, calc_nf_min, abs_tol=0.01):
|
||||
raise EquipmentConfigError(f'nf_min does not match calc_nf_min, {nf_min} vs {calc_nf_min} for amp {type_variety}')
|
||||
calc_nf_max = lin2db(db2lin(nf1) + db2lin(nf2) / db2lin(g1a_min))
|
||||
if not isclose(nf_max, calc_nf_max, abs_tol=0.01):
|
||||
raise EquipmentConfigError(f'nf_max does not match calc_nf_max, {nf_max} vs {calc_nf_max} for amp {type_variety}')
|
||||
|
||||
return nf1, nf2, delta_p
|
||||
@@ -1,2 +0,0 @@
|
||||
UNITS = {'m': 1,
|
||||
'km': 1E3}
|
||||
@@ -1,75 +1,257 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
import json
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# gnpy.core.utils: utility functions that are used with gnpy
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
import numpy as np
|
||||
from numpy import pi, cos, sqrt, log10
|
||||
"""
|
||||
gnpy.core.utils
|
||||
===============
|
||||
|
||||
This module contains utility functions that are used with gnpy.
|
||||
"""
|
||||
|
||||
from csv import writer
|
||||
from numpy import pi, cos, sqrt, log10, linspace, zeros, shape, where, logical_and, mean, array
|
||||
from scipy import constants
|
||||
from copy import deepcopy
|
||||
from typing import List, Union, Dict
|
||||
|
||||
from gnpy.core.exceptions import ConfigurationError
|
||||
|
||||
|
||||
def load_json(filename):
|
||||
with open(filename, 'r') as f:
|
||||
data = json.load(f)
|
||||
return data
|
||||
|
||||
|
||||
def save_json(obj, filename):
|
||||
with open(filename, 'w') as f:
|
||||
json.dump(obj, f)
|
||||
|
||||
|
||||
def c():
|
||||
def write_csv(obj, filename):
|
||||
"""
|
||||
Returns the speed of light in meters per second
|
||||
Convert dictionary items to a CSV file the dictionary format:
|
||||
::
|
||||
|
||||
{'result category 1':
|
||||
[
|
||||
# 1st line of results
|
||||
{'header 1' : value_xxx,
|
||||
'header 2' : value_yyy},
|
||||
# 2nd line of results: same headers, different results
|
||||
{'header 1' : value_www,
|
||||
'header 2' : value_zzz}
|
||||
],
|
||||
'result_category 2':
|
||||
[
|
||||
{},{}
|
||||
]
|
||||
}
|
||||
|
||||
The generated csv file will be:
|
||||
::
|
||||
|
||||
result_category 1
|
||||
header 1 header 2
|
||||
value_xxx value_yyy
|
||||
value_www value_zzz
|
||||
result_category 2
|
||||
...
|
||||
"""
|
||||
return 299792458.0
|
||||
with open(filename, 'w', encoding='utf-8') as f:
|
||||
w = writer(f)
|
||||
for data_key, data_list in obj.items():
|
||||
# main header
|
||||
w.writerow([data_key])
|
||||
# sub headers:
|
||||
headers = [_ for _ in data_list[0].keys()]
|
||||
w.writerow(headers)
|
||||
for data_dict in data_list:
|
||||
w.writerow([_ for _ in data_dict.values()])
|
||||
|
||||
|
||||
def itufs(spacing, startf=191.35, stopf=196.10):
|
||||
"""Creates an array of frequencies whose default range is
|
||||
191.35-196.10 THz
|
||||
def arrange_frequencies(length, start, stop):
|
||||
"""Create an array of frequencies
|
||||
|
||||
: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
|
||||
:param length: number of elements
|
||||
:param start: Start frequency in THz
|
||||
:param stop: Stop frequency in THz
|
||||
:type length: integer
|
||||
:type start: float
|
||||
:type stop: float
|
||||
:return: an array of frequencies 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
|
||||
return linspace(start, stop, length)
|
||||
|
||||
|
||||
def lin2db(value):
|
||||
"""Convert linear unit to logarithmic (dB)
|
||||
|
||||
>>> lin2db(0.001)
|
||||
-30.0
|
||||
>>> round(lin2db(1.0), 2)
|
||||
0.0
|
||||
>>> round(lin2db(1.26), 2)
|
||||
1.0
|
||||
>>> round(lin2db(10.0), 2)
|
||||
10.0
|
||||
>>> round(lin2db(100.0), 2)
|
||||
20.0
|
||||
"""
|
||||
return 10 * log10(value)
|
||||
|
||||
|
||||
def db2lin(value):
|
||||
"""Convert logarithimic units to linear
|
||||
|
||||
>>> round(db2lin(10.0), 2)
|
||||
10.0
|
||||
>>> round(db2lin(20.0), 2)
|
||||
100.0
|
||||
>>> round(db2lin(1.0), 2)
|
||||
1.26
|
||||
>>> round(db2lin(0.0), 2)
|
||||
1.0
|
||||
>>> round(db2lin(-10.0), 2)
|
||||
0.1
|
||||
"""
|
||||
return 10**(value / 10)
|
||||
|
||||
|
||||
def wavelength2freq(value):
|
||||
""" Converts wavelength units to frequeuncy units.
|
||||
def watt2dbm(value):
|
||||
"""Convert Watt units to dBm
|
||||
|
||||
>>> round(watt2dbm(0.001), 1)
|
||||
0.0
|
||||
>>> round(watt2dbm(0.02), 1)
|
||||
13.0
|
||||
"""
|
||||
return c() / value
|
||||
return lin2db(value * 1e3)
|
||||
|
||||
|
||||
def freq2wavelength(value):
|
||||
""" Converts frequency units to wavelength units.
|
||||
def dbm2watt(value):
|
||||
"""Convert dBm units to Watt
|
||||
|
||||
>>> round(dbm2watt(0), 4)
|
||||
0.001
|
||||
>>> round(dbm2watt(-3), 4)
|
||||
0.0005
|
||||
>>> round(dbm2watt(13), 4)
|
||||
0.02
|
||||
"""
|
||||
return c() / value
|
||||
return db2lin(value) * 1e-3
|
||||
|
||||
|
||||
def psd2powerdbm(psd_mwperghz, baudrate_baud):
|
||||
"""computes power in dBm based on baudrate in bauds and psd in mW/GHz
|
||||
|
||||
>>> round(psd2powerdbm(0.031176, 64e9),3)
|
||||
3.0
|
||||
>>> round(psd2powerdbm(0.062352, 32e9),3)
|
||||
3.0
|
||||
>>> round(psd2powerdbm(0.015625, 64e9),3)
|
||||
0.0
|
||||
"""
|
||||
return lin2db(baudrate_baud * psd_mwperghz * 1e-9)
|
||||
|
||||
|
||||
def power_dbm_to_psd_mw_ghz(power_dbm, baudrate_baud):
|
||||
"""computes power spectral density in mW/GHz based on baudrate in bauds and power in dBm
|
||||
|
||||
>>> power_dbm_to_psd_mw_ghz(0, 64e9)
|
||||
0.015625
|
||||
>>> round(power_dbm_to_psd_mw_ghz(3, 64e9), 6)
|
||||
0.031176
|
||||
>>> round(power_dbm_to_psd_mw_ghz(3, 32e9), 6)
|
||||
0.062352
|
||||
"""
|
||||
return db2lin(power_dbm) / (baudrate_baud * 1e-9)
|
||||
|
||||
|
||||
def psd_mw_per_ghz(power_watt, baudrate_baud):
|
||||
"""computes power spectral density in mW/GHz based on baudrate in bauds and power in W
|
||||
|
||||
>>> psd_mw_per_ghz(2e-3, 32e9)
|
||||
0.0625
|
||||
>>> psd_mw_per_ghz(1e-3, 64e9)
|
||||
0.015625
|
||||
>>> psd_mw_per_ghz(0.5e-3, 32e9)
|
||||
0.015625
|
||||
"""
|
||||
return power_watt * 1e3 / (baudrate_baud * 1e-9)
|
||||
|
||||
|
||||
def round2float(number, step):
|
||||
"""Round a floating point number so that its "resolution" is not bigger than 'step'
|
||||
|
||||
The finest step is fixed at 0.01; smaller values are silently changed to 0.01.
|
||||
|
||||
>>> round2float(123.456, 1000)
|
||||
0.0
|
||||
>>> round2float(123.456, 100)
|
||||
100.0
|
||||
>>> round2float(123.456, 10)
|
||||
120.0
|
||||
>>> round2float(123.456, 1)
|
||||
123.0
|
||||
>>> round2float(123.456, 0.1)
|
||||
123.5
|
||||
>>> round2float(123.456, 0.01)
|
||||
123.46
|
||||
>>> round2float(123.456, 0.001)
|
||||
123.46
|
||||
>>> round2float(123.249, 0.5)
|
||||
123.0
|
||||
>>> round2float(123.250, 0.5)
|
||||
123.0
|
||||
>>> round2float(123.251, 0.5)
|
||||
123.5
|
||||
>>> round2float(123.300, 0.2)
|
||||
123.2
|
||||
>>> round2float(123.301, 0.2)
|
||||
123.4
|
||||
"""
|
||||
step = round(step, 1)
|
||||
if step >= 0.01:
|
||||
number = round(number / step, 0)
|
||||
number = round(number * step, 1)
|
||||
else:
|
||||
number = round(number, 2)
|
||||
return number
|
||||
|
||||
|
||||
wavelength2freq = constants.lambda2nu
|
||||
freq2wavelength = constants.nu2lambda
|
||||
|
||||
|
||||
def snr_sum(snr, bw, snr_added, bw_added=12.5e9):
|
||||
snr_added = snr_added - lin2db(bw / bw_added)
|
||||
snr = -lin2db(db2lin(-snr) + db2lin(-snr_added))
|
||||
return snr
|
||||
|
||||
|
||||
def per_label_average(values, labels):
|
||||
"""computes the average per defined spectrum band, using labels
|
||||
|
||||
>>> labels = ['A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'B', 'C', 'D', 'D', 'D', 'D']
|
||||
>>> values = [28.51, 28.23, 28.15, 28.17, 28.36, 28.53, 28.64, 28.68, 28.7, 28.71, 28.72, 28.73, 28.74, 28.91, 27.96, 27.85, 27.87, 28.02]
|
||||
>>> per_label_average(values, labels)
|
||||
{'A': 28.28, 'B': 28.68, 'C': 28.91, 'D': 27.92}
|
||||
"""
|
||||
|
||||
label_set = sorted(set(labels))
|
||||
summary = {}
|
||||
for label in label_set:
|
||||
vals = [val for val, lab in zip(values, labels) if lab == label]
|
||||
summary[label] = round(mean(vals), 2)
|
||||
return summary
|
||||
|
||||
|
||||
def pretty_summary_print(summary):
|
||||
"""Build a prettty string that shows the summary dict values per label with 2 digits"""
|
||||
if len(summary) == 1:
|
||||
return f'{list(summary.values())[0]:.2f}'
|
||||
text = ', '.join([f'{label}: {value:.2f}' for label, value in summary.items()])
|
||||
return text
|
||||
|
||||
|
||||
def deltawl2deltaf(delta_wl, wavelength):
|
||||
""" 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
|
||||
@@ -87,9 +269,9 @@ def deltawl2deltaf(delta_wl, 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
|
||||
"""convert 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
|
||||
@@ -104,8 +286,7 @@ def deltaf2deltawl(delta_f, frequency):
|
||||
|
||||
|
||||
def rrc(ffs, baud_rate, alpha):
|
||||
""" rrc(ffs, baud_rate, alpha): computes the root-raised cosine filter
|
||||
function.
|
||||
"""compute the root-raised cosine filter function
|
||||
|
||||
:param ffs: A numpy array of frequencies
|
||||
:param baud_rate: The Baud Rate of the System
|
||||
@@ -120,11 +301,525 @@ def rrc(ffs, baud_rate, alpha):
|
||||
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 = zeros(shape(ffs))
|
||||
slope_inds = where(
|
||||
logical_and(abs(ffs) > l_lim, 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))
|
||||
(abs(ffs[slope_inds]) - l_lim)))
|
||||
p_inds = where(logical_and(abs(ffs) > 0, abs(ffs) < l_lim))
|
||||
hf[p_inds] = 1
|
||||
return sqrt(hf)
|
||||
|
||||
|
||||
def merge_amplifier_restrictions(dict1, dict2):
|
||||
"""Update contents of dicts recursively
|
||||
|
||||
>>> d1 = {'params': {'restrictions': {'preamp_variety_list': [], 'booster_variety_list': []}}}
|
||||
>>> d2 = {'params': {'target_pch_out_db': -20}}
|
||||
>>> merge_amplifier_restrictions(d1, d2)
|
||||
{'params': {'restrictions': {'preamp_variety_list': [], 'booster_variety_list': []}, 'target_pch_out_db': -20}}
|
||||
|
||||
>>> d3 = {'params': {'restrictions': {'preamp_variety_list': ['foo'], 'booster_variety_list': ['bar']}}}
|
||||
>>> merge_amplifier_restrictions(d1, d3)
|
||||
{'params': {'restrictions': {'preamp_variety_list': [], 'booster_variety_list': []}}}
|
||||
"""
|
||||
|
||||
copy_dict1 = dict1.copy()
|
||||
for key in dict2:
|
||||
if key in dict1:
|
||||
if isinstance(dict1[key], dict):
|
||||
copy_dict1[key] = merge_amplifier_restrictions(copy_dict1[key], dict2[key])
|
||||
else:
|
||||
copy_dict1[key] = dict2[key]
|
||||
return copy_dict1
|
||||
|
||||
|
||||
def use_pmd_coef(dict1: dict, dict2: dict):
|
||||
"""If Fiber dict1 is missing the pmd_coef value then use the one of dict2.
|
||||
In addition records in "pmd_coef_defined" key the pmd_coef if is was defined in dict1.
|
||||
|
||||
:param dict1: A dictionnary that contains "pmd_coef" key.
|
||||
:type dict1: dict
|
||||
:param dict2: Another dictionnary that contains "pmd_coef" key.
|
||||
:type dict2: dict
|
||||
|
||||
>>> dict1 = {'a': 1, 'pmd_coef': 1.5e-15}
|
||||
>>> dict2 = {'a': 2, 'pmd_coef': 2e-15}
|
||||
>>> use_pmd_coef(dict1, dict2)
|
||||
>>> dict1
|
||||
{'a': 1, 'pmd_coef': 1.5e-15, 'pmd_coef_defined': True}
|
||||
|
||||
>>> dict1 = {'a': 1}
|
||||
>>> use_pmd_coef(dict1, dict2)
|
||||
>>> dict1
|
||||
{'a': 1, 'pmd_coef_defined': False, 'pmd_coef': 2e-15}
|
||||
"""
|
||||
if 'pmd_coef' in dict1 and not dict1['pmd_coef'] \
|
||||
or ('pmd_coef' not in dict1 and 'pmd_coef' in dict2):
|
||||
dict1['pmd_coef_defined'] = False
|
||||
dict1['pmd_coef'] = dict2['pmd_coef']
|
||||
elif 'pmd_coef' in dict1 and dict1['pmd_coef']:
|
||||
dict1['pmd_coef_defined'] = True
|
||||
# all other case do not need any change
|
||||
|
||||
|
||||
def silent_remove(this_list, elem):
|
||||
"""Remove matching elements from a list without raising ValueError
|
||||
|
||||
>>> li = [0, 1]
|
||||
>>> li = silent_remove(li, 1)
|
||||
>>> li
|
||||
[0]
|
||||
>>> li = silent_remove(li, 1)
|
||||
>>> li
|
||||
[0]
|
||||
"""
|
||||
|
||||
try:
|
||||
this_list.remove(elem)
|
||||
except ValueError:
|
||||
pass
|
||||
return this_list
|
||||
|
||||
|
||||
def automatic_nch(f_min, f_max, spacing):
|
||||
"""How many channels are available in the spectrum
|
||||
|
||||
:param f_min Lowest frequenecy [Hz]
|
||||
:param f_max Highest frequency [Hz]
|
||||
:param spacing Channel width [Hz]
|
||||
:return Number of uniform channels
|
||||
|
||||
>>> automatic_nch(191.325e12, 196.125e12, 50e9)
|
||||
96
|
||||
>>> automatic_nch(193.475e12, 193.525e12, 50e9)
|
||||
1
|
||||
"""
|
||||
return int((f_max - f_min) // spacing)
|
||||
|
||||
|
||||
def automatic_fmax(f_min, spacing, nch):
|
||||
"""Find the high-frequenecy boundary of a spectrum
|
||||
|
||||
:param f_min Start of the spectrum (lowest frequency edge) [Hz]
|
||||
:param spacing Grid/channel spacing [Hz]
|
||||
:param nch Number of channels
|
||||
:return End of the spectrum (highest frequency) [Hz]
|
||||
|
||||
>>> automatic_fmax(191.325e12, 50e9, 96)
|
||||
196125000000000.0
|
||||
"""
|
||||
return f_min + spacing * nch
|
||||
|
||||
|
||||
def convert_length(value, units):
|
||||
"""Convert length into basic SI units
|
||||
|
||||
>>> convert_length(1, 'km')
|
||||
1000.0
|
||||
>>> convert_length(2.0, 'km')
|
||||
2000.0
|
||||
>>> convert_length(123, 'm')
|
||||
123.0
|
||||
>>> convert_length(123.0, 'm')
|
||||
123.0
|
||||
>>> convert_length(42.1, 'km')
|
||||
42100.0
|
||||
>>> convert_length(666, 'yards')
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
gnpy.core.exceptions.ConfigurationError: Cannot convert length in "yards" into meters
|
||||
"""
|
||||
if units == 'm':
|
||||
return value * 1e0
|
||||
elif units == 'km':
|
||||
return value * 1e3
|
||||
else:
|
||||
raise ConfigurationError(f'Cannot convert length in "{units}" into meters')
|
||||
|
||||
|
||||
def replace_none(dictionary):
|
||||
""" Replaces None with inf values in a frequency slots dict
|
||||
|
||||
>>> replace_none({'N': 3, 'M': None})
|
||||
{'N': 3, 'M': inf}
|
||||
|
||||
"""
|
||||
for key, val in dictionary.items():
|
||||
if val is None:
|
||||
dictionary[key] = float('inf')
|
||||
if val == float('inf'):
|
||||
dictionary[key] = None
|
||||
return dictionary
|
||||
|
||||
|
||||
def order_slots(slots):
|
||||
""" Order frequency slots from larger slots to smaller ones up to None
|
||||
|
||||
>>> l = [{'N': 3, 'M': None}, {'N': 2, 'M': 1}, {'N': None, 'M': None},{'N': 7, 'M': 2},{'N': None, 'M': 1} , {'N': None, 'M': 0}]
|
||||
>>> order_slots(l)
|
||||
([7, 2, None, None, 3, None], [2, 1, 1, 0, None, None], [3, 1, 4, 5, 0, 2])
|
||||
"""
|
||||
slots_list = deepcopy(slots)
|
||||
slots_list = [replace_none(e) for e in slots_list]
|
||||
for i, e in enumerate(slots_list):
|
||||
e['i'] = i
|
||||
slots_list = sorted(slots_list, key=lambda x: (-x['M'], x['N']) if x['M'] != float('inf') else (x['M'], x['N']))
|
||||
slots_list = [replace_none(e) for e in slots_list]
|
||||
return [e['N'] for e in slots_list], [e['M'] for e in slots_list], [e['i'] for e in slots_list]
|
||||
|
||||
|
||||
def restore_order(elements, order):
|
||||
""" Use order to re-order the element of the list, and ignore None values
|
||||
|
||||
>>> restore_order([7, 2, None, None, 3, None], [3, 1, 4, 5, 0, 2])
|
||||
[3, 2, 7]
|
||||
"""
|
||||
return [elements[i[0]] for i in sorted(enumerate(order), key=lambda x:x[1]) if elements[i[0]] is not None]
|
||||
|
||||
|
||||
def unique_ordered(elements):
|
||||
"""
|
||||
"""
|
||||
unique_elements = []
|
||||
for element in elements:
|
||||
if element not in unique_elements:
|
||||
unique_elements.append(element)
|
||||
return unique_elements
|
||||
|
||||
|
||||
def convert_empty_to_none(json_data: Union[list, dict]) -> dict:
|
||||
"""Convert all instances of "a": [None] into "a": None
|
||||
|
||||
:param json_data: the input data.
|
||||
:type json_data: dict
|
||||
:return: the converted data.
|
||||
:rtype: dict
|
||||
|
||||
>>> json_data = {
|
||||
... "uid": "[east edfa in Lannion",
|
||||
... "type_variety": "multiband_booster",
|
||||
... "metadata": {
|
||||
... "location": {
|
||||
... "latitude": 0.000000,
|
||||
... "longitude": 0.000000,
|
||||
... "city": "Zion",
|
||||
... "region": ""
|
||||
... }
|
||||
... },
|
||||
... "type": "Multiband_amplifier",
|
||||
... "amplifiers": [{
|
||||
... "type_variety": "multiband_booster_LOW_C",
|
||||
... "operational": {
|
||||
... "gain_target": 12.22,
|
||||
... "delta_p": 4.19,
|
||||
... "out_voa": [None],
|
||||
... "tilt_target": 0.00,
|
||||
... "f_min": 191.3,
|
||||
... "f_max": 196.1
|
||||
... }
|
||||
... }, {
|
||||
... "type_variety": "multiband_booster_LOW_L",
|
||||
... "operational": {
|
||||
... "gain_target": 12.05,
|
||||
... "delta_p": 4.19,
|
||||
... "out_voa": [None],
|
||||
... "tilt_target": 0.00,
|
||||
... "f_min": 186.1,
|
||||
... "f_max": 190.9
|
||||
... }
|
||||
... }
|
||||
... ]
|
||||
... }
|
||||
>>> convert_empty_to_none(json_data)
|
||||
{'uid': '[east edfa in Lannion', 'type_variety': 'multiband_booster', \
|
||||
'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}}, \
|
||||
'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'multiband_booster_LOW_C', \
|
||||
'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0, \
|
||||
'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'multiband_booster_LOW_L', \
|
||||
'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0, \
|
||||
'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
|
||||
"""
|
||||
if isinstance(json_data, dict):
|
||||
for key, value in json_data.items():
|
||||
json_data[key] = convert_empty_to_none(value)
|
||||
elif isinstance(json_data, list):
|
||||
if len(json_data) == 1 and json_data[0] is None:
|
||||
return None
|
||||
for i, elem in enumerate(json_data):
|
||||
json_data[i] = convert_empty_to_none(elem)
|
||||
return json_data
|
||||
|
||||
|
||||
def convert_none_to_empty(json_data: Union[list, dict]) -> dict:
|
||||
"""Convert all instances of "a": None into "a": [None], to be compliant with RFC7951.
|
||||
|
||||
:param json_data: the input data.
|
||||
:type json_data: dict
|
||||
:return: the converted data.
|
||||
:rtype: dict
|
||||
|
||||
>>> a = {'uid': '[east edfa in Lannion', 'type_variety': 'multiband_booster',
|
||||
... 'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}},
|
||||
... 'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'multiband_booster_LOW_C',
|
||||
... 'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0,
|
||||
... 'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'multiband_booster_LOW_L',
|
||||
... 'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': None, 'tilt_target': 0.0,
|
||||
... 'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
>>> convert_none_to_empty(a)
|
||||
{'uid': '[east edfa in Lannion', 'type_variety': 'multiband_booster', \
|
||||
'metadata': {'location': {'latitude': 0.0, 'longitude': 0.0, 'city': 'Zion', 'region': ''}}, \
|
||||
'type': 'Multiband_amplifier', 'amplifiers': [{'type_variety': 'multiband_booster_LOW_C', \
|
||||
'operational': {'gain_target': 12.22, 'delta_p': 4.19, 'out_voa': [None], 'tilt_target': 0.0, \
|
||||
'f_min': 191.3, 'f_max': 196.1}}, {'type_variety': 'multiband_booster_LOW_L', \
|
||||
'operational': {'gain_target': 12.05, 'delta_p': 4.19, 'out_voa': [None], 'tilt_target': 0.0, \
|
||||
'f_min': 186.1, 'f_max': 190.9}}]}
|
||||
|
||||
"""
|
||||
if json_data == [None]:
|
||||
# already conformed
|
||||
return json_data
|
||||
if isinstance(json_data, dict):
|
||||
for key, value in json_data.items():
|
||||
json_data[key] = convert_none_to_empty(value)
|
||||
elif isinstance(json_data, list):
|
||||
for i, elem in enumerate(json_data):
|
||||
json_data[i] = convert_none_to_empty(elem)
|
||||
elif json_data is None:
|
||||
return [None]
|
||||
return json_data
|
||||
|
||||
|
||||
def calculate_absolute_min_or_zero(x: array) -> array:
|
||||
"""Calculates the element-wise absolute minimum between the x and zero.
|
||||
|
||||
Parameters:
|
||||
x (array): The first input array.
|
||||
|
||||
Returns:
|
||||
array: The element-wise absolute minimum between x and zero.
|
||||
|
||||
Example:
|
||||
>>> x = array([-1, 2, -3])
|
||||
>>> calculate_absolute_min_or_zero(x)
|
||||
array([1., 0., 3.])
|
||||
"""
|
||||
return (abs(x) - x) / 2
|
||||
|
||||
|
||||
def nice_column_str(data: List[List[str]], max_length: int = 30, padding: int = 1) -> str:
|
||||
"""data is a list of rows, creates strings with nice alignment per colum and padding with spaces
|
||||
letf justified
|
||||
|
||||
>>> table_data = [['aaa', 'b', 'c'], ['aaaaaaaa', 'bbb', 'c'], ['a', 'bbbbbbbbbb', 'c']]
|
||||
>>> print(nice_column_str(table_data))
|
||||
aaa b c
|
||||
aaaaaaaa bbb c
|
||||
a bbbbbbbbbb c
|
||||
"""
|
||||
# transpose data to determine size of columns
|
||||
transposed_data = list(map(list, zip(*data)))
|
||||
column_width = [max(len(word) for word in column) + padding for column in transposed_data]
|
||||
nice_str = []
|
||||
for row in data:
|
||||
column = ''.join(word[0:max_length].ljust(min(width, max_length)) for width, word in zip(column_width, row))
|
||||
nice_str.append(f'{column}')
|
||||
return '\n'.join(nice_str)
|
||||
|
||||
|
||||
def filter_valid_amp_bands(amp_bands: List[List[dict]]) -> List[List[dict]]:
|
||||
"""Filter out invalid amplifier bands that lack f_min or f_max.
|
||||
|
||||
:param amp_bands: A list of lists containing amplifier band dictionaries.
|
||||
:type amp_bands: List[List[dict]]
|
||||
:return: A filtered list of amplifier bands that contain valid f_min and f_max.
|
||||
:rtype: List[List[dict]]
|
||||
"""
|
||||
return [amp for amp in amp_bands if all(band.get('f_min') is not None and band.get('f_max') is not None
|
||||
for band in amp)]
|
||||
|
||||
|
||||
def remove_duplicates(amp_bands: List[List[dict]]) -> List[List[dict]]:
|
||||
"""Remove duplicate amplifier bands.
|
||||
|
||||
:param amp_bands: A list of lists containing amplifier band dictionaries.
|
||||
:type amp_bands: List[List[dict]]
|
||||
:return: A list of unique amplifier bands.
|
||||
:rtype: List[List[dict]]
|
||||
"""
|
||||
unique_amp_bands = []
|
||||
for amp in amp_bands:
|
||||
if amp not in unique_amp_bands:
|
||||
unique_amp_bands.append(amp)
|
||||
return unique_amp_bands
|
||||
|
||||
|
||||
def calculate_spacing(first: dict, second: dict, default_spacing: float, default_design_bands: Union[List[Dict], None],
|
||||
f_min: float, f_max: float) -> float:
|
||||
"""Calculate the spacing for the given frequency range.
|
||||
|
||||
:param first: The first amplifier band dictionary.
|
||||
:type first: dict
|
||||
:param second: The second amplifier band dictionary.
|
||||
:type second: dict
|
||||
:param default_spacing: The default spacing to use if no specific spacing can be determined.
|
||||
:type default_spacing: float
|
||||
:param default_design_bands: Optional list of design bands to determine spacing from.
|
||||
:type default_design_bands: Union[List[Dict], None]
|
||||
:param f_min: The minimum frequency of the range.
|
||||
:type f_min: float
|
||||
:param f_max: The maximum frequency of the range.
|
||||
:type f_max: float
|
||||
:return: The calculated spacing for the given frequency range.
|
||||
:rtype: float
|
||||
"""
|
||||
if first.get('spacing') is not None and second.get('spacing') is not None:
|
||||
return max(first['spacing'], second['spacing'])
|
||||
elif first.get('spacing') is not None:
|
||||
return first['spacing']
|
||||
elif second.get('spacing') is not None:
|
||||
return second['spacing']
|
||||
elif default_design_bands:
|
||||
temp = get_spacing_from_band(default_design_bands, f_min, f_max)
|
||||
return temp if temp is not None else default_spacing
|
||||
return default_spacing
|
||||
|
||||
|
||||
def find_common_range(amp_bands: List[List[dict]], default_band_f_min: Union[float, None],
|
||||
default_band_f_max: Union[float, None], default_spacing: float,
|
||||
default_design_bands: Union[List[Dict], None] = None) -> List[dict]:
|
||||
"""
|
||||
Find the common frequency range of amplifier bands.
|
||||
|
||||
If there are no amplifiers in the path, then use the default band parameters.
|
||||
|
||||
:param amp_bands: A list of lists containing amplifier band dictionaries, each with 'f_min', 'f_max',
|
||||
and optionally 'spacing'.
|
||||
:type amp_bands: List[List[dict]]
|
||||
:param default_band_f_min: The minimum frequency of the default band.
|
||||
:type default_band_f_min: Union[float, None]
|
||||
:param default_band_f_max: The maximum frequency of the default band.
|
||||
:type default_band_f_max: Union[float, None]
|
||||
:param default_spacing: The default spacing to use if no specific spacing can be determined.
|
||||
:type default_spacing: float
|
||||
:param default_design_bands: Optional list of design bands to determine spacing from.
|
||||
:type default_design_bands: Union[List[Dict], None]
|
||||
:return: A list of dictionaries representing the common frequency ranges with their respective spacings.
|
||||
:rtype: List[dict]
|
||||
|
||||
>>> amp_bands = [[{'f_min': 191e12, 'f_max' : 195e12, 'spacing': 70e9}, {'f_min': 186e12, 'f_max' : 190e12}], \
|
||||
[{'f_min': 185e12, 'f_max' : 189e12}, {'f_min': 192e12, 'f_max' : 196e12}], \
|
||||
[{'f_min': 186e12, 'f_max': 193e12}]]
|
||||
>>> find_common_range(amp_bands, 190e12, 195e12, 50e9)
|
||||
[{'f_min': 186000000000000.0, 'f_max': 189000000000000.0, 'spacing': 50000000000.0}, \
|
||||
{'f_min': 192000000000000.0, 'f_max': 193000000000000.0, 'spacing': 70000000000.0}]
|
||||
|
||||
>>> amp_bands = [[{'f_min': 191e12, 'f_max' : 195e12}, {'f_min': 186e12, 'f_max' : 190e12}], \
|
||||
[{'f_min': 185e12, 'f_max' : 189e12}, {'f_min': 192e12, 'f_max' : 196e12}], \
|
||||
[{'f_min': 186e12, 'f_max': 192e12}]]
|
||||
>>> find_common_range(amp_bands, 190e12, 195e12, 50e9)
|
||||
[{'f_min': 186000000000000.0, 'f_max': 189000000000000.0, 'spacing': 50000000000.0}]
|
||||
"""
|
||||
# Step 1: Filter and sort amplifier bands
|
||||
_amp_bands = [sorted(amp, key=lambda x: x['f_min']) for amp in filter_valid_amp_bands(amp_bands)]
|
||||
unique_amp_bands = remove_duplicates(_amp_bands)
|
||||
|
||||
# Step 2: Handle cases with no valid bands
|
||||
if unique_amp_bands:
|
||||
common_range = unique_amp_bands[0]
|
||||
else:
|
||||
if default_band_f_min is None or default_band_f_max is None:
|
||||
return []
|
||||
return [{'f_min': default_band_f_min, 'f_max': default_band_f_max, 'spacing': None}]
|
||||
|
||||
# Step 3: Calculate common frequency range
|
||||
for bands in unique_amp_bands:
|
||||
new_common_range = []
|
||||
for first in common_range:
|
||||
for second in bands:
|
||||
f_min = max(first['f_min'], second['f_min'])
|
||||
f_max = min(first['f_max'], second['f_max'])
|
||||
if f_min < f_max:
|
||||
spacing = calculate_spacing(first, second, default_spacing, default_design_bands, f_min, f_max)
|
||||
new_common_range.append({'f_min': f_min, 'f_max': f_max, 'spacing': spacing})
|
||||
|
||||
common_range = new_common_range
|
||||
|
||||
return sorted(common_range, key=lambda x: x['f_min'])
|
||||
|
||||
|
||||
def transform_data(data: str) -> Union[List[int], None]:
|
||||
"""Transforms a float into an list of one integer or a string separated by "|" into a list of integers.
|
||||
|
||||
Args:
|
||||
data (float or str): The data to transform.
|
||||
|
||||
Returns:
|
||||
list of int: The transformed data as a list of integers.
|
||||
|
||||
Examples:
|
||||
>>> transform_data(5.0)
|
||||
[5]
|
||||
|
||||
>>> transform_data('1 | 2 | 3')
|
||||
[1, 2, 3]
|
||||
"""
|
||||
if isinstance(data, float):
|
||||
return [int(data)]
|
||||
if isinstance(data, str):
|
||||
return [int(x) for x in data.split(' | ')]
|
||||
return None
|
||||
|
||||
|
||||
def convert_pmd_lineic(pmd: Union[float, None], length: float, length_unit: str) -> Union[float, None]:
|
||||
"""Convert PMD value of the span in ps into pmd_lineic in s/sqrt(km)
|
||||
|
||||
:param pmd: value in ps
|
||||
:type pmd: Union[float, None]
|
||||
:param length: value in length_unit
|
||||
:type length: float
|
||||
:param length_unit: 'km' or 'm'
|
||||
:type length_unit: str
|
||||
:return: lineic PMD s/sqrt(m)
|
||||
:rtype: Union[float, None]
|
||||
|
||||
>>> convert_pmd_lineic(10, 0.001, 'km')
|
||||
1e-11
|
||||
"""
|
||||
if pmd:
|
||||
return pmd * 1e-12 / sqrt(convert_length(length, length_unit))
|
||||
return None
|
||||
def get_spacing_from_band(design_bands: List[Dict], f_min, f_max):
|
||||
"""Retrieve the spacing for a frequency range based on design bands.
|
||||
|
||||
This function checks if the midpoint of the provided frequency range (f_min, f_max)
|
||||
falls within any of the design bands. If it does, the corresponding spacing is returned.
|
||||
|
||||
:param design_bands: A list of design band dictionaries, each containing 'f_min', 'f_max', and 'spacing'.
|
||||
:type design_bands: List[Dict]
|
||||
:param f_min: The minimum frequency of the range.
|
||||
:type f_min: float
|
||||
:param f_max: The maximum frequency of the range.
|
||||
:type f_max: float
|
||||
:return: The spacing corresponding to the design band that contains the midpoint of the range,
|
||||
or None if no such band exists.
|
||||
:rtype: Union[float, None]
|
||||
"""
|
||||
midpoint = (f_min + f_max) / 2
|
||||
for band in design_bands:
|
||||
if midpoint >= band['f_min'] and midpoint <= band['f_max']:
|
||||
return band['spacing']
|
||||
return None
|
||||
|
||||
|
||||
def reorder_per_degree_design_bands(per_degree_design_bands: dict):
|
||||
"""Sort the design bands for each degree by their minimum frequency (f_min).
|
||||
|
||||
This function modifies the input dictionary in place, sorting the design bands for each unique identifier.
|
||||
|
||||
:param per_degree_design_bands: A dictionary where keys are unique identifiers and values are lists of design band dictionaries.
|
||||
:type per_degree_design_bands: Dict[str, List[Dict]]
|
||||
"""
|
||||
for uid, design_bands in per_degree_design_bands.items():
|
||||
per_degree_design_bands[uid] = sorted(design_bands, key=lambda x: x['f_min'])
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
10278
gnpy/example-data/CORONET_Global_Topology.json
Normal file
10278
gnpy/example-data/CORONET_Global_Topology.json
Normal file
File diff suppressed because it is too large
Load Diff
BIN
gnpy/example-data/CORONET_Global_Topology.xls
Normal file
BIN
gnpy/example-data/CORONET_Global_Topology.xls
Normal file
Binary file not shown.
160
gnpy/example-data/Juniper-BoosterHG.json
Normal file
160
gnpy/example-data/Juniper-BoosterHG.json
Normal file
@@ -0,0 +1,160 @@
|
||||
{
|
||||
"nf_fit_coeff": [
|
||||
0.0008,
|
||||
0.0272,
|
||||
-0.2249,
|
||||
6.4902
|
||||
],
|
||||
"f_min": 191.4e12,
|
||||
"f_max": 196.1e12,
|
||||
"nf_ripple": [
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
],
|
||||
"gain_ripple": [
|
||||
-0.15656302345061,
|
||||
-0.22244242043552,
|
||||
-0.25188965661642,
|
||||
-0.23575900335007,
|
||||
-0.20897508375209,
|
||||
-0.19440221943049,
|
||||
-0.18324644053602,
|
||||
-0.18053287269681,
|
||||
-0.17113588777219,
|
||||
-0.15460322445561,
|
||||
-0.13550774706866,
|
||||
-0.10606051088777,
|
||||
-0.0765630234506,
|
||||
-0.04962835008375,
|
||||
-0.01319618927973,
|
||||
0.01027114740367,
|
||||
0.03378873534338,
|
||||
0.04961788107202,
|
||||
0.04494451423784,
|
||||
0.0399193886097,
|
||||
0.01584903685091,
|
||||
-0.00420121440538,
|
||||
-0.01847257118928,
|
||||
-0.02475397822447,
|
||||
-0.01053287269681,
|
||||
0.01509526800668,
|
||||
0.05921587102177,
|
||||
0.1191656197655,
|
||||
0.18147717755444,
|
||||
0.23579878559464,
|
||||
0.26941687604691,
|
||||
0.27836159966498,
|
||||
0.26956762981574,
|
||||
0.23826109715241,
|
||||
0.18936662479061,
|
||||
0.1204721524288,
|
||||
0.0453465242881,
|
||||
-0.00877407872698,
|
||||
-0.02199015912898,
|
||||
0.00107516750419,
|
||||
0.02795958961474,
|
||||
0.02740682579566,
|
||||
-0.01028161641541,
|
||||
-0.05982935510889,
|
||||
-0.06701528475711,
|
||||
0.00223094639866,
|
||||
0.14157768006701,
|
||||
0.15017064489112
|
||||
],
|
||||
"dgt": [
|
||||
1.0,
|
||||
1.03941448941778,
|
||||
1.07773189112355,
|
||||
1.11575888725852,
|
||||
1.15209185089701,
|
||||
1.18632744096844,
|
||||
1.21911100318577,
|
||||
1.24931318255134,
|
||||
1.27657903892303,
|
||||
1.30069883494415,
|
||||
1.32210817897091,
|
||||
1.3405812000038,
|
||||
1.35690844654118,
|
||||
1.3710092503689,
|
||||
1.38430337205545,
|
||||
1.3966294751726,
|
||||
1.40864903907609,
|
||||
1.42089447397912,
|
||||
1.43476940680732,
|
||||
1.44977369463316,
|
||||
1.46637521309853,
|
||||
1.48420288841848,
|
||||
1.50335352244996,
|
||||
1.5242627235492,
|
||||
1.54578500307573,
|
||||
1.56750088631614,
|
||||
1.58973304612691,
|
||||
1.61073904908309,
|
||||
1.63068023161292,
|
||||
1.64799163036252,
|
||||
1.66286684904577,
|
||||
1.6761448370895,
|
||||
1.68845480656382,
|
||||
1.70379790088896,
|
||||
1.72461030013125,
|
||||
1.75428006928365,
|
||||
1.79748596476494,
|
||||
1.85543800978691,
|
||||
1.92915262384742,
|
||||
2.01414465424155,
|
||||
2.10336369905543,
|
||||
2.19013043016015,
|
||||
2.26678136721453,
|
||||
2.33147727493671,
|
||||
2.38192717604575,
|
||||
2.41879254989742,
|
||||
2.44342862248888,
|
||||
2.4553191172498
|
||||
]
|
||||
}
|
||||
6233
gnpy/example-data/Sweden_OpenROADMv4_example_network.json
Normal file
6233
gnpy/example-data/Sweden_OpenROADMv4_example_network.json
Normal file
File diff suppressed because it is too large
Load Diff
6233
gnpy/example-data/Sweden_OpenROADMv5_example_network.json
Normal file
6233
gnpy/example-data/Sweden_OpenROADMv5_example_network.json
Normal file
File diff suppressed because it is too large
Load Diff
109
gnpy/example-data/create_eqpt_sheet.py
Normal file
109
gnpy/example-data/create_eqpt_sheet.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# Utility functions that creates an Eqpt sheet template
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
create_eqpt_sheet.py
|
||||
====================
|
||||
|
||||
XLS parser that can be called to create a "City" column in the "Eqpt" sheet.
|
||||
|
||||
If not present in the "Nodes" sheet, the "Type" column will be implicitly
|
||||
determined based on the topology.
|
||||
"""
|
||||
|
||||
from xlrd import open_workbook
|
||||
from argparse import ArgumentParser
|
||||
|
||||
PARSER = ArgumentParser()
|
||||
PARSER.add_argument('workbook', nargs='?', default='meshTopologyExampleV2.xls',
|
||||
help='create the mandatory columns in Eqpt sheet')
|
||||
|
||||
|
||||
def ALL_ROWS(sh, start=0):
|
||||
return (sh.row(x) for x in range(start, sh.nrows))
|
||||
|
||||
|
||||
class Node:
|
||||
""" Node element contains uid, list of connected nodes and eqpt type
|
||||
"""
|
||||
|
||||
def __init__(self, uid, to_node):
|
||||
self.uid = uid
|
||||
self.to_node = to_node
|
||||
self.eqpt = None
|
||||
|
||||
def __repr__(self):
|
||||
return f'uid {self.uid} \nto_node {[node for node in self.to_node]}\neqpt {self.eqpt}\n'
|
||||
|
||||
def __str__(self):
|
||||
return f'uid {self.uid} \nto_node {[node for node in self.to_node]}\neqpt {self.eqpt}\n'
|
||||
|
||||
|
||||
def read_excel(input_filename):
|
||||
""" read excel Nodes and Links sheets and create a dict of nodes with
|
||||
their to_nodes and type of eqpt
|
||||
"""
|
||||
with open_workbook(input_filename) as wobo:
|
||||
# reading Links sheet
|
||||
links_sheet = wobo.sheet_by_name('Links')
|
||||
nodes = {}
|
||||
for row in ALL_ROWS(links_sheet, start=5):
|
||||
try:
|
||||
nodes[row[0].value].to_node.append(row[1].value)
|
||||
except KeyError:
|
||||
nodes[row[0].value] = Node(row[0].value, [row[1].value])
|
||||
try:
|
||||
nodes[row[1].value].to_node.append(row[0].value)
|
||||
except KeyError:
|
||||
nodes[row[1].value] = Node(row[1].value, [row[0].value])
|
||||
|
||||
nodes_sheet = wobo.sheet_by_name('Nodes')
|
||||
for row in ALL_ROWS(nodes_sheet, start=5):
|
||||
node = row[0].value
|
||||
eqpt = row[6].value
|
||||
try:
|
||||
if eqpt == 'ILA' and len(nodes[node].to_node) != 2:
|
||||
print(f'Inconsistancy ILA node with degree > 2: {node} ')
|
||||
exit()
|
||||
if eqpt == '' and len(nodes[node].to_node) == 2:
|
||||
nodes[node].eqpt = 'ILA'
|
||||
elif eqpt == '' and len(nodes[node].to_node) != 2:
|
||||
nodes[node].eqpt = 'ROADM'
|
||||
else:
|
||||
nodes[node].eqpt = eqpt
|
||||
except KeyError:
|
||||
print(f'inconsistancy between nodes and links sheet: {node} is not listed in links')
|
||||
exit()
|
||||
return nodes
|
||||
|
||||
|
||||
def create_eqt_template(nodes, input_filename):
|
||||
""" writes list of node A node Z corresponding to Nodes and Links sheets in order
|
||||
to help user populating Eqpt
|
||||
"""
|
||||
output_filename = f'{input_filename[:-4]}_eqpt_sheet.txt'
|
||||
with open(output_filename, 'w', encoding='utf-8') as my_file:
|
||||
# print header similar to excel
|
||||
my_file.write('OPTIONAL\n\n\n\
|
||||
\t\tNode a egress amp (from a to z)\t\t\t\t\tNode a ingress amp (from z to a) \
|
||||
\nNode A \tNode Z \tamp type \tatt_in \tamp gain \ttilt \tatt_out\
|
||||
amp type \tatt_in \tamp gain \ttilt \tatt_out\n')
|
||||
|
||||
for node in nodes.values():
|
||||
if node.eqpt == 'ILA':
|
||||
my_file.write(f'{node.uid}\t{node.to_node[0]}\n')
|
||||
if node.eqpt == 'ROADM':
|
||||
for to_node in node.to_node:
|
||||
my_file.write(f'{node.uid}\t{to_node}\n')
|
||||
|
||||
print(f'File {output_filename} successfully created with Node A - Node Z entries for Eqpt sheet in excel file.')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
ARGS = PARSER.parse_args()
|
||||
create_eqt_template(read_excel(ARGS.workbook), ARGS.workbook)
|
||||
81
gnpy/example-data/edfa_example_network.json
Normal file
81
gnpy/example-data/edfa_example_network.json
Normal file
@@ -0,0 +1,81 @@
|
||||
{
|
||||
"network_name": "EDFA Example Network - P2P",
|
||||
"elements": [
|
||||
{
|
||||
"uid": "Site_A",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site A",
|
||||
"region": "",
|
||||
"latitude": 0,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Span1",
|
||||
"type": "Fiber",
|
||||
"type_variety": "SSMF",
|
||||
"params": {
|
||||
"length": 80,
|
||||
"loss_coef": 0.2,
|
||||
"length_units": "km",
|
||||
"att_in": 0,
|
||||
"con_in": 0.5,
|
||||
"con_out": 0.5,
|
||||
"pmd_coef": 3.0e-15
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": 1,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Edfa1",
|
||||
"type": "Edfa",
|
||||
"type_variety": "std_low_gain",
|
||||
"operational": {
|
||||
"gain_target": 17,
|
||||
"tilt_target": 0,
|
||||
"out_voa": 0
|
||||
},
|
||||
"metadata": {
|
||||
"location": {
|
||||
"region": "",
|
||||
"latitude": 2,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"uid": "Site_B",
|
||||
"type": "Transceiver",
|
||||
"metadata": {
|
||||
"location": {
|
||||
"city": "Site B",
|
||||
"region": "",
|
||||
"latitude": 2,
|
||||
"longitude": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"connections": [
|
||||
{
|
||||
"from_node": "Site_A",
|
||||
"to_node": "Span1"
|
||||
},
|
||||
{
|
||||
"from_node": "Span1",
|
||||
"to_node": "Edfa1"
|
||||
},
|
||||
{
|
||||
"from_node": "Edfa1",
|
||||
"to_node": "Site_B"
|
||||
}
|
||||
]
|
||||
}
|
||||
0
examples/edfa_model/DFG_96.txt → gnpy/example-data/edfa_model/DFG_96.txt
Executable file → Normal file
0
examples/edfa_model/DFG_96.txt → gnpy/example-data/edfa_model/DFG_96.txt
Executable file → Normal file
0
examples/edfa_model/DGT_96.txt → gnpy/example-data/edfa_model/DGT_96.txt
Executable file → Normal file
0
examples/edfa_model/DGT_96.txt → gnpy/example-data/edfa_model/DGT_96.txt
Executable file → Normal file
0
examples/edfa_model/NFR_96.txt → gnpy/example-data/edfa_model/NFR_96.txt
Executable file → Normal file
0
examples/edfa_model/NFR_96.txt → gnpy/example-data/edfa_model/NFR_96.txt
Executable file → Normal file
6
gnpy/example-data/edfa_model/OA.json
Normal file
6
gnpy/example-data/edfa_model/OA.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"nf_ripple": "NFR_96.txt",
|
||||
"gain_ripple": "DFG_96.txt",
|
||||
"dgt": "DGT_96.txt",
|
||||
"nf_fit_coeff": "pNFfit3.txt"
|
||||
}
|
||||
95
gnpy/example-data/edfa_model/build_oa_json.py
Normal file
95
gnpy/example-data/edfa_model/build_oa_json.py
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
# update an existing json file with all the 96ch txt files for a given amplifier type
|
||||
# Copyright (C) 2025 Telecom Infra Project and GNPy contributors
|
||||
# see AUTHORS.rst for a list of contributors
|
||||
|
||||
"""
|
||||
Created on Tue Jan 30 12:32:00 2018
|
||||
|
||||
@author: jeanluc-auge
|
||||
|
||||
update an existing json file with all the 96ch txt files for a given amplifier type
|
||||
amplifier type 'OA_type1' is hard coded but can be modified and other types added
|
||||
returns an updated amplifier json file: output_json_file_name = 'edfa_config.json'
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import numpy as np
|
||||
|
||||
"""amplifier file names
|
||||
convert a set of amplifier files + input json definiton file into a valid edfa_json_file:
|
||||
nf_fit_coeff: NF 3rd order polynomial coefficients txt file
|
||||
nf = f(dg)
|
||||
with dg = gain_operational - gain_max
|
||||
nf_ripple: NF ripple excursion txt file
|
||||
gain_ripple: gain ripple txt file
|
||||
dgt: dynamic gain txt file
|
||||
input json file in argument (defult = 'OA.json')
|
||||
|
||||
the json input file should have the following fields:
|
||||
{
|
||||
"nf_fit_coeff": "nf_filename.txt",
|
||||
"nf_ripple": "nf_ripple_filename.txt",
|
||||
"gain_ripple": "DFG_filename.txt",
|
||||
"dgt": "DGT_filename.txt",
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
input_json_file_name = "OA.json" # default path
|
||||
output_json_file_name = "default_edfa_config.json"
|
||||
gain_ripple_field = "gain_ripple"
|
||||
nf_ripple_field = "nf_ripple"
|
||||
nf_fit_coeff = "nf_fit_coeff"
|
||||
|
||||
|
||||
def read_file(field, file_name):
|
||||
"""read and format the 96 channels txt files describing the amplifier NF and ripple
|
||||
convert dfg into gain ripple by removing the mean component
|
||||
"""
|
||||
|
||||
# with open(path + file_name,'r') as this_file:
|
||||
# data = this_file.read()
|
||||
# data.strip()
|
||||
#data = re.sub(r"([0-9])([ ]{1,3})([0-9-+])",r"\1,\3",data)
|
||||
#data = list(data.split(","))
|
||||
#data = [float(x) for x in data]
|
||||
data = np.loadtxt(file_name)
|
||||
print(len(data), file_name)
|
||||
if field == gain_ripple_field or field == nf_ripple_field:
|
||||
# consider ripple excursion only to avoid redundant information
|
||||
# because the max flat_gain is already given by the 'gain_flat' field in json
|
||||
# remove the mean component
|
||||
print(file_name, ', mean value =', data.mean(), ' is substracted')
|
||||
data = data - data.mean()
|
||||
data = data.tolist()
|
||||
return data
|
||||
|
||||
|
||||
def input_json(path):
|
||||
"""read the json input file and add all the 96 channels txt files
|
||||
create the output json file with output_json_file_name"""
|
||||
with open(path, 'r') as edfa_json_file:
|
||||
amp_text = edfa_json_file.read()
|
||||
amp_dict = json.loads(amp_text)
|
||||
|
||||
for k, v in amp_dict.items():
|
||||
if re.search(r'.txt$', str(v)):
|
||||
amp_dict[k] = read_file(k, v)
|
||||
|
||||
amp_text = json.dumps(amp_dict, indent=4)
|
||||
# print(amp_text)
|
||||
with open(output_json_file_name, 'w') as edfa_json_file:
|
||||
edfa_json_file.write(amp_text)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) == 2:
|
||||
path = sys.argv[1]
|
||||
else:
|
||||
path = input_json_file_name
|
||||
input_json(path)
|
||||
0
examples/edfa_model/pNFfit3.txt → gnpy/example-data/edfa_model/pNFfit3.txt
Executable file → Normal file
0
examples/edfa_model/pNFfit3.txt → gnpy/example-data/edfa_model/pNFfit3.txt
Executable file → Normal file
444
gnpy/example-data/eqpt_config.json
Normal file
444
gnpy/example-data/eqpt_config.json
Normal file
@@ -0,0 +1,444 @@
|
||||
{
|
||||
"Edfa": [
|
||||
{
|
||||
"type_variety": "high_detail_model_example",
|
||||
"type_def": "advanced_model",
|
||||
"gain_flatmax": 25,
|
||||
"gain_min": 15,
|
||||
"p_max": 21,
|
||||
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "Juniper_BoosterHG",
|
||||
"type_def": "advanced_model",
|
||||
"gain_flatmax": 25,
|
||||
"gain_min": 10,
|
||||
"p_max": 21,
|
||||
"advanced_config_from_json": "Juniper-BoosterHG.json",
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "operator_model_example",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 23,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "openroadm_ila_low_noise",
|
||||
"type_def": "openroadm",
|
||||
"gain_flatmax": 27,
|
||||
"gain_min": 0,
|
||||
"p_max": 22,
|
||||
"nf_coef": [
|
||||
-8.104e-4,
|
||||
-6.221e-2,
|
||||
-5.889e-1,
|
||||
37.62
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "openroadm_ila_standard",
|
||||
"type_def": "openroadm",
|
||||
"gain_flatmax": 27,
|
||||
"gain_min": 0,
|
||||
"p_max": 22,
|
||||
"nf_coef": [
|
||||
-5.952e-4,
|
||||
-6.250e-2,
|
||||
-1.071,
|
||||
28.99
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "openroadm_mw_mw_preamp",
|
||||
"type_def": "openroadm_preamp",
|
||||
"gain_flatmax": 27,
|
||||
"gain_min": 0,
|
||||
"p_max": 22,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "openroadm_mw_mw_preamp_typical_ver5",
|
||||
"type_def": "openroadm",
|
||||
"gain_flatmax": 27,
|
||||
"gain_min": 0,
|
||||
"p_max": 22,
|
||||
"nf_coef": [
|
||||
-5.952e-4,
|
||||
-6.250e-2,
|
||||
-1.071,
|
||||
28.99
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "openroadm_mw_mw_preamp_worstcase_ver5",
|
||||
"type_def": "openroadm",
|
||||
"gain_flatmax": 27,
|
||||
"gain_min": 0,
|
||||
"p_max": 22,
|
||||
"nf_coef": [
|
||||
-5.952e-4,
|
||||
-6.250e-2,
|
||||
-1.071,
|
||||
27.99
|
||||
],
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "openroadm_mw_mw_booster",
|
||||
"type_def": "openroadm_booster",
|
||||
"gain_flatmax": 32,
|
||||
"gain_min": 0,
|
||||
"p_max": 22,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_high_gain",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 35,
|
||||
"gain_min": 25,
|
||||
"p_max": 21,
|
||||
"nf_min": 5.5,
|
||||
"nf_max": 7,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_medium_gain",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 26,
|
||||
"gain_min": 15,
|
||||
"p_max": 23,
|
||||
"nf_min": 6,
|
||||
"nf_max": 10,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "std_low_gain",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 23,
|
||||
"nf_min": 6.5,
|
||||
"nf_max": 11,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "high_power",
|
||||
"type_def": "variable_gain",
|
||||
"gain_flatmax": 16,
|
||||
"gain_min": 8,
|
||||
"p_max": 25,
|
||||
"nf_min": 9,
|
||||
"nf_max": 15,
|
||||
"out_voa_auto": false,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "std_fixed_gain",
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 21,
|
||||
"gain_min": 20,
|
||||
"p_max": 21,
|
||||
"nf0": 5.5,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "4pumps_raman",
|
||||
"type_def": "fixed_gain",
|
||||
"gain_flatmax": 12,
|
||||
"gain_min": 12,
|
||||
"p_max": 21,
|
||||
"nf0": -1,
|
||||
"allowed_for_design": false
|
||||
},
|
||||
{
|
||||
"type_variety": "hybrid_4pumps_lowgain",
|
||||
"type_def": "dual_stage",
|
||||
"raman": true,
|
||||
"gain_min": 25,
|
||||
"preamp_variety": "4pumps_raman",
|
||||
"booster_variety": "std_low_gain",
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "hybrid_4pumps_mediumgain",
|
||||
"type_def": "dual_stage",
|
||||
"raman": true,
|
||||
"gain_min": 25,
|
||||
"preamp_variety": "4pumps_raman",
|
||||
"booster_variety": "std_medium_gain",
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "medium+low_gain",
|
||||
"type_def": "dual_stage",
|
||||
"gain_min": 25,
|
||||
"preamp_variety": "std_medium_gain",
|
||||
"booster_variety": "std_low_gain",
|
||||
"allowed_for_design": true
|
||||
},
|
||||
{
|
||||
"type_variety": "medium+high_power",
|
||||
"type_def": "dual_stage",
|
||||
"gain_min": 25,
|
||||
"preamp_variety": "std_medium_gain",
|
||||
"booster_variety": "high_power",
|
||||
"allowed_for_design": false
|
||||
}
|
||||
],
|
||||
"Fiber": [
|
||||
{
|
||||
"type_variety": "SSMF",
|
||||
"dispersion": 1.67e-05,
|
||||
"effective_area": 83e-12,
|
||||
"pmd_coef": 1.265e-15
|
||||
},
|
||||
{
|
||||
"type_variety": "NZDF",
|
||||
"dispersion": 0.5e-05,
|
||||
"effective_area": 72e-12,
|
||||
"pmd_coef": 1.265e-15
|
||||
},
|
||||
{
|
||||
"type_variety": "LOF",
|
||||
"dispersion": 2.2e-05,
|
||||
"effective_area": 125e-12,
|
||||
"pmd_coef": 1.265e-15
|
||||
}
|
||||
],
|
||||
"RamanFiber": [
|
||||
{
|
||||
"type_variety": "SSMF",
|
||||
"dispersion": 1.67e-05,
|
||||
"effective_area": 83e-12,
|
||||
"pmd_coef": 1.265e-15
|
||||
}
|
||||
],
|
||||
"Span": [
|
||||
{
|
||||
"power_mode": true,
|
||||
"delta_power_range_db": [
|
||||
-2,
|
||||
3,
|
||||
0.5
|
||||
],
|
||||
"max_fiber_lineic_loss_for_raman": 0.25,
|
||||
"target_extended_gain": 2.5,
|
||||
"max_length": 150,
|
||||
"length_units": "km",
|
||||
"max_loss": 28,
|
||||
"padding": 10,
|
||||
"EOL": 0,
|
||||
"con_in": 0,
|
||||
"con_out": 0
|
||||
}
|
||||
],
|
||||
"Roadm": [
|
||||
{
|
||||
"target_pch_out_db": -20,
|
||||
"add_drop_osnr": 38,
|
||||
"pmd": 0,
|
||||
"pdl": 0,
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"type_variety": "roadm_type_1",
|
||||
"target_pch_out_db": -18,
|
||||
"add_drop_osnr": 35,
|
||||
"pmd": 0,
|
||||
"pdl": 0,
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
},
|
||||
"roadm-path-impairments": []
|
||||
},
|
||||
{
|
||||
"type_variety": "detailed_impairments",
|
||||
"target_pch_out_db": -20,
|
||||
"add_drop_osnr": 38,
|
||||
"pmd": 0,
|
||||
"pdl": 0,
|
||||
"restrictions": {
|
||||
"preamp_variety_list": [],
|
||||
"booster_variety_list": []
|
||||
},
|
||||
"roadm-path-impairments": [
|
||||
{
|
||||
"roadm-path-impairments-id": 0,
|
||||
"roadm-express-path": [
|
||||
{
|
||||
"frequency-range": {
|
||||
"lower-frequency": 191.3e12,
|
||||
"upper-frequency": 196.1e12
|
||||
},
|
||||
"roadm-pmd": 0,
|
||||
"roadm-cd": 0,
|
||||
"roadm-pdl": 0,
|
||||
"roadm-inband-crosstalk": 0,
|
||||
"roadm-maxloss": 16.5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"roadm-path-impairments-id": 1,
|
||||
"roadm-add-path": [
|
||||
{
|
||||
"frequency-range": {
|
||||
"lower-frequency": 191.3e12,
|
||||
"upper-frequency": 196.1e12
|
||||
},
|
||||
"roadm-pmd": 0,
|
||||
"roadm-cd": 0,
|
||||
"roadm-pdl": 0,
|
||||
"roadm-inband-crosstalk": 0,
|
||||
"roadm-maxloss": 11.5,
|
||||
"roadm-pmax": 2.5,
|
||||
"roadm-osnr": 41,
|
||||
"roadm-noise-figure": 23
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"roadm-path-impairments-id": 2,
|
||||
"roadm-drop-path": [
|
||||
{
|
||||
"frequency-range": {
|
||||
"lower-frequency": 191.3e12,
|
||||
"upper-frequency": 196.1e12
|
||||
},
|
||||
"roadm-pmd": 0,
|
||||
"roadm-cd": 0,
|
||||
"roadm-pdl": 0,
|
||||
"roadm-inband-crosstalk": 0,
|
||||
"roadm-maxloss": 11.5,
|
||||
"roadm-minloss": 7.5,
|
||||
"roadm-typloss": 10,
|
||||
"roadm-pmin": -13.5,
|
||||
"roadm-pmax": -9.5,
|
||||
"roadm-ptyp": -12,
|
||||
"roadm-osnr": 41,
|
||||
"roadm-noise-figure": 15
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"SI": [
|
||||
{
|
||||
"f_min": 191.3e12,
|
||||
"baud_rate": 32e9,
|
||||
"f_max": 195.1e12,
|
||||
"spacing": 50e9,
|
||||
"power_dbm": 0,
|
||||
"power_range_db": [
|
||||
0,
|
||||
0,
|
||||
1
|
||||
],
|
||||
"tx_power_dbm": 0,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"sys_margins": 2,
|
||||
"use_si_channel_count_for_design": true
|
||||
}
|
||||
],
|
||||
"Transceiver": [
|
||||
{
|
||||
"type_variety": "vendorA_trx-type1",
|
||||
"frequency": {
|
||||
"min": 191.35e12,
|
||||
"max": 196.1e12
|
||||
},
|
||||
"mode": [
|
||||
{
|
||||
"format": "mode 1",
|
||||
"baud_rate": 32e9,
|
||||
"OSNR": 11,
|
||||
"bit_rate": 100e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost": 1
|
||||
},
|
||||
{
|
||||
"format": "mode 2",
|
||||
"baud_rate": 66e9,
|
||||
"OSNR": 15,
|
||||
"bit_rate": 200e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost": 1
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"type_variety": "Voyager",
|
||||
"frequency": {
|
||||
"min": 191.35e12,
|
||||
"max": 196.1e12
|
||||
},
|
||||
"mode": [
|
||||
{
|
||||
"format": "mode 1",
|
||||
"baud_rate": 32e9,
|
||||
"OSNR": 12,
|
||||
"bit_rate": 100e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 37.5e9,
|
||||
"cost": 1
|
||||
},
|
||||
{
|
||||
"format": "mode 3",
|
||||
"baud_rate": 44e9,
|
||||
"OSNR": 18,
|
||||
"bit_rate": 300e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 62.5e9,
|
||||
"cost": 1
|
||||
},
|
||||
{
|
||||
"format": "mode 2",
|
||||
"baud_rate": 66e9,
|
||||
"OSNR": 21,
|
||||
"bit_rate": 400e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost": 1
|
||||
},
|
||||
{
|
||||
"format": "mode 4",
|
||||
"baud_rate": 66e9,
|
||||
"OSNR": 16,
|
||||
"bit_rate": 200e9,
|
||||
"roll_off": 0.15,
|
||||
"tx_osnr": 40,
|
||||
"min_spacing": 75e9,
|
||||
"cost": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user