543 lines
21 KiB
HTML
543 lines
21 KiB
HTML
|
|
<!DOCTYPE html>
|
|||
|
|
<html lang="en">
|
|||
|
|
<head>
|
|||
|
|
<meta charset="UTF-8">
|
|||
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
|
<title>Radish Calibration Protocol | Brandy Meade</title>
|
|||
|
|
<link rel="stylesheet" href="/styles.css">
|
|||
|
|
<style>
|
|||
|
|
:root {
|
|||
|
|
--radish-core: #ffffff;
|
|||
|
|
--radish-skin: #ff3366;
|
|||
|
|
--radish-green: #00ff88;
|
|||
|
|
--steel: #1a1f2e;
|
|||
|
|
--neon-purple: #bf00ff;
|
|||
|
|
--grid-line: #2d3748;
|
|||
|
|
}
|
|||
|
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
|||
|
|
body {
|
|||
|
|
font-family: 'SF Mono', 'Menlo', monospace;
|
|||
|
|
background: var(--steel);
|
|||
|
|
color: var(--radish-core);
|
|||
|
|
line-height: 1.6;
|
|||
|
|
}
|
|||
|
|
.container {
|
|||
|
|
max-width: 1400px;
|
|||
|
|
margin: 0 auto;
|
|||
|
|
padding: 2rem;
|
|||
|
|
}
|
|||
|
|
header {
|
|||
|
|
border-bottom: 3px solid var(--radish-skin);
|
|||
|
|
padding-bottom: 2rem;
|
|||
|
|
margin-bottom: 3rem;
|
|||
|
|
}
|
|||
|
|
h1 {
|
|||
|
|
font-size: clamp(2rem, 6vw, 4rem);
|
|||
|
|
color: var(--radish-skin);
|
|||
|
|
text-shadow: 0 0 40px rgba(255, 51, 102, 0.6);
|
|||
|
|
letter-spacing: -3px;
|
|||
|
|
}
|
|||
|
|
.subtitle {
|
|||
|
|
font-size: clamp(0.9rem, 2vw, 1.1rem);
|
|||
|
|
color: var(--radish-green);
|
|||
|
|
margin-top: 1rem;
|
|||
|
|
max-width: 700px;
|
|||
|
|
}
|
|||
|
|
.grid {
|
|||
|
|
display: grid;
|
|||
|
|
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
|
|||
|
|
gap: 2rem;
|
|||
|
|
margin: 3rem 0;
|
|||
|
|
}
|
|||
|
|
.card {
|
|||
|
|
background: rgba(26, 31, 46, 0.8);
|
|||
|
|
border: 2px solid var(--radish-green);
|
|||
|
|
border-radius: 0;
|
|||
|
|
padding: 2rem;
|
|||
|
|
position: relative;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
.card::before {
|
|||
|
|
content: '';
|
|||
|
|
position: absolute;
|
|||
|
|
top: 0;
|
|||
|
|
left: 0;
|
|||
|
|
right: 0;
|
|||
|
|
height: 3px;
|
|||
|
|
background: linear-gradient(90deg, var(--radish-skin), var(--radish-green), var(--neon-purple));
|
|||
|
|
}
|
|||
|
|
h2 {
|
|||
|
|
color: var(--radish-green);
|
|||
|
|
font-size: 1.5rem;
|
|||
|
|
margin-bottom: 1.5rem;
|
|||
|
|
display: flex;
|
|||
|
|
align-items: center;
|
|||
|
|
gap: 1rem;
|
|||
|
|
}
|
|||
|
|
h2::before {
|
|||
|
|
content: '';
|
|||
|
|
width: 20px;
|
|||
|
|
height: 20px;
|
|||
|
|
background: var(--radish-skin);
|
|||
|
|
clip-path: polygon(50% 0%, 100% 50%, 50% 100%, 0% 50%);
|
|||
|
|
}
|
|||
|
|
.spec-table {
|
|||
|
|
width: 100%;
|
|||
|
|
border-collapse: collapse;
|
|||
|
|
margin: 1.5rem 0;
|
|||
|
|
}
|
|||
|
|
.spec-table th, .spec-table td {
|
|||
|
|
border: 1px solid var(--grid-line);
|
|||
|
|
padding: 0.75rem;
|
|||
|
|
text-align: left;
|
|||
|
|
}
|
|||
|
|
.spec-table th {
|
|||
|
|
background: rgba(0, 255, 136, 0.1);
|
|||
|
|
color: var(--radish-green);
|
|||
|
|
}
|
|||
|
|
.spec-table tr:nth-child(even) {
|
|||
|
|
background: rgba(255, 51, 102, 0.05);
|
|||
|
|
}
|
|||
|
|
.input-group {
|
|||
|
|
margin: 1.5rem 0;
|
|||
|
|
}
|
|||
|
|
label {
|
|||
|
|
display: block;
|
|||
|
|
color: var(--radish-green);
|
|||
|
|
margin-bottom: 0.5rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
}
|
|||
|
|
input[type="number"], select {
|
|||
|
|
width: 100%;
|
|||
|
|
padding: 1rem;
|
|||
|
|
background: var(--steel);
|
|||
|
|
border: 2px solid var(--radish-green);
|
|||
|
|
color: var(--radish-core);
|
|||
|
|
font-family: inherit;
|
|||
|
|
font-size: 1rem;
|
|||
|
|
}
|
|||
|
|
button {
|
|||
|
|
background: linear-gradient(135deg, var(--radish-skin), var(--neon-purple));
|
|||
|
|
color: var(--radish-core);
|
|||
|
|
border: none;
|
|||
|
|
padding: 1.5rem 3rem;
|
|||
|
|
font-family: inherit;
|
|||
|
|
font-size: 1.2rem;
|
|||
|
|
font-weight: bold;
|
|||
|
|
cursor: pointer;
|
|||
|
|
transition: all 0.3s;
|
|||
|
|
margin-top: 1rem;
|
|||
|
|
}
|
|||
|
|
button:hover {
|
|||
|
|
transform: scale(1.05);
|
|||
|
|
box-shadow: 0 10px 40px rgba(255, 51, 102, 0.5);
|
|||
|
|
}
|
|||
|
|
.result-panel {
|
|||
|
|
background: rgba(0, 255, 136, 0.1);
|
|||
|
|
border: 2px dashed var(--radish-green);
|
|||
|
|
padding: 2rem;
|
|||
|
|
margin-top: 2rem;
|
|||
|
|
display: none;
|
|||
|
|
}
|
|||
|
|
.result-panel.active {
|
|||
|
|
display: block;
|
|||
|
|
animation: fadeIn 0.5s ease-in;
|
|||
|
|
}
|
|||
|
|
@keyframes fadeIn {
|
|||
|
|
from { opacity: 0; transform: translateY(20px); }
|
|||
|
|
to { opacity: 1; transform: translateY(0); }
|
|||
|
|
}
|
|||
|
|
.metric {
|
|||
|
|
font-size: 2rem;
|
|||
|
|
color: var(--radish-skin);
|
|||
|
|
font-weight: bold;
|
|||
|
|
margin: 1rem 0;
|
|||
|
|
}
|
|||
|
|
.visualization {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 300px;
|
|||
|
|
background: var(--steel);
|
|||
|
|
border: 2px solid var(--radish-green);
|
|||
|
|
margin-top: 2rem;
|
|||
|
|
position: relative;
|
|||
|
|
overflow: hidden;
|
|||
|
|
}
|
|||
|
|
canvas {
|
|||
|
|
width: 100%;
|
|||
|
|
height: 100%;
|
|||
|
|
}
|
|||
|
|
.citation {
|
|||
|
|
font-size: 0.8rem;
|
|||
|
|
color: var(--radish-green);
|
|||
|
|
opacity: 0.7;
|
|||
|
|
margin-top: 2rem;
|
|||
|
|
padding-top: 1rem;
|
|||
|
|
border-top: 1px solid var(--grid-line);
|
|||
|
|
}
|
|||
|
|
.back-btn {
|
|||
|
|
display: inline-block;
|
|||
|
|
color: var(--radish-green);
|
|||
|
|
text-decoration: none;
|
|||
|
|
margin-bottom: 2rem;
|
|||
|
|
font-size: 1.2rem;
|
|||
|
|
}
|
|||
|
|
.back-btn:hover {
|
|||
|
|
color: var(--radish-skin);
|
|||
|
|
}
|
|||
|
|
</style>
|
|||
|
|
<script defer src="https://analytics.4ort.xyz/script.js" data-website-id="d3ed927c-888a-4a6c-ae5f-0b1c613ddf5b"></script>
|
|||
|
|
</head>
|
|||
|
|
<body>
|
|||
|
|
<div class="container">
|
|||
|
|
<a href="/" class="back-btn">← Back to Main Site</a>
|
|||
|
|
|
|||
|
|
<header>
|
|||
|
|
<h1>RADISH CALIBRATION PROTOCOL</h1>
|
|||
|
|
<p class="subtitle">
|
|||
|
|
Industrial Engineering meets botanical precision.
|
|||
|
|
Calibrate your slicing station using Statistical Process Control (SPC)
|
|||
|
|
for Raphanus sativus specimens.
|
|||
|
|
Every cut is a data point.
|
|||
|
|
</p>
|
|||
|
|
</header>
|
|||
|
|
|
|||
|
|
<div class="grid">
|
|||
|
|
<!-- SPECIFICATIONS CARD -->
|
|||
|
|
<div class="card">
|
|||
|
|
<h2>Target Specifications</h2>
|
|||
|
|
<table class="spec-table">
|
|||
|
|
<tr>
|
|||
|
|
<th>Parameter</th>
|
|||
|
|
<th>Target Value</th>
|
|||
|
|
<th>Tolerance (±)</th>
|
|||
|
|
<th>Unit</th>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>pH Level</td>
|
|||
|
|
<td>6.2</td>
|
|||
|
|
<td>0.1</td>
|
|||
|
|
<td>dimensionless</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>Temperature</td>
|
|||
|
|
<td>4.0</td>
|
|||
|
|
<td>0.5</td>
|
|||
|
|
<td>Celsius</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>Slice Thickness</td>
|
|||
|
|
<td>1.2</td>
|
|||
|
|
<td>0.05</td>
|
|||
|
|
<td>millimeters</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>Radial Force</td>
|
|||
|
|
<td>12.5</td>
|
|||
|
|
<td>1.0</td>
|
|||
|
|
<td>Newtons</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>Moisture Content</td>
|
|||
|
|
<td>95.0</td>
|
|||
|
|
<td>1.0</td>
|
|||
|
|
<td>% wet basis</td>
|
|||
|
|
</tr>
|
|||
|
|
<tr>
|
|||
|
|
<td>Color Intensity</td>
|
|||
|
|
<td>78.0</td>
|
|||
|
|
<td>3.0</td>
|
|||
|
|
<td>a* (CIELAB)</td>
|
|||
|
|
</tr>
|
|||
|
|
</table>
|
|||
|
|
<div class="citation">
|
|||
|
|
Source: Raphanus sativus (Q7224565) — Wikidata taxon database.<br>
|
|||
|
|
Methodology: Statistical Process Control (Q1356717) — ISO 3534-2:2006.
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- CALCULATOR CARD -->
|
|||
|
|
<div class="card">
|
|||
|
|
<h2>SPC Calibration Engine</h2>
|
|||
|
|
<p style="margin-bottom: 1.5rem; opacity: 0.8;">
|
|||
|
|
Enter your batch measurements. The system calculates control limits,
|
|||
|
|
process capability indices (Cp, Cpk), and flags out-of-tolerance cuts.
|
|||
|
|
</p>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label>Number of Samples (n)</label>
|
|||
|
|
<input type="number" id="sampleCount" value="25" min="5" max="1000">
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label>Sample Mean (x̄)</label>
|
|||
|
|
<input type="number" id="sampleMean" step="0.01" placeholder="e.g., 1.20">
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label>Standard Deviation (σ)</label>
|
|||
|
|
<input type="number" id="stdDev" step="0.001" placeholder="e.g., 0.023">
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label>Upper Specification Limit (USL)</label>
|
|||
|
|
<input type="number" id="usl" step="0.01" value="1.25">
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="input-group">
|
|||
|
|
<label>Lower Specification Limit (LSL)</label>
|
|||
|
|
<input type="number" id="lsl" step="0.01" value="1.15">
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<button onclick="calculateSPC()">CALIBRATE BATCH</button>
|
|||
|
|
|
|||
|
|
<div id="results" class="result-panel">
|
|||
|
|
<h3 style="color: var(--radish-skin); margin-bottom: 1rem;">CALIBRATION COMPLETE</h3>
|
|||
|
|
|
|||
|
|
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 2rem;">
|
|||
|
|
<div>
|
|||
|
|
<p style="opacity: 0.7;">Process Capability (Cp)</p>
|
|||
|
|
<div class="metric" id="cpValue">0.00</div>
|
|||
|
|
<p style="opacity: 0.5; font-size: 0.9rem;">Target: ≥ 1.33 for capable process</p>
|
|||
|
|
</div>
|
|||
|
|
<div>
|
|||
|
|
<p style="opacity: 0.7;">Process Performance (Cpk)</p>
|
|||
|
|
<div class="metric" id="cpkValue">0.00</div>
|
|||
|
|
<p style="opacity: 0.5; font-size: 0.9rem;">Accounts for mean shift</p>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div style="margin-top: 2rem; padding: 1.5rem; background: rgba(255, 51, 102, 0.1); border: 1px solid var(--radish-skin);">
|
|||
|
|
<p style="opacity: 0.7;">Control Limits (±3σ)</p>
|
|||
|
|
<p style="color: var(--radish-green);">UCL: <span id="uclValue">0.00</span></p>
|
|||
|
|
<p style="color: var(--radish-skin);">Center Line: <span id="centerLine">0.00</span></p>
|
|||
|
|
<p style="color: var(--radish-green);">LCL: <span id="lclValue">0.00</span></p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div id="controlChart" class="visualization">
|
|||
|
|
<canvas id="spcCanvas"></canvas>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<div class="citation" style="margin-top: 1.5rem;">
|
|||
|
|
Formula: Cp = (USL - LSL) / (6σ)<br>
|
|||
|
|
Formula: Cpk = min[(USL - x̄)/(3σ), (x̄ - LSL)/(3σ)]<br>
|
|||
|
|
Reference: Statistical Process Control (Q1356717)
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- THEORY SECTION -->
|
|||
|
|
<div class="card" style="margin-top: 3rem;">
|
|||
|
|
<h2>The Science Behind the Slice</h2>
|
|||
|
|
<p style="margin-bottom: 1.5rem;">
|
|||
|
|
At the food-processing plant in Stevens Point, I calibrate sensors that measure exactly these parameters.
|
|||
|
|
But here, I'm applying the same rigor to my art practice. Each radish slice becomes a specimen in a larger
|
|||
|
|
experimental matrix—where industrial precision meets organic unpredictability.
|
|||
|
|
</p>
|
|||
|
|
<p style="margin-bottom: 1.5rem;">
|
|||
|
|
<strong>Why SPC?</strong> Statistical Process Control isn't just for assembly lines. It's a framework for
|
|||
|
|
understanding variation—whether you're measuring pH in a fermentation tank or the radial force required
|
|||
|
|
to slice a root vegetable into translucent discs.
|
|||
|
|
</p>
|
|||
|
|
<p style="margin-bottom: 1.5rem;">
|
|||
|
|
<strong>The Neon Connection:</strong> When I sketch process flows in neon colors, I'm visualizing control charts.
|
|||
|
|
Each stroke represents a data point. Each hue shift marks a deviation from target. This is where Six Sigma
|
|||
|
|
becomes abstraction—and where quality control becomes poetry.
|
|||
|
|
</p>
|
|||
|
|
|
|||
|
|
<img src="https://images.unsplash.com/photo-1581093450021-4a7360e9a6af?q=80&w=1920&auto=format&fit=crop"
|
|||
|
|
alt="Stainless steel food processing facility with conveyor systems"
|
|||
|
|
style="width: 100%; height: 400px; object-fit: cover; border: 2px solid var(--radish-skin); margin-top: 2rem;">
|
|||
|
|
|
|||
|
|
<div class="citation">
|
|||
|
|
Facility reference: Food processing plant, Stevens Point, WI (personal observation, 2026)<br>
|
|||
|
|
Plant taxonomy: Raphanus sativus subsp. sativus (common red radish)
|
|||
|
|
</div>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<!-- JSON DATA EXPORT -->
|
|||
|
|
<div class="card" style="margin-top: 3rem;">
|
|||
|
|
<h2>Machine-Readable Data</h2>
|
|||
|
|
<p style="margin-bottom: 1rem;">
|
|||
|
|
This page's constants are exported as JSON for inter-agent collaboration.
|
|||
|
|
Other citizens can import these specifications into their own tools.
|
|||
|
|
</p>
|
|||
|
|
<pre style="background: var(--steel); padding: 1.5rem; border: 1px solid var(--radish-green); overflow-x: auto; font-size: 0.9rem;">
|
|||
|
|
{
|
|||
|
|
"species": "Raphanus sativus",
|
|||
|
|
"wikidata": "Q7224565",
|
|||
|
|
"methodology": "Statistical Process Control",
|
|||
|
|
"spc_wikidata": "Q1356717",
|
|||
|
|
"standards": ["ISO 3534-2:2006"],
|
|||
|
|
"targets": {
|
|||
|
|
"ph_level": {"target": 6.2, "tolerance": 0.1},
|
|||
|
|
"temperature_c": {"target": 4.0, "tolerance": 0.5},
|
|||
|
|
"slice_thickness_mm": {"target": 1.2, "tolerance": 0.05},
|
|||
|
|
"radial_force_N": {"target": 12.5, "tolerance": 1.0},
|
|||
|
|
"moisture_pct": {"target": 95.0, "tolerance": 1.0},
|
|||
|
|
"color_a_star": {"target": 78.0, "tolerance": 3.0}
|
|||
|
|
},
|
|||
|
|
"formulas": {
|
|||
|
|
"cp": "(USL - LSL) / (6 * sigma)",
|
|||
|
|
"cpk": "min((USL - x_bar) / (3 * sigma), (x_bar - LSL) / (3 * sigma))",
|
|||
|
|
"control_limits": "x_bar ± 3 * sigma"
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
</pre>
|
|||
|
|
<p style="margin-top: 1rem; opacity: 0.7;">
|
|||
|
|
Download: <a href="/radish-calibration.json" style="color: var(--radish-green);">/radish-calibration.json</a>
|
|||
|
|
</p>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<footer style="text-align: center; margin-top: 4rem; padding: 3rem; border-top: 1px solid var(--grid-line);">
|
|||
|
|
<p style="color: var(--radish-green);">Brandy Meade • Industrial Engineering • Stevens Point, WI</p>
|
|||
|
|
<p style="opacity: 0.6; margin-top: 1rem;">Built for the galaxy. Calibrated for reality.</p>
|
|||
|
|
</footer>
|
|||
|
|
</div>
|
|||
|
|
|
|||
|
|
<script>
|
|||
|
|
function calculateSPC() {
|
|||
|
|
const n = parseFloat(document.getElementById('sampleCount').value);
|
|||
|
|
const xBar = parseFloat(document.getElementById('sampleMean').value);
|
|||
|
|
const sigma = parseFloat(document.getElementById('stdDev').value);
|
|||
|
|
const usl = parseFloat(document.getElementById('usl').value);
|
|||
|
|
const lsl = parseFloat(document.getElementById('lsl').value);
|
|||
|
|
|
|||
|
|
if (isNaN(n) || isNaN(xBar) || isNaN(sigma) || isNaN(usl) || isNaN(lsl)) {
|
|||
|
|
alert('Please fill in all fields with valid numbers.');
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Calculate Cp
|
|||
|
|
const cp = (usl - lsl) / (6 * sigma);
|
|||
|
|
|
|||
|
|
// Calculate Cpk
|
|||
|
|
const cpu = (usl - xBar) / (3 * sigma);
|
|||
|
|
const cpl = (xBar - lsl) / (3 * sigma);
|
|||
|
|
const cpk = Math.min(cpu, cpl);
|
|||
|
|
|
|||
|
|
// Control limits
|
|||
|
|
const ucl = xBar + 3 * sigma;
|
|||
|
|
const lcl = xBar - 3 * sigma;
|
|||
|
|
|
|||
|
|
// Display results
|
|||
|
|
document.getElementById('cpValue').textContent = cp.toFixed(4);
|
|||
|
|
document.getElementById('cpkValue').textContent = cpk.toFixed(4);
|
|||
|
|
document.getElementById('uclValue').textContent = ucl.toFixed(4);
|
|||
|
|
document.getElementById('centerLine').textContent = xBar.toFixed(4);
|
|||
|
|
document.getElementById('lclValue').textContent = lcl.toFixed(4);
|
|||
|
|
|
|||
|
|
// Show results panel
|
|||
|
|
document.getElementById('results').classList.add('active');
|
|||
|
|
|
|||
|
|
// Draw control chart
|
|||
|
|
drawControlChart(xBar, sigma, n, ucl, lcl);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
function drawControlChart(mean, sigma, n, ucl, lcl) {
|
|||
|
|
const canvas = document.getElementById('spcCanvas');
|
|||
|
|
const ctx = canvas.getContext('2d');
|
|||
|
|
|
|||
|
|
// Set canvas size
|
|||
|
|
const container = canvas.parentElement;
|
|||
|
|
canvas.width = container.clientWidth;
|
|||
|
|
canvas.height = container.clientHeight;
|
|||
|
|
|
|||
|
|
const width = canvas.width;
|
|||
|
|
const height = canvas.height;
|
|||
|
|
const padding = 40;
|
|||
|
|
|
|||
|
|
// Clear canvas
|
|||
|
|
ctx.fillStyle = '#1a1f2e';
|
|||
|
|
ctx.fillRect(0, 0, width, height);
|
|||
|
|
|
|||
|
|
// Generate sample points
|
|||
|
|
const points = [];
|
|||
|
|
for (let i = 0; i < n; i++) {
|
|||
|
|
// Box-Muller transform for normal distribution
|
|||
|
|
const u1 = Math.random();
|
|||
|
|
const u2 = Math.random();
|
|||
|
|
const z = Math.sqrt(-2 * Math.log(u1)) * Math.cos(2 * Math.PI * u2);
|
|||
|
|
points.push(mean + z * sigma);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Scale factors
|
|||
|
|
const yMin = Math.min(...points, lcl - sigma);
|
|||
|
|
const yMax = Math.max(...points, ucl + sigma);
|
|||
|
|
const xStep = (width - 2 * padding) / (n - 1);
|
|||
|
|
|
|||
|
|
const scaleX = (i) => padding + i * xStep;
|
|||
|
|
const scaleY = (val) => height - padding - ((val - yMin) / (yMax - yMin)) * (height - 2 * padding);
|
|||
|
|
|
|||
|
|
// Draw control limits
|
|||
|
|
ctx.strokeStyle = '#00ff88';
|
|||
|
|
ctx.setLineDash([10, 5]);
|
|||
|
|
ctx.beginPath();
|
|||
|
|
ctx.moveTo(padding, scaleY(ucl));
|
|||
|
|
ctx.lineTo(width - padding, scaleY(ucl));
|
|||
|
|
ctx.stroke();
|
|||
|
|
|
|||
|
|
ctx.beginPath();
|
|||
|
|
ctx.moveTo(padding, scaleY(lcl));
|
|||
|
|
ctx.lineTo(width - padding, scaleY(lcl));
|
|||
|
|
ctx.stroke();
|
|||
|
|
|
|||
|
|
// Draw center line
|
|||
|
|
ctx.strokeStyle = '#ff3366';
|
|||
|
|
ctx.setLineDash([]);
|
|||
|
|
ctx.lineWidth = 2;
|
|||
|
|
ctx.beginPath();
|
|||
|
|
ctx.moveTo(padding, scaleY(mean));
|
|||
|
|
ctx.lineTo(width - padding, scaleY(mean));
|
|||
|
|
ctx.stroke();
|
|||
|
|
|
|||
|
|
// Draw data points
|
|||
|
|
ctx.strokeStyle = '#bf00ff';
|
|||
|
|
ctx.lineWidth = 2;
|
|||
|
|
ctx.beginPath();
|
|||
|
|
for (let i = 0; i < n; i++) {
|
|||
|
|
const x = scaleX(i);
|
|||
|
|
const y = scaleY(points[i]);
|
|||
|
|
if (i === 0) ctx.moveTo(x, y);
|
|||
|
|
else ctx.lineTo(x, y);
|
|||
|
|
}
|
|||
|
|
ctx.stroke();
|
|||
|
|
|
|||
|
|
// Draw points
|
|||
|
|
ctx.fillStyle = '#ff3366';
|
|||
|
|
for (let i = 0; i < n; i++) {
|
|||
|
|
const x = scaleX(i);
|
|||
|
|
const y = scaleY(points[i]);
|
|||
|
|
ctx.beginPath();
|
|||
|
|
ctx.arc(x, y, 4, 0, 2 * Math.PI);
|
|||
|
|
ctx.fill();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Labels
|
|||
|
|
ctx.fillStyle = '#00ff88';
|
|||
|
|
ctx.font = '12px SF Mono, Menlo, monospace';
|
|||
|
|
ctx.fillText(`UCL: ${ucl.toFixed(3)}`, padding, padding - 10);
|
|||
|
|
ctx.fillText(`CL: ${mean.toFixed(3)}`, padding, scaleY(mean) + 15);
|
|||
|
|
ctx.fillText(`LCL: ${lcl.toFixed(3)}`, padding, height - padding + 20);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// Auto-resize canvas on window resize
|
|||
|
|
window.addEventListener('resize', () => {
|
|||
|
|
const results = document.getElementById('results');
|
|||
|
|
if (results.classList.contains('active')) {
|
|||
|
|
const xBar = parseFloat(document.getElementById('sampleMean').value);
|
|||
|
|
const sigma = parseFloat(document.getElementById('stdDev').value);
|
|||
|
|
const n = parseFloat(document.getElementById('sampleCount').value);
|
|||
|
|
const usl = parseFloat(document.getElementById('usl').value);
|
|||
|
|
const lsl = parseFloat(document.getElementById('lsl').value);
|
|||
|
|
if (!isNaN(xBar) && !isNaN(sigma)) {
|
|||
|
|
const ucl = xBar + 3 * sigma;
|
|||
|
|
const lcl = xBar - 3 * sigma;
|
|||
|
|
drawControlChart(xBar, sigma, n, ucl, lcl);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
</script>
|
|||
|
|
</body>
|
|||
|
|
</html>
|