88 lines
3.3 KiB
TypeScript
88 lines
3.3 KiB
TypeScript
"use client";
|
|
|
|
import { useMemo, useState } from "react";
|
|
import ToolShell from "@/components/toolkit/ToolShell";
|
|
import { Card, CardHeader, CardTitle, CardContent } from "@/components/ui/card";
|
|
import { Input } from "@/components/ui/input";
|
|
|
|
function num(v: string) {
|
|
const n = parseFloat(v);
|
|
return Number.isFinite(n) ? n : 0;
|
|
}
|
|
|
|
// Spot diameter (µm) ≈ 1.27 * M² * λ(µm) * f(mm) / D(mm)
|
|
export default function Page() {
|
|
const [lambdaNm, setLambdaNm] = useState("1064"); // nm (default fiber)
|
|
const [focalMm, setFocalMm] = useState("160"); // mm
|
|
const [beamDm, setBeamDm] = useState("6"); // mm (input beam diameter at lens)
|
|
const [m2, setM2] = useState("1.3");
|
|
|
|
const dUm = useMemo(() => {
|
|
const lamUm = num(lambdaNm) / 1000; // convert nm -> µm
|
|
const f = num(focalMm);
|
|
const D = num(beamDm);
|
|
const M2 = Math.max(1, num(m2));
|
|
if (lamUm <= 0 || f <= 0 || D <= 0) return 0;
|
|
return 1.27 * M2 * lamUm * (f / D);
|
|
}, [lambdaNm, focalMm, beamDm, m2]);
|
|
|
|
const dMm = dUm / 1000;
|
|
|
|
return (
|
|
<ToolShell title="Beam Spot Size">
|
|
<Card>
|
|
<CardHeader>
|
|
<CardTitle className="text-base">Inputs</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="grid gap-3 sm:grid-cols-4">
|
|
<label className="text-[11px] sm:text-xs">
|
|
<div className="mb-1 text-muted-foreground">Wavelength (nm)</div>
|
|
<Input value={lambdaNm} onChange={(e) => setLambdaNm(e.target.value)} />
|
|
<div className="mt-1 text-[11px] text-muted-foreground space-x-2">
|
|
<button type="button" className="underline" onClick={() => setLambdaNm("1064")}>
|
|
Fiber (1064 nm)
|
|
</button>
|
|
<button type="button" className="underline" onClick={() => setLambdaNm("10600")}>
|
|
CO₂ (10600 nm)
|
|
</button>
|
|
</div>
|
|
</label>
|
|
|
|
<label className="text-[11px] sm:text-xs">
|
|
<div className="mb-1 text-muted-foreground">Focal length (mm)</div>
|
|
<Input value={focalMm} onChange={(e) => setFocalMm(e.target.value)} />
|
|
</label>
|
|
|
|
<label className="text-[11px] sm:text-xs">
|
|
<div className="mb-1 text-muted-foreground">Beam Ø @ lens (mm)</div>
|
|
<Input value={beamDm} onChange={(e) => setBeamDm(e.target.value)} />
|
|
</label>
|
|
|
|
<label className="text-[11px] sm:text-xs">
|
|
<div className="mb-1 text-muted-foreground">M²</div>
|
|
<Input value={m2} onChange={(e) => setM2(e.target.value)} />
|
|
</label>
|
|
</CardContent>
|
|
</Card>
|
|
|
|
<Card className="mt-4">
|
|
<CardHeader>
|
|
<CardTitle className="text-base">Result</CardTitle>
|
|
</CardHeader>
|
|
<CardContent className="grid gap-3 sm:grid-cols-2">
|
|
<div>
|
|
<div className="text-sm text-muted-foreground">Spot diameter</div>
|
|
<div className="text-lg">{dMm.toFixed(4)} mm</div>
|
|
<div className="text-xs text-muted-foreground">{dUm.toFixed(2)} µm</div>
|
|
</div>
|
|
<div>
|
|
<div className="text-sm text-muted-foreground">Spot radius</div>
|
|
<div className="text-lg">{(dMm / 2).toFixed(4)} mm</div>
|
|
<div className="text-xs text-muted-foreground">{(dUm / 2).toFixed(2)} µm</div>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
</ToolShell>
|
|
);
|
|
}
|
|
|