Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Ok-landscape
GitHub Repository: Ok-landscape/computational-pipeline
Path: blob/main/latex-templates/templates/optics/fiber_modes.tex
51 views
unlisted
1
\documentclass[a4paper, 11pt]{article}
2
\usepackage[utf8]{inputenc}
3
\usepackage[T1]{fontenc}
4
\usepackage{amsmath, amssymb}
5
\usepackage{graphicx}
6
\usepackage{siunitx}
7
\usepackage{booktabs}
8
\usepackage[makestderr]{pythontex}
9
10
\title{Optics: Optical Fiber Mode Analysis}
11
\author{Computational Science Templates}
12
\date{\today}
13
14
\begin{document}
15
\maketitle
16
17
\section{Introduction}
18
Optical fibers guide light through total internal reflection. The number and characteristics of guided modes depend on the fiber parameters including core radius, refractive indices, and wavelength. This analysis examines single-mode and multi-mode fiber behavior, mode field characteristics, dispersion properties, and bend loss effects.
19
20
\section{Mathematical Framework}
21
22
\subsection{Normalized Frequency (V-number)}
23
The V-number determines the number of modes:
24
\begin{equation}
25
V = \frac{2\pi a}{\lambda}\sqrt{n_1^2 - n_2^2} = \frac{2\pi a}{\lambda} \cdot NA
26
\end{equation}
27
28
For step-index fiber, the number of modes is approximately:
29
\begin{equation}
30
N \approx \frac{V^2}{2}
31
\end{equation}
32
33
Single-mode condition: $V < 2.405$ (LP$_{01}$ mode only)
34
35
\subsection{LP Mode Characteristic Equation}
36
The characteristic equation for LP$_{lm}$ modes:
37
\begin{equation}
38
u \frac{J_{l\pm 1}(u)}{J_l(u)} = \pm w \frac{K_{l\pm 1}(w)}{K_l(w)}
39
\end{equation}
40
41
where $u = a\sqrt{k_0^2 n_1^2 - \beta^2}$, $w = a\sqrt{\beta^2 - k_0^2 n_2^2}$, and $u^2 + w^2 = V^2$.
42
43
\subsection{Mode Field Diameter}
44
The Marcuse approximation for mode field diameter:
45
\begin{equation}
46
\frac{w}{a} = 0.65 + \frac{1.619}{V^{3/2}} + \frac{2.879}{V^6}
47
\end{equation}
48
49
\subsection{Dispersion}
50
Total dispersion in single-mode fiber:
51
\begin{equation}
52
D_{total} = D_M + D_W = -\frac{\lambda}{c}\frac{d^2 n}{d\lambda^2}
53
\end{equation}
54
55
\section{Environment Setup}
56
\begin{pycode}
57
import numpy as np
58
from scipy.special import jv, kv, jn_zeros
59
from scipy.optimize import brentq
60
import matplotlib.pyplot as plt
61
plt.rc('text', usetex=True)
62
plt.rc('font', family='serif')
63
64
def save_plot(filename, caption=""):
65
plt.savefig(filename, bbox_inches='tight', dpi=150)
66
print(r'\begin{figure}[htbp]')
67
print(r'\centering')
68
print(r'\includegraphics[width=0.95\textwidth]{' + filename + '}')
69
if caption:
70
print(r'\caption{' + caption + '}')
71
print(r'\end{figure}')
72
plt.close()
73
\end{pycode}
74
75
\section{V-Number and Mode Count Analysis}
76
\begin{pycode}
77
# Fiber parameters
78
a = 4e-6 # Core radius (m) for single-mode
79
a_mm = 25e-6 # Core radius (m) for multi-mode
80
n1 = 1.48 # Core refractive index
81
n2 = 1.46 # Cladding refractive index
82
NA = np.sqrt(n1**2 - n2**2)
83
delta = (n1 - n2) / n1 # Relative index difference
84
85
# Wavelength range
86
wavelengths = np.linspace(800e-9, 1700e-9, 200)
87
88
# V-number calculation
89
def V_number(a, wavelength, NA):
90
return 2 * np.pi * a * NA / wavelength
91
92
# Calculate V for both fibers
93
V_sm = V_number(a, wavelengths, NA)
94
V_mm = V_number(a_mm, wavelengths, NA)
95
96
# Number of modes (approximate)
97
N_modes_mm = V_mm**2 / 2
98
99
# Mode field diameter (Marcuse approximation)
100
def MFD(a, V):
101
return 2 * a * (0.65 + 1.619/V**1.5 + 2.879/V**6)
102
103
MFD_sm = MFD(a, V_sm)
104
105
# Cutoff wavelength for single-mode operation
106
lambda_cutoff = 2 * np.pi * a * NA / 2.405
107
108
# Create plots
109
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
110
111
# Plot 1: V-number vs wavelength
112
axes[0, 0].plot(wavelengths*1e9, V_sm, 'b-', linewidth=2, label=f'Single-mode (a={a*1e6:.0f}$\\mu$m)')
113
axes[0, 0].plot(wavelengths*1e9, V_mm/10, 'r-', linewidth=2, label=f'Multi-mode (a={a_mm*1e6:.0f}$\\mu$m, /10)')
114
axes[0, 0].axhline(y=2.405, color='gray', linestyle='--', alpha=0.7, label='SM cutoff')
115
axes[0, 0].set_xlabel('Wavelength (nm)')
116
axes[0, 0].set_ylabel('V-number')
117
axes[0, 0].set_title('Normalized Frequency')
118
axes[0, 0].legend(fontsize=8)
119
axes[0, 0].grid(True, alpha=0.3)
120
121
# Plot 2: Number of modes
122
axes[0, 1].semilogy(wavelengths*1e9, N_modes_mm, 'r-', linewidth=2)
123
axes[0, 1].set_xlabel('Wavelength (nm)')
124
axes[0, 1].set_ylabel('Number of Modes')
125
axes[0, 1].set_title('Multi-mode Fiber Mode Count')
126
axes[0, 1].grid(True, alpha=0.3, which='both')
127
128
# Plot 3: Mode field diameter
129
axes[1, 0].plot(wavelengths*1e9, MFD_sm*1e6, 'g-', linewidth=2)
130
axes[1, 0].axhline(y=2*a*1e6, color='gray', linestyle='--', alpha=0.7, label='Core diameter')
131
axes[1, 0].set_xlabel('Wavelength (nm)')
132
axes[1, 0].set_ylabel('MFD ($\\mu$m)')
133
axes[1, 0].set_title('Mode Field Diameter')
134
axes[1, 0].legend()
135
axes[1, 0].grid(True, alpha=0.3)
136
137
# Plot 4: NA vs wavelength (constant for step-index)
138
wavelength_array = np.linspace(800, 1700, 100)
139
NA_array = NA * np.ones_like(wavelength_array)
140
acceptance_angle = np.arcsin(NA) * 180 / np.pi
141
axes[1, 1].plot(wavelength_array, NA_array, 'purple', linewidth=2, label=f'NA = {NA:.3f}')
142
axes[1, 1].axhline(y=NA, color='gray', linestyle='--', alpha=0.5)
143
axes[1, 1].set_xlabel('Wavelength (nm)')
144
axes[1, 1].set_ylabel('Numerical Aperture')
145
axes[1, 1].set_title(f'NA and Acceptance Angle ($\\theta_a = {acceptance_angle:.1f}^\\circ$)')
146
axes[1, 1].legend()
147
axes[1, 1].grid(True, alpha=0.3)
148
axes[1, 1].set_ylim([0, 0.4])
149
150
plt.tight_layout()
151
save_plot('fiber_v_number.pdf', 'V-number, mode count, and MFD analysis for step-index fibers.')
152
\end{pycode}
153
154
\section{LP Mode Profiles and Characteristic Equation}
155
\begin{pycode}
156
# Solve LP mode characteristic equation
157
def lp_characteristic(u, V, l):
158
"""Characteristic equation for LP modes."""
159
if u <= 0 or u >= V:
160
return np.inf
161
w = np.sqrt(V**2 - u**2)
162
if w <= 0:
163
return np.inf
164
165
# Handle Bessel function edge cases
166
try:
167
if l == 0:
168
lhs = u * jv(1, u) / jv(0, u)
169
else:
170
lhs = u * jv(l-1, u) / jv(l, u) - l
171
rhs = -w * kv(l-1, w) / kv(l, w) - l
172
return lhs - rhs
173
except:
174
return np.inf
175
176
# Find modes for V = 5
177
V_test = 5.0
178
modes_found = []
179
180
for l in range(10): # Azimuthal mode number
181
# Find zeros of Bessel function to bracket solutions
182
zeros = jn_zeros(l, 10)
183
u_brackets = [0.01] + list(zeros[zeros < V_test])
184
185
m = 1 # Radial mode number
186
for i in range(len(u_brackets) - 1):
187
try:
188
u_low, u_high = u_brackets[i], u_brackets[i+1]
189
if u_high > V_test - 0.01:
190
u_high = V_test - 0.01
191
192
# Check for sign change
193
f_low = lp_characteristic(u_low + 0.01, V_test, l)
194
f_high = lp_characteristic(u_high - 0.01, V_test, l)
195
196
if f_low * f_high < 0:
197
u_sol = brentq(lp_characteristic, u_low + 0.01, u_high - 0.01,
198
args=(V_test, l))
199
w_sol = np.sqrt(V_test**2 - u_sol**2)
200
beta_norm = w_sol / V_test
201
modes_found.append((l, m, u_sol, w_sol, beta_norm))
202
m += 1
203
except:
204
pass
205
206
# Generate mode profiles
207
r = np.linspace(0, 3*a, 300)
208
rho = r / a
209
210
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
211
212
# Plot selected LP mode intensity profiles
213
mode_colors = ['blue', 'red', 'green', 'orange', 'purple']
214
mode_names = ['LP$_{01}$', 'LP$_{11}$', 'LP$_{21}$', 'LP$_{02}$', 'LP$_{31}$']
215
216
# Gaussian approximation for LP01
217
w_mode = a * (0.65 + 1.619/V_test**1.5 + 2.879/V_test**6)
218
E_01 = np.exp(-(r/w_mode)**2)
219
220
# Higher order mode approximations
221
E_11 = (r/a) * np.exp(-(r/(1.2*w_mode))**2)
222
E_21 = (r/a)**2 * np.exp(-(r/(1.4*w_mode))**2)
223
E_02 = (1 - 2*(r/w_mode)**2) * np.exp(-(r/w_mode)**2)
224
E_31 = (r/a)**3 * np.exp(-(r/(1.6*w_mode))**2)
225
226
mode_profiles = [E_01, E_11, E_21, E_02, E_31]
227
228
# Plot 1: Intensity profiles
229
for i, (E, name, color) in enumerate(zip(mode_profiles[:4], mode_names[:4], mode_colors[:4])):
230
I = np.abs(E)**2
231
I = I / np.max(I)
232
axes[0, 0].plot(r*1e6, I, color=color, linewidth=2, label=name)
233
234
axes[0, 0].axvline(x=a*1e6, color='gray', linestyle='--', alpha=0.7, label='Core edge')
235
axes[0, 0].set_xlabel('Radius ($\\mu$m)')
236
axes[0, 0].set_ylabel('Intensity (normalized)')
237
axes[0, 0].set_title(f'LP Mode Intensity Profiles (V = {V_test})')
238
axes[0, 0].legend(fontsize=8)
239
axes[0, 0].grid(True, alpha=0.3)
240
241
# Plot 2: 2D mode pattern for LP11
242
theta = np.linspace(0, 2*np.pi, 100)
243
R, THETA = np.meshgrid(r[:100], theta)
244
X = R * np.cos(THETA)
245
Y = R * np.sin(THETA)
246
247
# LP11 has cos(theta) angular dependence
248
E_11_2d = (R/a) * np.exp(-(R/(1.2*w_mode))**2) * np.cos(THETA)
249
I_11_2d = np.abs(E_11_2d)**2
250
251
im = axes[0, 1].pcolormesh(X*1e6, Y*1e6, I_11_2d, cmap='hot', shading='auto')
252
circle = plt.Circle((0, 0), a*1e6, fill=False, color='white', linestyle='--')
253
axes[0, 1].add_patch(circle)
254
axes[0, 1].set_xlabel('x ($\\mu$m)')
255
axes[0, 1].set_ylabel('y ($\\mu$m)')
256
axes[0, 1].set_title('LP$_{11}$ Mode 2D Pattern')
257
axes[0, 1].set_aspect('equal')
258
259
# Plot 3: b-V diagram (normalized propagation constant)
260
V_range = np.linspace(0.5, 8, 200)
261
b_values = {}
262
263
# Approximate b-V curves for LP modes
264
# b = (beta/k0 - n2)/(n1 - n2) = (1 - (u/V)^2)
265
for V in V_range:
266
for l in range(4):
267
# Simple approximation: cutoff at V = 2.405 * sqrt(l+1)
268
V_cutoff = 2.405 * np.sqrt(l + 0.5) if l > 0 else 0
269
if V > V_cutoff:
270
# Approximate b value
271
if l == 0:
272
b = (1.1428 - 0.996/V)**2 if V > 1 else 0.1 * V**2
273
else:
274
x = (V - V_cutoff) / V_cutoff if V_cutoff > 0 else V
275
b = x**2 / (1 + x**2)
276
277
if l not in b_values:
278
b_values[l] = {'V': [], 'b': []}
279
b_values[l]['V'].append(V)
280
b_values[l]['b'].append(b)
281
282
for l, data in b_values.items():
283
axes[1, 0].plot(data['V'], data['b'], linewidth=2, label=f'LP$_{{{l}m}}$')
284
285
axes[1, 0].axvline(x=2.405, color='gray', linestyle='--', alpha=0.5, label='SM cutoff')
286
axes[1, 0].set_xlabel('V-number')
287
axes[1, 0].set_ylabel('Normalized propagation constant $b$')
288
axes[1, 0].set_title('b-V Diagram')
289
axes[1, 0].legend(fontsize=8)
290
axes[1, 0].grid(True, alpha=0.3)
291
axes[1, 0].set_xlim([0, 8])
292
axes[1, 0].set_ylim([0, 1])
293
294
# Plot 4: Mode confinement factor
295
V_conf = np.linspace(1, 6, 100)
296
# Confinement factor: fraction of power in core
297
Gamma = 1 - np.exp(-2 * (V_conf/2.405)**2)
298
299
axes[1, 1].plot(V_conf, Gamma * 100, 'b-', linewidth=2)
300
axes[1, 1].axhline(y=86.5, color='gray', linestyle='--', alpha=0.5, label='86.5\\% (Gaussian)')
301
axes[1, 1].set_xlabel('V-number')
302
axes[1, 1].set_ylabel('Confinement factor (\\%)')
303
axes[1, 1].set_title('Power Confinement in Core')
304
axes[1, 1].legend()
305
axes[1, 1].grid(True, alpha=0.3)
306
307
plt.tight_layout()
308
save_plot('fiber_mode_profiles.pdf', 'LP mode profiles, b-V diagram, and confinement analysis.')
309
\end{pycode}
310
311
\section{Dispersion Analysis}
312
\begin{pycode}
313
# Material dispersion (Sellmeier equation for silica)
314
def sellmeier_n(wavelength):
315
"""Refractive index of fused silica using Sellmeier equation."""
316
lam = wavelength * 1e6 # Convert to microns
317
n_sq = 1 + 0.6961663 * lam**2 / (lam**2 - 0.0684043**2)
318
n_sq += 0.4079426 * lam**2 / (lam**2 - 0.1162414**2)
319
n_sq += 0.8974794 * lam**2 / (lam**2 - 9.896161**2)
320
return np.sqrt(n_sq)
321
322
def material_dispersion(wavelength):
323
"""Material dispersion D_M in ps/(nm*km)."""
324
lam = wavelength * 1e6 # microns
325
c = 3e8 # m/s
326
327
# Numerical second derivative
328
dlam = 1e-9
329
n_plus = sellmeier_n(wavelength + dlam)
330
n_minus = sellmeier_n(wavelength - dlam)
331
n_center = sellmeier_n(wavelength)
332
333
d2n_dlam2 = (n_plus - 2*n_center + n_minus) / (dlam**2)
334
335
# D_M = -(lambda/c) * d2n/dlambda2
336
D_M = -lam * 1e-6 / c * d2n_dlam2 * 1e6 # Convert to ps/(nm*km)
337
return D_M
338
339
# Waveguide dispersion (approximate)
340
def waveguide_dispersion(wavelength, a, n1, n2):
341
"""Waveguide dispersion D_W in ps/(nm*km)."""
342
V = V_number(a, wavelength, np.sqrt(n1**2 - n2**2))
343
344
# Approximate second derivative of Vb
345
# D_W = -(n2 * delta / c * lambda) * V * d2(Vb)/dV2
346
delta = (n1 - n2) / n1
347
c = 3e8
348
349
# Simplified approximation
350
d2Vb_dV2 = 0.08 + 0.549 * (2.834 - V)**2
351
D_W = n2 * delta / c * wavelength * V * d2Vb_dV2 * 1e6
352
353
return D_W
354
355
# Wavelength range for dispersion
356
wavelengths_disp = np.linspace(1.0e-6, 1.7e-6, 200)
357
358
# Calculate dispersions
359
D_M = np.array([material_dispersion(lam) for lam in wavelengths_disp])
360
D_W = np.array([waveguide_dispersion(lam, a, n1, n2) for lam in wavelengths_disp])
361
D_total = D_M + D_W
362
363
# Find zero-dispersion wavelength
364
idx_zero = np.argmin(np.abs(D_total))
365
lambda_zero = wavelengths_disp[idx_zero]
366
367
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
368
369
# Plot 1: Material and waveguide dispersion
370
axes[0, 0].plot(wavelengths_disp*1e9, D_M, 'b-', linewidth=2, label='Material $D_M$')
371
axes[0, 0].plot(wavelengths_disp*1e9, D_W, 'r--', linewidth=2, label='Waveguide $D_W$')
372
axes[0, 0].plot(wavelengths_disp*1e9, D_total, 'k-', linewidth=2.5, label='Total $D$')
373
axes[0, 0].axhline(y=0, color='gray', linestyle='-', alpha=0.5)
374
axes[0, 0].axvline(x=lambda_zero*1e9, color='green', linestyle='--', alpha=0.7,
375
label=f'$\\lambda_0 = {lambda_zero*1e9:.0f}$ nm')
376
axes[0, 0].set_xlabel('Wavelength (nm)')
377
axes[0, 0].set_ylabel('Dispersion (ps/(nm$\\cdot$km))')
378
axes[0, 0].set_title('Chromatic Dispersion')
379
axes[0, 0].legend(fontsize=8)
380
axes[0, 0].grid(True, alpha=0.3)
381
382
# Plot 2: Pulse broadening vs fiber length
383
fiber_lengths = np.array([1, 10, 50, 100]) # km
384
delta_lambda = 0.1 # nm (source linewidth)
385
D_at_1550 = D_total[np.argmin(np.abs(wavelengths_disp - 1550e-9))]
386
387
pulse_broadening = np.abs(D_at_1550) * delta_lambda * fiber_lengths
388
389
axes[0, 1].bar(range(len(fiber_lengths)), pulse_broadening, color='steelblue', alpha=0.7)
390
axes[0, 1].set_xticks(range(len(fiber_lengths)))
391
axes[0, 1].set_xticklabels([f'{L} km' for L in fiber_lengths])
392
axes[0, 1].set_ylabel('Pulse broadening (ps)')
393
axes[0, 1].set_title(f'Dispersion at 1550 nm ($\\Delta\\lambda = {delta_lambda}$ nm)')
394
axes[0, 1].grid(True, alpha=0.3, axis='y')
395
396
# Plot 3: Refractive index vs wavelength
397
n_silica = np.array([sellmeier_n(lam) for lam in wavelengths_disp])
398
dn_dlambda = np.gradient(n_silica, wavelengths_disp)
399
400
ax3 = axes[1, 0]
401
ax3.plot(wavelengths_disp*1e9, n_silica, 'b-', linewidth=2)
402
ax3.set_xlabel('Wavelength (nm)')
403
ax3.set_ylabel('Refractive index $n$', color='b')
404
ax3.tick_params(axis='y', labelcolor='b')
405
ax3.set_title('Silica Refractive Index (Sellmeier)')
406
ax3.grid(True, alpha=0.3)
407
408
ax3b = ax3.twinx()
409
ax3b.plot(wavelengths_disp*1e9, dn_dlambda*1e9, 'r--', linewidth=2)
410
ax3b.set_ylabel('$dn/d\\lambda$ (nm$^{-1}$)', color='r')
411
ax3b.tick_params(axis='y', labelcolor='r')
412
413
# Plot 4: Group velocity dispersion parameter beta2
414
c = 3e8
415
# beta_2 = D * lambda^2 / (2*pi*c)
416
beta_2 = D_total * (wavelengths_disp * 1e9)**2 / (2 * np.pi * c) * 1e-3 # ps^2/km
417
418
axes[1, 1].plot(wavelengths_disp*1e9, beta_2, 'purple', linewidth=2)
419
axes[1, 1].axhline(y=0, color='gray', linestyle='-', alpha=0.5)
420
axes[1, 1].set_xlabel('Wavelength (nm)')
421
axes[1, 1].set_ylabel('$\\beta_2$ (ps$^2$/km)')
422
axes[1, 1].set_title('Group Velocity Dispersion')
423
axes[1, 1].grid(True, alpha=0.3)
424
425
plt.tight_layout()
426
save_plot('fiber_dispersion.pdf', 'Chromatic dispersion analysis and pulse broadening effects.')
427
\end{pycode}
428
429
\section{Bend Loss and Attenuation}
430
\begin{pycode}
431
# Bend loss calculation
432
def bend_loss_coefficient(wavelength, a, n1, n2, R_bend):
433
"""
434
Calculate bend loss coefficient (dB/turn) for single-mode fiber.
435
Uses Marcuse formula.
436
"""
437
V = V_number(a, wavelength, np.sqrt(n1**2 - n2**2))
438
w_mode = a * (0.65 + 1.619/V**1.5 + 2.879/V**6)
439
440
# Normalized parameters
441
delta = (n1 - n2) / n1
442
k0 = 2 * np.pi / wavelength
443
444
# Effective index approximation
445
n_eff = n1 * (1 - delta * (1.1428 - 0.996/V)**2)
446
447
# Bend loss coefficient (simplified)
448
gamma = np.sqrt(k0**2 * (n_eff**2 - n2**2))
449
450
# Marcuse formula (approximation)
451
alpha_bend = np.sqrt(np.pi / (2 * gamma * R_bend)) * np.exp(-4 * delta * gamma**3 * R_bend**2 / (3 * k0**2 * n_eff**2))
452
453
# Convert to dB per turn
454
loss_per_turn = 4.343 * 2 * np.pi * R_bend * alpha_bend
455
456
return loss_per_turn
457
458
# Bend radii range
459
R_bends = np.linspace(5e-3, 50e-3, 100) # 5 mm to 50 mm
460
461
# Calculate bend loss at different wavelengths
462
wavelengths_bend = [1310e-9, 1550e-9, 1625e-9]
463
colors_bend = ['blue', 'green', 'red']
464
465
fig, axes = plt.subplots(2, 2, figsize=(10, 8))
466
467
# Plot 1: Bend loss vs bend radius
468
for lam, color in zip(wavelengths_bend, colors_bend):
469
loss = []
470
for R in R_bends:
471
try:
472
l = bend_loss_coefficient(lam, a, n1, n2, R)
473
loss.append(min(l, 100)) # Cap at 100 dB
474
except:
475
loss.append(100)
476
axes[0, 0].semilogy(R_bends*1e3, loss, color=color, linewidth=2,
477
label=f'$\\lambda = {lam*1e9:.0f}$ nm')
478
479
axes[0, 0].set_xlabel('Bend radius (mm)')
480
axes[0, 0].set_ylabel('Bend loss (dB/turn)')
481
axes[0, 0].set_title('Bend Loss vs Radius')
482
axes[0, 0].legend()
483
axes[0, 0].grid(True, alpha=0.3, which='both')
484
axes[0, 0].set_ylim([1e-6, 100])
485
486
# Plot 2: Fiber attenuation spectrum
487
wavelengths_atten = np.linspace(800e-9, 1700e-9, 200)
488
489
# Typical silica fiber attenuation (empirical model)
490
def fiber_attenuation(wavelength):
491
"""Attenuation in dB/km for standard silica fiber."""
492
lam = wavelength * 1e6 # microns
493
494
# Rayleigh scattering
495
alpha_R = 0.75 / lam**4
496
497
# OH absorption peak at 1383 nm
498
alpha_OH = 0.5 * np.exp(-((lam - 1.383)**2) / (0.02)**2)
499
500
# IR absorption
501
alpha_IR = 0.01 * np.exp(lam - 1.5)
502
503
return alpha_R + alpha_OH + alpha_IR
504
505
attenuation = np.array([fiber_attenuation(lam) for lam in wavelengths_atten])
506
507
axes[0, 1].plot(wavelengths_atten*1e9, attenuation, 'b-', linewidth=2)
508
axes[0, 1].axvline(x=1310, color='green', linestyle='--', alpha=0.7, label='O-band')
509
axes[0, 1].axvline(x=1550, color='red', linestyle='--', alpha=0.7, label='C-band')
510
axes[0, 1].set_xlabel('Wavelength (nm)')
511
axes[0, 1].set_ylabel('Attenuation (dB/km)')
512
axes[0, 1].set_title('Fiber Attenuation Spectrum')
513
axes[0, 1].legend()
514
axes[0, 1].grid(True, alpha=0.3)
515
axes[0, 1].set_ylim([0, 3])
516
517
# Plot 3: Power budget calculation
518
link_length = np.linspace(0, 100, 100) # km
519
P_launch = 0 # dBm
520
alpha_1310 = fiber_attenuation(1310e-9)
521
alpha_1550 = fiber_attenuation(1550e-9)
522
523
P_1310 = P_launch - alpha_1310 * link_length
524
P_1550 = P_launch - alpha_1550 * link_length
525
526
axes[1, 0].plot(link_length, P_1310, 'g-', linewidth=2, label=f'1310 nm ($\\alpha = {alpha_1310:.2f}$ dB/km)')
527
axes[1, 0].plot(link_length, P_1550, 'r-', linewidth=2, label=f'1550 nm ($\\alpha = {alpha_1550:.2f}$ dB/km)')
528
axes[1, 0].axhline(y=-30, color='gray', linestyle='--', alpha=0.7, label='Receiver sensitivity')
529
axes[1, 0].set_xlabel('Link length (km)')
530
axes[1, 0].set_ylabel('Received power (dBm)')
531
axes[1, 0].set_title('Optical Power Budget')
532
axes[1, 0].legend(fontsize=8)
533
axes[1, 0].grid(True, alpha=0.3)
534
535
# Plot 4: Splice and connector loss budget
536
components = ['Launch', 'Connector', 'Splice 1', '10 km fiber', 'Splice 2', 'Connector', 'Received']
537
loss_values = [0, -0.5, -0.1, -2.0, -0.1, -0.5, 0]
538
cumulative_power = np.cumsum([P_launch] + loss_values)
539
540
axes[1, 1].bar(range(len(components)), cumulative_power[:-1], color='steelblue', alpha=0.7)
541
axes[1, 1].step(range(len(components)), cumulative_power[:-1], 'r-', linewidth=2, where='mid')
542
axes[1, 1].axhline(y=-30, color='gray', linestyle='--', alpha=0.7)
543
axes[1, 1].set_xticks(range(len(components)))
544
axes[1, 1].set_xticklabels(components, rotation=45, ha='right', fontsize=8)
545
axes[1, 1].set_ylabel('Power (dBm)')
546
axes[1, 1].set_title('Link Loss Budget')
547
axes[1, 1].grid(True, alpha=0.3, axis='y')
548
549
plt.tight_layout()
550
save_plot('fiber_attenuation.pdf', 'Bend loss, attenuation spectrum, and link power budget.')
551
\end{pycode}
552
553
\section{Results Summary}
554
\begin{pycode}
555
# Calculate values at key wavelengths
556
V_1310 = V_number(a, 1310e-9, NA)
557
V_1550 = V_number(a, 1550e-9, NA)
558
MFD_1310 = MFD(a, V_1310)
559
MFD_1550 = MFD(a, V_1550)
560
N_modes_mm_1550 = V_number(a_mm, 1550e-9, NA)**2 / 2
561
562
# Dispersion at 1550 nm
563
D_1550 = D_total[np.argmin(np.abs(wavelengths_disp - 1550e-9))]
564
565
# Attenuation
566
alpha_1310_val = fiber_attenuation(1310e-9)
567
alpha_1550_val = fiber_attenuation(1550e-9)
568
569
# Generate results table
570
print(r'\begin{table}[htbp]')
571
print(r'\centering')
572
print(r'\caption{Summary of Optical Fiber Parameters}')
573
print(r'\begin{tabular}{llcc}')
574
print(r'\toprule')
575
print(r'Parameter & Symbol & 1310 nm & 1550 nm \\')
576
print(r'\midrule')
577
print(f'V-number (SM) & $V$ & {V_1310:.2f} & {V_1550:.2f} \\\\')
578
print(f'Mode field diameter & MFD & {MFD_1310*1e6:.1f} $\\mu$m & {MFD_1550*1e6:.1f} $\\mu$m \\\\')
579
print(f'Attenuation & $\\alpha$ & {alpha_1310_val:.2f} dB/km & {alpha_1550_val:.2f} dB/km \\\\')
580
print(f'Dispersion & $D$ & -- & {D_1550:.1f} ps/(nm$\\cdot$km) \\\\')
581
print(r'\midrule')
582
print(f'Numerical aperture & NA & \\multicolumn{{2}}{{c}}{{{NA:.3f}}} \\\\')
583
print(f'Cutoff wavelength & $\\lambda_c$ & \\multicolumn{{2}}{{c}}{{{lambda_cutoff*1e9:.0f} nm}} \\\\')
584
print(f'Zero-dispersion & $\\lambda_0$ & \\multicolumn{{2}}{{c}}{{{lambda_zero*1e9:.0f} nm}} \\\\')
585
print(f'MM fiber modes & $N$ & \\multicolumn{{2}}{{c}}{{$\\approx$ {N_modes_mm_1550:.0f}}} \\\\')
586
print(r'\bottomrule')
587
print(r'\end{tabular}')
588
print(r'\end{table}')
589
\end{pycode}
590
591
\section{Statistical Summary}
592
\begin{itemize}
593
\item \textbf{Core refractive index}: $n_1 = $ \py{f"{n1:.2f}"}
594
\item \textbf{Cladding refractive index}: $n_2 = $ \py{f"{n2:.2f}"}
595
\item \textbf{Core radius (SM)}: $a = $ \py{f"{a*1e6:.0f}"} $\mu$m
596
\item \textbf{Core radius (MM)}: $a = $ \py{f"{a_mm*1e6:.0f}"} $\mu$m
597
\item \textbf{Relative index difference}: $\Delta = $ \py{f"{delta*100:.2f}"}\%
598
\item \textbf{Acceptance angle}: $\theta_a = $ \py{f"{np.arcsin(NA)*180/np.pi:.1f}"}$^\circ$
599
\item \textbf{Minimum attenuation at}: \py{f"{wavelengths_atten[np.argmin(attenuation)]*1e9:.0f}"} nm
600
\end{itemize}
601
602
\section{Conclusion}
603
Single-mode fibers require $V < 2.405$, achieved through small core diameters around 8-10 $\mu$m. The mode field extends beyond the core into the cladding, with the MFD increasing with wavelength. Chromatic dispersion arises from both material and waveguide contributions, with a zero-dispersion wavelength around 1310 nm for standard fiber. Multi-mode fibers support many modes that travel different paths, causing modal dispersion. The 1550 nm C-band offers minimum attenuation (0.2 dB/km) and is preferred for long-haul telecommunications, while dispersion-shifted fibers move the zero-dispersion wavelength to 1550 nm for optimized performance.
604
605
\end{document}
606
607