Gaussian Beam Propagation
KrakenOS now exposes a lightweight Gaussian beam propagation path on top of the
same paraxial matrices used by system.ParaxMatrices() and
Actions -> Paraxial Matrix Report. It is intended for first-order laser
layout work: waist size, beam radius, divergence, Rayleigh range, wavefront
radius, Gouy phase, and CSV export at every paraxial step.
Beam fundamentals
A monochromatic Gaussian beam in homogeneous medium is fully specified by its beam radius \(w(z)\), wavefront radius of curvature \(R(z)\), and Gouy phase \(\psi(z)\), all measured from the waist position \(z_{w}\):
with the Rayleigh range and far-field half-divergence:
Here
\(w_{0}\) is the waist radius (1/e² field amplitude),
\(z_{w}\) is the waist position along the optical axis,
\(z_{R}\) is the Rayleigh range — the distance from the waist at which the beam area doubles (\(w(z_{w} + z_{R}) = w_{0}\sqrt{2}\)),
\(R(z)\) is the radius of curvature of the wavefront (\(R \to \infty\) at the waist; \(R \to z - z_{w}\) in the far field),
\(\psi(z)\) is the Gouy phase — an axial phase slip of \(\pi\) rad between the two far fields,
\(\lambda\) is the vacuum wavelength,
\(n\) is the refractive index of the current medium,
\(M^{2}\) is the beam-quality factor (1 for an ideal TEM₀₀).
The amber envelope is \(\pm w(z)\). The waist sits where the envelope pinches. \(z_R\) is the distance to where the envelope has expanded by \(\sqrt{2}\); the dashed grey lines are the far-field asymptotes that open at the half-angle \(\theta\).
Worked example. Take \(\lambda = 0.6328\) µm (HeNe), \(n = 1\), \(M^{2} = 1\), \(w_{0} = 0.5\) mm.
\(z_{R} = \pi \cdot 1 \cdot (0.5)^{2} / 0.0006328 \approx 1241\) mm.
\(\theta = 0.0006328 / (\pi \cdot 0.5) \approx 4.03 \cdot 10^{-4}\) rad \(= 0.403\) mrad (full divergence \(\Theta_{\mathrm{full}} = 0.806\) mrad).
At \(z - z_{w} = z_{R}\): \(w = w_{0}\sqrt{2} = 0.707\) mm, \(R = z_{R}\,(1 + 1) = 2482\) mm, \(\psi = \arctan(1) = \pi/4 \approx 0.785\) rad.
At \(z - z_{w} = 2\,z_{R}\): \(w = w_{0}\sqrt{5} = 1.118\) mm, \(R = 2z_{R}(1 + 1/4) = 3103\) mm.
Far-field beam diameter at 10 m: \(2\,w(10\,\mathrm{m}) \approx 2\,w_{0}\,\sqrt{1 + (10000/1241)^{2}} \approx 8.06\) mm — i.e. essentially the far-field cone \(2\theta \cdot z = 0.806\,\mathrm{mrad} \cdot 10\,\mathrm{m} = 8.06\) mm.
KrakenOS code:
import numpy as np
import KrakenOS as Kos
lam_um = 0.6328
w0_mm = 0.5
n = 1.0
M2 = 1.0
lam_mm = lam_um * 1e-3
zR = np.pi * n * w0_mm**2 / (M2 * lam_mm)
theta = M2 * lam_mm / (np.pi * n * w0_mm)
print(f"zR = {zR:.2f} mm theta_half = {theta*1e3:.3f} mrad")
# Trace q through a 100-mm propagation step using the q-transform:
beam = Kos.GaussianBeamInput(wavelength_um=lam_um,
waist_radius_mm=w0_mm,
waist_offset_mm=0.0,
m2=M2)
z = 100.0 # mm from waist
q_in = complex(0.0, zR) # q at the waist
A, B, C, D = 1.0, z, 0.0, 1.0 # free-space propagation matrix
q_out = (A*q_in + B) / (C*q_in + D)
w_z = np.sqrt(-lam_mm / (np.pi * (1/q_out).imag))
R_z = 1.0 / (1/q_out).real
psi_z = np.arctan2(q_out.real, q_out.imag)
print(f"at z = {z:.0f} mm: w = {w_z*1e3:.3f} um, R = {R_z:.1f} mm, "
f"Gouy = {psi_z:.4f} rad")
Complex beam parameter and ABCD transformation
The implementation uses the conventional complex beam parameter:
where A, B, C, and D are the step matrix values in the
(height, angle) convention. The single complex number encodes both
the beam radius and the wavefront curvature through
KrakenOS refraction matrices include refractive index transitions, so a flat air-to-glass interface scales the Rayleigh range correctly.
q is a single complex number that carries both
\(R(z)\) (its inverse real part) and \(w(z)\) (via the imaginary
part). It transforms by the same ABCD matrix that propagates paraxial
rays.
Worked example. Pass the HeNe beam above (\(q_{0} = 0 + i\,z_{R} = i\,1241\) mm) through a 100-mm free-space step and then through a thin lens of focal length \(f = 80\) mm.
Free-space propagation matrix: \((A, B, C, D) = (1, 100, 0, 1)\). So \(q_{1} = q_{0} + 100 = 100 + i\,1241\) mm. \(w(z = 100) = \sqrt{|q_{1}|^{2} \cdot \lambda / (\pi z_{R})} = 0.5\,\sqrt{1 + (100/1241)^{2}} \approx 0.502\) mm.
Thin-lens matrix: \((A, B, C, D) = (1, 0,\, -1/f,\, 1) = (1, 0, -0.0125, 1)\). Then \(q_{2} = q_{1} / (1 - q_{1}/f) = (100 + 1241i) / (1 - (100 + 1241i)/80) = (100 + 1241i) / (-0.25 - 15.5125 i)\) \(\approx -3.20 - 79.7\,i\) mm.
Read out: new waist offset = \(\mathrm{Re}(q_{2}) = -3.20\) mm (waist is 3.2 mm before the lens plane, i.e. on the source side), new Rayleigh range = \(\mathrm{Im}(q_{2}) = 79.7\) mm, so \(w_{0}' = \sqrt{\lambda\,z_{R}' / \pi} = \sqrt{0.0006328 \cdot 79.7 / \pi} \approx 0.127\) mm — the lens has refocused the beam to a tight new waist.
KrakenOS code:
# Same setup as the previous block; demonstrate the ABCD chain.
def step(q, A, B, C, D):
return (A*q + B) / (C*q + D)
q = complex(0.0, zR)
q1 = step(q, 1.0, 100.0, 0.0, 1.0) # 100 mm air
q2 = step(q1, 1.0, 0.0, -1.0/80.0, 1.0) # thin lens f=80 mm
def w_R(q, lam, n=1.0):
w = np.sqrt(-lam / (np.pi * (1/q).imag * n))
R = 1.0 / (1/q).real if (1/q).real != 0 else np.inf
return w, R
for label, qq in [("q_in", q), ("after 100 mm", q1), ("after lens", q2)]:
w, R = w_R(qq, lam_mm)
print(f"{label:<14} q = {qq.real:+.3f} {qq.imag:+.3f}i mm "
f"w = {w*1e3:.2f} um R = {R:+.1f} mm")
Input conventions
All distances are in millimeters. Wavelength is in micrometers, matching the rest of KrakenOS.
Source X/Y/ZandSource L/M/NThe Gaussian source can be launched from a physical origin and chief-ray direction.
Source L/M/Nare normalized direction cosines. The traced representative rays follow that direction, so the source can be separated from theObjectreference row for beam-splitter geometry. The amber q-envelope overlay is intentionally limited to centered+Zparaxial layouts; for tilted or folded Gaussian systems, use the traced rays and the Gaussian Beam Report until the future non-sequential astigmatic q model is implemented.GB input modeWaist + offsetis the direct q-parameter workflow.Diameter + divergenceis the laser-datasheet workflow: enter the beam diameter at the source/reference plane and the full far-field divergence, then KrakenOS back-calculates the equivalent waist radius and waist location.Cone half-angle [deg]This is not the Gaussian divergence field. It belongs to geometric random source models such as
Random point coneand random area sources. Edit it inScene Source Manager.... It is a half-angle in degrees, so the full geometric cone angle is twice the entered value.waist_radius_mmThe 1/e^2 Gaussian field radius at the input waist.
waist_offset_mmThe signed real part of the input
qparameter. A value of0means the waist is located exactly at the first paraxial input plane. A positive value means the input plane is downstream of the waist. A negative value means the waist is downstream of the input plane.m2Beam quality factor.
m2=1is diffraction-limited. Larger values increase the effective wavelength used by the q-parameter report.
Datasheet diameter/divergence flow
Laser manufacturers often specify a beam diameter at the laser output and a full-angle divergence. Use this flow for beam expanders and collimators:
Choose
Source model -> Gaussian beam.Set
GB input mode -> Diameter + divergence.Enter
GB diameter [mm]as the 1/e^2 beam diameter at the source plane.Enter
GB full div [mrad]as the full far-field divergence angle.Choose
GB waist side.Waist before sourceis the normal diverging laser-output case.Waist after sourcerepresents a converging beam.Set
GB M2if the laser is not diffraction-limited.Click
Update. The UI computes the equivalentw0and waist offset, traces representative rays, and draws the amber 1/e^2 q-envelope.
In Gaussian beam mode, the Source panel shows the laser-datasheet inputs
and hides irrelevant pupil/field controls.
The calculation uses:
where
\(\Theta_{\mathrm{full}}\) is the full-angle far-field divergence (datasheet value, mrad → rad),
\(\theta\) is the corresponding half-divergence,
\(w_{0}\) is the back-calculated waist radius (mm),
\(z_{R}\) is the Rayleigh range implied by that \(w_{0}\),
\(w\) is half the specified beam diameter at the source plane (\(w = D/2\)),
\(z\) is the signed offset from the source plane to the waist: positive when the waist sits before the source plane (
Waist before source), negative when it sits after it.
If \(w < w_{0}\) the requested (D, Θ_full) pair is unphysical and the UI flags an invalid Gaussian source input.
The source plane defines where you measure D; the waist sits an offset distance away — KrakenOS solves for that distance from the diameter/divergence pair.
Worked example. Datasheet entry for a small 650-nm visible diode: \(D = 1.0\) mm, \(\Theta_{\mathrm{full}} = 2.0\) mrad, \(M^{2} = 1\), \(n = 1\).
\(\theta = 2.0/2 = 1.0\) mrad \(= 10^{-3}\) rad.
\(w_{0} = M^{2}\,\lambda / (\pi\,n\,\theta) = 1 \cdot 0.00065 / (\pi \cdot 1 \cdot 10^{-3}) \approx 0.2069\) mm.
\(z_{R} = \pi\,n\,w_{0}^{2}/(M^{2}\,\lambda) = \pi \cdot 1 \cdot 0.2069^{2}/0.00065 \approx 206.9\) mm.
Source-plane radius \(w = D/2 = 0.5\) mm.
Waist offset: \(z = z_{R}\,\sqrt{(w/w_{0})^{2} - 1} = 206.9\,\sqrt{(0.5/0.2069)^{2} - 1} = 206.9\,\sqrt{4.836} \approx 455.1\) mm.
So the laser-output plane is ~455 mm downstream of the implied waist.
KrakenOS code:
beam = Kos.gaussian_beam_from_diameter_divergence(
wavelength_um=0.650,
beam_diameter_mm=1.0,
full_divergence_mrad=2.0,
m2=1.0,
waist_after_input=False, # waist before source plane
)
print(f"w0 = {beam.waist_radius_mm*1e3:.2f} um")
print(f"waist offset= {beam.waist_offset_mm:.2f} mm")
# Compare against the analytic value:
lam = 0.650e-3
theta = 1.0e-3
w0 = 1.0 * lam / (np.pi * theta)
zR = np.pi * w0**2 / lam
z = zR * np.sqrt((0.5/w0)**2 - 1)
print(f"analytic w0 = {w0*1e3:.2f} um z = {z:.2f} mm")
Report columns
Re(q)andIm(q)Complex beam parameter after the paraxial step.
Im(q)is the local Rayleigh range in the current medium.wand2wGaussian beam radius and diameter at the current step.
RwfWavefront radius.
infmeans a flat wavefront at the waist.w0Waist radius implied by the current
qstate in the current medium.Waist offsetDistance from the current step plane to the waist. Positive values mean the waist is still downstream of the current step.
DivFar-field half-angle divergence in milliradians.
GouyGouy phase in radians for the current
qstate.
Astigmatic and elliptical beams
KrakenOS also exposes a two-axis helper for laser sources whose tangential and
sagittal beam diameters, divergences, or M2 values are different. This is
useful for diode lasers and beam-shaping lenses where the source is elliptical.
Two independent q-states propagate along the same axis; the cross-section ellipse rotates and changes aspect ratio as each axis crosses its own waist.
Worked example. Diode laser: \(\lambda = 0.6328\) µm, M² = 1.1 tangential and 1.3 sagittal, with datasheet \(D_{t} = 1.2\) mm, \(\Theta_{t} = 0.9\) mrad, \(D_{s} = 0.8\) mm, \(\Theta_{s} = 1.4\) mrad. Per-axis:
tangential: \(\theta_{t} = 0.45\) mrad, \(w_{0,t} = 1.1 \cdot 0.0006328 / (\pi \cdot 0.45 \cdot 10^{-3}) \approx 0.4922\) mm, \(z_{R,t} = \pi \cdot 0.4922^{2}/(1.1 \cdot 0.0006328) \approx 1094\) mm.
sagittal: \(\theta_{s} = 0.70\) mrad, \(w_{0,s} = 1.3 \cdot 0.0006328 / (\pi \cdot 0.70 \cdot 10^{-3}) \approx 0.3738\) mm, \(z_{R,s} = \pi \cdot 0.3738^{2}/(1.3 \cdot 0.0006328) \approx 534\) mm.
At \(z = 200\) mm downstream of each waist: \(w_{t}(200) = 0.4922\,\sqrt{1 + (200/1094)^{2}} \approx 0.501\) mm, \(w_{s}(200) = 0.3738\,\sqrt{1 + (200/534)^{2}} \approx 0.400\) mm — the beam is already noticeably elliptical (ratio 1.25).
The astigmatic separation (different waist positions for the two axes) combined with different \(z_{R}\) is why the cross-section ellipse rotates with z.
The current UI and ParaxMatrices() path use one centered ABCD sequence, so
the two axes differ because the input beam data differ. Branch-carried Gaussian
q propagation has a Phase 8B validation baseline for oblique mirrors and
first-order oblique refractive powers, but it is not yet a full thick tilted
plate or non-sequential wave-optics model. When future non-sequential or tilted
surface matrices expose separate tangential/sagittal ABCD chains, the same
per-axis propagation routine can consume them.
For splitter and folded-laser future work, see Beam Splitters. Deterministic beam-splitter ray branches now carry power and phase metadata. Ray Inspector and Trace Path Inspector CSV exports now also carry branch-local Gaussian frame columns at every traced hit:
GB KThe local propagation axis for the outgoing branch after that hit.
GB TThe local tangential axis. When a surface normal is available this is the projection of the normal into the plane perpendicular to
GB K.GB SThe local sagittal axis, perpendicular to the local plane of incidence. The frame is right-handed, so
GB T x GB S = GB K.Inc [deg]The unsigned incidence angle between incoming ray direction and surface normal. It is blank when no reliable surface normal exists.
These columns are the first non-sequential Gaussian contract. KrakenOS also
provides KrakenOS.propagate_branch_gaussian_q(record, beam, surfaces=rows)
for traced branch records. It propagates independent tangential/sagittal
q states, branch distance, optical path, beam radii, wavefront radii, and
cumulative centered aperture/obscuration clipping.
The UI exposes the same contract through Actions -> Branch Gaussian Q
Report. The report lists one row per branch hit with the q-update note,
tangential/sagittal surface powers, q states, beam radii, clipping, and
stability flags. Use its CSV export when auditing oblique powered refraction,
flat tilted-plate q-only diagnostics, or TIR-deferred cases.
astigmatic_beam = Kos.astigmatic_gaussian_beam_from_diameter_divergence(
wavelength_um=0.6328,
tangential_beam_diameter_mm=1.2,
tangential_full_divergence_mrad=0.9,
sagittal_beam_diameter_mm=0.8,
sagittal_full_divergence_mrad=1.4,
tangential_m2=1.1,
sagittal_m2=1.3,
waist_after_input=False,
)
astigmatic_trace = Kos.propagate_astigmatic_gaussian_beam(
paraxial_trace,
astigmatic_beam,
)
print(astigmatic_trace.final_tangential.beam_radius_mm)
print(astigmatic_trace.final_sagittal.beam_radius_mm)
Validate the branch-frame contract with:
python -m KrakenOS.UI.validate_gaussian_branch_frames
Validate branch-carried q and detector-side Gaussian recombination with:
python -m KrakenOS.UI.validate_gaussian_branch_q
python -m KrakenOS.UI.validate_gaussian_detector_recombination
For active Source-panel Gaussian interferometer layouts, the Interf analysis
uses the branch-carried q envelope and cumulative clipping when detector-bin
coherent promotion is reliable. The displayed annotation reads
Gaussian-q detector-bin coherent sum. This is a detector-bin geometric
field model.
Phase 8 branch-field propagation
Phase 8 starts the higher-order field-propagation layer with a small reusable
contract in KrakenOS.BranchField. The first helper is scalar and grid-based:
it is designed to sit between traced branch/detector data and future UI field
plots without adding more analysis logic directly to the editor.
BranchFieldGridA complex scalar field sampled on monotonic
x_edges_mmandy_edges_mm. The first contract uses the same discrete power convention asCohDetandDiffr:sum(abs(field)**2).BranchFieldGrid.centroid_mm()Returns the intensity-weighted sampled field centroid. The UI uses this as the center for the first fitted TEM00 overlap estimate.
make_gaussian_tem00_field(...)Builds a normalized waist-plane TEM00 field on a rectangular grid.
propagate_branch_field(grid, distance_mm)Propagates the scalar field through homogeneous free space using a unitary paraxial/Fresnel transfer function. This conserves the discrete field power to numerical precision.
gaussian_mode_overlap(grid, waist_radius_mm=...)Computes normalized overlap efficiency against a waist-plane TEM00 reference sampled on the same grid.
branch_field_from_detector_data(data, component=...)Converts current coherent-detector data dictionaries into the Phase 8 field contract. This is the bridge from Phase 7 detector-bin fields to future branch-field plots.
Worked example. Place a TEM₀₀ field of \(w_{0} = 0.55\) mm at \(\lambda = 0.6328\) µm on a 129×129 grid over ±4 mm. Propagate \(L = 250\) mm forward and check what should happen analytically.
\(z_{R} = \pi \cdot 0.55^{2}/0.0006328 \approx 1501\) mm.
\(w(250) = 0.55\,\sqrt{1 + (250/1501)^{2}} \approx 0.55 \cdot 1.0138 \approx 0.558\) mm — barely larger than at the waist (we are well inside the Rayleigh range, \(L/z_{R} \approx 0.166\)).
\(R(250) = 250\,(1 + (1501/250)^{2}) \approx 250 \cdot 37.05 \approx 9{,}260\) mm — long-radius curvature.
Gouy phase: \(\psi(250) = \arctan(250/1501) \approx 0.165\) rad \(\approx 9.5°\).
Self-overlap of the propagated field with a waist-plane TEM₀₀ template of the same \(w_{0}\): because the propagated field carries curvature \(1/R(250)\) that the flat template lacks, the overlap drops slightly below 1. The closed-form for two co-axial Gaussians with matched \(w_{0}\) but mismatched curvature \((1/R_{1}, 1/R_{2}) = (0, 1/R(250))\) gives \(\eta \approx 1/\!\left[1 + (\pi\,w_{0}^{2}/(\lambda\,R(250)))^{2}\right] \approx 0.9978\) — slight curvature-mismatch loss.
KrakenOS code:
import numpy as np
import KrakenOS as Kos
x_edges = np.linspace(-4.0, 4.0, 129)
y_edges = np.linspace(-4.0, 4.0, 129)
field = Kos.make_gaussian_tem00_field(
x_edges_mm=x_edges,
y_edges_mm=y_edges,
wavelength_um=0.6328,
waist_radius_mm=0.55,
power=1.0,
)
propagated = Kos.propagate_branch_field(field, 250.0)
overlap = Kos.gaussian_mode_overlap(propagated, waist_radius_mm=0.55)
print(f"power conserved: {propagated.total_power:.6f}")
print(f"TEM00 overlap : {overlap.efficiency:.6f}")
# Analytic comparison
lam = 0.6328e-3
w0 = 0.55
zR = np.pi * w0**2 / lam
L = 250.0
w = w0 * np.sqrt(1 + (L/zR)**2)
R = L * (1 + (zR/L)**2)
psi = np.arctan(L/zR)
eta_a = 1.0 / (1.0 + (np.pi*w0**2/(lam*R))**2)
print(f"analytic w({L:.0f}) = {w*1e3:.2f} um R = {R:.0f} mm "
f"Gouy = {psi:.3f} rad eta = {eta_a:.6f}")
Run the example and validators with:
python KrakenOS/Examples/Examp_Branch_Field_Propagation.py
python -m KrakenOS.UI.validate_phase8_field_contract
python -m KrakenOS.UI.validate_phase8_complete
The UI-facing entry point is the BField analysis button beside CohDet
and Diffr. It reuses the selected Analysis path and detector-bin count,
promotes the coherent detector samples into BranchFieldGrid, then plots:
normalized scalar field intensity,
wrapped phase contours in radians where the field has enough power,
the fitted intensity centroid,
a TEM00 overlap estimate using the second-moment radius as the fitted waist.
The BField z [mm] field in the left analysis controls applies the first
Phase 8 paraxial propagation helper before plotting and measuring the field.
Use 0 for the detector plane. Positive and negative distances are accepted
for forward/backward propagation on the same sampled grid. Actions -> Export
Branch Field CSV... writes one row per field bin with complex field,
intensity, phase, propagation distance, centroid, fitted waist, and TEM00
overlap metadata.
Headless snapshot example:
python -m KrakenOS.UI.render_layout_snapshot \
--file KrakenOS/common_optical_layouts/michelson_interferometer_ray_only.py \
--mode branch_field \
--output testing/branch_field.png
This first slice is intentionally not a full tilted thick-plate field propagator. Fully oblique astigmatic matrices and richer mode-overlap workflows remain Phase 8 follow-up slices.
Phase 8B oblique astigmatic q baseline
Phase 8B validates the branch-carried Gaussian-q surface-power contract. The current behavior is:
flat mirrors/folds behave as pure branch-local free-space q propagation,
flat oblique refractive plate faces are marked as q-only index steps, not full tilted-plate field propagation,
oblique spherical reflection applies different tangential and sagittal curvature powers,
near-normal spherical refraction applies symmetric first-order power,
oblique spherical refraction applies first-order Coddington tangential and sagittal powers in the branch-local frame,
above-critical synthetic transmit hits are marked as TIR-deferred q diagnostics instead of silently applying a spherical power.
The validator also loads the real Galvo F-Theta Laser Scanner common
layout, runs the same headless UI trace used by the ray inspector, and checks
that traced oblique refractive hits match the first-order tangential/sagittal
surface powers.
Run the diagnostic example and validator with:
python KrakenOS/Examples/Examp_Oblique_Astigmatic_Q.py
python -m KrakenOS.UI.validate_phase8b_complete
python -m KrakenOS.UI.validate_branch_gaussian_q_report
python -m KrakenOS.UI.validate_oblique_astigmatic_q
python -m KrakenOS.UI.validate_phase8_complete
Phase 8B is closed at this Gaussian-q contract scope. This is still a first-order q update at traced surface hits. Flat oblique refractive plates are labeled as q-only index steps; they do not yet replace full wave propagation through thick tilted splitter plates or arbitrary CAD prisms. That work belongs in a later branch-field/physical-optics layer, not another silent q-only patch.
Cavity eigenmode flow
The Gaussian Beam Report includes a Use Cavity Eigenmode button. It solves
the self-consistent mode:
for the current ABCD matrix, then fills the report input waist and waist offset with that eigenmode. Use this only when the current ABCD matrix represents one complete cavity round trip at the chosen reference plane. A normal single-pass imaging lens is not a cavity round trip, so the button may correctly report an unstable or invalid eigenmode.
The reported stability parameter is:
where \((A, B, C, D)\) are the entries of the round-trip matrix, and the mode is stable when \(|g| < 1\) and the solved \(q\) has a positive imaginary part. For a two-mirror cavity of length \(L\) and radii \(R_{1}, R_{2}\), this is equivalent to the geometric
For a symmetric cavity (\(R_{1} = R_{2} = R\)) the waist sits at the centre, and
The mode profile that survives one full round trip is the cavity eigenmode. For a symmetric cavity the waist sits at the geometric centre.
Worked example. Symmetric two-mirror cavity, \(L = 300\) mm, \(R_{1} = R_{2} = 1000\) mm, \(\lambda = 0.6328\) µm, \(M^{2} = 1\).
\(g_{1} = g_{2} = 1 - 300/1000 = 0.7\), \(g_{1}g_{2} = 0.49\) → stable (well inside \([0, 1]\)).
\(z_{R} = (L/2)\,\sqrt{2R/L - 1} = 150\,\sqrt{2000/300 - 1} = 150 \cdot \sqrt{5.667} \approx 357.1\) mm.
\(w_{0} = \sqrt{\lambda\,z_{R} / \pi} = \sqrt{0.0006328 \cdot 357.1 / \pi} \approx 0.268\) mm.
Beam radius at each mirror (\(z = L/2 = 150\) mm from waist): \(w_{\mathrm{mirror}} = w_{0}\,\sqrt{1 + (150/357.1)^{2}} \approx 0.290\) mm.
The same solve is available from Python:
import numpy as np
import KrakenOS as Kos
L = 300.0
R = 1000.0
propagation = np.array([[1.0, L], [0.0, 1.0]])
mirror = np.array([[1.0, 0.0], [-2.0/R, 1.0]])
round_trip = mirror @ propagation @ mirror @ propagation
mode = Kos.solve_gaussian_cavity_eigenmode(
round_trip,
wavelength_um=0.6328,
m2=1.0,
)
if mode.stable:
beam = mode.beam
print(f"w0 = {beam.waist_radius_mm*1e3:.2f} um")
print(f"waist offset = {beam.waist_offset_mm:.2f} mm")
# Analytic cross-check (symmetric cavity, waist at centre):
zR_a = (L/2) * np.sqrt(2*R/L - 1)
w0_a = np.sqrt(0.6328e-3 * zR_a / np.pi)
g1 = 1.0 - L/R
print(f"analytic w0 = {w0_a*1e3:.2f} um zR = {zR_a:.1f} mm g1*g2 = {g1*g1:.3f}")
UI workflow
Load
Common Optical Layout -> Gaussian Beam ABCD Example.In the Source panel, choose
Gaussian beam.Set
GB waist [mm],GB waist offset [mm], andGB M2.Click
Updateto trace representative Gaussian source rays and draw the amber 1/e^2 q-envelope in the 2-D layout.Open
Actions -> Gaussian Beam Reportfor the per-surface q table.For resonator layouts whose ABCD matrix is one complete round trip, click
Use Cavity Eigenmodeto seed the report from the stable cavity mode.Use
Export CSVwhen you want to compare the per-step q trace externally.
Low ray-count Gaussian previews use equal-spaced meridional samples inside the
current beam radius so the 2-D layout gaps are uniform. The outer preview rays
stay conservatively inside the source edge to avoid accidental clipping on
tilted finite plates. Increase Ray count above nine when you want the
representative rays to fill the 2-D source disk.
Folded laser scanner example
Common Optical Layout -> Galvo F-Theta Laser Scanner demonstrates a typical
laser-scanner path:
a Gaussian 650 nm source using diameter/divergence input (1 mm beam diameter and 2 mrad full divergence in the preset);
a negative/positive two-lens beam expander tuned for about 2x expansion, so the beam at the galvo/entrance stop is compatible with the Figure 8 2 mm EPD;
a 45 degree galvo mirror;
a 50 mm F-theta lens transcribed from
attachment/F-theta.pdfFigure 8;a flat scan/focus plane.
The preset uses Folded Preview plus explicit Folded reach = Display
compatibility so the 2-D layout reads like the physical bench: beam expander,
fold mirror, downward F-theta leg, and scan plane. That detector reach mode is
legacy display compatibility; exported ray records still mark the folded
terminal provenance. The case is also covered by the branch-frame and branch-q
validators, so it is useful for checking folded Gaussian q propagation
contracts. It is still not a higher-order diffraction or mode-overlap field
solver. The F-theta lens data is also available as Common Optical Layout ->
F-Theta Lens 50mm Figure 8. Its original Zemax K9 glass is mapped to
bundled CDGM H-K9L.
The galvo mirror row also supports a 2-D scan overlay directly in the
prescription table. Edit the mirror TiltX cell and enter comma-separated
values, such as 40,45,50, or a range like 40:50:5. These values
use the same displayed mirror angle as the table cell; they are not the optical
F-theta field angle. Around the 45 degree fold, the optical scan angle is twice
the displayed mirror-slant change from the nominal 45 degree fold. Thus
40,45,50 is a conservative -10,0,+10 degree optical scan. The
Figure 8 prescription is a 40 degree full-field lens, so its nominal full
optical scan is -20,0,+20 degrees, entered as 35,45,55. The middle
value becomes the nominal pose stored on the row; the full list draws
additional mirror positions and representative focused bundles without
duplicating rows in the prescription table. The right-click
Galvo scan overlay... dialog edits the same setting.
For a step-by-step UI walkthrough with reproducible snapshots, see Case Study 19: Galvo F-Theta Laser Scanner.
Other pose cells use the same comma/range syntax for mechanical tolerance
overlays. For example, entering -0.05,0,0.05 in a lens DespX cell keeps
0 as the nominal prescription value and overlays the decentered ray traces
in the 2-D plot without duplicating lens rows.
If the folded scanner spot is not exactly on the scan plane, first validate the
standalone F-Theta Lens 50mm Figure 8 layout with object mode
Infinity. The integrated scanner also includes a finite Gaussian source and
beam expander; its exact plane focus depends on the expander collimating the
beam at the galvo/entrance stop.
Python example
The same feature is available directly from Python:
import KrakenOS as Kos
setup = Kos.Setup()
obj = Kos.surf()
obj.Name = "Input plane"
obj.Thickness = 80.0
obj.Diameter = 20.0
obj.Glass = "AIR"
lens = Kos.surf()
lens.Name = "Focusing lens f=100"
lens.Thin_Lens = 100.0
lens.Thickness = 130.0
lens.Diameter = 30.0
lens.Glass = "AIR"
image = Kos.surf()
image.Name = "Readout plane"
image.Thickness = 0.0
image.Diameter = 16.0
image.Glass = "AIR"
system = Kos.system([obj, lens, image], setup)
paraxial_trace = system.ParaxMatrices(0.6328)
beam = Kos.GaussianBeamInput(
wavelength_um=0.6328,
waist_radius_mm=0.5,
waist_offset_mm=0.0,
m2=1.0,
)
# Alternative manufacturer-style input:
beam = Kos.gaussian_beam_from_diameter_divergence(
wavelength_um=0.6328,
beam_diameter_mm=1.0,
full_divergence_mrad=1.0,
m2=1.0,
waist_after_input=False,
)
beam_trace = Kos.propagate_gaussian_beam(paraxial_trace, beam)
for step in beam_trace.steps:
print(
step.step_index,
step.label,
f"w={step.beam_radius_mm:.6g} mm",
f"R={step.wavefront_radius_mm:.6g} mm",
f"waist_offset={step.waist_offset_mm:.6g} mm",
)
A runnable version of this example is available at
KrakenOS/Examples/Examp_Gaussian_Beam_Propagation.py. A second runnable
example for astigmatic beams and cavity eigenmodes is available at
KrakenOS/Examples/Examp_Gaussian_Laser_Modes.py.
Scope and limitations
This is a q-parameter and detector-bin Gaussian envelope tool, not a full diffraction field propagator. Branch q traces include centered aperture/obscuration clipping, and promoted Gaussian-source interferograms can use detector-bin coherent recombination. Higher-order modes, FFT propagation through arbitrary clipping, and true tilted thick-plate mode-overlap still require future wave-optics work. Tangential/sagittal helpers model independent two-axis source data on the current centered ABCD path; fully oblique astigmatic optics still require future separate axis matrices.
The 2-D layout also traces an exact-count representative 2-D disk bundle so the source appears in the normal ray display. The amber envelope is the physical Gaussian beam size; the traced rays are still a visual/geometric guide rather than a diffraction-field calculation.
Source-mode field relevance
When Gaussian beam or another physical source is selected, object/field and
pupil controls do not define the source. The UI therefore hides unused controls
such as Object mode, Field type, Pupil pattern, and Pupil
factor. The saved values are preserved internally and restored when returning
to Pupil / field.
This distinction is intentional for future beam-splitter and illumination workflows: an illumination source is a separate entity from the optical object. For example, a source can illuminate an object through a 45 degree beam splitter from a 90 degree direction. In that case source position, direction, beam diameter, divergence, and power define the launched rays; object mode and pupil-factor ray-height scaling are not the ray-generation controls.