001/******************************************************************************* 002 * Copyright (c) 2016 Pablo Pavon Mariņo. 003 * All rights reserved. This program and the accompanying materials 004 * are made available under the terms of the GNU Lesser Public License v2.1 005 * which accompanies this distribution, and is available at 006 * http://www.gnu.org/licenses/lgpl.html 007 ******************************************************************************/ 008 009 010 011 012 013 014 015 016 017 018package com.net2plan.examples.general.reports; 019 020import java.text.DecimalFormat; 021import java.util.Iterator; 022import java.util.LinkedHashMap; 023import java.util.LinkedList; 024import java.util.List; 025import java.util.Map; 026 027import com.net2plan.interfaces.networkDesign.IReport; 028import com.net2plan.interfaces.networkDesign.Link; 029import com.net2plan.interfaces.networkDesign.Net2PlanException; 030import com.net2plan.interfaces.networkDesign.NetPlan; 031import com.net2plan.interfaces.networkDesign.Route; 032import com.net2plan.utils.Constants.OrderingType; 033import com.net2plan.utils.DoubleUtils; 034import com.net2plan.utils.Pair; 035import com.net2plan.utils.StringUtils; 036import com.net2plan.utils.Triple; 037 038/** 039 * <p> 040 * This report shows line engineering information for WDM links in a multilayer 041 * optical network. The impairment calculations are inspired in the procedures 042 * described in the 2009 ITU-T WDM manual "Optical fibres, cabbles and 043 * systems".</p> 044 * 045 * <p> 046 * The report assumes that the WDM network follows the scheme:</p> 047 * <ul> 048 * <li>In the net2plan object, nodes are OADMs, links are fiber links, and 049 * routes are lightpaths: WDM channels optically switched at intermediate nodes. 050 * </li> 051 * <li>Nodes are connected by unidirectional fiber links. Fiber link distance is 052 * given by the link length. Other specifications are given by fiber_XXX input 053 * parameters. The fiber can be split into spans if optical amplifers (EDFAs) 054 * and/or dispersion compensating modules (DCMs) are placed along the 055 * fiber.</li> 056 * <li>Optical line amplifiers (EDFAs) can be located in none, one or more 057 * positions in the fiber link, separating them in different spans. EDFAs are 058 * supposed to operate in the automatic gain control mode. Thus, the gain is the 059 * same, whatever the number of input WDM channels. EDFA positions (as distance 060 * in km from the link start to the EDFA location) and EDFA gains (assumed in 061 * dB) are read from the "edfaPositions_km" and "edfaGains_dB" attributes of the 062 * links. The format of both attributes are the same: a string of numbers 063 * separated by spaces. The <i>i</i>-th number corresponding to the 064 * position/gain of the 065 * <i>i</i>-th EDFA. If the attributes do not exist, it is assumed that no EDFAs 066 * are placed in this link. EDFA specifications are given by "edfa_XXX" 067 * parameters</li> 068 * <li>Dispersion compensating modules (DCMs) can be located in none, one or 069 * more positions in the fiber link, separating them in different spans. If a 070 * DCM and a EDFA have the same location, it is assumed that the DCM is placed 071 * first, to reduce the non-linear effects. DCM positions (as distance in km 072 * from the link start to the DCM location) are read from the "dcmPositions_km" 073 * attribute of the link, and the same format as with "edfaPositions_km" 074 * attribute is expected. If the attribute does not exist, it is assumed that no 075 * DCMs are placed in this link. DCM specifications are given by "dcm_XXX" 076 * parameters</li> 077 * <li>Fiber links start and end in OADM modules, that permit adding, dropping 078 * and optically switch individual WDM channels. OADMs have a pre-amplifier 079 * (traversed by drop and express channels) and a boost amplifier (traversed by 080 * add and express channels). They are supposed to equalize the channel power at 081 * their outputs, to a fixed value (added and express channels will thus have 082 * the same power in the fibers). Also, OADMs attenuate appropriately the 083 * optical signal coming from the pre-amplifier, in the drop channels, so that 084 * they fall within the receiver sensitivity range. OADM noise figures for add, 085 * drop and express channels are given as input parameters. PMD values for add, 086 * drop and express channels are computed assumming that: (i) add channel 087 * traverse a multiplexer and the booster, (ii) drop channels travese the 088 * pre-amplifier and a demultiplexer, (iii) express channels traverse the two 089 * amplifiers. The required parameters are provided in oadm_XXX parameters. 090 * </li> 091 * <li>Each channel ends in a receiver, with specifications given by "tp_XXX" 092 * parameters.</li> 093 * </ul> 094 * 095 * <p> 096 * The basic checks performed are:</p> 097 * <ul> 098 * <li>For each link, signal power levels are within operating ranges at the 099 * oadm/edfas/dcms, both when the link has one single active channel, or when 100 * all the "channels_maxNumChannels" are active</li> 101 * <li>For each link, chromatic dispersion is within the limits set per 102 * link</li> 103 * <li>For each route (lightpath), chromatic dispersion is within the limits of 104 * the receiver.</li> 105 * <li>For each route (lightpath), OSNR (Optical Signal to Noise Ration) is 106 * within the operating range at the receiver. A set of margins are considered 107 * to account to several not directly considered impairments. </li> 108 * <li>For each route (lightpath), PMD (Polarization mode dispersion) is within 109 * the operating range at the receiver</li> 110 * </ul> 111 * @net2plan.keywords WDM, Multilayer 112 * @author Pablo Pavon-Marino, Jose-Luis Izquierdo-Zaragoza 113 * @version 1.1, May 2015 114 */ 115public class Report_WDM_lineEngineering implements IReport 116{ 117 /* Constants */ 118 private final static double constant_c = 299792458; /* speed of light in m/s */ 119 private final static double constant_h = 6.626E-34; /* Plank constant m^2 kg/sec */ 120 121 /* Input parameters */ 122 private NetPlan netPlan; 123 private Map<String, String> reportParameters; 124 125 /* Usable wavelengths */ 126 private double channels_minChannelLambda_nm; 127 private double channels_channelSpacing_GHz; 128 private int channels_maxNumChannels; 129 private double channels_maxChannelLambda_nm; 130 131 /* Fiber specifications */ 132 private double fiber_attenuation_dB_per_km; 133 private double fiber_worseChromaticDispersion_ps_per_nm_per_km; 134 private double fiber_PMD_ps_per_sqroot_km; 135 136 /* Transponder specifications */ 137 private double tp_maxChromaticDispersionTolerance_ps_per_nm; 138 private double tp_minOSNR_dB; 139 private double tp_minWavelength_nm; 140 private double tp_maxWavelength_nm; 141 private double tp_pmdTolerance_ps; 142 private double tp_inputPowerSensitivityMin_dBm; 143 private double tp_inputPowerSensitivityMax_dBm; 144 145 /* OADM specs */ 146 private double oadm_perChannelOutputPower_dBm; 147 private double oadm_perChannelMinInputPower_dBm; 148 private double oadm_perChannelMaxInputPower_dBm; 149 private double oadm_muxDemuxPMD_ps; 150 private double oadm_preAmplifierPMD_ps; 151 private double oadm_boosterPMD_ps; 152 private double oadm_addChannelNoiseFactor_dB; 153 private double oadm_dropChannelNoiseFactor_dB; 154 private double oadm_expressChannelNoiseFactor_dB; 155 private double oadm_noiseFactorReferenceBandwidth_nm; 156 private double oadm_maxAbsoluteChromaticDispersionAtInput_ps_per_nm; 157 158 /* Optical line amplifier specifications */ 159 private double edfa_minWavelength_nm; 160 private double edfa_maxWavelength_nm; 161 private double edfa_minInputPower_dBm; 162 private double edfa_maxInputPower_dBm; 163 private double edfa_minOutputPower_dBm; 164 private double edfa_maxOutputPower_dBm; 165 private double edfa_minGain_dB; 166 private double edfa_maxGain_dB; 167 private double edfa_PMD_ps; 168 private double edfa_noiseFactorMaximumGain_dB; 169 private double edfa_noiseFactorMinimumGain_dB; 170 private double edfa_noiseFactorReferenceBandwidth_nm; 171 172 /* Dispersion compensation modules specifications */ 173 private double dcm_channelDispersionMax_ps_per_nm; 174 private double dcm_channelDispersionMin_ps_per_nm; 175 private double dcm_PMD_ps; 176 private double dcm_insertionLoss_dB; 177 178 /* OSNR penalties */ 179 private double osnrPenalty_CD_dB; 180 private double osnrPenalty_nonLinear_dB; 181 private double osnrPenalty_PMD_dB; 182 private double osnrPenalty_PDL_dB; 183 private double osnrPenalty_transmitterChirp_dB; 184 private double osnrPenalty_OADMCrosstalk_dB; 185 private double osnrPenalty_unassignedMargin_dB; 186 private double osnrPenalty_SUM_dB; 187 188 @Override 189 public String executeReport(NetPlan netPlan, Map<String, String> reportParameters, Map<String, String> net2planParameters) 190 { 191 /* Input parameters */ 192 this.netPlan = netPlan; 193 this.reportParameters = reportParameters; 194 195 /* Usable wavelengths */ 196 channels_minChannelLambda_nm = Double.parseDouble(reportParameters.get("channels_minChannelLambda_nm")); 197 channels_channelSpacing_GHz = Double.parseDouble(reportParameters.get("channels_channelSpacing_GHz")); 198 channels_maxNumChannels = Integer.parseInt(reportParameters.get("channels_maxNumChannels")); 199 channels_maxChannelLambda_nm = constant_c / ((constant_c / channels_minChannelLambda_nm) - (channels_maxNumChannels - 1) * channels_channelSpacing_GHz); 200 201 /* Fiber specifications */ 202 fiber_attenuation_dB_per_km = Double.parseDouble(reportParameters.get("fiber_attenuation_dB_per_km")); 203 fiber_worseChromaticDispersion_ps_per_nm_per_km = Double.parseDouble(reportParameters.get("fiber_worseChromaticDispersion_ps_per_nm_per_km")); 204 fiber_PMD_ps_per_sqroot_km = Double.parseDouble(reportParameters.get("fiber_PMD_ps_per_sqroot_km")); 205 206 /* Transponder specifications */ 207 tp_maxChromaticDispersionTolerance_ps_per_nm = Double.parseDouble(reportParameters.get("tp_maxChromaticDispersionTolerance_ps_per_nm")); 208 tp_minOSNR_dB = Double.parseDouble(reportParameters.get("tp_minOSNR_dB")); 209 tp_minWavelength_nm = Double.parseDouble(reportParameters.get("tp_minWavelength_nm")); 210 tp_maxWavelength_nm = Double.parseDouble(reportParameters.get("tp_maxWavelength_nm")); 211 tp_pmdTolerance_ps = Double.parseDouble(reportParameters.get("tp_pmdTolerance_ps")); 212 tp_inputPowerSensitivityMin_dBm = Double.parseDouble(reportParameters.get("tp_inputPowerSensitivityMin_dBm")); 213 tp_inputPowerSensitivityMax_dBm = Double.parseDouble(reportParameters.get("tp_inputPowerSensitivityMax_dBm")); 214 215 /* OADM specs */ 216 oadm_perChannelOutputPower_dBm = Double.parseDouble(reportParameters.get("oadm_perChannelOutputPower_dBm")); 217 oadm_perChannelMinInputPower_dBm = Double.parseDouble(reportParameters.get("oadm_perChannelMinInputPower_dBm")); 218 oadm_perChannelMaxInputPower_dBm = Double.parseDouble(reportParameters.get("oadm_perChannelMaxInputPower_dBm")); 219 oadm_muxDemuxPMD_ps = Double.parseDouble(reportParameters.get("oadm_muxDemuxPMD_ps")); 220 oadm_preAmplifierPMD_ps = Double.parseDouble(reportParameters.get("oadm_preAmplifierPMD_ps")); 221 oadm_boosterPMD_ps = Double.parseDouble(reportParameters.get("oadm_boosterPMD_ps")); 222 oadm_addChannelNoiseFactor_dB = Double.parseDouble(reportParameters.get("oadm_addChannelNoiseFactor_dB")); 223 oadm_dropChannelNoiseFactor_dB = Double.parseDouble(reportParameters.get("oadm_dropChannelNoiseFactor_dB")); 224 oadm_expressChannelNoiseFactor_dB = Double.parseDouble(reportParameters.get("oadm_expressChannelNoiseFactor_dB")); 225 oadm_noiseFactorReferenceBandwidth_nm = Double.parseDouble(reportParameters.get("oadm_noiseFactorReferenceBandwidth_nm")); 226 oadm_maxAbsoluteChromaticDispersionAtInput_ps_per_nm = Double.parseDouble(reportParameters.get("oadm_maxAbsoluteChromaticDispersionAtInput_ps_per_nm")); 227 228 /* Optical line amplifier specifications */ 229 edfa_minWavelength_nm = Double.parseDouble(reportParameters.get("edfa_minWavelength_nm")); 230 edfa_maxWavelength_nm = Double.parseDouble(reportParameters.get("edfa_maxWavelength_nm")); 231 edfa_minInputPower_dBm = Double.parseDouble(reportParameters.get("edfa_minInputPower_dBm")); 232 edfa_maxInputPower_dBm = Double.parseDouble(reportParameters.get("edfa_maxInputPower_dBm")); 233 edfa_minOutputPower_dBm = Double.parseDouble(reportParameters.get("edfa_minOutputPower_dBm")); 234 edfa_maxOutputPower_dBm = Double.parseDouble(reportParameters.get("edfa_maxOutputPower_dBm")); 235 edfa_minGain_dB = Double.parseDouble(reportParameters.get("edfa_minGain_dB")); 236 edfa_maxGain_dB = Double.parseDouble(reportParameters.get("edfa_maxGain_dB")); 237 edfa_PMD_ps = Double.parseDouble(reportParameters.get("edfa_PMD_ps")); 238 edfa_noiseFactorMaximumGain_dB = Double.parseDouble(reportParameters.get("edfa_noiseFactorMaximumGain_dB")); 239 edfa_noiseFactorMinimumGain_dB = Double.parseDouble(reportParameters.get("edfa_noiseFactorMinimumGain_dB")); 240 edfa_noiseFactorReferenceBandwidth_nm = Double.parseDouble(reportParameters.get("edfa_noiseFactorReferenceBandwidth_nm")); 241 242 /* Dispersion compensation modules specifications */ 243 dcm_channelDispersionMax_ps_per_nm = Double.parseDouble(reportParameters.get("dcm_channelDispersionMax_ps_per_nm")); 244 dcm_channelDispersionMin_ps_per_nm = Double.parseDouble(reportParameters.get("dcm_channelDispersionMin_ps_per_nm")); 245 dcm_PMD_ps = Double.parseDouble(reportParameters.get("dcm_PMD_ps")); 246 dcm_insertionLoss_dB = Double.parseDouble(reportParameters.get("dcm_insertionLoss_dB")); 247 248 /* OSNR penalties */ 249 osnrPenalty_CD_dB = Double.parseDouble(reportParameters.get("osnrPenalty_CD_dB")); 250 osnrPenalty_nonLinear_dB = Double.parseDouble(reportParameters.get("osnrPenalty_nonLinear_dB")); 251 osnrPenalty_PMD_dB = Double.parseDouble(reportParameters.get("osnrPenalty_PMD_dB")); 252 osnrPenalty_PDL_dB = Double.parseDouble(reportParameters.get("osnrPenalty_PDL_dB")); 253 osnrPenalty_transmitterChirp_dB = Double.parseDouble(reportParameters.get("osnrPenalty_transmitterChirp_dB")); 254 osnrPenalty_OADMCrosstalk_dB = Double.parseDouble(reportParameters.get("osnrPenalty_OADMCrosstalk_dB")); 255 osnrPenalty_unassignedMargin_dB = Double.parseDouble(reportParameters.get("osnrPenalty_unassignedMargin_dB")); 256 osnrPenalty_SUM_dB = osnrPenalty_CD_dB + osnrPenalty_nonLinear_dB + osnrPenalty_PMD_dB + osnrPenalty_PDL_dB + osnrPenalty_transmitterChirp_dB + osnrPenalty_OADMCrosstalk_dB + osnrPenalty_unassignedMargin_dB; 257 258 Map<Link, LinkedList<Triple<Double, String, Double>>> elements_e = new LinkedHashMap<Link, LinkedList<Triple<Double, String, Double>>>(); 259 Map<Link, LinkedList<Pair<double[], double[]>>> impairments_e = new LinkedHashMap<Link, LinkedList<Pair<double[], double[]>>>(); 260 Map<Link, LinkedList<String>> warnings_e = new LinkedHashMap<Link, LinkedList<String>>(); 261 262 for (Link link : netPlan.getLinks()) 263 { 264 final List<Link> seqLinks = new LinkedList<Link>(); seqLinks.add (link); 265 final LinkedList<Triple<Double, String, Double>> elementPositions = getElementPositionsList(seqLinks); 266 final LinkedList<Pair<double[], double[]>> impairmentsAtInputAndOutputs = computeImpairments(elementPositions); 267 final LinkedList<String> warningMessages = computeWarningMessages(elementPositions, impairmentsAtInputAndOutputs); 268 269 elements_e.put(link, elementPositions); 270 impairments_e.put(link, impairmentsAtInputAndOutputs); 271 warnings_e.put(link, warningMessages); 272 } 273 274 Map<Route, LinkedList<Triple<Double, String, Double>>> elements_r = new LinkedHashMap<Route, LinkedList<Triple<Double, String, Double>>>(); 275 Map<Route, LinkedList<Pair<double[], double[]>>> impairments_r = new LinkedHashMap<Route, LinkedList<Pair<double[], double[]>>>(); 276 Map<Route, LinkedList<String>> warnings_r = new LinkedHashMap<Route, LinkedList<String>>(); 277 for (Route r : netPlan.getRoutes()) 278 { 279 final List<Link> seqLinks = r.getSeqLinksRealPath(); 280 final LinkedList<Triple<Double, String, Double>> elementPositions = getElementPositionsList(seqLinks); 281 final LinkedList<Pair<double[], double[]>> impairmentsAtInputAndOutputs = computeImpairments(elementPositions); 282 final LinkedList<String> warningMessages = computeWarningMessages(elementPositions, impairmentsAtInputAndOutputs); 283 284 elements_r.put(r, elementPositions); 285 impairments_r.put(r, impairmentsAtInputAndOutputs); 286 warnings_r.put(r, warningMessages); 287 } 288 289 return printReport(elements_e, impairments_e, warnings_e, elements_r, impairments_r, warnings_r); 290 } 291 292 @Override 293 public String getDescription() 294 { 295 return "This report shows line engineering information for WDM links in the network. Further description in the HTML generated."; 296 } 297 298 @Override 299 public List<Triple<String, String, String>> getParameters() 300 { 301 List<Triple<String, String, String>> parameters = new LinkedList<Triple<String, String, String>>(); 302 303 /* Usable wavelengths */ 304 parameters.add(Triple.of("channels_minChannelLambda_nm", "1530.33", "Channel minimum wavelength in nm")); 305 parameters.add(Triple.of("channels_channelSpacing_GHz", "100", "Channel spacing in GHz")); 306 parameters.add(Triple.of("channels_maxNumChannels", "16", "Maximum number of WDM channels that will be used")); 307 308 /* Fiber specifications */ 309 parameters.add(Triple.of("fiber_attenuation_dB_per_km", "0.25", "Fiber attenuation in dB/km")); 310 parameters.add(Triple.of("fiber_worseChromaticDispersion_ps_per_nm_per_km", "6", "Chromatic dispersion of the fiber in ps/nm/km")); 311 parameters.add(Triple.of("fiber_PMD_ps_per_sqroot_km", "0.4", "Polarization mode dispersion per km^0.5 of fiber (PMD_Q link factor)")); 312 313 /* Transponder specifications */ 314 parameters.add(Triple.of("tp_maxChromaticDispersionTolerance_ps_per_nm", "800", "Maximum chromatic dispersion tolerance in ps/nm at the receiver")); 315 parameters.add(Triple.of("tp_minOSNR_dB", "7", "Minimum OSNR needed at the receiver")); 316 parameters.add(Triple.of("tp_inputPowerSensitivityMin_dBm", "-20", "Minimum input power at the receiver in dBm")); 317 parameters.add(Triple.of("tp_inputPowerSensitivityMax_dBm", "-8", "Maximum input power at the receiver in dBm")); 318 parameters.add(Triple.of("tp_minWavelength_nm", "1529.55", "Minimum wavelength usable by the transponder")); 319 parameters.add(Triple.of("tp_maxWavelength_nm", "1561.84", "Maximum wavelength usable by the transponder")); 320 parameters.add(Triple.of("tp_pmdTolerance_ps", "10", "Maximum tolarance of polarizarion mode dispersion (mean of differential group delay) in ps at the receiver")); 321 322 /* Optical amplifier specifications */ 323 parameters.add(Triple.of("edfa_minWavelength_nm", "1530", "Minimum wavelength usable by the EDFA")); 324 parameters.add(Triple.of("edfa_maxWavelength_nm", "1563", "Maximum wavelength usable by the EDFA")); 325 parameters.add(Triple.of("edfa_minInputPower_dBm", "-29", "Minimum input power at the EDFA")); 326 parameters.add(Triple.of("edfa_maxInputPower_dBm", "2", "Maximum input power at the EDFA")); 327 parameters.add(Triple.of("edfa_minOutputPower_dBm", "-6", "Minimum output power at the EDFA")); 328 parameters.add(Triple.of("edfa_maxOutputPower_dBm", "19", "Maximum output power at the EDFA")); 329 parameters.add(Triple.of("edfa_minGain_dB", "17", "Minimum gain at the EDFA")); 330 parameters.add(Triple.of("edfa_maxGain_dB", "23", "Maximum gain at the EDFA")); 331 parameters.add(Triple.of("edfa_PMD_ps", "0.5", "Polarization mode dispersion in ps added by the EDFA")); 332 parameters.add(Triple.of("edfa_noiseFactorMaximumGain_dB", "5", "Noise factor at the EDFA when the gain is in its upper limit (linear interpolation is used to estimate the noise figura at other gains)")); 333 parameters.add(Triple.of("edfa_noiseFactorMinimumGain_dB", "5", "Noise factor at the EDFA when the gain is in its lower limit (linear interpolation is used to estimate the noise figura at other gains)")); 334 parameters.add(Triple.of("edfa_noiseFactorReferenceBandwidth_nm", "0.5", "Reference bandwidth that measures the noise factor at the EDFA")); 335 336 /* OADM specs */ 337 parameters.add(Triple.of("oadm_perChannelOutputPower_dBm", "6", "Output power per channel at the OADM in dBm")); 338 parameters.add(Triple.of("oadm_perChannelMinInputPower_dBm", "-19", "Minimum power needed at the OADM input")); 339 parameters.add(Triple.of("oadm_perChannelMaxInputPower_dBm", "1000", "Maximum power admitted at the OADM input")); 340 parameters.add(Triple.of("oadm_maxAbsoluteChromaticDispersionAtInput_ps_per_nm", "150", "Maximum chromatic dispersion tolerance in ps/nm at te end of each link (absolute value)")); 341 parameters.add(Triple.of("oadm_muxDemuxPMD_ps", "0.5", "PMD of the mux/demux inside the OADMs. Does not affect express lightpaths")); 342 parameters.add(Triple.of("oadm_preAmplifierPMD_ps", "0.5", "PMD off OADM preamplifier")); 343 parameters.add(Triple.of("oadm_boosterPMD_ps", "0.5", "PMD off OADM booster amplifier")); 344 parameters.add(Triple.of("oadm_addChannelNoiseFactor_dB", "6", "Noise factor observed by add channels")); 345 parameters.add(Triple.of("oadm_dropChannelNoiseFactor_dB", "6", "Noise factor observed by drop channels")); 346 parameters.add(Triple.of("oadm_expressChannelNoiseFactor_dB", "10", "Noise factor observed by express channels")); 347 parameters.add(Triple.of("oadm_noiseFactorReferenceBandwidth_nm", "0.5", "Reference bandwidth that measures the noise factor at the OADM amplifiers")); 348 349 /* Dispersion compensation modules specifications */ 350 parameters.add(Triple.of("dcm_channelDispersionMax_ps_per_nm", "-827", "Max (in absolute value) dispersion compensation a DCM can place (ps/nm). It is assumed to be the same for all wavelengths")); 351 parameters.add(Triple.of("dcm_channelDispersionMin_ps_per_nm", "-276", "Min (in absolute value) dispersion compensation a DCM can place (ps/nm). It is assumed to be the same for all wavelengths")); 352 parameters.add(Triple.of("dcm_PMD_ps", "0.7", "Polarization mode dispersion in ps added by the DCM")); 353 parameters.add(Triple.of("dcm_insertionLoss_dB", "3.5", "Maximum insertion loss added by the DCM")); 354 355 /* OSNR penalties */ 356 parameters.add(Triple.of("osnrPenalty_CD_dB", "1", "OSNR penalty caused by residual chromatic dispersion (assumed within limits)")); 357 parameters.add(Triple.of("osnrPenalty_nonLinear_dB", "2", "OSNR penalty caused by the non-linear effects SPM, XPM, FWM and Brillouin / Raman scattering")); 358 parameters.add(Triple.of("osnrPenalty_PMD_dB", "0.5", "OSNR penalty caused by the polarization mode dispersion (assumed within limits)")); 359 parameters.add(Triple.of("osnrPenalty_PDL_dB", "0.3", "OSNR penalty caused by polarization dispersion losses")); 360 parameters.add(Triple.of("osnrPenalty_transmitterChirp_dB", "0.5", "OSNR penalty caused by transmitter chirp ")); 361 parameters.add(Triple.of("osnrPenalty_OADMCrosstalk_dB", "0.8", "OSNR penalty caused by the crosstalk at the OADMs")); 362 parameters.add(Triple.of("osnrPenalty_unassignedMargin_dB", "3", "OSNR penalty caused by not assigned margins (e.g. random effects, aging, ...)")); 363 364 return parameters; 365 } 366 367 @Override 368 public String getTitle() 369 { 370 return "WDM line engineering"; 371 } 372 373 private LinkedList<Pair<double[], double[]>> computeImpairments(LinkedList<Triple<Double, String, Double>> elementPositions) 374 { 375 LinkedList<Pair<double[], double[]>> res = new LinkedList<Pair<double[], double[]>>(); 376 377 /* In the transmitter */ 378 double current_powerPerChannel_dBm = oadm_perChannelOutputPower_dBm; 379 double current_CD_ps_per_nm = 0; 380 double current_PMDSquared_ps2 = 0; 381 double current_OSNR_linear = Double.MAX_VALUE; /* no noise */ 382 383 if (!elementPositions.getFirst().getSecond().equalsIgnoreCase("OADM-ADD")) throw new RuntimeException("The route should start in a OADM-ADD element"); 384 if (!elementPositions.getLast().getSecond().equalsIgnoreCase("OADM-DROP")) throw new RuntimeException("The route should end in a OADM-DROP element"); 385 386 for (Triple<Double, String, Double> element : elementPositions) 387 { 388 final String name = element.getSecond(); 389 final double elementData = element.getThird(); 390 391 double[] prevState = DoubleUtils.arrayOf(current_powerPerChannel_dBm, current_CD_ps_per_nm, current_PMDSquared_ps2, current_OSNR_linear); 392 if (name.equalsIgnoreCase("OADM-ADD")) 393 { 394 current_OSNR_linear = updateOSNRAfterEDFA(Double.MAX_VALUE, oadm_addChannelNoiseFactor_dB, oadm_noiseFactorReferenceBandwidth_nm, current_powerPerChannel_dBm); 395 current_powerPerChannel_dBm = oadm_perChannelOutputPower_dBm; 396 current_CD_ps_per_nm = 0; 397 current_PMDSquared_ps2 = Math.pow(oadm_muxDemuxPMD_ps, 2) + Math.pow(oadm_boosterPMD_ps, 2); 398 399 } 400 else if (name.equalsIgnoreCase("OADM-EXPRESS")) 401 { 402 current_OSNR_linear = updateOSNRAfterEDFA(current_OSNR_linear, oadm_expressChannelNoiseFactor_dB, oadm_noiseFactorReferenceBandwidth_nm, current_powerPerChannel_dBm); 403 current_powerPerChannel_dBm = oadm_perChannelOutputPower_dBm; 404 current_PMDSquared_ps2 += Math.pow(oadm_preAmplifierPMD_ps, 2) + Math.pow(oadm_boosterPMD_ps, 2); 405 } 406 else if (name.equalsIgnoreCase("OADM-DROP")) 407 { 408 current_OSNR_linear = updateOSNRAfterEDFA(current_OSNR_linear, oadm_dropChannelNoiseFactor_dB, oadm_noiseFactorReferenceBandwidth_nm, current_powerPerChannel_dBm); 409 current_powerPerChannel_dBm = (tp_inputPowerSensitivityMin_dBm + tp_inputPowerSensitivityMax_dBm) / 2; 410 current_PMDSquared_ps2 += Math.pow(oadm_preAmplifierPMD_ps, 2); 411 } 412 else if (name.equalsIgnoreCase("SPAN")) 413 { 414 final double spanLength_km = elementData; 415 current_powerPerChannel_dBm -= fiber_attenuation_dB_per_km * spanLength_km; 416 current_CD_ps_per_nm += fiber_worseChromaticDispersion_ps_per_nm_per_km * spanLength_km; 417 current_PMDSquared_ps2 += spanLength_km * Math.pow(fiber_PMD_ps_per_sqroot_km, 2); 418 } 419 else if (name.equalsIgnoreCase("EDFA")) 420 { 421 final double edfaGain_dB = elementData; 422 final double edfa_noiseFactorThisGain_dB = edfa_noiseFactorMinimumGain_dB + (edfaGain_dB - edfa_minGain_dB) * (edfa_noiseFactorMaximumGain_dB - edfa_noiseFactorMinimumGain_dB) / (edfa_maxGain_dB - edfa_minGain_dB); 423 if ((edfa_noiseFactorThisGain_dB < Math.min(edfa_noiseFactorMinimumGain_dB, edfa_noiseFactorMaximumGain_dB)) || (edfa_noiseFactorThisGain_dB > Math.max(edfa_noiseFactorMinimumGain_dB, edfa_noiseFactorMaximumGain_dB))) 424 throw new RuntimeException("Bad"); 425 426 current_OSNR_linear = updateOSNRAfterEDFA(current_OSNR_linear, edfa_noiseFactorThisGain_dB, edfa_noiseFactorReferenceBandwidth_nm, current_powerPerChannel_dBm); 427 current_powerPerChannel_dBm += edfaGain_dB; 428 current_PMDSquared_ps2 += Math.pow(edfa_PMD_ps, 2); 429 } 430 else if (name.equalsIgnoreCase("DCM")) 431 { 432 final double cdCompensated_ps_per_nm = elementData; 433 current_powerPerChannel_dBm -= dcm_insertionLoss_dB; 434 current_CD_ps_per_nm += cdCompensated_ps_per_nm; 435 current_PMDSquared_ps2 += Math.pow(dcm_PMD_ps, 2); 436 } 437 else 438 { 439 throw new RuntimeException("Unknown element type"); 440 } 441 442 double[] postState = DoubleUtils.arrayOf(current_powerPerChannel_dBm, current_CD_ps_per_nm, current_PMDSquared_ps2, current_OSNR_linear); 443 res.add(Pair.of(prevState, postState)); 444 } 445 return res; 446 } 447 448 private LinkedList<String> computeWarningMessages(LinkedList<Triple<Double, String, Double>> elementPositions, LinkedList<Pair<double[], double[]>> impairmentsAtInputAndOutputs) 449 { 450 final double numChannels_dB = linear2dB((double) channels_maxNumChannels); 451 LinkedList<String> res = new LinkedList<String>(); 452 453 Iterator<Triple<Double, String, Double>> it_elementPositions = elementPositions.iterator(); 454 Iterator<Pair<double[], double[]>> it_impairments = impairmentsAtInputAndOutputs.iterator(); 455 456 int numberOfExpressOADMs = 0; 457 while (it_elementPositions.hasNext()) 458 { 459 String st = ""; 460 461 final Triple<Double, String, Double> thisElement = it_elementPositions.next(); 462 final Pair<double[], double[]> thisImpairments = it_impairments.next(); 463 464 final double initialPosition_km = thisElement.getFirst(); 465 final String name = thisElement.getSecond(); 466 final double elementData = thisElement.getThird(); 467 468 final double[] prevImp = thisImpairments.getFirst(); 469 final double[] postImp = thisImpairments.getSecond(); 470 471 final double pre_powerPerChannel_dBm = prevImp[0]; 472 final double pre_CD_ps_per_nm = prevImp[1]; 473 474 final double post_powerPerChannel_dBm = postImp[0]; 475 final double post_CD_ps_per_nm = postImp[1]; 476 final double post_PMDSquared_ps2 = postImp[2]; 477 final double post_OSNR_linear = postImp[3]; 478 479 if (name.equalsIgnoreCase("OADM-ADD")) 480 { 481 /* Wavelengths in use within transponder range */ 482 if (channels_minChannelLambda_nm < tp_minWavelength_nm) st += "Wavelength " + channels_minChannelLambda_nm + " nm is outside the transponder range [" + tp_minWavelength_nm + " nm, " + tp_maxWavelength_nm + " nm]"; 483 if (channels_maxChannelLambda_nm > tp_maxWavelength_nm) st += "Wavelength " + channels_maxChannelLambda_nm + " nm is outside the transponder range [" + tp_minWavelength_nm + " nm, " + tp_maxWavelength_nm + " nm]"; 484 485 /* Output power within limits */ 486 if (Math.abs(post_powerPerChannel_dBm - oadm_perChannelOutputPower_dBm) > 1E-3) st += "At " + initialPosition_km + "km: Power at the OADM-ADD output is " + post_powerPerChannel_dBm + " dBm. It should be: " + oadm_perChannelOutputPower_dBm; 487 } 488 else if (name.equalsIgnoreCase("OADM-EXPRESS")) 489 { 490 /* Input power within limits */ 491 if (pre_powerPerChannel_dBm < oadm_perChannelMinInputPower_dBm - 1E-3) st += "At " + initialPosition_km + "km: Power at the OADM-EXPRESS input is " + pre_powerPerChannel_dBm + " dBm. It should be between [" + oadm_perChannelMinInputPower_dBm + ", " + oadm_perChannelMaxInputPower_dBm + "] dBm"; 492 if (pre_powerPerChannel_dBm > oadm_perChannelMaxInputPower_dBm + 1E-3) st += "At " + initialPosition_km + "km: Power at the OADM-EXPRESS input is " + pre_powerPerChannel_dBm + " dBm. It should be between [" + oadm_perChannelMinInputPower_dBm + ", " + oadm_perChannelMaxInputPower_dBm + "] dBm"; 493 494 /* Output power within limits */ 495 if (Math.abs(post_powerPerChannel_dBm - oadm_perChannelOutputPower_dBm) > 1E-3) st += "At " + initialPosition_km + "km: Power at the OADM-EXPRESS output is " + post_powerPerChannel_dBm + " dBm. It should be: " + oadm_perChannelOutputPower_dBm; 496 497 numberOfExpressOADMs++; 498 } 499 else if (name.equalsIgnoreCase("OADM-DROP")) 500 { 501 final double cdLimit = numberOfExpressOADMs == 0 ? oadm_maxAbsoluteChromaticDispersionAtInput_ps_per_nm : tp_maxChromaticDispersionTolerance_ps_per_nm; 502 503 /* CD at input */ 504 if (Math.abs(pre_CD_ps_per_nm) > cdLimit + 1E-3) st += "At " + initialPosition_km + "km: CD at the input of OADM-DROP is " + pre_CD_ps_per_nm + " dBm. It should be in absolute value below: " + cdLimit; 505 506 /* Input power within limits */ 507 if (pre_powerPerChannel_dBm < oadm_perChannelMinInputPower_dBm - 1E-3) st += "At " + initialPosition_km + "km: Power at the OADM-DROP input is " + pre_powerPerChannel_dBm + " dBm. It should be between [" + oadm_perChannelMinInputPower_dBm + "," + oadm_perChannelMaxInputPower_dBm + "] dBm"; 508 if (pre_powerPerChannel_dBm > oadm_perChannelMaxInputPower_dBm + 1E-3) st += "At " + initialPosition_km + "km: Power at the OADM-DROP input is " + pre_powerPerChannel_dBm + " dBm. It should be between [" + oadm_perChannelMinInputPower_dBm + "," + oadm_perChannelMaxInputPower_dBm + "] dBm"; 509 510 /* Output power within limits */ 511 if (post_powerPerChannel_dBm < tp_inputPowerSensitivityMin_dBm - 1E-3) st += "At " + initialPosition_km + "km: Power at the OADM-DROP output is " + post_powerPerChannel_dBm + ". It should be between [" + tp_inputPowerSensitivityMin_dBm + "," + tp_inputPowerSensitivityMax_dBm + "] dBm"; 512 if (post_powerPerChannel_dBm > tp_inputPowerSensitivityMax_dBm + 1E-3) st += "At " + initialPosition_km + "km: Power at the OADM-DROP output is " + post_powerPerChannel_dBm + ". It should be between [" + tp_inputPowerSensitivityMin_dBm + "," + tp_inputPowerSensitivityMax_dBm + "] dBm"; 513 514 /* Chromatic dispersion in the receiver */ 515 if (post_CD_ps_per_nm > tp_maxChromaticDispersionTolerance_ps_per_nm) st += "At " + initialPosition_km + "km: Chromatic dispersion at the RECEIVER is " + post_CD_ps_per_nm + " ps/nm. It should be within +- " + tp_maxChromaticDispersionTolerance_ps_per_nm + " ps/nm"; 516 if (post_CD_ps_per_nm < -tp_maxChromaticDispersionTolerance_ps_per_nm) st += "At " + initialPosition_km + "km: Chromatic dispersion at the RECEIVER is " + post_CD_ps_per_nm + " ps/nm. It should be within +- " + tp_maxChromaticDispersionTolerance_ps_per_nm + " ps/nm"; 517 518 /* OSNR within limits */ 519 if (linear2dB(post_OSNR_linear) < tp_minOSNR_dB + osnrPenalty_SUM_dB) st += "At " + initialPosition_km + "km: OSNR at the RECEIVER is " + linear2dB(post_OSNR_linear) + " dB. It is below the tolerance plus margin " + tp_minOSNR_dB + " dB " + osnrPenalty_SUM_dB + " dB = " + (tp_minOSNR_dB + osnrPenalty_SUM_dB) + " dB)"; 520 521 /* PMD tolerance at the receiver */ 522 final double pmdAtReceiver = Math.sqrt(post_PMDSquared_ps2); 523 if (pmdAtReceiver > tp_pmdTolerance_ps) st += "At " + initialPosition_km + "km: PMD at the RECEIVER is " + pmdAtReceiver + " ps. It is above the maximum PMD tolerance (" + tp_pmdTolerance_ps + " ps)"; 524 } 525 else if (name.equalsIgnoreCase("SPAN")) 526 { 527 } 528 else if (name.equalsIgnoreCase("EDFA")) 529 { 530 final double edfaGain_dB = elementData; 531 532 /* Wavelengths within limits */ 533 if (channels_minChannelLambda_nm < edfa_minWavelength_nm) st += "Wavelength " + channels_minChannelLambda_nm + " nm is outside the transponder range [" + edfa_minWavelength_nm + " nm, " + edfa_maxWavelength_nm + " nm]"; 534 if (channels_maxChannelLambda_nm > edfa_maxWavelength_nm) st += "Wavelength " + channels_maxChannelLambda_nm + " nm is outside the transponder range [" + edfa_minWavelength_nm + " nm, " + edfa_maxWavelength_nm + " nm]"; 535 536 /* Gain within limits */ 537 if (edfaGain_dB < edfa_minGain_dB - 1E-3) st += "At " + initialPosition_km + "km: EDFA gain is " + edfaGain_dB + " dB. It should be between [" + edfa_minGain_dB + ", " + edfa_maxGain_dB + "] dB"; 538 if (edfaGain_dB > edfa_maxGain_dB + 1E-3) st += "At " + initialPosition_km + "km: EDFA gain is " + edfaGain_dB + " dB. It should be between [" + edfa_minGain_dB + ", " + edfa_maxGain_dB + "] dB"; 539 540 /* Input power within limits */ 541 if (pre_powerPerChannel_dBm < edfa_minInputPower_dBm - 1E-3) st += "At " + initialPosition_km + "km: Power at the EDFA input is (is one WDM channel) " + pre_powerPerChannel_dBm + " dBm. It should be between [" + edfa_minInputPower_dBm + ", " + edfa_maxInputPower_dBm + "] dBm"; 542 if (pre_powerPerChannel_dBm + numChannels_dB > edfa_maxInputPower_dBm + 1E-3) st += "At " + initialPosition_km + "km: Power at the EDFA input is (if all WDM channels are active) " + (pre_powerPerChannel_dBm + numChannels_dB) + " dBm. It should be between [" + edfa_minInputPower_dBm + "," + edfa_maxInputPower_dBm + "] dBm"; 543 544 /* Output power within limits */ 545 if (post_powerPerChannel_dBm < edfa_minOutputPower_dBm - 1E-3) st += "At " + initialPosition_km + "km: Power at the EDFA output is (is one WDM channel) " + post_powerPerChannel_dBm + " dBm. It should be between [" + edfa_minOutputPower_dBm + ", " + edfa_maxOutputPower_dBm + "] dBm"; 546 if (post_powerPerChannel_dBm + numChannels_dB > edfa_maxOutputPower_dBm + 1E-3) st += "At " + initialPosition_km + "km: Power at the EDFA output is (if all WDM channels are active) " + (post_powerPerChannel_dBm + numChannels_dB) + " dBm. It should be between [" + edfa_minOutputPower_dBm + ", " + edfa_maxOutputPower_dBm + "] dBm"; 547 } 548 else if (name.equalsIgnoreCase("DCM")) 549 { 550 final double dcmCompensation_ps_per_nm = elementData; 551 if ((dcmCompensation_ps_per_nm < dcm_channelDispersionMax_ps_per_nm) || (dcmCompensation_ps_per_nm > dcm_channelDispersionMin_ps_per_nm)) st += "At " + initialPosition_km + "km: DCM compensation is " + dcmCompensation_ps_per_nm + " ps/nm. It should be between [" + dcm_channelDispersionMax_ps_per_nm + ", " + dcm_channelDispersionMin_ps_per_nm + "] ps/nm"; 552 } 553 else 554 { 555 throw new RuntimeException("Unknown element type"); 556 } 557 558 res.add(st); 559 } 560 561 return res; 562 } 563 564 private LinkedList<Triple<Double, String, Double>> getElementPositionsList(List<Link> seqLinks) 565 { 566 LinkedList<Triple<Double, String, Double>> res = new LinkedList<Triple<Double, String, Double>>(); 567 double currentDistanceFromRouteInit_km = 0; 568 569 res.add(Triple.of(currentDistanceFromRouteInit_km, "OADM-ADD", (double) seqLinks.get(0).getOriginNode().getId ())); 570 for (Link e : seqLinks) 571 { 572 final double d_e = e.getLengthInKm(); 573 final String st_edfaPositions_km = e.getAttribute("edfaPositions_km") == null ? "" : e.getAttribute("edfaPositions_km"); 574 final String st_edfaGains_dB = e.getAttribute("edfaGains_dB") == null ? "" : e.getAttribute("edfaGains_dB"); 575 final String st_dcmPositions_km = e.getAttribute("dcmPositions_km") == null ? "" : e.getAttribute("dcmPositions_km"); 576 final String st_dcmCDCompensation_ps_per_nm = e.getAttribute("dcmCDCompensation_ps_per_nm") == null ? "" : e.getAttribute("dcmCDCompensation_ps_per_nm"); 577 final double[] edfaPositions_km = StringUtils.toDoubleArray(StringUtils.split(st_edfaPositions_km)); 578 final double[] edfaGains_dB = StringUtils.toDoubleArray(StringUtils.split(st_edfaGains_dB)); 579 final double[] dcmPositions_km = StringUtils.toDoubleArray(StringUtils.split(st_dcmPositions_km)); 580 final double[] dcmCDCompensation_ps_per_nm = StringUtils.toDoubleArray(StringUtils.split(st_dcmCDCompensation_ps_per_nm)); 581 if (edfaPositions_km.length != edfaGains_dB.length) throw new Net2PlanException("Link: " + e + ". Number of elements in edfaPositions_km is not equal to the number of elements in edfaGains_dB"); 582 if (dcmPositions_km.length != dcmCDCompensation_ps_per_nm.length) throw new Net2PlanException("Link: " + e + ". Number of elements in dcmPositions_km is not equal to the number of elements in dcmCDCompensation_ps_per_nm"); 583 584 for (double edfaPosition : edfaPositions_km) 585 if ((edfaPosition < 0) || (edfaPosition > d_e)) 586 throw new Net2PlanException("Link: " + e + ". Wrong OA position: " + edfaPosition + ", link length = " + d_e); 587 588 for (double dcmPosition : dcmPositions_km) 589 if ((dcmPosition < 0) || (dcmPosition > d_e)) 590 throw new Net2PlanException("Link: " + e + ". Wrong DCM position: " + ", link length = " + d_e); 591 592 /* Place in a sorted form the spans, dcms and EDFAS. If DCM and EDFA colocated, DCM goes first */ 593 double[] dcmAndEDFAPositions_km = DoubleUtils.concatenate(dcmPositions_km, edfaPositions_km); 594 int[] sortedDCMAndEDFAPositionsIndexes = dcmAndEDFAPositions_km.length == 0 ? new int[0] : DoubleUtils.sortIndexes(dcmAndEDFAPositions_km, OrderingType.ASCENDING); 595 double posKmLastElementThisLink_km = 0; 596 for (int cont = 0; cont < sortedDCMAndEDFAPositionsIndexes.length; cont++) 597 { 598 final int indexInCommonArray = sortedDCMAndEDFAPositionsIndexes[cont]; 599 final boolean isDCM = (indexInCommonArray < dcmPositions_km.length); 600 final double posFromLinkInit_km = dcmAndEDFAPositions_km[indexInCommonArray]; 601 final double previousSpanLength = (Math.abs(posFromLinkInit_km - posKmLastElementThisLink_km) < 1E-3) ? 0 : posFromLinkInit_km - posKmLastElementThisLink_km; 602 603 if (previousSpanLength < 0) throw new RuntimeException("Bad"); 604 605 if (previousSpanLength > 0) 606 { 607 res.add(Triple.of(currentDistanceFromRouteInit_km, "SPAN", previousSpanLength)); 608 currentDistanceFromRouteInit_km += previousSpanLength; 609 posKmLastElementThisLink_km += previousSpanLength; 610 } 611 612 if (isDCM) res.add(Triple.of(currentDistanceFromRouteInit_km, "DCM", dcmCDCompensation_ps_per_nm[indexInCommonArray])); 613 else res.add(Triple.of(currentDistanceFromRouteInit_km, "EDFA", edfaGains_dB[indexInCommonArray - dcmPositions_km.length])); 614 } 615 616 /* Last span of the link before the OADM */ 617 final double lastSpanOfLink_km = (Math.abs(d_e - posKmLastElementThisLink_km) < 1E-3) ? 0 : d_e - posKmLastElementThisLink_km; 618 619 if (lastSpanOfLink_km < 0) throw new RuntimeException("Bad"); 620 621 if (lastSpanOfLink_km > 0) 622 { 623 res.add(Triple.of(currentDistanceFromRouteInit_km, "SPAN", lastSpanOfLink_km)); 624 currentDistanceFromRouteInit_km += lastSpanOfLink_km; 625 posKmLastElementThisLink_km += lastSpanOfLink_km; 626 } 627 628 /* OADM at the end of the link */ 629 final long endNodeLink = e.getDestinationNode().getId (); 630 final long lastLink = seqLinks.get(seqLinks.size() - 1).getId (); 631 if (e.getId () == lastLink) res.add(Triple.of(currentDistanceFromRouteInit_km, "OADM-DROP", (double) endNodeLink)); 632 else res.add(Triple.of(currentDistanceFromRouteInit_km, "OADM-EXPRESS", (double) endNodeLink)); 633 } 634 635 /* Check current distance equals the sum of the traversed links */ 636 double sumLinks = 0; 637 for (Link e : seqLinks) sumLinks += e.getLengthInKm(); 638 639 if (Math.abs(sumLinks - currentDistanceFromRouteInit_km) > 1E-3) throw new RuntimeException("Bad"); 640 return res; 641 } 642 643 private static double dB2Linear(double dB) 644 { 645 return Math.pow(10, dB / 10); 646 } 647 648 private static double linear2dB(double num) 649 { 650 return 10 * Math.log10(num); 651 } 652 653 private String printReport(Map<Link, LinkedList<Triple<Double, String, Double>>> elements_e, Map<Link, LinkedList<Pair<double[], double[]>>> impairments_e, Map<Link, LinkedList<String>> warnings_e, Map<Route, LinkedList<Triple<Double, String, Double>>> elements_r, Map<Route, LinkedList<Pair<double[], double[]>>> impairments_r, Map<Route, LinkedList<String>> warnings_r) 654 { 655 StringBuilder out = new StringBuilder(); 656 DecimalFormat df_2 = new DecimalFormat("###.##"); 657 658 out.append("<html><body>"); 659 out.append("<head><title>WDM line engineering in multilayer (lightpath based) networks</title></head>"); 660 out.append("<h1>WDM line engineering report for lighptath-based networks</h1>"); 661 662 out.append("<p>This report shows line engineering information for WDM links in a multilayer optical network. The impairment calculations are inspired in the procedures described in the 2009 ITU-T WDM manual \"Optical fibres, cabbles and systems\".</p>"); 663 out.append("<p>The report assumes that the WDM network follows the scheme:</p>"); 664 out.append("<ul>"); 665 out.append("<li>In the net2plan object, nodes are OADMs, links are fiber links, and routes are lightpaths: WDM channels optically switched at intermediate nodes. </li>"); 666 out.append("<li>Nodes are connected by unidirectional fiber links. Fiber link distance is given by the link length."); 667 out.append("Other specifications are given by fiber_XXX input parameters. The fiber can be split into spans if optical amplifers (EDFAs)"); 668 out.append("and/or dispersion compensating modules (DCMs) are placed along the fiber.</li>"); 669 out.append("<li>Optical line amplifiers (EDFAs) can be located in none, one or more positions in the"); 670 out.append("fiber link, separating them in different spans. EDFAs are supposed to operate in the "); 671 out.append("automatic gain control mode. Thus, the gain is the same, whatever the number of input"); 672 out.append("WDM channels. EDFA positions (as distance in km from the link start to the EDFA location)"); 673 out.append("and EDFA gains (assumed in dB) are read from the \"edfaPositions_km\" and \"edfaGains_dB\" "); 674 out.append("attributes of the links. The format of both attributes are the same: a string of numbers "); 675 out.append("separated by spaces. The <i>i</i>-th number corresponding to the position/gain of the "); 676 out.append("<i>i</i>-th EDFA. If the attributes do not exist, it is assumed that no EDFAs are placed "); 677 out.append("in this link. EDFA specifications are given by \"edfa_XXX\" parameters</li>"); 678 out.append("<li>Dispersion compensating modules (DCMs) can be located in none, one or more positions"); 679 out.append("in the fiber link, separating them in different spans. If a DCM and a EDFA have the same "); 680 out.append("location, it is assumed that the DCM is placed first, to reduce the non-linear effects. DCM "); 681 out.append("positions (as distance in km from the link start to the DCM location) are read from the "); 682 out.append("\"dcmPositions_km\" attribute of the link, and the same format as with \"edfaPositions_km\" "); 683 out.append("attribute is expected. If the attribute does not exist, it is assumed that no DCMs are "); 684 out.append("placed in this link. DCM specifications are given by \"dcm_XXX\" parameters</li>"); 685 out.append("<li>Fiber links start and end in OADM modules, that permit adding, dropping and optically switch"); 686 out.append("individual WDM channels. OADMs have a pre-amplifier (traversed by drop and express channels) and "); 687 out.append("a boost amplifier (traversed by add and express channels). They are supposed to equalize the "); 688 out.append("channel power at their outputs, to a fixed value (added and express channels will thus have the same power in the fibers)."); 689 out.append("Also, OADMs attenuate appropriately the optical signal coming from the pre-amplifier, in the drop channels,"); 690 out.append("so that they fall within the receiver sensitivity range. OADM noise figures for add, drop and express channels"); 691 out.append("are given as input parameters. PMD values for add, drop and express channels are computed assumming that: (i) "); 692 out.append("add channel traverse a multiplexer and the booster, (ii) drop channels travese the pre-amplifier and a demultiplexer,"); 693 out.append("(iii) express channels traverse the two amplifiers. The required parameters are provided in oadm_XXX parameters. </li>"); 694 out.append("<li>Each channel ends in a receiver, with specifications given by \"tp_XXX\" parameters.</li>"); 695 out.append("</ul></p>"); 696 out.append("<p>The basic checks performed are:</p>"); 697 out.append("<ul>"); 698 out.append("<li>For each link, signal power levels are within operating ranges at the oadm/edfas/dcms, both when the link has one single active channel, or when all the"); 699 out.append("\"channels_maxNumChannels\" are active</li>"); 700 out.append("<li>For each link, chromatic dispersion is within the limits set per link</li>"); 701 out.append("<li>For each route (lightpath), chromatic dispersion is within the limits of the receiver.</li>"); 702 out.append("<li>For each route (lightpath), OSNR (Optical Signal to Noise Ration) is within the operating range at the receiver."); 703 out.append("A set of margins are considered to account to several not directly considered impairments. </li>"); 704 out.append("<li>For each route (lightpath), PMD (Polarization mode dispersion) is within the operating range at the receiver</li>"); 705 out.append("</ul></p>"); 706 707 out.append("<h2>Input Parameters</h2>"); 708 out.append("<table border='1'>"); 709 out.append("<tr><th><b>Name</b></th><th><b>Value</b></th><th><b>Description</b></th>"); 710 711 for (Triple<String, String, String> paramDef : getParameters()) 712 { 713 String name = paramDef.getFirst(); 714 String description = paramDef.getThird(); 715 String value = reportParameters.get(name); 716 out.append("<tr><td>").append(name).append("</td><td>").append(value).append("</td><td>").append(description).append("</td></tr>"); 717 } 718 out.append("</table>"); 719 720 out.append("<h2>PER LINK INFORMATION SUMMARY - Signal metrics at the input of end OADM</h2>"); 721 out.append("<table border='1'>"); 722 out.append("<tr><th><b>Link #</b></th><th><b>Length (km)</b></th><th><b># EDFAs</b></th><th><b># DCMs</b></th><th><b>Chromatic Dispersion (ps/nm)</b></th><th><b>OSNR (dB)</b></th><th><b>Power per WDM channel (dBm)</b></th><th><b>Polarization Mode Dispersion (ps)</b></th><th><b>Warnings</b></th></tr>"); 723 for (Link e : netPlan.getLinks()) 724 { 725 final double d_e = e.getLengthInKm(); 726 final String st_a_e = e.getOriginNode().getName(); 727 final String st_b_e = e.getDestinationNode().getName(); 728 LinkedList<Triple<Double, String, Double>> el = elements_e.get(e); 729 LinkedList<Pair<double[], double[]>> imp = impairments_e.get(e); 730 LinkedList<String> w = warnings_e.get(e); 731 732 int numEDFAs = 0; 733 for (Triple<Double, String, Double> t : el) 734 if (t.getSecond().equalsIgnoreCase("EDFA")) 735 numEDFAs++; 736 737 int numDCMs = 0; 738 for (Triple<Double, String, Double> t : el) 739 if (t.getSecond().equalsIgnoreCase("DCM")) 740 numDCMs++; 741 742 final double[] impInfoInputOADM = imp.getLast().getFirst(); 743 StringBuilder warnings = new StringBuilder(); 744 for (String s : w) warnings.append("<p>").append(s).append("</p>"); 745 746 out.append("<tr><td>").append(e).append(" (").append(st_a_e).append(" --> ").append(st_b_e).append(") </td><td>").append(df_2.format(d_e)).append("</td><td>").append(numEDFAs).append("</td><td>").append(numDCMs).append("</td><td>").append(df_2.format(impInfoInputOADM[1])).append("</td><td>").append(df_2.format(linear2dB(impInfoInputOADM[3]))).append("</td><td>").append(df_2.format(impInfoInputOADM[0])).append("</td><td>").append(df_2.format(Math.sqrt(impInfoInputOADM[2]))).append("</td><td>").append(warnings).append("</td></tr>"); 747 } 748 out.append("</table>"); 749 750 out.append("<h2>PER ROUTE INFORMATION SUMMARY - Signal metrics at the transponder</h2>"); 751 out.append("<table border='1'>"); 752 out.append("<tr><th><b>Route #</b></th><th><b>Length (km)</b></th><th><b># EDFAs</b></th><th><b># DCMs</b></th><th><b>Chromatic Dispersion (ps/nm)</b></th><th><b>OSNR (dB)</b></th><th><b>Power per WDM channel (dBm)</b></th><th><b>Polarization Mode Dispersion (ps)</b></th><th><b>Warnings</b></th></tr>"); 753 for (Route r : netPlan.getRoutes()) 754 { 755 final double d_r = r.getLengthInKm(); 756 final String st_a_r = r.getIngressNode().getName (); 757 final String st_b_r = r.getEgressNode().getName (); 758 LinkedList<Triple<Double, String, Double>> el = elements_r.get(r); 759 LinkedList<Pair<double[], double[]>> imp = impairments_r.get(r); 760 LinkedList<String> w = warnings_r.get(r); 761 762 int numEDFAs = 0; 763 for (Triple<Double, String, Double> t : el) 764 if (t.getSecond().equalsIgnoreCase("EDFA")) 765 numEDFAs++; 766 767 int numDCMs = 0; 768 for (Triple<Double, String, Double> t : el) 769 if (t.getSecond().equalsIgnoreCase("DCM")) 770 numDCMs++; 771 772 final double[] impInfoInputOADM = imp.getLast().getFirst(); 773 StringBuilder warnings = new StringBuilder(); 774 for (String s : w) warnings.append("<p>").append(s).append("</p>"); 775 776 out.append("<tr><td>").append(r).append(" (").append(st_a_r).append(" --> ").append(st_b_r).append(") </td><td>").append(df_2.format(d_r)).append("</td><td>").append(numEDFAs).append("</td><td>").append(numDCMs).append("</td><td>").append(df_2.format(impInfoInputOADM[1])).append("</td><td>").append(df_2.format(linear2dB(impInfoInputOADM[3]))).append("</td><td>").append(df_2.format(impInfoInputOADM[0])).append("</td><td>").append(df_2.format(Math.sqrt(impInfoInputOADM[2]))).append("</td><td>").append(warnings.toString()).append("</td>" + "</tr>"); 777 } 778 out.append("</table>"); 779 780 out.append("<h2>PER-LINK DETAILED INFORMATION </h2>"); 781 out.append("<p>Number of links: ").append(netPlan.getNumberOfLinks()).append("</p>"); 782 783 for (Link e : netPlan.getLinks()) 784 { 785 final double d_e = e.getLengthInKm(); 786 final String st_a_e = e.getOriginNode().getName (); 787 final String st_b_e = e.getDestinationNode().getName (); 788 LinkedList<Triple<Double, String, Double>> el = elements_e.get(e); 789 LinkedList<Pair<double[], double[]>> imp = impairments_e.get(e); 790 LinkedList<String> w = warnings_e.get(e); 791 final String st_edfaPositions_km = e.getAttribute("edfaPositions_km") == null ? "" : e.getAttribute("edfaPositions_km"); 792 final String st_edfaGains_dB = e.getAttribute("edfaGains_dB") == null ? "" : e.getAttribute("edfaGains_dB"); 793 final String st_dcmPositions_km = e.getAttribute("dcmPositions_km") == null ? "" : e.getAttribute("dcmPositions_km"); 794 795 out.append("<h3>LINK # ").append(e).append(" (").append(st_a_e).append(" --> ").append(st_b_e).append(")</h3>"); 796 out.append("<table border=\"1\">"); 797 out.append("<caption>Link input information</caption>"); 798 out.append("<tr><td>Link length (km)</td><td>").append(d_e).append("</td></tr>"); 799 out.append("<tr><td>EDFA positions (km)</td><td>").append(st_edfaPositions_km).append("</td></tr>"); 800 out.append("<tr><td>EDFA gains (dB)</td><td>").append(st_edfaGains_dB).append("</td></tr>"); 801 out.append("<tr><td>DCM positions (km)</td><td>").append(st_dcmPositions_km).append("</td></tr>"); 802 out.append("</table>"); 803 804 out.append("<table border=\"1\">"); 805 out.append("<caption>Signal metrics evolution</caption>"); 806 out.append("<tr><th><b>Position (km)</b></th><th><b>Position (description)</b></th><th><b>Chromatic Dispersion (ps/nm)</b></th><th><b>OSNR (dB)</b></th><th><b>Power per WDM channel (dBm)</b></th><th><b>Polarization Mode Dispersion (ps)</b></th><th><b>Warnings</b></th></tr>"); 807 Iterator<Triple<Double, String, Double>> it_el = el.iterator(); 808 Iterator<Pair<double[], double[]>> it_imp = imp.iterator(); 809 Iterator<String> it_w = w.iterator(); 810 while (it_el.hasNext()) 811 { 812 final Triple<Double, String, Double> this_el = it_el.next(); 813 final Pair<double[], double[]> this_imp = it_imp.next(); 814 final String this_warnings = it_w.next(); 815 816 final double pos_km = this_el.getFirst(); 817 String elementType = this_el.getSecond(); 818 final double elementAuxData = this_el.getThird(); 819 final double[] prevInfo = this_imp.getFirst(); 820 821 if (elementType.equalsIgnoreCase("EDFA")) elementType += " (gain " + elementAuxData + " dB)"; 822 else if (elementType.equalsIgnoreCase("SPAN")) elementType += " (" + elementAuxData + " km)"; 823 else if (elementType.equalsIgnoreCase("DCM")) elementType += " (comp " + elementAuxData + " ps/nm)"; 824 825 out.append("<tr><td>").append(df_2.format(pos_km)).append("</td><td>" + "Input of ").append(elementType).append("</td><td>").append(df_2.format(prevInfo[1])).append("</td><td>").append(df_2.format(linear2dB(prevInfo[3]))).append("</td><td>").append(df_2.format(prevInfo[0])).append("</td><td>").append(df_2.format(Math.sqrt(prevInfo[2]))).append("</td><td>").append(this_warnings).append("</td>" + "</tr>"); 826 827 } 828 out.append("</table>"); 829 } 830 831 out.append("<h2>PER-LIGHTPATH DETAILED INFORMATION</h2>"); 832 out.append("<p>Number of lightpaths: ").append(netPlan.getNumberOfRoutes()).append("</p>"); 833 834 for (Route r : netPlan.getRoutes()) 835 { 836 final double d_r = r.getLengthInKm(); 837 final String st_a_r = r.getIngressNode().getName(); 838 final String st_b_r = r.getEgressNode().getName(); 839 LinkedList<Triple<Double, String, Double>> el = elements_r.get(r); 840 LinkedList<Pair<double[], double[]>> imp = impairments_r.get(r); 841 LinkedList<String> w = warnings_r.get(r); 842 843 out.append("<h3>ROUTE # ").append(r).append(" (").append(st_a_r).append(" --> ").append(st_b_r).append("), Length: ").append(d_r).append(" km</h3>"); 844 out.append("<table border=\"1\">"); 845 out.append("<caption>Signal metrics evolution</caption>"); 846 out.append("<tr><th><b>Position (km)</b></th><th><b>Position (description)</b></th><th><b>Chromatic Dispersion (ps/nm)</b></th><th><b>OSNR (dB)</b></th><th><b>Power per WDM channel (dBm)</b></th><th><b>Polarization Mode Dispersion (ps)</b></th><th><b>Warnings</b></th></tr>"); 847 Iterator<Triple<Double, String, Double>> it_el = el.iterator(); 848 Iterator<Pair<double[], double[]>> it_imp = imp.iterator(); 849 Iterator<String> it_w = w.iterator(); 850 while (it_el.hasNext()) 851 { 852 final Triple<Double, String, Double> this_el = it_el.next(); 853 final Pair<double[], double[]> this_imp = it_imp.next(); 854 final String this_warnings = it_w.next(); 855 856 final double pos_km = this_el.getFirst(); 857 String elementType = this_el.getSecond(); 858 final double elementAuxData = this_el.getThird(); 859 final double[] prevInfo = this_imp.getFirst(); 860 if (elementType.equalsIgnoreCase("EDFA")) elementType += " (gain " + elementAuxData + " dB)"; 861 else if (elementType.equalsIgnoreCase("SPAN")) elementType += " (" + elementAuxData + " km)"; 862 else if (elementType.equalsIgnoreCase("DCM")) elementType += " (comp " + elementAuxData + " ps/nm)"; 863 864 out.append("<tr><td>").append(df_2.format(pos_km)).append("</td><td>" + "Input of ").append(elementType).append("</td><td>").append(df_2.format(prevInfo[1])).append("</td><td>").append(df_2.format(linear2dB(prevInfo[3]))).append("</td><td>").append(df_2.format(prevInfo[0])).append("</td><td>").append(df_2.format(Math.sqrt(prevInfo[2]))).append("</td><td>").append(this_warnings).append("</td>" + "</tr>"); 865 866 } 867 final Triple<Double, String, Double> this_el = el.getLast(); 868 final Pair<double[], double[]> this_imp = imp.getLast(); 869 final String this_warnings = w.getLast(); 870 final double pos_km = this_el.getFirst(); 871 final double[] postInfo = this_imp.getSecond(); 872 out.append("<tr><td>").append(df_2.format(pos_km)).append("</td><td>" + "Receiver" + "</td><td>").append(df_2.format(postInfo[1])).append("</td><td>").append(df_2.format(linear2dB(postInfo[3]))).append("</td><td>").append(df_2.format(postInfo[0])).append("</td><td>").append(df_2.format(Math.sqrt(postInfo[2]))).append("</td><td>").append(this_warnings).append("</td>" + "</tr>"); 873 874 out.append("</table>"); 875 } 876 877 out.append("</body></html>"); 878 return out.toString(); 879 } 880 881 private double updateOSNRAfterEDFA(double currentOSNR_linear, double noiseFactor_dB, double noiseFactorReferenceBandwidth_nm, double inputPowerPerChannel_dBm) 882 { 883 final double edfa_NF_linear = dB2Linear(noiseFactor_dB); 884 final double highestFrequencyChannel_Hz = constant_c / (channels_minChannelLambda_nm * 1e-9); 885 final double referenceBandwidthAtHighestFrequency_Hz = -highestFrequencyChannel_Hz + constant_c / ((channels_minChannelLambda_nm - noiseFactorReferenceBandwidth_nm) * 1e-9); 886 final double inputPower_linear = dB2Linear(inputPowerPerChannel_dBm) * 1E-3; 887 final double thisEDFAAddedNoise_linear = edfa_NF_linear * constant_h * highestFrequencyChannel_Hz * referenceBandwidthAtHighestFrequency_Hz; 888 final double addedOSNRThisOA_linear = inputPower_linear / thisEDFAAddedNoise_linear; 889 final double new_OSNR_linear = (currentOSNR_linear == Double.MAX_VALUE) ? addedOSNRThisOA_linear : 1 / (1 / currentOSNR_linear + 1 / addedOSNRThisOA_linear); 890 return new_OSNR_linear; 891 } 892}