viewof fermiMass = Inputs.range([0, 3], {
value: 1,
step: 0.1,
label: html`
<span class="spectrum-slider-label">
${tex`m_\nu,\ \text{эВ}`}
</span>
`
})
fermiElectronMass = 511000
fermiEndpoint = 18575
fermiWindow = 3
fermiSpectrum = (energy, mass) => {
const neutrinoEnergy = fermiEndpoint - energy;
if (neutrinoEnergy < mass) return 0;
const electronMomentum = Math.sqrt(
energy * energy + 2 * fermiElectronMass * energy
);
const neutrinoMomentum = Math.sqrt(Math.max(
0,
neutrinoEnergy * neutrinoEnergy - mass * mass
));
return electronMomentum
* (energy + fermiElectronMass)
* neutrinoEnergy
* neutrinoMomentum;
}
fermiIntegrate = (lower, upper, mass, steps = 1000) => {
if (upper <= lower) return 0;
const step = (upper - lower) / steps;
let sum = (
fermiSpectrum(lower, mass)
+ fermiSpectrum(upper, mass)
) / 2;
for (let i = 1; i < steps; i += 1) {
sum += fermiSpectrum(lower + i * step, mass);
}
return sum * step;
}
fermiNorm = fermiSpectrum(fermiEndpoint - fermiWindow, 0)
fermiTotalIntegral = fermiIntegrate(0, fermiEndpoint, 0, 8000)
fermiShadedIntegral = fermiIntegrate(
fermiEndpoint - fermiMass,
fermiEndpoint,
0,
400
)
fermiShadedFraction = fermiShadedIntegral / fermiTotalIntegral
fermiFractionExponent = fermiShadedFraction === 0
? 0
: Math.floor(Math.log10(fermiShadedFraction))
fermiFractionMantissa = fermiShadedFraction === 0
? "0"
: (
fermiShadedFraction / 10 ** fermiFractionExponent
).toFixed(2)
fermiX = Array.from({length: 501}, (_, i) =>
-fermiWindow + fermiWindow * i / 500
)
fermiMassless = fermiX.map(x => ({
x,
y: fermiSpectrum(fermiEndpoint + x, 0) / fermiNorm
}))
fermiMassive = fermiX
.filter(x => -x >= fermiMass)
.map(x => ({
x,
y: fermiSpectrum(fermiEndpoint + x, fermiMass) / fermiNorm
}))
fermiShaded = fermiMassless.filter(d => d.x >= -fermiMass)
fermiPlot = Plot.plot({
width: 1120,
height: 300,
marginTop: 18,
marginRight: 25,
marginBottom: 45,
marginLeft: 72,
style: {
background: "#ffffff",
color: "#111111",
fontSize: "20px"
},
x: {
axis: "bottom",
label: null,
domain: [-fermiWindow, 0],
ticks: 6,
grid: true
},
y: {
axis: "left",
label: null,
domain: [0, 1.05],
ticks: 5,
grid: true,
tickFormat: value => value.toFixed(1)
},
marks: [
Plot.areaY(fermiShaded, {
x: "x",
y: "y",
fill: "#999999",
fillOpacity: 0.65
}),
Plot.ruleY([0], {
stroke: "#111111",
strokeWidth: 1.5
}),
Plot.line(fermiMassless, {
x: "x",
y: "y",
stroke: "#4ea1ff",
strokeWidth: 4
}),
Plot.line(fermiMassive, {
x: "x",
y: "y",
stroke: "#ffb347",
strokeWidth: 4
}),
Plot.ruleX([-fermiMass], {
stroke: "#ffb347",
strokeDasharray: "7,5",
strokeWidth: 2.5
}),
Plot.frame({stroke: "#111111"})
]
})
html`
<div class="spectrum-panel">
<div class="spectrum-legend">
<span>
<i class="spectrum-swatch spectrum-swatch-massless"></i>
${tex`m_\nu=0`}
</span>
<span>
<i class="spectrum-swatch spectrum-swatch-massive"></i>
${tex`m_\nu=${fermiMass.toFixed(1)}\ \mathrm{eV}`}
</span>
</div>
<div class="spectrum-plot-row">
<div class="spectrum-y-label">
${tex`\dfrac{d\Gamma}{dE}\;(\mathrm{a.u.})`}
</div>
<div class="spectrum-plot-host">
${fermiPlot}
<div class="spectrum-integral-overlay">
<span>
${tex`\dfrac{\int_{E_0-m_\nu}^{E_0}(d\Gamma/dE)\,dE}
{\int_0^{E_0}(d\Gamma/dE)\,dE}`}
</span>
<span>
≈ ${fermiFractionMantissa}
${fermiShadedFraction === 0
? ""
: html`× 10<sup>${fermiFractionExponent}</sup>`}
</span>
</div>
</div>
</div>
<div class="spectrum-x-label">
${tex`E-E_0\;(\mathrm{eV})`}
</div>
<div class="spectrum-summary">
<span>${tex`E_0=18.575\ \mathrm{keV}`}</span>
<span>${tex`E_{\max}=E_0-m_\nu`}</span>
</div>
</div>`Конец β-спектра и энергетическое разрешение
След массы нейтрино и его размытие детектором
Сначала измените массу нейтрино и найдите сдвиг конечной точки. Затем увеличьте ширину отклика детектора и проследите, как приборное размытие маскирует физический эффект.
viewof resolutionSigma = Inputs.range([0, 2], {
value: 0.5,
step: 0.1,
label: html`
<span class="spectrum-slider-label">
${tex`\sigma_E,\ \text{эВ}`}
</span>
`
})
resolutionMass = 1
resolutionXMin = -3
resolutionXMax = 1.5
resolutionGaussianNorm = Math.sqrt(2 * Math.PI)
resolutionConvolvedSpectrum = (xReco, mass, sigma) => {
if (sigma === 0) {
return fermiSpectrum(fermiEndpoint + xReco, mass) / fermiNorm;
}
const lower = Math.max(-fermiEndpoint, xReco - 6 * sigma);
const upper = Math.min(-mass, xReco + 6 * sigma);
if (upper <= lower) return 0;
const steps = 240;
const step = (upper - lower) / steps;
const integrand = xTrue => {
const pull = (xReco - xTrue) / sigma;
const response = Math.exp(-0.5 * pull * pull)
/ (resolutionGaussianNorm * sigma);
return response
* fermiSpectrum(fermiEndpoint + xTrue, mass)
/ fermiNorm;
};
let sum = (integrand(lower) + integrand(upper)) / 2;
for (let i = 1; i < steps; i += 1) {
sum += integrand(lower + i * step);
}
return sum * step;
}
resolutionX = Array.from({length: 501}, (_, i) =>
resolutionXMin
+ (resolutionXMax - resolutionXMin) * i / 500
)
resolutionData = resolutionX.map(x => ({
x,
massless: resolutionConvolvedSpectrum(x, 0, resolutionSigma),
massive: resolutionConvolvedSpectrum(
x,
resolutionMass,
resolutionSigma
)
}))
resolutionPlot = Plot.plot({
width: 1120,
height: 300,
marginTop: 18,
marginRight: 25,
marginBottom: 45,
marginLeft: 72,
style: {
background: "#ffffff",
color: "#111111",
fontSize: "20px"
},
x: {
axis: "bottom",
label: null,
domain: [resolutionXMin, resolutionXMax],
ticks: 7,
grid: true
},
y: {
axis: "left",
label: null,
domain: [0, 1.5],
ticks: 6,
grid: true,
tickFormat: value => value.toFixed(1)
},
marks: [
Plot.areaY(resolutionData, {
x: "x",
y1: "massive",
y2: "massless",
fill: "#999999",
fillOpacity: 0.55
}),
Plot.ruleY([0], {
stroke: "#111111",
strokeWidth: 1.5
}),
Plot.line(resolutionData, {
x: "x",
y: "massless",
stroke: "#4ea1ff",
strokeWidth: 4
}),
Plot.line(resolutionData, {
x: "x",
y: "massive",
stroke: "#ffb347",
strokeWidth: 4
}),
Plot.ruleX([0], {
stroke: "#4ea1ff",
strokeDasharray: "7,5",
strokeWidth: 2.5
}),
Plot.ruleX([-resolutionMass], {
stroke: "#ffb347",
strokeDasharray: "7,5",
strokeWidth: 2.5
}),
Plot.frame({stroke: "#111111"})
]
})
html`
<div class="spectrum-panel">
<div class="spectrum-legend">
<span>
<i class="spectrum-swatch spectrum-swatch-massless"></i>
${tex`m_\nu=0`}
</span>
<span>
<i class="spectrum-swatch spectrum-swatch-massive"></i>
${tex`m_\nu=1\ \text{эВ}`}
</span>
</div>
<div class="spectrum-plot-row">
<div class="spectrum-y-label">
${tex`\dfrac{d\Gamma_{\mathrm{rec}}}{dE_{\mathrm{rec}}}
\;(\text{отн. ед.})`}
</div>
<div class="spectrum-plot-host">
${resolutionPlot}
</div>
</div>
<div class="spectrum-x-label">
${tex`E_{\mathrm{rec}}-E_0\;(\text{эВ})`}
</div>
</div>`Первый график показывает истинный спектр, второй — реконструированную энергию после свёртки с гауссовым откликом. Масса и разрешение меняют форму по-разному, хотя оба эффекта сосредоточены у конечной точки.