Fiber#
What the fibre is, separated from how it is simulated (decision D46).
FiberLink used to take twenty-one constructor arguments, mixing
two things that change for entirely different reasons: the glass –
its loss, its Kerr coefficient, its dispersion – and the numerics
– how many split-steps, which step distribution, what sampling rate. A
user swapping SMF for a dispersion-compensating fibre had to retype four
unrelated numbers in the middle of a list of solver settings, and
nothing tied them together or said where they came from.
FiberSpec is the fourth instance of the pattern D15/D43/D45
established on the frequency, delay and Raman-shift axes: a frozen value
object carrying the numbers and their provenance, a registry of
standard entries, and a self-check at construction against a figure
published alongside them.
It also removes a latent incoherence. The link took lamb and
nu as independent arguments, so a chain set to 1310 nm computed its
dispersion at 1310 nm and its ASE photon energy at 1550: the two agreed
only because the two defaults happened to. Here \(\nu = c / \lambda\)
is derived, and cannot disagree with itself.
- class FiberSpec(alpha_dB: float = 0.2, *, gamma: float = 1.3, cd_coefficient: float = 17, wavelength_nm: float = 1550, raman_gain_W_km: float | None = None, standard: str = 'custom', reference: str = '')[source]#
Physical parameters of an optical fibre, with their provenance.
Signal Model#
The three coefficients that drive the nonlinear Schrödinger equation the split-step method integrates:
\[\frac{\partial A}{\partial z} = \underbrace{-\frac{\alpha}{2} A}_{\text{loss}} \underbrace{- j \frac{\beta_2}{2} \frac{\partial^2 A}{\partial t^2}}_{\text{dispersion}} + \underbrace{j \gamma |A|^2 A}_{\text{Kerr}}\]The dispersion is given as the engineering coefficient \(D\) in ps/nm/km, which is what data sheets quote, and converted to the group-velocity dispersion the equation uses:
\[\beta_2 = -\frac{D \lambda^2}{2 \pi c}\]The carrier frequency is derived, \(\nu = c / \lambda\), and is not a separate parameter: two independent arguments that must agree are the defect D41 exists to prevent.
- param alpha_dB:
Attenuation \(\alpha\) in dB/km.
- type alpha_dB:
float, optional
- param gamma:
Kerr coefficient \(\gamma\) in rad/W/km.
- type gamma:
float, optional, keyword-only
- param cd_coefficient:
Dispersion coefficient \(D\) in ps/nm/km, quoted at
wavelength_nm. Negative for a dispersion-compensating fibre.- type cd_coefficient:
float, optional, keyword-only
- param wavelength_nm:
Wavelength \(\lambda\) in nm the coefficients are quoted at, and which fixes the carrier frequency.
- type wavelength_nm:
float, optional, keyword-only
- param raman_gain_W_km:
Peak Raman gain \(g_R / A_\mathrm{eff}\) in \(\mathrm{W}^{-1}\mathrm{km}^{-1}\). A fibre property, not a property of the glass spectrum, which is why it lives here and not in
RamanGainSpectrum.Nonewhen the entry does not quote one.- type raman_gain_W_km:
float, optional, keyword-only
- param standard:
Name of the fibre, e.g.
"SMF".- type standard:
str, optional, keyword-only
- param reference:
Where the numbers come from.
- type reference:
str, optional, keyword-only
- raises ValueError:
If the attenuation is negative, if the Kerr coefficient is negative, or if the wavelength is not positive. The dispersion may be of either sign; a Raman gain may not be negative.
References
G. P. Agrawal, Nonlinear Fiber Optics, 5th ed., Academic Press, 2013, Sections 1.2 and 2.3.
Examples
>>> fiber = get_fiber("SMF") >>> round(fiber.beta2, 3), round(fiber.carrier_frequency_Hz / 1e12, 4) (-21.683, 193.4145) >>> round(fiber.effective_length_km(80.0), 3) 21.169
- property beta2: float#
Group-velocity dispersion \(\beta_2\) in ps²/km.
Delegates to
compute_beta2(): one formula, one place. Writing the conversion a second time here got the unit scaling wrong by a factor of a thousand, and the self-check below is what caught it.
- property carrier_frequency_Hz: float#
Optical carrier \(\nu = c / \lambda\), in Hz.
- property alpha_per_km: float#
Attenuation \(\alpha\) in 1/km, the equation’s unit.
- effective_length_km(length_km: float) float[source]#
Nonlinear effective length \((1 - e^{-\alpha L})/\alpha\).
The length a lossless fibre would need to accumulate the same Kerr phase. Equal to
length_kmfor a lossless fibre.- Parameters:
length_km (float) – Physical span length \(L\) in km.
- Returns:
float – Effective length in km.
Examples
>>> round(get_fiber("SMF").effective_length_km(80.0), 3) 21.169 >>> round(FiberSpec(0.0).effective_length_km(80.0), 3) 80.0
- get_fiber(standard: str, **kwargs: Any) FiberSpec[source]#
Return a catalog fibre by name.
- Parameters:
standard (str) – Entry name; see
available_fibers().**kwargs – Forwarded to the entry factory.
- Raises:
KeyError – If the name is not in the catalog.
Examples
>>> get_fiber("SMF").cd_coefficient 17.0
- register_fiber(name: str)[source]#
Register a catalog entry; users can add their own fibres.
- Parameters:
name (str) – Name the factory answers to in
get_fiber().
Examples
>>> @register_fiber("LAB") ... def _lab(): ... return FiberSpec(0.19, gamma=1.2, standard="LAB", ... reference="bench") >>> get_fiber("LAB").alpha_dB 0.19
- available_fibers() list[str][source]#
Names accepted by
get_fiber().- Returns:
list of str – Registered names, sorted.
Examples
>>> available_fibers() ['DCF', 'NZDSF', 'SMF']