mirror of
https://github.com/Telecominfraproject/oopt-gnpy.git
synced 2025-11-02 19:18:02 +00:00
Merge pull request #215 from Orange-OpenSource/roadm_equalization
Roadm equalization
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
{ "Edfa":[{
|
{ "Edfa":[{
|
||||||
"type_variety": "high_detail_model_example",
|
"type_variety": "high_detail_model_example",
|
||||||
|
"type_def": "advanced_model",
|
||||||
"gain_flatmax": 25,
|
"gain_flatmax": 25,
|
||||||
"gain_min": 15,
|
"gain_min": 15,
|
||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||||
"out_voa_auto": false,
|
"out_voa_auto": false,
|
||||||
"allowed_for_design": false
|
"allowed_for_design": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type_variety": "operator_model_example",
|
"type_variety": "operator_model_example",
|
||||||
"type_def": "variable_gain",
|
"type_def": "variable_gain",
|
||||||
@@ -37,6 +38,17 @@
|
|||||||
"allowed_for_design": false
|
"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_variety": "std_medium_gain",
|
||||||
"type_def": "variable_gain",
|
"type_def": "variable_gain",
|
||||||
"gain_flatmax": 26,
|
"gain_flatmax": 26,
|
||||||
@@ -59,6 +71,17 @@
|
|||||||
"allowed_for_design": true
|
"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_variety": "std_fixed_gain",
|
||||||
"type_def": "fixed_gain",
|
"type_def": "fixed_gain",
|
||||||
"gain_flatmax": 21,
|
"gain_flatmax": 21,
|
||||||
@@ -66,7 +89,50 @@
|
|||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"nf0": 5.5,
|
"nf0": 5.5,
|
||||||
"allowed_for_design": false
|
"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":[{
|
"Fiber":[{
|
||||||
"type_variety": "SSMF",
|
"type_variety": "SSMF",
|
||||||
@@ -84,9 +150,11 @@
|
|||||||
"gamma": 0.000843
|
"gamma": 0.000843
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Spans":[{
|
"Span":[{
|
||||||
"power_mode":true,
|
"power_mode":true,
|
||||||
"delta_power_range_db": [0,0,0.5],
|
"delta_power_range_db": [-2,3,0.5],
|
||||||
|
"max_fiber_lineic_loss_for_raman": 0.25,
|
||||||
|
"target_extended_gain": 2.5,
|
||||||
"max_length": 150,
|
"max_length": 150,
|
||||||
"length_units": "km",
|
"length_units": "km",
|
||||||
"max_loss": 28,
|
"max_loss": 28,
|
||||||
@@ -96,10 +164,13 @@
|
|||||||
"con_out": 0
|
"con_out": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Roadms":[{
|
"Roadm":[{
|
||||||
"gain_mode_default_loss": 20,
|
"target_pch_out_db": -20,
|
||||||
"power_mode_pout_target": -20,
|
"add_drop_osnr": 38,
|
||||||
"add_drop_osnr": 38
|
"restrictions": {
|
||||||
|
"preamp_variety_list":["low_gain_preamp", "high_gain_preamp"],
|
||||||
|
"booster_variety_list":["std_booster"]
|
||||||
|
}
|
||||||
}],
|
}],
|
||||||
"SI":[{
|
"SI":[{
|
||||||
"f_min": 191.3e12,
|
"f_min": 191.3e12,
|
||||||
@@ -107,10 +178,10 @@
|
|||||||
"f_max":195.1e12,
|
"f_max":195.1e12,
|
||||||
"spacing": 50e9,
|
"spacing": 50e9,
|
||||||
"power_dbm": 0,
|
"power_dbm": 0,
|
||||||
"power_range_db": [0,0,0.5],
|
"power_range_db": [0,0,1],
|
||||||
"roll_off": 0.15,
|
"roll_off": 0.15,
|
||||||
"tx_osnr": 40,
|
"tx_osnr": 40,
|
||||||
"sys_margins": 0
|
"sys_margins": 2
|
||||||
}],
|
}],
|
||||||
"Transceiver":[
|
"Transceiver":[
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -623,31 +623,473 @@
|
|||||||
"con_in": null,
|
"con_in": null,
|
||||||
"con_out": null
|
"con_out": null
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lannion_CAS to Corlay",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Corlay to Loudeac",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Corlay",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Loudeac to Lorient_KMA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Loudeac",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 2.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lorient_KMA to Vannes_KBE",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lorient_KMA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 3.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lannion_CAS to Stbrieuc",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Stbrieuc to Rennes_STA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Stbrieuc",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 1.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lannion_CAS to Morlaix",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Lorient_KMA to Loudeac",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lorient_KMA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 3.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Vannes_KBE to Lorient_KMA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Vannes_KBE",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 4.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Rennes_STA to Stbrieuc",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Rennes_STA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 0.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "east edfa in Brest_KLA to Morlaix",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Brest_KLA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 4.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lannion_CAS to Corlay",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Corlay to Loudeac",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Corlay",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 1.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Loudeac to Lorient_KMA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Loudeac",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 2.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lorient_KMA to Vannes_KBE",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lorient_KMA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 3.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lannion_CAS to Stbrieuc",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Stbrieuc to Rennes_STA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Stbrieuc",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 1.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lannion_CAS to Morlaix",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lannion_CAS",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Lorient_KMA to Loudeac",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Lorient_KMA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 3.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Vannes_KBE to Lorient_KMA",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Vannes_KBE",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 2.0,
|
||||||
|
"longitude": 4.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Rennes_STA to Stbrieuc",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Rennes_STA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 0.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"uid": "west edfa in Brest_KLA to Morlaix",
|
||||||
|
"metadata": {
|
||||||
|
"location": {
|
||||||
|
"city": "Brest_KLA",
|
||||||
|
"region": "RLD",
|
||||||
|
"latitude": 4.0,
|
||||||
|
"longitude": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"type": "Edfa",
|
||||||
|
"type_variety": "std_low_gain",
|
||||||
|
"operational": {
|
||||||
|
"gain_target": null,
|
||||||
|
"delta_p": 1.0,
|
||||||
|
"tilt_target": 0,
|
||||||
|
"out_voa": null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"connections": [
|
"connections": [
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lannion_CAS",
|
"from_node": "roadm Lannion_CAS",
|
||||||
|
"to_node": "east edfa in Lannion_CAS to Corlay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lannion_CAS to Corlay",
|
||||||
"to_node": "fiber (Lannion_CAS → Corlay)-F061"
|
"to_node": "fiber (Lannion_CAS → Corlay)-F061"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Corlay → Lannion_CAS)-F061",
|
"from_node": "fiber (Corlay → Lannion_CAS)-F061",
|
||||||
|
"to_node": "west edfa in Lannion_CAS to Corlay"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lannion_CAS to Corlay",
|
||||||
"to_node": "roadm Lannion_CAS"
|
"to_node": "roadm Lannion_CAS"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lannion_CAS",
|
"from_node": "roadm Lannion_CAS",
|
||||||
|
"to_node": "east edfa in Lannion_CAS to Stbrieuc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lannion_CAS to Stbrieuc",
|
||||||
"to_node": "fiber (Lannion_CAS → Stbrieuc)-F056"
|
"to_node": "fiber (Lannion_CAS → Stbrieuc)-F056"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Stbrieuc → Lannion_CAS)-F056",
|
"from_node": "fiber (Stbrieuc → Lannion_CAS)-F056",
|
||||||
|
"to_node": "west edfa in Lannion_CAS to Stbrieuc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lannion_CAS to Stbrieuc",
|
||||||
"to_node": "roadm Lannion_CAS"
|
"to_node": "roadm Lannion_CAS"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lannion_CAS",
|
"from_node": "roadm Lannion_CAS",
|
||||||
|
"to_node": "east edfa in Lannion_CAS to Morlaix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lannion_CAS to Morlaix",
|
||||||
"to_node": "fiber (Lannion_CAS → Morlaix)-F059"
|
"to_node": "fiber (Lannion_CAS → Morlaix)-F059"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Morlaix → Lannion_CAS)-F059",
|
"from_node": "fiber (Morlaix → Lannion_CAS)-F059",
|
||||||
|
"to_node": "west edfa in Lannion_CAS to Morlaix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lannion_CAS to Morlaix",
|
||||||
"to_node": "roadm Lannion_CAS"
|
"to_node": "roadm Lannion_CAS"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -684,18 +1126,34 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lorient_KMA",
|
"from_node": "roadm Lorient_KMA",
|
||||||
|
"to_node": "east edfa in Lorient_KMA to Loudeac"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lorient_KMA to Loudeac",
|
||||||
"to_node": "fiber (Lorient_KMA → Loudeac)-F054"
|
"to_node": "fiber (Lorient_KMA → Loudeac)-F054"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Loudeac → Lorient_KMA)-F054",
|
"from_node": "fiber (Loudeac → Lorient_KMA)-F054",
|
||||||
|
"to_node": "west edfa in Lorient_KMA to Loudeac"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lorient_KMA to Loudeac",
|
||||||
"to_node": "roadm Lorient_KMA"
|
"to_node": "roadm Lorient_KMA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Lorient_KMA",
|
"from_node": "roadm Lorient_KMA",
|
||||||
|
"to_node": "east edfa in Lorient_KMA to Vannes_KBE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Lorient_KMA to Vannes_KBE",
|
||||||
"to_node": "fiber (Lorient_KMA → Vannes_KBE)-F055"
|
"to_node": "fiber (Lorient_KMA → Vannes_KBE)-F055"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Vannes_KBE → Lorient_KMA)-F055",
|
"from_node": "fiber (Vannes_KBE → Lorient_KMA)-F055",
|
||||||
|
"to_node": "west edfa in Lorient_KMA to Vannes_KBE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Lorient_KMA to Vannes_KBE",
|
||||||
"to_node": "roadm Lorient_KMA"
|
"to_node": "roadm Lorient_KMA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -708,10 +1166,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Vannes_KBE",
|
"from_node": "roadm Vannes_KBE",
|
||||||
|
"to_node": "east edfa in Vannes_KBE to Lorient_KMA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Vannes_KBE to Lorient_KMA",
|
||||||
"to_node": "fiber (Vannes_KBE → Lorient_KMA)-F055"
|
"to_node": "fiber (Vannes_KBE → Lorient_KMA)-F055"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Lorient_KMA → Vannes_KBE)-F055",
|
"from_node": "fiber (Lorient_KMA → Vannes_KBE)-F055",
|
||||||
|
"to_node": "west edfa in Vannes_KBE to Lorient_KMA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Vannes_KBE to Lorient_KMA",
|
||||||
"to_node": "roadm Vannes_KBE"
|
"to_node": "roadm Vannes_KBE"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -724,18 +1190,34 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Lannion_CAS → Stbrieuc)-F056",
|
"from_node": "fiber (Lannion_CAS → Stbrieuc)-F056",
|
||||||
|
"to_node": "east edfa in Stbrieuc to Rennes_STA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Stbrieuc to Rennes_STA",
|
||||||
"to_node": "fiber (Stbrieuc → Rennes_STA)-F057"
|
"to_node": "fiber (Stbrieuc → Rennes_STA)-F057"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Rennes_STA → Stbrieuc)-F057",
|
"from_node": "fiber (Rennes_STA → Stbrieuc)-F057",
|
||||||
|
"to_node": "west edfa in Stbrieuc to Rennes_STA"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Stbrieuc to Rennes_STA",
|
||||||
"to_node": "fiber (Stbrieuc → Lannion_CAS)-F056"
|
"to_node": "fiber (Stbrieuc → Lannion_CAS)-F056"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Rennes_STA",
|
"from_node": "roadm Rennes_STA",
|
||||||
|
"to_node": "east edfa in Rennes_STA to Stbrieuc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Rennes_STA to Stbrieuc",
|
||||||
"to_node": "fiber (Rennes_STA → Stbrieuc)-F057"
|
"to_node": "fiber (Rennes_STA → Stbrieuc)-F057"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Stbrieuc → Rennes_STA)-F057",
|
"from_node": "fiber (Stbrieuc → Rennes_STA)-F057",
|
||||||
|
"to_node": "west edfa in Rennes_STA to Stbrieuc"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Rennes_STA to Stbrieuc",
|
||||||
"to_node": "roadm Rennes_STA"
|
"to_node": "roadm Rennes_STA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -764,10 +1246,18 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "roadm Brest_KLA",
|
"from_node": "roadm Brest_KLA",
|
||||||
|
"to_node": "east edfa in Brest_KLA to Morlaix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "east edfa in Brest_KLA to Morlaix",
|
||||||
"to_node": "fiber (Brest_KLA → Morlaix)-F060"
|
"to_node": "fiber (Brest_KLA → Morlaix)-F060"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"from_node": "fiber (Morlaix → Brest_KLA)-F060",
|
"from_node": "fiber (Morlaix → Brest_KLA)-F060",
|
||||||
|
"to_node": "west edfa in Brest_KLA to Morlaix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_node": "west edfa in Brest_KLA to Morlaix",
|
||||||
"to_node": "roadm Brest_KLA"
|
"to_node": "roadm Brest_KLA"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
Binary file not shown.
@@ -23,7 +23,7 @@ from networkx import (draw_networkx_nodes, draw_networkx_edges,
|
|||||||
from numpy import mean
|
from numpy import mean
|
||||||
from gnpy.core.service_sheet import convert_service_sheet, Request_element, Element
|
from gnpy.core.service_sheet import convert_service_sheet, Request_element, Element
|
||||||
from gnpy.core.utils import load_json
|
from gnpy.core.utils import load_json
|
||||||
from gnpy.core.network import load_network, build_network, set_roadm_loss, save_network
|
from gnpy.core.network import load_network, build_network, save_network
|
||||||
from gnpy.core.equipment import load_equipment, trx_mode_params, automatic_nch, automatic_spacing
|
from gnpy.core.equipment import load_equipment, trx_mode_params, automatic_nch, automatic_spacing
|
||||||
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fused, Fiber
|
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fused, Fiber
|
||||||
from gnpy.core.utils import db2lin, lin2db
|
from gnpy.core.utils import db2lin, lin2db
|
||||||
|
|||||||
@@ -106,8 +106,8 @@ def main(network, equipment, source, destination, req = None):
|
|||||||
}]
|
}]
|
||||||
result_dicts.update({'network': network_data})
|
result_dicts.update({'network': network_data})
|
||||||
design_data = [{
|
design_data = [{
|
||||||
'power_mode' : equipment['Spans']['default'].power_mode,
|
'power_mode' : equipment['Span']['default'].power_mode,
|
||||||
'span_power_range' : equipment['Spans']['default'].delta_power_range_db,
|
'span_power_range' : equipment['Span']['default'].delta_power_range_db,
|
||||||
'design_pch' : equipment['SI']['default'].power_dbm,
|
'design_pch' : equipment['SI']['default'].power_dbm,
|
||||||
'baud_rate' : equipment['SI']['default'].baud_rate
|
'baud_rate' : equipment['SI']['default'].baud_rate
|
||||||
}]
|
}]
|
||||||
@@ -115,9 +115,9 @@ def main(network, equipment, source, destination, req = None):
|
|||||||
simulation_data = []
|
simulation_data = []
|
||||||
result_dicts.update({'simulation results': simulation_data})
|
result_dicts.update({'simulation results': simulation_data})
|
||||||
|
|
||||||
power_mode = equipment['Spans']['default'].power_mode
|
power_mode = equipment['Span']['default'].power_mode
|
||||||
print('\n'.join([f'Power mode is set to {power_mode}',
|
print('\n'.join([f'Power mode is set to {power_mode}',
|
||||||
f'=> it can be modified in eqpt_config.json - Spans']))
|
f'=> it can be modified in eqpt_config.json - Span']))
|
||||||
|
|
||||||
pref_ch_db = lin2db(req.power*1e3) #reference channel power / span (SL=20dB)
|
pref_ch_db = lin2db(req.power*1e3) #reference channel power / span (SL=20dB)
|
||||||
pref_total_db = pref_ch_db + lin2db(req.nb_channel) #reference total power / span (SL=20dB)
|
pref_total_db = pref_ch_db + lin2db(req.nb_channel) #reference total power / span (SL=20dB)
|
||||||
@@ -136,25 +136,44 @@ def main(network, equipment, source, destination, req = None):
|
|||||||
print('invalid power range definition in eqpt_config, should be power_range_db: [lower, upper, step]')
|
print('invalid power range definition in eqpt_config, should be power_range_db: [lower, upper, step]')
|
||||||
power_range = [0]
|
power_range = [0]
|
||||||
|
|
||||||
|
if not power_mode:
|
||||||
|
#power cannot be changed in gain mode
|
||||||
|
power_range = [0]
|
||||||
for dp_db in power_range:
|
for dp_db in power_range:
|
||||||
req.power = db2lin(pref_ch_db + dp_db)*1e-3
|
req.power = db2lin(pref_ch_db + dp_db)*1e-3
|
||||||
print(f'\nPropagating with input power = {lin2db(req.power*1e3):.2f}dBm :')
|
if power_mode:
|
||||||
|
print(f'\nPropagating with input power = {lin2db(req.power*1e3):.2f}dBm :')
|
||||||
|
else:
|
||||||
|
print(f'\nPropagating in gain mode: power cannot be set manually')
|
||||||
infos = propagate2(path, req, equipment, show=len(power_range)==1)
|
infos = propagate2(path, req, equipment, show=len(power_range)==1)
|
||||||
print(f'\nTransmission result for input power = {lin2db(req.power*1e3):.2f}dBm :')
|
if power_mode:
|
||||||
|
print(f'\nTransmission result for input power = {lin2db(req.power*1e3):.2f}dBm :')
|
||||||
|
else:
|
||||||
|
print(f'\nTransmission results:')
|
||||||
|
#info message in gain mode
|
||||||
print(destination)
|
print(destination)
|
||||||
|
|
||||||
#print(f'\n !!!!!!!!!!!!!!!!! TEST POINT !!!!!!!!!!!!!!!!!!!!!')
|
#print(f'\n !!!!!!!!!!!!!!!!! TEST POINT !!!!!!!!!!!!!!!!!!!!!')
|
||||||
#print(f'carriers ase output of {path[1]} =\n {list(path[1].carriers("out", "nli"))}')
|
#print(f'carriers ase output of {path[1]} =\n {list(path[1].carriers("out", "nli"))}')
|
||||||
# => use "in" or "out" parameter
|
# => use "in" or "out" parameter
|
||||||
# => use "nli" or "ase" or "signal" or "total" parameter
|
# => use "nli" or "ase" or "signal" or "total" parameter
|
||||||
|
if power_mode:
|
||||||
simulation_data.append({
|
simulation_data.append({
|
||||||
'Pch_dBm' : pref_ch_db + dp_db,
|
'Pch_dBm' : pref_ch_db + dp_db,
|
||||||
'OSNR_ASE_0.1nm' : round(mean(destination.osnr_ase_01nm),2),
|
'OSNR_ASE_0.1nm' : round(mean(destination.osnr_ase_01nm),2),
|
||||||
'OSNR_ASE_signal_bw' : round(mean(destination.osnr_ase),2),
|
'OSNR_ASE_signal_bw' : round(mean(destination.osnr_ase),2),
|
||||||
'SNR_nli_signal_bw' : round(mean(destination.osnr_nli),2),
|
'SNR_nli_signal_bw' : round(mean(destination.osnr_nli),2),
|
||||||
'SNR_total_signal_bw' : round(mean(destination.snr),2)
|
'SNR_total_signal_bw' : round(mean(destination.snr),2)
|
||||||
})
|
})
|
||||||
|
else:
|
||||||
|
simulation_data.append({
|
||||||
|
'gain_mode' : 'power canot be set',
|
||||||
|
'OSNR_ASE_0.1nm' : round(mean(destination.osnr_ase_01nm),2),
|
||||||
|
'OSNR_ASE_signal_bw' : round(mean(destination.osnr_ase),2),
|
||||||
|
'SNR_nli_signal_bw' : round(mean(destination.osnr_nli),2),
|
||||||
|
'SNR_total_signal_bw' : round(mean(destination.snr),2)
|
||||||
|
})
|
||||||
|
#info message in gain mode
|
||||||
write_csv(result_dicts, 'simulation_result.csv')
|
write_csv(result_dicts, 'simulation_result.csv')
|
||||||
return path, infos
|
return path, infos
|
||||||
|
|
||||||
|
|||||||
@@ -111,11 +111,12 @@ class Eqpt(object):
|
|||||||
{
|
{
|
||||||
'from_city': '',
|
'from_city': '',
|
||||||
'to_city': '',
|
'to_city': '',
|
||||||
'east_amp_type': '',
|
'east_amp_type': '',
|
||||||
'east_att_in': 0,
|
'east_att_in': 0,
|
||||||
'east_amp_gain': 0,
|
'east_amp_gain': None,
|
||||||
'east_tilt': 0,
|
'east_amp_dp': None,
|
||||||
'east_att_out': 0
|
'east_tilt': 0,
|
||||||
|
'east_att_out': None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -163,8 +164,8 @@ def parse_headers(my_sheet, input_headers_dict, headers, start_line, slice_in):
|
|||||||
slice_out = read_slice(my_sheet, start_line+iteration, slice_in, h0)
|
slice_out = read_slice(my_sheet, start_line+iteration, slice_in, h0)
|
||||||
iteration += 1
|
iteration += 1
|
||||||
if slice_out == (-1, -1):
|
if slice_out == (-1, -1):
|
||||||
if h0 == 'east':
|
if h0 in ('east', 'Node A', 'Node Z', 'City') :
|
||||||
print(f'\x1b[1;31;40m'+f'CRITICAL: missing _east_ header above other headers (hierarchical) _ ABORT'+ '\x1b[0m')
|
print(f'\x1b[1;31;40m'+f'CRITICAL: missing _{h0}_ header: EXECUTION ENDS'+ '\x1b[0m')
|
||||||
exit()
|
exit()
|
||||||
else:
|
else:
|
||||||
print(f'missing header {h0}')
|
print(f'missing header {h0}')
|
||||||
@@ -344,6 +345,7 @@ def convert_file(input_filename, names_matching=False, filter_region=[]):
|
|||||||
'type': 'Edfa',
|
'type': 'Edfa',
|
||||||
'type_variety': e.east_amp_type,
|
'type_variety': e.east_amp_type,
|
||||||
'operational': {'gain_target': e.east_amp_gain,
|
'operational': {'gain_target': e.east_amp_gain,
|
||||||
|
'delta_p': e.east_amp_dp,
|
||||||
'tilt_target': e.east_tilt,
|
'tilt_target': e.east_tilt,
|
||||||
'out_voa' : e.east_att_out}
|
'out_voa' : e.east_att_out}
|
||||||
}
|
}
|
||||||
@@ -356,6 +358,7 @@ def convert_file(input_filename, names_matching=False, filter_region=[]):
|
|||||||
'type': 'Edfa',
|
'type': 'Edfa',
|
||||||
'type_variety': e.west_amp_type,
|
'type_variety': e.west_amp_type,
|
||||||
'operational': {'gain_target': e.west_amp_gain,
|
'operational': {'gain_target': e.west_amp_gain,
|
||||||
|
'delta_p': e.west_amp_dp,
|
||||||
'tilt_target': e.west_tilt,
|
'tilt_target': e.west_tilt,
|
||||||
'out_voa' : e.west_att_out}
|
'out_voa' : e.west_att_out}
|
||||||
}
|
}
|
||||||
@@ -420,6 +423,7 @@ def parse_excel(input_filename):
|
|||||||
'amp type': 'east_amp_type',
|
'amp type': 'east_amp_type',
|
||||||
'att_in': 'east_att_in',
|
'att_in': 'east_att_in',
|
||||||
'amp gain': 'east_amp_gain',
|
'amp gain': 'east_amp_gain',
|
||||||
|
'delta p': 'east_amp_dp',
|
||||||
'tilt': 'east_tilt',
|
'tilt': 'east_tilt',
|
||||||
'att_out': 'east_att_out'
|
'att_out': 'east_att_out'
|
||||||
},
|
},
|
||||||
@@ -427,6 +431,7 @@ def parse_excel(input_filename):
|
|||||||
'amp type': 'west_amp_type',
|
'amp type': 'west_amp_type',
|
||||||
'att_in': 'west_att_in',
|
'att_in': 'west_att_in',
|
||||||
'amp gain': 'west_amp_gain',
|
'amp gain': 'west_amp_gain',
|
||||||
|
'delta p': 'west_amp_dp',
|
||||||
'tilt': 'west_tilt',
|
'tilt': 'west_tilt',
|
||||||
'att_out': 'west_att_out'
|
'att_out': 'west_att_out'
|
||||||
}
|
}
|
||||||
@@ -566,12 +571,12 @@ def midpoint(city_a, city_b):
|
|||||||
#output_json_file_name = 'coronet_conus_example.json'
|
#output_json_file_name = 'coronet_conus_example.json'
|
||||||
#TODO get column size automatically from tupple size
|
#TODO get column size automatically from tupple size
|
||||||
|
|
||||||
NODES_COLUMN = 7
|
NODES_COLUMN = 8
|
||||||
NODES_LINE = 4
|
NODES_LINE = 4
|
||||||
LINKS_COLUMN = 16
|
LINKS_COLUMN = 16
|
||||||
LINKS_LINE = 3
|
LINKS_LINE = 3
|
||||||
EQPTS_LINE = 3
|
EQPTS_LINE = 3
|
||||||
EQPTS_COLUMN = 12
|
EQPTS_COLUMN = 14
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
parser.add_argument('workbook', nargs='?', type=Path , default='meshTopologyExampleV2.xls')
|
parser.add_argument('workbook', nargs='?', type=Path , default='meshTopologyExampleV2.xls')
|
||||||
parser.add_argument('-f', '--filter-region', action='append', default=[])
|
parser.add_argument('-f', '--filter-region', action='append', default=[])
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ class Transceiver(Node):
|
|||||||
with errstate(divide='ignore'):
|
with errstate(divide='ignore'):
|
||||||
self.baud_rate = [c.baud_rate for c in spectral_info.carriers]
|
self.baud_rate = [c.baud_rate for c in spectral_info.carriers]
|
||||||
ratio_01nm = [lin2db(12.5e9/b_rate) for b_rate in self.baud_rate]
|
ratio_01nm = [lin2db(12.5e9/b_rate) for b_rate in self.baud_rate]
|
||||||
|
|
||||||
#set raw values to record original calculation, before update_snr()
|
#set raw values to record original calculation, before update_snr()
|
||||||
self.raw_osnr_ase = [lin2db(divide(c.power.signal, c.power.ase))
|
self.raw_osnr_ase = [lin2db(divide(c.power.signal, c.power.ase))
|
||||||
for c in spectral_info.carriers]
|
for c in spectral_info.carriers]
|
||||||
@@ -112,25 +111,21 @@ class Transceiver(Node):
|
|||||||
self._calc_snr(spectral_info)
|
self._calc_snr(spectral_info)
|
||||||
return spectral_info
|
return spectral_info
|
||||||
|
|
||||||
RoadmParams = namedtuple('RoadmParams', 'loss')
|
RoadmParams = namedtuple('RoadmParams', 'target_pch_out_db add_drop_osnr')
|
||||||
|
|
||||||
class Roadm(Node):
|
class Roadm(Node):
|
||||||
def __init__(self, *args, params=None, **kwargs):
|
def __init__(self, *args, params, **kwargs):
|
||||||
if params is None:
|
|
||||||
# default loss value if not mentioned in loaded network json
|
|
||||||
params = {'loss':None}
|
|
||||||
super().__init__(*args, params=RoadmParams(**params), **kwargs)
|
super().__init__(*args, params=RoadmParams(**params), **kwargs)
|
||||||
self.loss = self.params.loss
|
self.loss = 0 #auto-design interest
|
||||||
self.target_pch_out_db = None #set in Networks.py by def set_roadm_loss
|
self.effective_loss = None
|
||||||
self.effective_pch_out_db = None
|
self.effective_pch_out_db = self.params.target_pch_out_db
|
||||||
self.effective_loss = None #set in self.propagate
|
|
||||||
self.passive = True
|
self.passive = True
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
return {'uid' : self.uid,
|
return {'uid' : self.uid,
|
||||||
'type' : type(self).__name__,
|
'type' : type(self).__name__,
|
||||||
'params' : {'loss' : self.loss},
|
'params' : {'target_pch_out_db' : self.effective_pch_out_db},
|
||||||
'metadata' : {
|
'metadata' : {
|
||||||
'location': self.metadata['location']._asdict()
|
'location': self.metadata['location']._asdict()
|
||||||
}
|
}
|
||||||
@@ -141,26 +136,25 @@ class Roadm(Node):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return '\n'.join([f'{type(self).__name__} {self.uid}',
|
return '\n'.join([f'{type(self).__name__} {self.uid}',
|
||||||
f' loss (dB): {self.effective_loss:.2f}',
|
f' effective loss (dB): {self.effective_loss:.2f}',
|
||||||
f' pch out (dBm): {self.effective_pch_out_db!r}'])
|
f' pch out (dBm): {self.effective_pch_out_db!r}'])
|
||||||
|
|
||||||
def propagate(self, pref, *carriers):
|
def propagate(self, pref, *carriers):
|
||||||
#pin_target and loss are read from eqpt_config.json['Roadm']
|
#pin_target and loss are read from eqpt_config.json['Roadm']
|
||||||
#all ingress channels in xpress are set to this power level
|
#all ingress channels in xpress are set to this power level
|
||||||
#but add channels are not, so we define an effective loss
|
#but add channels are not, so we define an effective loss
|
||||||
#in the case of add channels
|
#in the case of add channels
|
||||||
if self.target_pch_out_db:
|
self.effective_pch_out_db = min(pref.pi, self.params.target_pch_out_db)
|
||||||
self.effective_loss = pref.pi - self.target_pch_out_db
|
self.effective_loss = pref.pi - self.effective_pch_out_db
|
||||||
else:
|
carriers_power = array([c.power.signal +c.power.nli+c.power.ase for c in carriers])
|
||||||
self.effective_loss = self.loss
|
carriers_att = list(map(lambda x : lin2db(x*1e3)-self.params.target_pch_out_db, carriers_power))
|
||||||
self.effective_pch_out_db = pref.pi - self.effective_loss
|
exceeding_att = -min(list(filter(lambda x: x < 0, carriers_att)), default = 0)
|
||||||
attenuation = db2lin(self.effective_loss)
|
carriers_att = list(map(lambda x: db2lin(x+exceeding_att), carriers_att))
|
||||||
|
for carrier_att, carrier in zip(carriers_att, carriers) :
|
||||||
for carrier in carriers:
|
|
||||||
pwr = carrier.power
|
pwr = carrier.power
|
||||||
pwr = pwr._replace(signal=pwr.signal/attenuation,
|
pwr = pwr._replace( signal = pwr.signal/carrier_att,
|
||||||
nonlinear_interference=pwr.nli/attenuation,
|
nonlinear_interference = pwr.nli/carrier_att,
|
||||||
amplified_spontaneous_emission=pwr.ase/attenuation)
|
amplified_spontaneous_emission = pwr.ase/carrier_att)
|
||||||
yield carrier._replace(power=pwr)
|
yield carrier._replace(power=pwr)
|
||||||
|
|
||||||
def update_pref(self, pref):
|
def update_pref(self, pref):
|
||||||
@@ -430,16 +424,16 @@ class EdfaParams:
|
|||||||
if params == {}:
|
if params == {}:
|
||||||
self.type_variety = ''
|
self.type_variety = ''
|
||||||
self.type_def = ''
|
self.type_def = ''
|
||||||
self.gain_flatmax = 0
|
# self.gain_flatmax = 0
|
||||||
self.gain_min = 0
|
# self.gain_min = 0
|
||||||
self.p_max = 0
|
# self.p_max = 0
|
||||||
self.nf_model = None
|
# self.nf_model = None
|
||||||
self.nf_fit_coeff = None
|
# self.nf_fit_coeff = None
|
||||||
self.nf_ripple = None
|
# self.nf_ripple = None
|
||||||
self.dgt = None
|
# self.dgt = None
|
||||||
self.gain_ripple = None
|
# self.gain_ripple = None
|
||||||
self.out_voa_auto = False
|
# self.out_voa_auto = False
|
||||||
self.allowed_for_design = None
|
# self.allowed_for_design = None
|
||||||
|
|
||||||
def update_params(self, kwargs):
|
def update_params(self, kwargs):
|
||||||
for k,v in kwargs.items() :
|
for k,v in kwargs.items() :
|
||||||
@@ -447,10 +441,22 @@ class EdfaParams:
|
|||||||
if isinstance(v, dict) else v)
|
if isinstance(v, dict) else v)
|
||||||
|
|
||||||
class EdfaOperational:
|
class EdfaOperational:
|
||||||
def __init__(self, gain_target, tilt_target, out_voa=None):
|
default_values = \
|
||||||
self.gain_target = gain_target
|
{
|
||||||
self.tilt_target = tilt_target
|
'gain_target': None,
|
||||||
self.out_voa = out_voa
|
'delta_p': None,
|
||||||
|
'out_voa': None,
|
||||||
|
'tilt_target': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
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):
|
def __repr__(self):
|
||||||
return (f'{type(self).__name__}('
|
return (f'{type(self).__name__}('
|
||||||
f'gain_target={self.gain_target!r}, '
|
f'gain_target={self.gain_target!r}, '
|
||||||
@@ -479,14 +485,16 @@ class Edfa(Node):
|
|||||||
self.pin_db = None
|
self.pin_db = None
|
||||||
self.nch = None
|
self.nch = None
|
||||||
self.pout_db = None
|
self.pout_db = None
|
||||||
self.dp_db = None #delta P with Pref (power swwep) in power mode
|
|
||||||
self.target_pch_out_db = None
|
self.target_pch_out_db = None
|
||||||
self.effective_pch_out_db = None
|
self.effective_pch_out_db = None
|
||||||
self.passive = False
|
self.passive = False
|
||||||
self.effective_gain = self.operational.gain_target
|
|
||||||
self.att_in = None
|
self.att_in = None
|
||||||
self.carriers_in = None
|
self.carriers_in = None
|
||||||
self.carriers_out = None
|
self.carriers_out = None
|
||||||
|
self.effective_gain = self.operational.gain_target
|
||||||
|
self.delta_p = self.operational.delta_p #delta P with Pref (power swwep) in power mode
|
||||||
|
self.tilt_target = self.operational.tilt_target
|
||||||
|
self.out_voa = self.operational.out_voa
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def to_json(self):
|
def to_json(self):
|
||||||
@@ -494,9 +502,10 @@ class Edfa(Node):
|
|||||||
'type' : type(self).__name__,
|
'type' : type(self).__name__,
|
||||||
'type_variety' : self.params.type_variety,
|
'type_variety' : self.params.type_variety,
|
||||||
'operational' : {
|
'operational' : {
|
||||||
'gain_target' : self.operational.gain_target,
|
'gain_target' : self.effective_gain,
|
||||||
'tilt_target' : self.operational.tilt_target,
|
'delta_p' : self.delta_p,
|
||||||
'out_voa' : self.operational.out_voa
|
'tilt_target' : self.tilt_target,
|
||||||
|
'out_voa' : self.out_voa
|
||||||
},
|
},
|
||||||
'metadata' : {
|
'metadata' : {
|
||||||
'location': self.metadata['location']._asdict()
|
'location': self.metadata['location']._asdict()
|
||||||
@@ -528,10 +537,10 @@ class Edfa(Node):
|
|||||||
f' pad att_in (dB): {self.att_in:.2f}',
|
f' pad att_in (dB): {self.att_in:.2f}',
|
||||||
f' Power In (dBm): {self.pin_db:.2f}',
|
f' Power In (dBm): {self.pin_db:.2f}',
|
||||||
f' Power Out (dBm): {self.pout_db:.2f}',
|
f' Power Out (dBm): {self.pout_db:.2f}',
|
||||||
f' Delta_P (dB): {self.dp_db!r}',
|
f' Delta_P (dB): {self.delta_p!r}',
|
||||||
f' target pch (dBm): {self.target_pch_out_db!r}',
|
f' target pch (dBm): {self.target_pch_out_db!r}',
|
||||||
f' effective pch (dBm): {self.effective_pch_out_db!r}',
|
f' effective pch (dBm): {self.effective_pch_out_db!r}',
|
||||||
f' output VOA (dB): {self.operational.out_voa:.2f}'])
|
f' output VOA (dB): {self.out_voa:.2f}'])
|
||||||
|
|
||||||
def carriers(self, loc, attr):
|
def carriers(self, loc, attr):
|
||||||
"""retrieve carriers information
|
"""retrieve carriers information
|
||||||
@@ -561,58 +570,101 @@ class Edfa(Node):
|
|||||||
amplifier_freq = itufs(0.05) * 1e12 # Hz
|
amplifier_freq = itufs(0.05) * 1e12 # Hz
|
||||||
self.channel_freq = frequencies
|
self.channel_freq = frequencies
|
||||||
self.interpol_dgt = interp(self.channel_freq, amplifier_freq, self.params.dgt)
|
self.interpol_dgt = interp(self.channel_freq, amplifier_freq, self.params.dgt)
|
||||||
|
|
||||||
self.interpol_gain_ripple = interp(self.channel_freq, amplifier_freq, self.params.gain_ripple)
|
self.interpol_gain_ripple = interp(self.channel_freq, amplifier_freq, self.params.gain_ripple)
|
||||||
self.interpol_nf_ripple =interp(self.channel_freq, amplifier_freq, self.params.nf_ripple)
|
self.interpol_nf_ripple =interp(self.channel_freq, amplifier_freq, self.params.nf_ripple)
|
||||||
|
|
||||||
self.nch = frequencies.size
|
self.nch = frequencies.size
|
||||||
self.pin_db = lin2db(sum(pin*1e3))
|
self.pin_db = lin2db(sum(pin*1e3))
|
||||||
|
|
||||||
"""in power mode: dp_db is defined and can be used to calculate the power target
|
"""in power mode: delta_p is defined and can be used to calculate the power target
|
||||||
This power target is used calculate the amplifier gain"""
|
This power target is used calculate the amplifier gain"""
|
||||||
if self.dp_db is not None:
|
if self.delta_p is not None:
|
||||||
self.target_pch_out_db = round(self.dp_db + pref.p0, 2)
|
self.target_pch_out_db = round(self.delta_p + pref.p0, 2)
|
||||||
self.effective_gain = self.target_pch_out_db - pref.pi
|
self.effective_gain = self.target_pch_out_db - pref.pi
|
||||||
else:
|
|
||||||
self.effective_gain = self.operational.gain_target
|
"""check power saturation and correct effective gain & power accordingly:"""
|
||||||
|
self.effective_gain = min(
|
||||||
"""check power saturation and correct target_gain accordingly:"""
|
self.effective_gain,
|
||||||
self.effective_gain = min(self.effective_gain, self.params.p_max - self.pin_db)
|
self.params.p_max - (pref.pi + pref.neq_ch)
|
||||||
|
)
|
||||||
|
#print(self.uid, self.effective_gain, self.operational.gain_target)
|
||||||
self.effective_pch_out_db = round(pref.pi + self.effective_gain, 2)
|
self.effective_pch_out_db = round(pref.pi + self.effective_gain, 2)
|
||||||
|
|
||||||
|
"""check power saturation and correct target_gain accordingly:"""
|
||||||
|
#print(self.uid, self.effective_gain, self.pin_db, pref.pi)
|
||||||
self.nf = self._calc_nf()
|
self.nf = self._calc_nf()
|
||||||
self.gprofile = self._gain_profile(pin)
|
self.gprofile = self._gain_profile(pin)
|
||||||
|
|
||||||
pout = (pin + self.noise_profile(baud_rates))*db2lin(self.gprofile)
|
pout = (pin + self.noise_profile(baud_rates))*db2lin(self.gprofile)
|
||||||
self.pout_db = lin2db(sum(pout*1e3))
|
self.pout_db = lin2db(sum(pout*1e3))
|
||||||
self.operational.gain_target = self.effective_gain
|
|
||||||
# ase & nli are only calculated in signal bandwidth
|
# ase & nli are only calculated in signal bandwidth
|
||||||
# pout_db is not the absolute full output power (negligible if sufficient channels)
|
# pout_db is not the absolute full output power (negligible if sufficient channels)
|
||||||
|
|
||||||
|
def _nf(self, type_def, nf_model, nf_fit_coeff, gain_min, gain_flatmax, gain_target):
|
||||||
|
#if hybrid raman, use edfa_gain_flatmax attribute, else use gain_flatmax
|
||||||
|
#gain_flatmax = getattr(params, 'edfa_gain_flatmax', params.gain_flatmax)
|
||||||
|
pad = max(gain_min - gain_target, 0)
|
||||||
|
gain_target += pad
|
||||||
|
dg = max(gain_flatmax - gain_target, 0)
|
||||||
|
if type_def == 'variable_gain':
|
||||||
|
g1a = gain_target - nf_model.delta_p - dg
|
||||||
|
nf_avg = lin2db(db2lin(nf_model.nf1) + db2lin(nf_model.nf2)/db2lin(g1a))
|
||||||
|
elif type_def == 'fixed_gain':
|
||||||
|
nf_avg = nf_model.nf0
|
||||||
|
elif type_def == 'openroadm':
|
||||||
|
pin_ch = self.pin_db - lin2db(self.nch)
|
||||||
|
# model OSNR = f(Pin)
|
||||||
|
nf_avg = pin_ch - polyval(nf_model.nf_coef, pin_ch) + 58
|
||||||
|
elif type_def == 'advanced_model':
|
||||||
|
nf_avg = polyval(nf_fit_coeff, -dg)
|
||||||
|
else :
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'CRITICAL: unrecognized type def _{self.params.type_def}_\n\
|
||||||
|
=> please check eqpt_config.json'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
exit()
|
||||||
|
return nf_avg+pad, pad
|
||||||
|
|
||||||
def _calc_nf(self, avg = False):
|
def _calc_nf(self, avg = False):
|
||||||
"""nf calculation based on 2 models: self.params.nf_model.enabled from json import:
|
"""nf calculation based on 2 models: self.params.nf_model.enabled from json import:
|
||||||
True => 2 stages amp modelling based on precalculated nf1, nf2 and delta_p in build_OA_json
|
True => 2 stages amp modelling based on precalculated nf1, nf2 and delta_p in build_OA_json
|
||||||
False => polynomial fit based on self.params.nf_fit_coeff"""
|
False => polynomial fit based on self.params.nf_fit_coeff"""
|
||||||
# TODO|jla: TBD alarm rising or input VOA padding in case
|
|
||||||
# gain_min > gain_target TBD:
|
# gain_min > gain_target TBD:
|
||||||
pad = max(self.params.gain_min - self.effective_gain, 0)
|
if self.params.type_def == 'dual_stage':
|
||||||
self.att_in = pad
|
g1 = self.params.preamp_gain_flatmax
|
||||||
gain_target = self.effective_gain + pad
|
g2 = self.effective_gain - g1
|
||||||
dg = max(self.params.gain_flatmax - gain_target, 0)
|
nf1_avg, pad = self._nf( self.params.preamp_type_def,
|
||||||
if self.params.type_def == 'variable_gain':
|
self.params.preamp_nf_model,
|
||||||
g1a = gain_target - self.params.nf_model.delta_p - dg
|
self.params.preamp_nf_fit_coeff,
|
||||||
nf_avg = lin2db(db2lin(self.params.nf_model.nf1) + db2lin(self.params.nf_model.nf2)/db2lin(g1a))
|
self.params.preamp_gain_min,
|
||||||
elif self.params.type_def == 'fixed_gain':
|
self.params.preamp_gain_flatmax,
|
||||||
nf_avg = self.params.nf_model.nf0
|
g1)
|
||||||
elif self.params.type_def == 'openroadm':
|
#no padding expected for the 1stage because g1 = gain_max
|
||||||
pin_ch = self.pin_db - lin2db(self.nch)
|
nf2_avg, pad = self._nf( self.params.booster_type_def,
|
||||||
# model OSNR = f(Pin)
|
self.params.booster_nf_model,
|
||||||
nf_avg = pin_ch - polyval(self.params.nf_model.nf_coef, pin_ch) + 58
|
self.params.booster_nf_fit_coeff,
|
||||||
else:
|
self.params.booster_gain_min,
|
||||||
nf_avg = polyval(self.params.nf_fit_coeff, -dg)
|
self.params.booster_gain_flatmax,
|
||||||
|
g2)
|
||||||
|
nf_avg = lin2db(db2lin(nf1_avg) + db2lin(nf2_avg-g1))
|
||||||
|
#no padding expected for the 1stage because g1 = gain_max
|
||||||
|
pad = 0
|
||||||
|
else:
|
||||||
|
nf_avg, pad = self._nf( self.params.type_def,
|
||||||
|
self.params.nf_model,
|
||||||
|
self.params.nf_fit_coeff,
|
||||||
|
self.params.gain_min,
|
||||||
|
self.params.gain_flatmax,
|
||||||
|
self.effective_gain)
|
||||||
|
|
||||||
|
self.att_in = pad # not used to attenuate carriers, only used in _repr_ and _str_
|
||||||
if avg:
|
if avg:
|
||||||
return nf_avg + pad
|
return nf_avg
|
||||||
else:
|
else:
|
||||||
return self.interpol_nf_ripple + nf_avg + pad # input VOA = 1 for 1 NF degradation
|
return self.interpol_nf_ripple + nf_avg # input VOA = 1 for 1 NF degradation
|
||||||
|
|
||||||
def noise_profile(self, df):
|
def noise_profile(self, df):
|
||||||
""" noise_profile(bw) computes amplifier ase (W) in signal bw (Hz)
|
""" noise_profile(bw) computes amplifier ase (W) in signal bw (Hz)
|
||||||
@@ -705,7 +757,7 @@ class Edfa(Node):
|
|||||||
|
|
||||||
# Calculate the target slope - currently assumes equal spaced channels
|
# Calculate the target slope - currently assumes equal spaced channels
|
||||||
# TODO|jla: support arbitrary channel spacing
|
# TODO|jla: support arbitrary channel spacing
|
||||||
targ_slope = self.operational.tilt_target / (len(nb_channel) - 1)
|
targ_slope = self.tilt_target / (len(nb_channel) - 1)
|
||||||
|
|
||||||
# first estimate of DGT scaling
|
# first estimate of DGT scaling
|
||||||
if abs(dgt_slope) > 0.001: # check for zero value due to flat dgt
|
if abs(dgt_slope) > 0.001: # check for zero value due to flat dgt
|
||||||
@@ -779,7 +831,7 @@ class Edfa(Node):
|
|||||||
|
|
||||||
gains = db2lin(self.gprofile)
|
gains = db2lin(self.gprofile)
|
||||||
carrier_ases = self.noise_profile(brate)
|
carrier_ases = self.noise_profile(brate)
|
||||||
att = db2lin(self.operational.out_voa)
|
att = db2lin(self.out_voa)
|
||||||
|
|
||||||
for gain, carrier_ase, carrier in zip(gains, carrier_ases, carriers):
|
for gain, carrier_ase, carrier in zip(gains, carrier_ases, carriers):
|
||||||
pwr = carrier.power
|
pwr = carrier.power
|
||||||
@@ -790,7 +842,7 @@ class Edfa(Node):
|
|||||||
|
|
||||||
def update_pref(self, pref):
|
def update_pref(self, pref):
|
||||||
return pref._replace(p_span0=pref.p0,
|
return pref._replace(p_span0=pref.p0,
|
||||||
p_spani=pref.pi + self.effective_gain - self.operational.out_voa)
|
p_spani=pref.pi + self.effective_gain - self.out_voa)
|
||||||
|
|
||||||
def __call__(self, spectral_info):
|
def __call__(self, spectral_info):
|
||||||
self.carriers_in = spectral_info.carriers
|
self.carriers_in = spectral_info.carriers
|
||||||
|
|||||||
@@ -17,44 +17,124 @@ from json import load
|
|||||||
from gnpy.core.utils import lin2db, db2lin, load_json
|
from gnpy.core.utils import lin2db, db2lin, load_json
|
||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from gnpy.core.elements import Edfa
|
from gnpy.core.elements import Edfa
|
||||||
|
import time
|
||||||
|
|
||||||
Model_vg = namedtuple('Model_vg', 'nf1 nf2 delta_p')
|
Model_vg = namedtuple('Model_vg', 'nf1 nf2 delta_p')
|
||||||
Model_fg = namedtuple('Model_fg', 'nf0')
|
Model_fg = namedtuple('Model_fg', 'nf0')
|
||||||
Model_openroadm = namedtuple('Model_openroadm', 'nf_coef')
|
Model_openroadm = namedtuple('Model_openroadm', 'nf_coef')
|
||||||
Fiber = namedtuple('Fiber', 'type_variety dispersion gamma')
|
Model_hybrid = namedtuple('Model_hybrid', 'nf_ram gain_ram edfa_variety')
|
||||||
Spans = namedtuple('Spans', 'power_mode delta_power_range_db max_length length_units \
|
Model_dual_stage = namedtuple('Model_dual_stage', 'preamp_variety booster_variety')
|
||||||
max_loss padding EOL con_in con_out')
|
|
||||||
Transceiver = namedtuple('Transceiver', 'type_variety frequency mode')
|
class common:
|
||||||
Roadms = namedtuple('Roadms', 'gain_mode_default_loss power_mode_pout_target add_drop_osnr')
|
def update_attr(self, default_values, kwargs, name):
|
||||||
SI = namedtuple('SI', 'f_min f_max baud_rate spacing roll_off \
|
clean_kwargs = {k:v for k,v in kwargs.items() if v !=''}
|
||||||
power_dbm power_range_db tx_osnr sys_margins')
|
for k,v in default_values.items():
|
||||||
AmpBase = namedtuple(
|
setattr(self, k, clean_kwargs.get(k,v))
|
||||||
'AmpBase',
|
if k not in clean_kwargs and name != 'Amp' :
|
||||||
'type_variety type_def gain_flatmax gain_min p_max'
|
print(f'\x1b[1;31;40m'+
|
||||||
' nf_model nf_fit_coeff nf_ripple dgt gain_ripple out_voa_auto allowed_for_design')
|
f'\n WARNING missing {k} attribute in eqpt_config.json[{name}]'
|
||||||
class Amp(AmpBase):
|
f'\n default value is {k} = {v}'
|
||||||
def __new__(cls,
|
+ '\x1b[0m')
|
||||||
type_variety, type_def, gain_flatmax, gain_min, p_max, nf_model=None,
|
time.sleep(1)
|
||||||
nf_fit_coeff=None, nf_ripple=None, dgt=None, gain_ripple=None,
|
|
||||||
out_voa_auto=False, allowed_for_design=True):
|
class SI(common):
|
||||||
return super().__new__(cls,
|
default_values =\
|
||||||
type_variety, type_def, gain_flatmax, gain_min, p_max,
|
{
|
||||||
nf_model, nf_fit_coeff, nf_ripple, dgt, gain_ripple,
|
"f_min": 191.35e12,
|
||||||
out_voa_auto, allowed_for_design)
|
"f_max": 196.1e12,
|
||||||
|
"baud_rate": 32e9,
|
||||||
|
"spacing": 50e9,
|
||||||
|
"power_dbm": 0,
|
||||||
|
"power_range_db": [0,0,0.5],
|
||||||
|
"roll_off": 0.15,
|
||||||
|
"tx_osnr": 45,
|
||||||
|
"sys_margins": 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'SI')
|
||||||
|
|
||||||
|
class Span(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'power_mode': True,
|
||||||
|
'delta_power_range_db': None,
|
||||||
|
'max_fiber_lineic_loss_for_raman': 0.25,
|
||||||
|
'target_extended_gain': 2.5,
|
||||||
|
'max_length': 150,
|
||||||
|
'length_units': 'km',
|
||||||
|
'max_loss': None,
|
||||||
|
'padding': 10,
|
||||||
|
'EOL': 0,
|
||||||
|
'con_in': 0,
|
||||||
|
'con_out': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Span')
|
||||||
|
|
||||||
|
class Roadm(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'target_pch_out_db': -17,
|
||||||
|
'add_drop_osnr': 100
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Roadm')
|
||||||
|
|
||||||
|
class Transceiver(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'type_variety': None,
|
||||||
|
'frequency': None,
|
||||||
|
'mode': {}
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Transceiver')
|
||||||
|
|
||||||
|
class Fiber(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'type_variety': '',
|
||||||
|
'dispersion': None,
|
||||||
|
'gamma': 0
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Fiber')
|
||||||
|
|
||||||
|
class Amp(common):
|
||||||
|
default_values = \
|
||||||
|
{
|
||||||
|
'type_variety': '',
|
||||||
|
'type_def': '',
|
||||||
|
'gain_flatmax': None,
|
||||||
|
'gain_min': None,
|
||||||
|
'p_max': None,
|
||||||
|
'nf_model': None,
|
||||||
|
'dual_stage_model': None,
|
||||||
|
'nf_fit_coeff': None,
|
||||||
|
'nf_ripple': None,
|
||||||
|
'dgt': None,
|
||||||
|
'gain_ripple': None,
|
||||||
|
'out_voa_auto': False,
|
||||||
|
'allowed_for_design': False,
|
||||||
|
'raman': False
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.update_attr(self.default_values, kwargs, 'Amp')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_advanced_json(cls, filename, **kwargs):
|
def from_json(cls, filename, **kwargs):
|
||||||
with open(filename, encoding='utf-8') as f:
|
config = Path(filename).parent / 'default_edfa_config.json'
|
||||||
json_data = load(f)
|
|
||||||
return cls(**{**kwargs, **json_data, 'type_def':None, 'nf_model':None})
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_default_json(cls, filename, **kwargs):
|
|
||||||
with open(filename, encoding='utf-8') as f:
|
|
||||||
json_data = load(f)
|
|
||||||
type_variety = kwargs['type_variety']
|
type_variety = kwargs['type_variety']
|
||||||
type_def = kwargs.get('type_def', 'variable_gain') #default compatibility with older json eqpt files
|
type_def = kwargs.get('type_def', 'variable_gain') #default compatibility with older json eqpt files
|
||||||
nf_def = None
|
nf_def = None
|
||||||
|
dual_stage_def = None
|
||||||
|
|
||||||
if type_def == 'fixed_gain':
|
if type_def == 'fixed_gain':
|
||||||
try:
|
try:
|
||||||
@@ -67,6 +147,8 @@ class Amp(AmpBase):
|
|||||||
del kwargs['nf_max']
|
del kwargs['nf_max']
|
||||||
except KeyError: pass #nf_min and nf_max are not needed for fixed gain amp
|
except KeyError: pass #nf_min and nf_max are not needed for fixed gain amp
|
||||||
nf_def = Model_fg(nf0)
|
nf_def = Model_fg(nf0)
|
||||||
|
elif type_def == 'advanced_model':
|
||||||
|
config = Path(filename).parent / kwargs.pop('advanced_config_from_json')
|
||||||
elif type_def == 'variable_gain':
|
elif type_def == 'variable_gain':
|
||||||
gain_min, gain_max = kwargs['gain_min'], kwargs['gain_flatmax']
|
gain_min, gain_max = kwargs['gain_min'], kwargs['gain_flatmax']
|
||||||
try: #nf_min and nf_max are expected for a variable gain amp
|
try: #nf_min and nf_max are expected for a variable gain amp
|
||||||
@@ -87,7 +169,20 @@ class Amp(AmpBase):
|
|||||||
print(f'missing nf_coef input for amplifier: {type_variety} in eqpt_config.json')
|
print(f'missing nf_coef input for amplifier: {type_variety} in eqpt_config.json')
|
||||||
exit()
|
exit()
|
||||||
nf_def = Model_openroadm(nf_coef)
|
nf_def = Model_openroadm(nf_coef)
|
||||||
return cls(**{**kwargs, **json_data, 'nf_model': nf_def})
|
elif type_def == 'dual_stage':
|
||||||
|
try: #nf_ram and gain_ram are expected for a hybrid amp
|
||||||
|
preamp_variety = kwargs.pop('preamp_variety')
|
||||||
|
booster_variety = kwargs.pop('booster_variety')
|
||||||
|
except KeyError:
|
||||||
|
print(f'missing preamp/booster variety input for amplifier: {type_variety} in eqpt_config.json')
|
||||||
|
exit()
|
||||||
|
dual_stage_def = Model_dual_stage(preamp_variety, booster_variety)
|
||||||
|
|
||||||
|
with open(config, encoding='utf-8') as f:
|
||||||
|
json_data = load(f)
|
||||||
|
|
||||||
|
return cls(**{**kwargs, **json_data,
|
||||||
|
'nf_model': nf_def, 'dual_stage_model': dual_stage_def})
|
||||||
|
|
||||||
|
|
||||||
def nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
def nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
||||||
@@ -123,7 +218,7 @@ def nf_model(type_variety, gain_min, gain_max, nf_min, nf_max):
|
|||||||
g1a_max = lin2db(db2lin(nf2) / (db2lin(nf_min) - db2lin(nf1)))
|
g1a_max = lin2db(db2lin(nf2) / (db2lin(nf_min) - db2lin(nf1)))
|
||||||
delta_p = gain_max - g1a_max
|
delta_p = gain_max - g1a_max
|
||||||
g1a_min = gain_min - (gain_max-gain_min) - delta_p
|
g1a_min = gain_min - (gain_max-gain_min) - delta_p
|
||||||
if not 1 < delta_p < 6:
|
if not 1 < delta_p < 11:
|
||||||
print(f'Computed \N{greek capital letter delta}P invalid \
|
print(f'Computed \N{greek capital letter delta}P invalid \
|
||||||
\n 1st coil vs 2nd coil calculated DeltaP {delta_p:.2f} for \
|
\n 1st coil vs 2nd coil calculated DeltaP {delta_p:.2f} for \
|
||||||
\n amplifier {type_variety} is not valid: revise inputs \
|
\n amplifier {type_variety} is not valid: revise inputs \
|
||||||
@@ -145,7 +240,7 @@ def edfa_nf(gain_target, variety_type, equipment):
|
|||||||
amp_params = equipment['Edfa'][variety_type]
|
amp_params = equipment['Edfa'][variety_type]
|
||||||
amp = Edfa(
|
amp = Edfa(
|
||||||
uid = f'calc_NF',
|
uid = f'calc_NF',
|
||||||
params = amp_params._asdict(),
|
params = amp_params.__dict__,
|
||||||
operational = {
|
operational = {
|
||||||
'gain_target': gain_target,
|
'gain_target': gain_target,
|
||||||
'tilt_target': 0
|
'tilt_target': 0
|
||||||
@@ -243,6 +338,30 @@ def update_trx_osnr(equipment):
|
|||||||
m['OSNR'] = m['OSNR'] + equipment['SI']['default'].sys_margins
|
m['OSNR'] = m['OSNR'] + equipment['SI']['default'].sys_margins
|
||||||
return equipment
|
return equipment
|
||||||
|
|
||||||
|
def update_dual_stage(equipment):
|
||||||
|
edfa_dict = equipment['Edfa']
|
||||||
|
for edfa in edfa_dict.values():
|
||||||
|
if edfa.type_def == 'dual_stage':
|
||||||
|
edfa_preamp = edfa_dict[edfa.dual_stage_model.preamp_variety]
|
||||||
|
edfa_booster = edfa_dict[edfa.dual_stage_model.booster_variety]
|
||||||
|
for k,v in edfa_preamp.__dict__.items():
|
||||||
|
attr_k = 'preamp_'+k
|
||||||
|
setattr(edfa, attr_k, v)
|
||||||
|
for k,v in edfa_booster.__dict__.items():
|
||||||
|
attr_k = 'booster_'+k
|
||||||
|
setattr(edfa, attr_k, v)
|
||||||
|
edfa.p_max = edfa_booster.p_max
|
||||||
|
edfa.gain_flatmax = edfa_booster.gain_flatmax + edfa_preamp.gain_flatmax
|
||||||
|
if edfa.gain_min < edfa_preamp.gain_min:
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'CRITICAL: dual stage {edfa.type_variety} min gain is lower than its preamp min gain\
|
||||||
|
=> please increase its min gain in eqpt_config.json'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
exit()
|
||||||
|
return equipment
|
||||||
|
|
||||||
def equipment_from_json(json_data, filename):
|
def equipment_from_json(json_data, filename):
|
||||||
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
"""build global dictionnary eqpt_library that stores all eqpt characteristics:
|
||||||
edfa type type_variety, fiber type_variety
|
edfa type type_variety, fiber type_variety
|
||||||
@@ -259,13 +378,9 @@ def equipment_from_json(json_data, filename):
|
|||||||
for entry in entries:
|
for entry in entries:
|
||||||
subkey = entry.get('type_variety', 'default')
|
subkey = entry.get('type_variety', 'default')
|
||||||
if key == 'Edfa':
|
if key == 'Edfa':
|
||||||
if 'advanced_config_from_json' in entry:
|
equipment[key][subkey] = Amp.from_json(filename, **entry)
|
||||||
config = Path(filename).parent / entry.pop('advanced_config_from_json')
|
|
||||||
equipment[key][subkey] = Amp.from_advanced_json(config, **entry)
|
|
||||||
else:
|
|
||||||
config = Path(filename).parent / 'default_edfa_config.json'
|
|
||||||
equipment[key][subkey] = Amp.from_default_json(config, **entry)
|
|
||||||
else:
|
else:
|
||||||
equipment[key][subkey] = typ(**entry)
|
equipment[key][subkey] = typ(**entry)
|
||||||
equipment = update_trx_osnr(equipment)
|
equipment = update_trx_osnr(equipment)
|
||||||
|
equipment = update_dual_stage(equipment)
|
||||||
return equipment
|
return equipment
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ class ConvenienceAccess:
|
|||||||
|
|
||||||
|
|
||||||
class Power(namedtuple('Power', 'signal nonlinear_interference amplified_spontaneous_emission'), ConvenienceAccess):
|
class Power(namedtuple('Power', 'signal nonlinear_interference amplified_spontaneous_emission'), ConvenienceAccess):
|
||||||
|
"""carriers power in W"""
|
||||||
_ABBREVS = {'nli': 'nonlinear_interference',
|
_ABBREVS = {'nli': 'nonlinear_interference',
|
||||||
'ase': 'amplified_spontaneous_emission',}
|
'ase': 'amplified_spontaneous_emission',}
|
||||||
|
|
||||||
@@ -42,14 +42,18 @@ class Channel(namedtuple('Channel', 'channel_number frequency baud_rate roll_off
|
|||||||
'ffs': 'frequency',
|
'ffs': 'frequency',
|
||||||
'freq': 'frequency',}
|
'freq': 'frequency',}
|
||||||
|
|
||||||
class Pref(namedtuple('Pref', 'p_span0, p_spani'), ConvenienceAccess):
|
class Pref(namedtuple('Pref', 'p_span0, p_spani, neq_ch '), ConvenienceAccess):
|
||||||
|
"""noiseless reference power in dBm:
|
||||||
|
p0: inital target carrier power
|
||||||
|
pi: carrier power after element i
|
||||||
|
neqch: equivalent channel count in dB"""
|
||||||
|
|
||||||
_ABBREVS = {'p0' : 'p_span0',
|
_ABBREVS = {'p0' : 'p_span0',
|
||||||
'pi' : 'p_spani'}
|
'pi' : 'p_spani'}
|
||||||
|
|
||||||
class SpectralInformation(namedtuple('SpectralInformation', 'pref carriers'), ConvenienceAccess):
|
class SpectralInformation(namedtuple('SpectralInformation', 'pref carriers'), ConvenienceAccess):
|
||||||
|
|
||||||
def __new__(cls, pref=Pref(0, 0), *carriers):
|
def __new__(cls, pref, carriers):
|
||||||
return super().__new__(cls, pref, carriers)
|
return super().__new__(cls, pref, carriers)
|
||||||
|
|
||||||
def merge_input_spectral_information(*si):
|
def merge_input_spectral_information(*si):
|
||||||
@@ -60,9 +64,10 @@ def merge_input_spectral_information(*si):
|
|||||||
def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing):
|
def create_input_spectral_information(f_min, f_max, roll_off, baud_rate, power, spacing):
|
||||||
# pref in dB : convert power lin into power in dB
|
# pref in dB : convert power lin into power in dB
|
||||||
pref = lin2db(power * 1e3)
|
pref = lin2db(power * 1e3)
|
||||||
si = SpectralInformation(pref=Pref(pref, pref))
|
|
||||||
nb_channel = automatic_nch(f_min, f_max, spacing)
|
nb_channel = automatic_nch(f_min, f_max, spacing)
|
||||||
si = si.update(carriers=[
|
si = SpectralInformation(
|
||||||
|
pref=Pref(pref, pref, lin2db(nb_channel)),
|
||||||
|
carriers=[
|
||||||
Channel(f, (f_min+spacing*f),
|
Channel(f, (f_min+spacing*f),
|
||||||
baud_rate, roll_off, Power(power, 0, 0)) for f in range(1,nb_channel+1)
|
baud_rate, roll_off, Power(power, 0, 0)) for f in range(1,nb_channel+1)
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ from numpy import arange
|
|||||||
from scipy.interpolate import interp1d
|
from scipy.interpolate import interp1d
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
from os import path
|
from os import path
|
||||||
from operator import itemgetter
|
from operator import itemgetter, attrgetter
|
||||||
from gnpy.core import elements
|
from gnpy.core import elements
|
||||||
from gnpy.core.elements import Fiber, Edfa, Transceiver, Roadm, Fused
|
from gnpy.core.elements import Fiber, Edfa, Transceiver, Roadm, Fused
|
||||||
from gnpy.core.equipment import edfa_nf
|
from gnpy.core.equipment import edfa_nf
|
||||||
@@ -50,9 +50,9 @@ def network_from_json(json_data, equipment):
|
|||||||
for el_config in json_data['elements']:
|
for el_config in json_data['elements']:
|
||||||
typ = el_config.pop('type')
|
typ = el_config.pop('type')
|
||||||
variety = el_config.pop('type_variety', 'default')
|
variety = el_config.pop('type_variety', 'default')
|
||||||
if typ in equipment and variety in equipment[typ]:
|
if typ in equipment and variety in equipment[typ]:
|
||||||
extra_params = equipment[typ][variety]
|
extra_params = equipment[typ][variety]
|
||||||
el_config.setdefault('params', {}).update(extra_params._asdict())
|
el_config.setdefault('params', {}).update(extra_params.__dict__)
|
||||||
elif typ in ['Edfa', 'Fiber']: #catch it now because the code will crash later!
|
elif typ in ['Edfa', 'Fiber']: #catch it now because the code will crash later!
|
||||||
print( f'The {typ} of variety type {variety} was not recognized:'
|
print( f'The {typ} of variety type {variety} was not recognized:'
|
||||||
'\nplease check it is properly defined in the eqpt_config json file')
|
'\nplease check it is properly defined in the eqpt_config json file')
|
||||||
@@ -87,17 +87,17 @@ def network_to_json(network):
|
|||||||
data.update(connections)
|
data.update(connections)
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def select_edfa(gain_target, power_target, equipment):
|
def select_edfa(raman_allowed, gain_target, power_target, equipment, uid):
|
||||||
"""amplifer selection algorithm
|
"""amplifer selection algorithm
|
||||||
@Orange Jean-Luc Augé
|
@Orange Jean-Luc Augé
|
||||||
"""
|
"""
|
||||||
Edfa_list = namedtuple('Edfa_list', 'variety power gain nf')
|
Edfa_list = namedtuple('Edfa_list', 'raman variety power gain_min nf')
|
||||||
TARGET_EXTENDED_GAIN = 2.1
|
TARGET_EXTENDED_GAIN = equipment['Span']['default'].target_extended_gain
|
||||||
#MAX_EXTENDED_GAIN = 5
|
|
||||||
edfa_dict = equipment['Edfa']
|
edfa_dict = equipment['Edfa']
|
||||||
pin = power_target - gain_target
|
pin = power_target - gain_target
|
||||||
|
|
||||||
edfa_list = [Edfa_list(
|
edfa_list = [Edfa_list(
|
||||||
|
raman=edfa.raman,
|
||||||
variety=edfa_variety,
|
variety=edfa_variety,
|
||||||
power=min(
|
power=min(
|
||||||
pin
|
pin
|
||||||
@@ -106,76 +106,87 @@ def select_edfa(gain_target, power_target, equipment):
|
|||||||
edfa.p_max
|
edfa.p_max
|
||||||
)
|
)
|
||||||
-power_target,
|
-power_target,
|
||||||
gain=edfa.gain_flatmax-gain_target,
|
gain_min=
|
||||||
|
gain_target+3
|
||||||
|
-edfa.gain_min,
|
||||||
nf=edfa_nf(gain_target, edfa_variety, equipment)) \
|
nf=edfa_nf(gain_target, edfa_variety, equipment)) \
|
||||||
for edfa_variety, edfa in edfa_dict.items()
|
for edfa_variety, edfa in edfa_dict.items()
|
||||||
if edfa.allowed_for_design]
|
if edfa.allowed_for_design]
|
||||||
|
|
||||||
acceptable_gain_list = \
|
#filter on raman restriction
|
||||||
list(filter(lambda x : x.gain>-TARGET_EXTENDED_GAIN, edfa_list))
|
raman_filter = lambda edfa: (edfa.raman and raman_allowed) or not edfa.raman
|
||||||
if len(acceptable_gain_list) < 1:
|
edfa_list = list(filter(raman_filter, edfa_list))
|
||||||
#no amplifier satisfies the required gain, so pick the highest gain:
|
#print(f'\n{uid}, gain {gain_target}, {power_target}')
|
||||||
gain_max = max(edfa_list, key=itemgetter(2)).gain
|
#print('edfa',edfa_list)
|
||||||
#pick up all amplifiers that share this max gain:
|
|
||||||
acceptable_gain_list = \
|
#filter on min gain limitation:
|
||||||
list(filter(lambda x : x.gain-gain_max>-0.1, edfa_list))
|
#consider gain_target+3 to allow some operation below min gain
|
||||||
|
#(~counterpart to the extended gain range)
|
||||||
|
acceptable_gain_min_list = \
|
||||||
|
list(filter(lambda x : x.gain_min>0, edfa_list))
|
||||||
|
if len(acceptable_gain_min_list) < 1:
|
||||||
|
#do not take this empty list into account for the rest of the code
|
||||||
|
#but issue a warning to the user
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'WARNING: target gain in node {uid} is below all available amplifiers min gain: \
|
||||||
|
amplifier input padding will be assumed, consider increase fiber padding instead'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
edfa_list = acceptable_gain_min_list
|
||||||
|
#print('gain_min', acceptable_gain_min_list)
|
||||||
|
|
||||||
|
#filter on max power limitation:
|
||||||
acceptable_power_list = \
|
acceptable_power_list = \
|
||||||
list(filter(lambda x : x.power>=0, acceptable_gain_list))
|
list(filter(lambda x : x.power>=0, edfa_list))
|
||||||
if len(acceptable_power_list) < 1:
|
if len(acceptable_power_list) < 1:
|
||||||
#no amplifier satisfies the required power, so pick the highest power:
|
#no amplifier satisfies the required power, so pick the highest power:
|
||||||
power_max = \
|
power_max = max(edfa_list, key=attrgetter('power')).power
|
||||||
max(acceptable_gain_list, key=itemgetter(1)).power
|
|
||||||
#pick up all amplifiers that share this max gain:
|
#pick up all amplifiers that share this max gain:
|
||||||
acceptable_power_list = \
|
acceptable_power_list = \
|
||||||
list(filter(lambda x : x.power-power_max>-0.1, acceptable_gain_list))
|
list(filter(lambda x : x.power-power_max>-0.3, edfa_list))
|
||||||
|
#print('power', acceptable_power_list)
|
||||||
|
|
||||||
|
# debug:
|
||||||
|
# print(gain_target, power_target, '=>\n',acceptable_power_list)
|
||||||
|
|
||||||
# gain and power requirements are resolved,
|
# gain and power requirements are resolved,
|
||||||
# =>chose the amp with the best NF among the acceptable ones:
|
# =>chose the amp with the best NF among the acceptable ones:
|
||||||
return min(acceptable_power_list, key=itemgetter(3)).variety #filter on NF
|
selected_edfa = min(acceptable_power_list, key=attrgetter('nf')) #filter on NF
|
||||||
|
power_reduction = round(min(selected_edfa.power, 0),2)
|
||||||
|
if power_reduction < -0.5:
|
||||||
|
print(
|
||||||
|
f'\x1b[1;31;40m'\
|
||||||
|
+ f'WARNING: target gain and power in node {uid}\n \
|
||||||
|
is beyond all available amplifiers capabilities and/or extended_gain_range:\n\
|
||||||
|
a power reduction of {power_reduction} is applied\n'\
|
||||||
|
+ '\x1b[0m'
|
||||||
|
)
|
||||||
|
|
||||||
|
return selected_edfa.variety, power_reduction
|
||||||
|
|
||||||
def set_roadm_loss(network, equipment, pref_ch_db):
|
def target_power(network, node, equipment): #get_fiber_dp
|
||||||
roadms = [roadm for roadm in network if isinstance(roadm, Roadm)]
|
|
||||||
power_mode = equipment['Spans']['default'].power_mode
|
|
||||||
default_roadm_loss = equipment['Roadms']['default'].gain_mode_default_loss
|
|
||||||
pout_target = equipment['Roadms']['default'].power_mode_pout_target
|
|
||||||
roadm_loss = pref_ch_db - pout_target
|
|
||||||
|
|
||||||
for roadm in roadms:
|
|
||||||
if power_mode:
|
|
||||||
roadm.loss = roadm_loss
|
|
||||||
roadm.target_pch_out_db = pout_target
|
|
||||||
elif roadm.loss == None:
|
|
||||||
roadm.loss = default_roadm_loss
|
|
||||||
|
|
||||||
def target_power(dp_from_gain, network, node, equipment): #get_fiber_dp
|
|
||||||
SPAN_LOSS_REF = 20
|
SPAN_LOSS_REF = 20
|
||||||
POWER_SLOPE = 0.3
|
POWER_SLOPE = 0.3
|
||||||
power_mode = equipment['Spans']['default'].power_mode
|
power_mode = equipment['Span']['default'].power_mode
|
||||||
dp_range = list(equipment['Spans']['default'].delta_power_range_db)
|
dp_range = list(equipment['Span']['default'].delta_power_range_db)
|
||||||
node_loss = span_loss(network, node)
|
node_loss = span_loss(network, node)
|
||||||
|
|
||||||
dp_gain_mode = 0
|
|
||||||
try:
|
try:
|
||||||
dp_power_mode = round2float((node_loss - SPAN_LOSS_REF) * POWER_SLOPE, dp_range[2])
|
dp = round2float((node_loss - SPAN_LOSS_REF) * POWER_SLOPE, dp_range[2])
|
||||||
dp_power_mode = max(dp_range[0], dp_power_mode)
|
dp = max(dp_range[0], dp)
|
||||||
dp_power_mode = min(dp_range[1], dp_power_mode)
|
dp = min(dp_range[1], dp)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
print(f'invalid delta_power_range_db definition in eqpt_config[Spans]'
|
print(f'invalid delta_power_range_db definition in eqpt_config[Span]'
|
||||||
f'delta_power_range_db: [lower_bound, upper_bound, step]')
|
f'delta_power_range_db: [lower_bound, upper_bound, step]')
|
||||||
exit()
|
exit()
|
||||||
|
|
||||||
if dp_from_gain:
|
|
||||||
dp_power_mode = dp_from_gain
|
|
||||||
dp_gain_mode = dp_from_gain
|
|
||||||
if isinstance(node, Roadm):
|
if isinstance(node, Roadm):
|
||||||
dp_power_mode = 0
|
dp = 0
|
||||||
|
|
||||||
dp = dp_power_mode if power_mode else dp_gain_mode
|
|
||||||
#print(f'{repr(node)} delta power in:\n{dp}dB')
|
|
||||||
|
|
||||||
return dp
|
return dp
|
||||||
|
|
||||||
|
|
||||||
def prev_node_generator(network, node):
|
def prev_node_generator(network, node):
|
||||||
"""fused spans interest:
|
"""fused spans interest:
|
||||||
iterate over all predecessors while they are Fused or Fiber type"""
|
iterate over all predecessors while they are Fused or Fiber type"""
|
||||||
@@ -244,23 +255,22 @@ def find_last_node(network, node):
|
|||||||
pass
|
pass
|
||||||
return this_node
|
return this_node
|
||||||
|
|
||||||
def set_amplifier_voa(amp, pref_total_db, power_mode):
|
def set_amplifier_voa(amp, power_target, power_mode):
|
||||||
VOA_MARGIN = 0
|
VOA_MARGIN = 1 #do not maximize the VOA optimization
|
||||||
if amp.operational.out_voa is None:
|
if amp.out_voa is None:
|
||||||
if power_mode:
|
if power_mode:
|
||||||
gain_target = amp.operational.gain_target
|
gain_target = amp.effective_gain
|
||||||
pout = pref_total_db + amp.dp_db
|
voa = min(amp.params.p_max-power_target,
|
||||||
voa = min(amp.params.p_max-pout,
|
amp.params.gain_flatmax-amp.effective_gain)
|
||||||
amp.params.gain_flatmax-amp.operational.gain_target)
|
voa = max(round2float(max(voa, 0), 0.5) - VOA_MARGIN, 0) if amp.params.out_voa_auto else 0
|
||||||
voa = round2float(max(voa, 0), 0.5) - VOA_MARGIN if amp.params.out_voa_auto else 0
|
amp.delta_p = amp.delta_p + voa
|
||||||
amp.dp_db = amp.dp_db + voa
|
amp.effective_gain = amp.effective_gain + voa
|
||||||
amp.operational.gain_target = amp.operational.gain_target + voa
|
|
||||||
else:
|
else:
|
||||||
voa = 0 # no output voa optimization in gain mode
|
voa = 0 # no output voa optimization in gain mode
|
||||||
amp.operational.out_voa = voa
|
amp.out_voa = voa
|
||||||
|
|
||||||
def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
||||||
power_mode = equipment['Spans']['default'].power_mode
|
power_mode = equipment['Span']['default'].power_mode
|
||||||
next_oms = (n for n in network.successors(roadm) if not isinstance(n, Transceiver))
|
next_oms = (n for n in network.successors(roadm) if not isinstance(n, Transceiver))
|
||||||
for oms in next_oms:
|
for oms in next_oms:
|
||||||
#go through all the OMS departing from the Roadm
|
#go through all the OMS departing from the Roadm
|
||||||
@@ -271,30 +281,49 @@ def set_egress_amplifier(network, roadm, equipment, pref_total_db):
|
|||||||
# node = find_last_node(next_node)
|
# node = find_last_node(next_node)
|
||||||
# next_node = next(n for n in network.successors(node))
|
# next_node = next(n for n in network.successors(node))
|
||||||
# next_node = find_last_node(next_node)
|
# next_node = find_last_node(next_node)
|
||||||
prev_dp = 0
|
prev_dp = getattr(node.params, 'target_pch_out_db', 0)
|
||||||
dp = 0
|
dp = prev_dp
|
||||||
|
prev_voa = 0
|
||||||
|
voa = 0
|
||||||
while True:
|
while True:
|
||||||
#go through all nodes in the OMS (loop until next Roadm instance)
|
#go through all nodes in the OMS (loop until next Roadm instance)
|
||||||
if isinstance(node, Edfa):
|
if isinstance(node, Edfa):
|
||||||
node_loss = span_loss(network, prev_node)
|
node_loss = span_loss(network, prev_node)
|
||||||
dp_from_gain = prev_dp + node.operational.gain_target - node_loss \
|
if node.out_voa:
|
||||||
if node.operational.gain_target > 0 else None
|
voa = node.out_voa
|
||||||
dp = target_power(dp_from_gain, network, next_node, equipment)
|
if node.delta_p is None:
|
||||||
gain_target = node_loss + dp - prev_dp
|
dp = target_power(network, next_node, equipment)
|
||||||
|
else:
|
||||||
|
dp = node.delta_p
|
||||||
|
gain_from_dp = node_loss + dp - prev_dp + prev_voa
|
||||||
|
if node.effective_gain is None or power_mode:
|
||||||
|
gain_target = gain_from_dp
|
||||||
|
else: #gain mode with effective_gain
|
||||||
|
gain_target = node.effective_gain
|
||||||
|
dp = prev_dp - node_loss + gain_target
|
||||||
|
#print(node.delta_p, dp, gain_target)
|
||||||
|
power_target = pref_total_db + dp
|
||||||
|
|
||||||
if power_mode:
|
if node.params.type_variety == '' :
|
||||||
node.dp_db = dp
|
raman_allowed = False
|
||||||
node.operational.gain_target = gain_target
|
if isinstance(prev_node, Fiber):
|
||||||
|
max_fiber_lineic_loss_for_raman = \
|
||||||
if node.params.type_variety == '':
|
equipment['Span']['default'].max_fiber_lineic_loss_for_raman
|
||||||
power_target = pref_total_db + dp
|
raman_allowed = prev_node.params.loss_coef < max_fiber_lineic_loss_for_raman
|
||||||
edfa_variety = select_edfa(gain_target, power_target, equipment)
|
edfa_variety, power_reduction = select_edfa(raman_allowed,
|
||||||
|
gain_target, power_target, equipment, node.uid)
|
||||||
extra_params = equipment['Edfa'][edfa_variety]
|
extra_params = equipment['Edfa'][edfa_variety]
|
||||||
node.params.update_params(extra_params._asdict())
|
node.params.update_params(extra_params.__dict__)
|
||||||
set_amplifier_voa(node, pref_total_db, power_mode)
|
dp += power_reduction
|
||||||
|
gain_target += power_reduction
|
||||||
|
|
||||||
|
node.delta_p = dp if power_mode else None
|
||||||
|
node.effective_gain = gain_target
|
||||||
|
set_amplifier_voa(node, power_target, power_mode)
|
||||||
if isinstance(next_node, Roadm) or isinstance(next_node, Transceiver):
|
if isinstance(next_node, Roadm) or isinstance(next_node, Transceiver):
|
||||||
break
|
break
|
||||||
prev_dp = dp
|
prev_dp = dp
|
||||||
|
prev_voa = voa
|
||||||
prev_node = node
|
prev_node = node
|
||||||
node = next_node
|
node = next_node
|
||||||
# print(f'{node.uid}')
|
# print(f'{node.uid}')
|
||||||
@@ -319,7 +348,7 @@ def add_egress_amplifier(network, node):
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
operational = {
|
operational = {
|
||||||
'gain_target': 0,
|
'gain_target': None,
|
||||||
'tilt_target': 0,
|
'tilt_target': 0,
|
||||||
})
|
})
|
||||||
network.add_node(amp)
|
network.add_node(amp)
|
||||||
@@ -421,7 +450,7 @@ def add_fiber_padding(network, fibers, padding):
|
|||||||
first_fiber.att_in = first_fiber.att_in + padding - this_span_loss
|
first_fiber.att_in = first_fiber.att_in + padding - this_span_loss
|
||||||
|
|
||||||
def build_network(network, equipment, pref_ch_db, pref_total_db):
|
def build_network(network, equipment, pref_ch_db, pref_total_db):
|
||||||
default_span_data = equipment['Spans']['default']
|
default_span_data = equipment['Span']['default']
|
||||||
max_length = int(default_span_data.max_length * UNITS[default_span_data.length_units])
|
max_length = int(default_span_data.max_length * UNITS[default_span_data.length_units])
|
||||||
min_length = max(int(default_span_data.padding/0.2*1e3),50_000)
|
min_length = max(int(default_span_data.padding/0.2*1e3),50_000)
|
||||||
bounds = range(min_length, max_length)
|
bounds = range(min_length, max_length)
|
||||||
@@ -431,7 +460,6 @@ def build_network(network, equipment, pref_ch_db, pref_total_db):
|
|||||||
padding = default_span_data.padding
|
padding = default_span_data.padding
|
||||||
|
|
||||||
#set raodm loss for gain_mode before to build network
|
#set raodm loss for gain_mode before to build network
|
||||||
set_roadm_loss(network, equipment, pref_ch_db)
|
|
||||||
fibers = [f for f in network.nodes() if isinstance(f, Fiber)]
|
fibers = [f for f in network.nodes() if isinstance(f, Fiber)]
|
||||||
add_connector_loss(fibers, con_in, con_out, default_span_data.EOL)
|
add_connector_loss(fibers, con_in, con_out, default_span_data.EOL)
|
||||||
add_fiber_padding(network, fibers, padding)
|
add_fiber_padding(network, fibers, padding)
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ from networkx.utils import pairwise
|
|||||||
from numpy import mean
|
from numpy import mean
|
||||||
from gnpy.core.service_sheet import convert_service_sheet, Request_element, Element
|
from gnpy.core.service_sheet import convert_service_sheet, Request_element, Element
|
||||||
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fused
|
from gnpy.core.elements import Transceiver, Roadm, Edfa, Fused
|
||||||
from gnpy.core.network import set_roadm_loss
|
|
||||||
from gnpy.core.utils import db2lin, lin2db
|
from gnpy.core.utils import db2lin, lin2db
|
||||||
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power
|
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power
|
||||||
from copy import copy, deepcopy
|
from copy import copy, deepcopy
|
||||||
@@ -386,8 +385,6 @@ def compute_constrained_path(network, req):
|
|||||||
return total_path
|
return total_path
|
||||||
|
|
||||||
def propagate(path, req, equipment, show=False):
|
def propagate(path, req, equipment, show=False):
|
||||||
#update roadm loss in case of power sweep (power mode only)
|
|
||||||
set_roadm_loss(path, equipment, lin2db(req.power*1e3))
|
|
||||||
si = create_input_spectral_information(
|
si = create_input_spectral_information(
|
||||||
req.f_min, req.f_max, req.roll_off, req.baud_rate,
|
req.f_min, req.f_max, req.roll_off, req.baud_rate,
|
||||||
req.power, req.spacing)
|
req.power, req.spacing)
|
||||||
@@ -395,12 +392,10 @@ def propagate(path, req, equipment, show=False):
|
|||||||
si = el(si)
|
si = el(si)
|
||||||
if show :
|
if show :
|
||||||
print(el)
|
print(el)
|
||||||
path[-1].update_snr(req.tx_osnr, equipment['Roadms']['default'].add_drop_osnr)
|
path[-1].update_snr(req.tx_osnr, equipment['Roadm']['default'].add_drop_osnr)
|
||||||
return path
|
return path
|
||||||
|
|
||||||
def propagate2(path, req, equipment, show=False):
|
def propagate2(path, req, equipment, show=False):
|
||||||
#update roadm loss in case of power sweep (power mode only)
|
|
||||||
set_roadm_loss(path, equipment, lin2db(req.power*1e3))
|
|
||||||
si = create_input_spectral_information(
|
si = create_input_spectral_information(
|
||||||
req.f_min, req.f_max, req.roll_off, req.baud_rate,
|
req.f_min, req.f_max, req.roll_off, req.baud_rate,
|
||||||
req.power, req.spacing)
|
req.power, req.spacing)
|
||||||
@@ -411,12 +406,10 @@ def propagate2(path, req, equipment, show=False):
|
|||||||
infos[el] = before_si, after_si
|
infos[el] = before_si, after_si
|
||||||
if show :
|
if show :
|
||||||
print(el)
|
print(el)
|
||||||
path[-1].update_snr(req.tx_osnr, equipment['Roadms']['default'].add_drop_osnr)
|
path[-1].update_snr(req.tx_osnr, equipment['Roadm']['default'].add_drop_osnr)
|
||||||
return infos
|
return infos
|
||||||
|
|
||||||
def propagate_and_optimize_mode(path, req, equipment):
|
def propagate_and_optimize_mode(path, req, equipment):
|
||||||
#update roadm loss in case of power sweep (power mode only)
|
|
||||||
set_roadm_loss(path, equipment, lin2db(req.power*1e3))
|
|
||||||
# if mode is unknown : loops on the modes starting from the highest baudrate fiting in the
|
# if mode is unknown : loops on the modes starting from the highest baudrate fiting in the
|
||||||
# step 1: create an ordered list of modes based on baudrate
|
# step 1: create an ordered list of modes based on baudrate
|
||||||
baudrate_to_explore = list(set([m['baud_rate'] for m in equipment['Transceiver'][req.tsp].mode
|
baudrate_to_explore = list(set([m['baud_rate'] for m in equipment['Transceiver'][req.tsp].mode
|
||||||
@@ -442,7 +435,7 @@ def propagate_and_optimize_mode(path, req, equipment):
|
|||||||
si = el(si)
|
si = el(si)
|
||||||
for m in modes_to_explore :
|
for m in modes_to_explore :
|
||||||
if path[-1].snr is not None:
|
if path[-1].snr is not None:
|
||||||
path[-1].update_snr(m['tx_osnr'], equipment['Roadms']['default'].add_drop_osnr)
|
path[-1].update_snr(m['tx_osnr'], equipment['Roadm']['default'].add_drop_osnr)
|
||||||
if round(min(path[-1].snr+lin2db(b/(12.5e9))),2) > m['OSNR'] :
|
if round(min(path[-1].snr+lin2db(b/(12.5e9))),2) > m['OSNR'] :
|
||||||
found_a_feasible_mode = True
|
found_a_feasible_mode = True
|
||||||
return path, m
|
return path, m
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
{ "Edfa":[{
|
{ "Edfa":[{
|
||||||
"type_variety": "CienaDB_medium_gain",
|
"type_variety": "CienaDB_medium_gain",
|
||||||
|
"type_def": "advanced_model",
|
||||||
"gain_flatmax": 25,
|
"gain_flatmax": 25,
|
||||||
"gain_min": 15,
|
"gain_min": 15,
|
||||||
"p_max": 21,
|
"p_max": 21,
|
||||||
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
"advanced_config_from_json": "std_medium_gain_advanced_config.json",
|
||||||
|
"out_voa_auto": false,
|
||||||
"allowed_for_design": true
|
"allowed_for_design": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -52,7 +54,7 @@
|
|||||||
"gamma": 0.00127
|
"gamma": 0.00127
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Spans":[{
|
"Span":[{
|
||||||
"power_mode": true,
|
"power_mode": true,
|
||||||
"delta_power_range_db": [0,0,1],
|
"delta_power_range_db": [0,0,1],
|
||||||
"max_length": 150,
|
"max_length": 150,
|
||||||
@@ -64,8 +66,7 @@
|
|||||||
"con_out": 0
|
"con_out": 0
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Roadms":[{
|
"Roadm":[{
|
||||||
"gain_mode_default_loss": 20,
|
|
||||||
"power_mode_pout_target": -20,
|
"power_mode_pout_target": -20,
|
||||||
"add_drop_osnr": 100
|
"add_drop_osnr": 100
|
||||||
}],
|
}],
|
||||||
|
|||||||
@@ -469,9 +469,10 @@
|
|||||||
"type": "Edfa",
|
"type": "Edfa",
|
||||||
"type_variety": "test",
|
"type_variety": "test",
|
||||||
"operational": {
|
"operational": {
|
||||||
"gain_target": 0,
|
"gain_target": null,
|
||||||
|
"delta_p": null,
|
||||||
"tilt_target": 0,
|
"tilt_target": 0,
|
||||||
"out_voa": 0
|
"out_voa": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -487,9 +488,10 @@
|
|||||||
"type": "Edfa",
|
"type": "Edfa",
|
||||||
"type_variety": "test",
|
"type_variety": "test",
|
||||||
"operational": {
|
"operational": {
|
||||||
"gain_target": 0,
|
"gain_target": null,
|
||||||
|
"delta_p": null,
|
||||||
"tilt_target": 0,
|
"tilt_target": 0,
|
||||||
"out_voa": 0
|
"out_voa": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -505,9 +507,10 @@
|
|||||||
"type": "Edfa",
|
"type": "Edfa",
|
||||||
"type_variety": "test",
|
"type_variety": "test",
|
||||||
"operational": {
|
"operational": {
|
||||||
"gain_target": 0,
|
"gain_target": null,
|
||||||
|
"delta_p": null,
|
||||||
"tilt_target": 0,
|
"tilt_target": 0,
|
||||||
"out_voa": 0
|
"out_voa": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -523,9 +526,10 @@
|
|||||||
"type": "Edfa",
|
"type": "Edfa",
|
||||||
"type_variety": "test",
|
"type_variety": "test",
|
||||||
"operational": {
|
"operational": {
|
||||||
"gain_target": 0,
|
"gain_target": null,
|
||||||
|
"delta_p": null,
|
||||||
"tilt_target": 0,
|
"tilt_target": 0,
|
||||||
"out_voa": 0
|
"out_voa": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -577,9 +577,10 @@
|
|||||||
"type": "Edfa",
|
"type": "Edfa",
|
||||||
"type_variety": "test",
|
"type_variety": "test",
|
||||||
"operational": {
|
"operational": {
|
||||||
"gain_target": 0,
|
"gain_target": null,
|
||||||
|
"delta_p": null,
|
||||||
"tilt_target": 0,
|
"tilt_target": 0,
|
||||||
"out_voa": 0
|
"out_voa": null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -595,9 +596,10 @@
|
|||||||
"type": "Edfa",
|
"type": "Edfa",
|
||||||
"type_variety": "test",
|
"type_variety": "test",
|
||||||
"operational": {
|
"operational": {
|
||||||
"gain_target": 0,
|
"gain_target": null,
|
||||||
|
"delta_p": null,
|
||||||
"tilt_target": 0,
|
"tilt_target": 0,
|
||||||
"out_voa": 0
|
"out_voa": null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ from json import load
|
|||||||
from gnpy.core.elements import Transceiver, Fiber, Edfa
|
from gnpy.core.elements import Transceiver, Fiber, Edfa
|
||||||
from gnpy.core.utils import lin2db, db2lin
|
from gnpy.core.utils import lin2db, db2lin
|
||||||
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power, Pref
|
from gnpy.core.info import create_input_spectral_information, SpectralInformation, Channel, Power, Pref
|
||||||
from gnpy.core.equipment import load_equipment, automatic_fmax
|
from gnpy.core.equipment import load_equipment, automatic_fmax, automatic_nch
|
||||||
from gnpy.core.network import build_network, load_network, set_roadm_loss
|
from gnpy.core.network import build_network, load_network
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ def test_variable_gain_nf(gain, nf_expected, setup_edfa_variable_gain, si):
|
|||||||
pin = pin/db2lin(gain)
|
pin = pin/db2lin(gain)
|
||||||
baud_rates = array([c.baud_rate for c in si.carriers])
|
baud_rates = array([c.baud_rate for c in si.carriers])
|
||||||
edfa.operational.gain_target = gain
|
edfa.operational.gain_target = gain
|
||||||
pref = Pref(0, -gain)
|
pref = Pref(0, -gain, lin2db(len(frequencies)))
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
result = edfa.nf
|
result = edfa.nf
|
||||||
assert pytest.approx(nf_expected, abs=0.01) == result[0]
|
assert pytest.approx(nf_expected, abs=0.01) == result[0]
|
||||||
@@ -93,7 +93,7 @@ def test_fixed_gain_nf(gain, nf_expected, setup_edfa_fixed_gain, si):
|
|||||||
pin = pin/db2lin(gain)
|
pin = pin/db2lin(gain)
|
||||||
baud_rates = array([c.baud_rate for c in si.carriers])
|
baud_rates = array([c.baud_rate for c in si.carriers])
|
||||||
edfa.operational.gain_target = gain
|
edfa.operational.gain_target = gain
|
||||||
pref = Pref(0, -gain)
|
pref = Pref(0, -gain, lin2db(len(frequencies)))
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
|
|
||||||
assert pytest.approx(nf_expected, abs=0.01) == edfa.nf[0]
|
assert pytest.approx(nf_expected, abs=0.01) == edfa.nf[0]
|
||||||
@@ -118,7 +118,7 @@ def test_compare_nf_models(gain, setup_edfa_variable_gain, si):
|
|||||||
pin = pin/db2lin(gain)
|
pin = pin/db2lin(gain)
|
||||||
baud_rates = array([c.baud_rate for c in si.carriers])
|
baud_rates = array([c.baud_rate for c in si.carriers])
|
||||||
edfa.operational.gain_target = gain
|
edfa.operational.gain_target = gain
|
||||||
pref = Pref(0, -gain)
|
pref = Pref(0, -gain, lin2db(len(frequencies)))
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
nf_model = edfa.nf[0]
|
nf_model = edfa.nf[0]
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
@@ -137,7 +137,7 @@ def test_ase_noise(gain, si, setup_edfa_variable_gain, setup_trx, bw):
|
|||||||
pin = array([c.power.signal+c.power.nli+c.power.ase for c in si.carriers])
|
pin = array([c.power.signal+c.power.nli+c.power.ase for c in si.carriers])
|
||||||
baud_rates = array([c.baud_rate for c in si.carriers])
|
baud_rates = array([c.baud_rate for c in si.carriers])
|
||||||
edfa.operational.gain_target = gain
|
edfa.operational.gain_target = gain
|
||||||
pref = Pref(0, 0)
|
pref = Pref(0, 0, lin2db(len(frequencies)))
|
||||||
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
edfa.interpol_params(frequencies, pin, baud_rates, pref)
|
||||||
nf = edfa.nf
|
nf = edfa.nf
|
||||||
pin = lin2db(pin[0]*1e3)
|
pin = lin2db(pin[0]*1e3)
|
||||||
|
|||||||
@@ -47,12 +47,8 @@ def propagation(input_power, con_in, con_out,dest):
|
|||||||
|
|
||||||
p = input_power
|
p = input_power
|
||||||
p = db2lin(p) * 1e-3
|
p = db2lin(p) * 1e-3
|
||||||
spacing = 0.05 # THz
|
spacing = 50e9 # THz
|
||||||
si = SpectralInformation() # SI units: W, Hz
|
si = create_input_spectral_information(191.3e12, 191.3e12+79*spacing, 0.15, 32e9, p, spacing)
|
||||||
si = si.update(carriers=[
|
|
||||||
Channel(f, (191.3 + spacing * f) * 1e12, 32e9, 0.15, Power(p, 0, 0))
|
|
||||||
for f in range(1,80)
|
|
||||||
])
|
|
||||||
source = next(transceivers[uid] for uid in transceivers if uid == 'trx A')
|
source = next(transceivers[uid] for uid in transceivers if uid == 'trx A')
|
||||||
sink = next(transceivers[uid] for uid in transceivers if uid == dest)
|
sink = next(transceivers[uid] for uid in transceivers if uid == dest)
|
||||||
path = dijkstra_path(network, source, sink)
|
path = dijkstra_path(network, source, sink)
|
||||||
|
|||||||
Reference in New Issue
Block a user