Before we close, three short Python computations to make the concepts concrete.
12.1 Computing the link budget for a 100 km coherent link
python
import numpy as np
# Transmitter
P_tx_dBm = 1.0 # launch power per channel (0 dBm typical)
# Fiber
alpha_dB_per_km = 0.20 # standard SMF at 1550 nm
L_km = 100.0
fiber_loss = alpha_dB_per_km * L_km
# Connectors and splices
N_connectors = 4
loss_per_connector = 0.30
N_splices = 8
loss_per_splice = 0.05
# Margin
margin = 3.0
P_rx_dBm = (
P_tx_dBm
- fiber_loss
- N_connectors * loss_per_connector
- N_splices * loss_per_splice
- margin
)
print(f"Fiber loss: {fiber_loss:5.2f} dB")
print(f"Connector loss: {N_connectors*loss_per_connector:5.2f} dB")
print(f"Splice loss: {N_splices*loss_per_splice:5.2f} dB")
print(f"Margin: {margin:5.2f} dB")
print(f"Received power: {P_rx_dBm:5.2f} dBm")
# A 100G coherent receiver needs around -18 dBm; 200G coherent needs -15 dBm.Run it: Received power: -22.6 dBm. With a 100G coherent receiver (sensitivity around -25 dBm), this works with 2.4 dB to spare. With a 200G receiver (-18 dBm), it fails by 4.6 dB and we need an EDFA.
12.2 Plotting fiber attenuation versus wavelength
python
import numpy as np
import matplotlib.pyplot as plt
lam_nm = np.linspace(800, 1700, 901)
lam_um = lam_nm / 1000.0
# Rayleigh scattering: ~1/lambda^4
A_rayleigh_um4 = 0.85 # empirical coefficient (dB/km * um^4)
rayleigh = A_rayleigh_um4 / (lam_um**4)
# IR absorption tail
ir = 7.81e11 * np.exp(-48.48 / lam_um)
# UV absorption tail (small in this band)
uv = 154 * np.exp(-4.63 / lam_um)
# OH peak around 1383 nm
oh_peak_nm = 1383.0
oh = 2.0 * np.exp(-((lam_nm - oh_peak_nm) / 12.0)**2)
total = rayleigh + ir + uv + oh
plt.figure(figsize=(7,4))
plt.plot(lam_nm, total, 'k', lw=2, label='total')
plt.plot(lam_nm, rayleigh, '--', label='Rayleigh ~1/λ⁴')
plt.plot(lam_nm, ir, '--', label='IR tail')
plt.plot(lam_nm, oh, '--', label='OH⁻ peak')
plt.axvline(850, color='gold', alpha=0.4)
plt.axvline(1310, color='skyblue', alpha=0.4)
plt.axvline(1550, color='coral', alpha=0.4)
plt.xlabel('wavelength (nm)')
plt.ylabel('attenuation (dB/km)')
plt.ylim(0, 4)
plt.legend()
plt.title('Silica fiber attenuation vs wavelength')
plt.grid(True, alpha=0.3)
plt.savefig('fiber_attenuation.png', dpi=150)This reproduces the standard textbook curve and shows visibly that the minimum is right around 1550 nm.
12.3 Simulating an eye diagram with chromatic dispersion
python
import numpy as np
import matplotlib.pyplot as plt
# Setup
fs = 100e9 # 100 GS/s sampling
T_bit = 1 / 10e9 # 10 Gbps
samples_per_bit = int(fs * T_bit)
n_bits = 4096
bits = np.random.randint(0, 2, n_bits)
# NRZ baseband with pulse shaping (rectangular for simplicity)
pulse = np.ones(samples_per_bit)
signal = np.repeat(bits, samples_per_bit).astype(float)
# Modulate onto an "optical" complex baseband
optical = signal.astype(complex)
# Apply chromatic dispersion: multiply spectrum by exp(-j*beta2*omega^2*L/2)
N = len(optical)
freqs = np.fft.fftfreq(N, 1/fs)
omega = 2 * np.pi * freqs
D = 17e-6 # 17 ps/nm/km in s/m^2
lam = 1550e-9
c = 3e8
beta2 = -D * lam**2 / (2 * np.pi * c) # in s^2/m
L = 80e3 # 80 km
H = np.exp(-1j * beta2 * omega**2 * L / 2)
disp_optical = np.fft.ifft(np.fft.fft(optical) * H)
# Direct-detect: square-law photodiode
detected = np.abs(disp_optical)**2
# Build eye diagram by overlapping bit windows
eye_window = 2 * samples_per_bit
plt.figure(figsize=(7,4))
for i in range(100, n_bits - 100):
start = i * samples_per_bit
plt.plot(np.arange(eye_window), detected[start:start+eye_window],
'b', alpha=0.05)
plt.xlabel('sample index within 2-bit window')
plt.ylabel('photocurrent (a.u.)')
plt.title('Eye diagram after 80 km of standard SMF (10 Gbps NRZ)')
plt.grid(True, alpha=0.3)
plt.savefig('eye.png', dpi=150)Run with : a fully open eye. Run with km of standard SMF at 1550 nm: a clearly closing eye, with edges blurred and the decision margin visibly reduced. Run with km: the eye is essentially closed, and direct detection no longer works without dispersion compensation. This is exactly the regime where coherent detection plus DSP becomes mandatory.