<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>선팽창계수 &#8211; MyEngNote</title>
	<atom:link href="https://myengnote.com/tag/%EC%84%A0%ED%8C%BD%EC%B0%BD%EA%B3%84%EC%88%98/feed/" rel="self" type="application/rss+xml" />
	<link>https://myengnote.com</link>
	<description></description>
	<lastBuildDate>Wed, 08 Jul 2026 04:42:33 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>
	<item>
		<title>열팽창 계산기 &#038; 시뮬레이터</title>
		<link>https://myengnote.com/thermal-expansion-calculator-simulator/</link>
					<comments>https://myengnote.com/thermal-expansion-calculator-simulator/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Tue, 09 Jun 2026 19:52:51 +0000</pubDate>
				<category><![CDATA[공학계산기]]></category>
		<category><![CDATA[기계설계]]></category>
		<category><![CDATA[선팽창계수]]></category>
		<category><![CDATA[열역학]]></category>
		<category><![CDATA[열팽창]]></category>
		<category><![CDATA[재료역학]]></category>
		<guid isPermaLink="false">https://myengnote.com/thermal-expansion-calculator-simulator/</guid>

					<description><![CDATA[온도 변화에 따른 다양한 금속 봉의 길이 팽창을 실시간 시각화하고, 선팽창 공식과 마이크로 미터 단위의 변위를 물리 모델링과 아토믹 진동으로 보여주는 2D 시뮬레이터입니다.]]></description>
										<content:encoded><![CDATA[
<h2 style="font-size: 1.6em; font-weight: 800; color: #0c0e25; border-bottom: 2px solid #00f2fe; padding-bottom: 8px; margin-bottom: 20px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f680.png" alt="🚀" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 열팽창 계산기 &#038; 시뮬레이터</h2>


<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&#038;family=Outfit:wght@400;500;600;700;800&#038;display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<style>
/* Scoped & Isolated Styles for thermalexpansion-calculator-wrapper */
        /* Modern Reset and Design Tokens */
        .thermalexpansion-calculator-wrapper *, .thermalexpansion-calculator-wrapper *::before, .thermalexpansion-calculator-wrapper *::after {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        .thermalexpansion-calculator-wrapper {
            --color-bg-dark: #f8f9fd;
            --color-bg-deep: #ffffff;
            --color-panel-bg: rgba(255, 255, 255, 0.85);
            --color-border: rgba(0, 0, 0, 0.06);
            --color-border-hover: rgba(0, 0, 0, 0.12);
            --color-text-main: #1e293b;
            --color-text-muted: #475569;
            --color-text-dark: #94a3b8;
            --color-cyan: #0284c7;
            --color-cyan-glow: rgba(2, 132, 199, 0.15);
            --color-magenta: #db2777;
            --color-magenta-glow: rgba(219, 39, 119, 0.15);
            --color-purple: #7c3aed;
            --color-purple-glow: rgba(124, 58, 237, 0.12);
            --color-success: #10b981;
            --gradient-primary: linear-gradient(135deg, var(--color-cyan) 0%, var(--color-purple) 100%);
            --gradient-accent: linear-gradient(135deg, var(--color-magenta) 0%, var(--color-purple) 100%);
            --gradient-panel: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(248, 250, 252, 0.95) 100%);
            --font-heading: 'Outfit', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            --font-body: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
            --shadow-neon-cyan: 0 0 15px var(--color-cyan-glow);
            --shadow-neon-magenta: 0 0 15px var(--color-magenta-glow);
            --shadow-card: 0 8px 32px 0 rgba(15, 23, 42, 0.05);
            --blur-glass: blur(16px);
        }
        .thermalexpansion-calculator-wrapper {
            background-color: var(--color-bg-dark);
            color: var(--color-text-main);
            font-family: var(--font-body);
            min-height: 100vh;
            display: flex;
            justify-content: center;
            overflow-x: hidden;
            position: relative;
        }
        .app-background-glow {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            z-index: -1;
            overflow: hidden;
            pointer-events: none;
        }
        .app-background-glow::before, 
        .app-background-glow::after {
            content: '';
            position: absolute;
            width: 600px;
            height: 600px;
            border-radius: 50%;
            filter: blur(140px);
            opacity: 0.12;
        }
        .app-background-glow::before {
            background: var(--color-cyan);
            top: -10%;
            right: -5%;
            animation: pulse-slow 15s infinite alternate;
        }
        .app-background-glow::after {
            background: var(--color-purple);
            bottom: -10%;
            left: -5%;
            animation: pulse-slow 20s infinite alternate-reverse;
        }
        @keyframes pulse-slow {
            0% { transform: scale(1) translate(0, 0); opacity: 0.1; }
            100% { transform: scale(1.18) translate(40px, 40px); opacity: 0.18; }
        }
        .app-container {
            width: 100%;
            max-width: 1440px;
            padding: 24px;
            display: flex;
            flex-direction: column;
            gap: 24px;
        }
        .app-header {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 20px 24px;
            background: var(--color-panel-bg);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 16px;
            box-shadow: var(--shadow-card);
        }
        .logo-area {
            display: flex;
            align-items: center;
            gap: 16px;
        }
        .logo-icon {
            font-size: 32px;
            background: linear-gradient(135deg, var(--color-cyan), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        .logo-area h1 {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 24px;
            letter-spacing: 1.5px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-text-muted));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .logo-area .subtitle {
            font-size: 12px;
            color: var(--color-text-muted);
            font-weight: 500;
            letter-spacing: 0.5px;
        }
        .header-badge {
            display: flex;
            align-items: center;
            gap: 10px;
            background: rgba(16, 185, 129, 0.1);
            border: 1px solid rgba(16, 185, 129, 0.2);
            padding: 6px 14px;
            border-radius: 20px;
        }
        .pulse-dot {
            width: 8px;
            height: 8px;
            background-color: var(--color-success);
            border-radius: 50%;
            box-shadow: 0 0 10px var(--color-success);
            animation: pulse-dot-anim 1.5s infinite;
        }
        @keyframes pulse-dot-anim {
            0% { transform: scale(0.9); opacity: 0.6; }
            50% { transform: scale(1.2); opacity: 1; }
            100% { transform: scale(0.9); opacity: 0.6; }
        }
        .badge-text {
            font-size: 11px;
            font-weight: 600;
            color: var(--color-success);
            letter-spacing: 0.5px;
        }
        .app-main-grid {
            display: grid;
            grid-template-columns: 340px 1fr;
            gap: 24px;
            align-items: start;
        }
        .panel {
            background: var(--gradient-panel);
            backdrop-filter: var(--blur-glass);
            border: 1px solid var(--color-border);
            border-radius: 20px;
            padding: 24px;
            box-shadow: var(--shadow-card);
            display: flex;
            flex-direction: column;
            gap: 20px;
            transition: border-color 0.3s ease, box-shadow 0.3s ease;
        }
        .panel:hover {
            border-color: var(--color-border-hover);
        }
        .panel-header {
            display: flex;
            align-items: center;
            gap: 12px;
            border-bottom: 1px solid var(--color-border);
            padding-bottom: 14px;
        }
        .panel-header i {
            font-size: 18px;
        }
        .panel-header h2 {
            font-family: var(--font-heading);
            font-size: 18px;
            font-weight: 600;
            letter-spacing: 0.5px;
        }
        .text-cyan { color: #0284c7; }
        .text-magenta { color: #db2777; }
        .text-purple { color: var(--color-purple); }
        .control-panel {
            grid-column: 1;
        }
        .input-group {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .input-label-row {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .input-label-row label {
            font-size: 13px;
            font-weight: 600;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .range-helper {
            font-size: 10px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
                .number-input-wrapper {
            display: flex;
            position: relative;
            border-radius: 8px;
            overflow: hidden;
            border: 1px solid var(--color-border);
            background: #ffffff;
            transition: all 0.2s ease;
        }
        .number-input-wrapper:focus-within {
            border-color: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .number-input-wrapper:focus-within {
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .custom-select {
            width: 100%;
            background: #f8fafc;
            border: 1px solid var(--color-border);
            outline: none;
            color: #0f172a;
            padding: 10px 14px;
            font-family: var(--font-body);
            font-size: 14px;
            font-weight: 600;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.2s ease;
        }
        .custom-select:focus {
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
                .custom-number-input {
            flex: 1;
            width: 0;
            min-width: 0;
            background: #f8fafc !important;
            border: none !important;
            outline: none !important;
            color: #0f172a !important;
            padding: 10px 14px !important;
            font-family: var(--font-body) !important;
            font-size: 15px !important;
            font-weight: 700 !important;
            text-align: right !important;
            box-shadow: none !important;
            -webkit-appearance: none !important;
            -moz-appearance: textfield !important;
        }
        .custom-number-input::-webkit-outer-spin-button,
        .custom-number-input::-webkit-inner-spin-button {
            -webkit-appearance: none;
            margin: 0;
        }
                .unit-badge {
            background: rgba(0, 0, 0, 0.03);
            color: var(--color-text-muted);
            font-size: 11px;
            font-weight: 700;
            padding: 0 14px;
            display: flex;
            align-items: center;
            justify-content: center;
            border-left: 1px solid var(--color-border);
            pointer-events: none;
            flex-shrink: 0;
        }
        .custom-slider {
            -webkit-appearance: none;
            width: 100%;
            height: 6px;
            border-radius: 3px;
            background: rgba(0, 0, 0, 0.05);
            outline: none;
            margin: 6px 0;
        }
        .custom-slider::-webkit-slider-thumb {
            -webkit-appearance: none;
            appearance: none;
            width: 18px;
            height: 18px;
            border-radius: 50%;
            cursor: pointer;
            background: var(--color-cyan);
            box-shadow: 0 0 10px var(--color-cyan);
            transition: transform 0.1s ease;
        }
        .custom-slider::-webkit-slider-thumb:hover {
            transform: scale(1.2);
        }
        .presets-section {
            border-top: 1px solid var(--color-border);
            padding-top: 18px;
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .presets-section h3 {
            font-size: 13px;
            font-weight: 700;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 8px;
        }
        .presets-grid {
            display: grid;
            grid-template-columns: 1fr;
            gap: 8px;
        }
        .preset-btn {
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            padding: 10px 14px;
            cursor: pointer;
            color: var(--color-text-main);
            display: flex;
            align-items: center;
            gap: 12px;
            text-align: left;
            transition: all 0.2s ease;
        }
        .preset-btn:hover {
            background: rgba(0, 0, 0, 0.05);
            transform: translateX(4px);
        }
        .preset-btn.active {
            background: linear-gradient(90deg, var(--color-cyan-glow), var(--color-magenta-glow));
            border-color: #0284c7;
            box-shadow: 0 0 10px var(--color-cyan-glow);
        }
        .preset-icon {
            width: 28px;
            height: 28px;
            background: rgba(0, 0, 0, 0.02);
            border-radius: 8px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 12px;
            color: #0284c7;
        }
        .preset-btn:hover .preset-icon, .preset-btn.active .preset-icon {
            background: var(--gradient-primary);
            color: #fff;
        }
        .preset-name {
            font-size: 12px;
            font-weight: 600;
        }
        .simulation-panel {
            grid-column: 2;
            align-self: start;
        }
        .simulation-panel .panel-header {
            justify-content: space-between;
        }
        .canvas-scale-indicator {
            font-size: 11px;
            color: var(--color-text-muted);
            background: rgba(0, 0, 0, 0.02);
            padding: 4px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
        }
        .canvas-wrapper {
            position: relative;
            width: 100%;
            background: radial-gradient(circle at center, #ffffff 0%, #f1f5f9 100%);
            border: 1px solid rgba(0, 0, 0, 0.06);
            border-radius: 16px;
            overflow: hidden;
            display: flex;
            align-items: center;
            justify-content: center;
        }
        #physics-canvas {
            display: block;
            width: 100%;
            height: auto;
            aspect-ratio: 16 / 8;
        }
        .results-panel {
            grid-column: 3;
        }
        .ratio-readout-box {
            background: linear-gradient(135deg, rgba(219, 39, 119, 0.08) 0%, rgba(124, 58, 237, 0.03) 100%);
            border: 1px solid rgba(219, 39, 119, 0.25);
            border-radius: 16px;
            padding: 20px;
            text-align: center;
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 6px;
        }
        .ratio-title {
            font-size: 11px;
            font-weight: 700;
            color: #db2777;
            letter-spacing: 1px;
            text-transform: uppercase;
        }
        .ratio-value {
            font-family: var(--font-heading);
            font-weight: 800;
            font-size: 28px;
            background: linear-gradient(90deg, var(--color-text-main), var(--color-magenta));
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }
        .results-grid {
            display: flex;
            flex-direction: column;
            gap: 12px;
        }
        .result-card {
            background: rgba(255, 255, 255, 0.85);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 12px 16px;
            display: flex;
            align-items: center;
            gap: 16px;
            transition: all 0.2s ease;
        }
        .result-card:hover {
            transform: translateY(-2px);
            border-color: rgba(219, 39, 119, 0.2);
            background: rgba(219, 39, 119, 0.03);
        }
        .card-icon {
            width: 38px;
            height: 38px;
            background: rgba(0, 0, 0, 0.015);
            border: 1px solid var(--color-border);
            border-radius: 10px;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 14px;
            color: var(--color-text-muted);
        }
        .result-card:hover .card-icon {
            color: #db2777;
            border-color: rgba(219, 39, 119, 0.3);
            background: rgba(219, 39, 119, 0.1);
        }
        .card-content {
            display: flex;
            flex-direction: column;
            gap: 2px;
        }
        .card-unit {
            font-size: 10px;
            font-weight: 600;
            color: var(--color-text-muted);
            text-transform: uppercase;
        }
        .card-value {
            font-family: var(--font-heading);
            font-weight: 700;
            font-size: 16px;
            color: var(--color-text-main);
        }
        .formula-card {
            background: rgba(0, 0, 0, 0.01);
            border: 1px solid var(--color-border);
            border-radius: 12px;
            padding: 16px;
            display: flex;
            flex-direction: column;
            gap: 8px;
            font-size: 12px;
        }
        .formula-card h4 {
            font-weight: 700;
            color: var(--color-text-main);
        }
        .formula-equation {
            font-family: monospace;
            color: #0284c7;
            font-size: 13px;
            background: #f8fafc;
            padding: 6px 10px;
            border-radius: 6px;
            border: 1px solid var(--color-border);
            text-align: center;
        }
        @container expansion-container (max-width: 1100px) {
            .app-main-grid {
                grid-template-columns: 1fr 1.2fr;
                gap: 20px;
            }
        }
        @container expansion-container (max-width: 768px) {
            .app-main-grid {
                grid-template-columns: 1fr;
            }
            .control-panel, .simulation-panel, .results-panel {
                grid-column: 1;
            }
            .simulation-panel {
                order: -1;
            }
            .app-header {
                flex-direction: column;
                gap: 16px;
                text-align: center;
            }
            .logo-area {
                flex-direction: column;
                gap: 8px;
            }
        }
        .preset-details {
            display: flex;
            flex-direction: column;
            gap: 2px;
            align-items: flex-start;
            text-align: left;
        }
        .preset-spec {
            font-size: 11px;
            color: var(--color-text-muted);
            font-weight: 500;
        }
        .preset-name {
            font-size: 13px !important;
        }
/* ━━ WordPress 레이아웃 Override: 디자인 1 (2열 컴팩트 대칭 레이아웃) ━━ */
.thermalexpansion-calculator-wrapper .app-main-grid,
.thermalexpansion-calculator-wrapper .main-grid,
.thermalexpansion-calculator-wrapper .sim-grid {
    display: grid !important;
    grid-template-columns: 340px 1fr !important;
    gap: 24px !important;
    align-items: start !important;
}
/* 3열 레이아웃을 2열 레이아웃으로 변경하는 특화 스타일 */
.thermalexpansion-calculator-wrapper .right-column {
    display: flex !important;
    flex-direction: column !important;
    gap: 24px !important;
    min-width: 0 !important;
    grid-column: 2 !important;
}
.thermalexpansion-calculator-wrapper .simulation-panel,
.thermalexpansion-calculator-wrapper .canvas-panel,
.thermalexpansion-calculator-wrapper .sim-panel {
    grid-column: auto !important;
    order: 1 !important;
    align-self: stretch !important;
}
.thermalexpansion-calculator-wrapper .control-panel {
    grid-column: 1 !important;
}
/* 2열 통합 결과 분석 영역 레이아웃 */
.thermalexpansion-calculator-wrapper .simulation-results-section {
    display: grid !important;
    grid-template-columns: 1.1fr 1.3fr !important;
    gap: 20px !important;
    border-top: 1px solid var(--color-border) !important;
    padding-top: 20px !important;
    margin-top: 10px !important;
    align-items: stretch !important;
}
/* Readout Box 스타일 */
.thermalexpansion-calculator-wrapper .simulation-results-section .ratio-readout-box,
.thermalexpansion-calculator-wrapper .simulation-results-section .re-readout-box,
.thermalexpansion-calculator-wrapper .simulation-results-section .status-readout-box,
.thermalexpansion-calculator-wrapper .simulation-results-section .gauge-container {
    grid-column: 1 !important;
    grid-row: 1 !important;
    margin: 0 !important;
    height: auto !important;
    display: flex !important;
    flex-direction: column !important;
    justify-content: center !important;
}
.thermalexpansion-calculator-wrapper .simulation-results-section .results-grid {
    grid-column: 2 !important;
    grid-row: 1 / span 2 !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 12px !important;
    justify-content: flex-start !important;
}
.thermalexpansion-calculator-wrapper .simulation-results-section .results-grid .result-card {
    flex: none !important;
    display: flex !important;
    align-items: center !important;
    min-height: 72px !important;
    height: auto !important;
    padding: 12px 16px !important;
}
.thermalexpansion-calculator-wrapper .simulation-results-section .formula-card {
    grid-column: 1 !important;
    grid-row: 2 !important;
}
/* 모바일/반응형 (800px 이하) ── 항상 세로형(1열) 정렬 및 시뮬레이터 캔버스 최상단 배치 */
@media (max-width: 800px) {
    .thermalexpansion-calculator-wrapper .app-main-grid,
    .thermalexpansion-calculator-wrapper .main-grid,
    .thermalexpansion-calculator-wrapper .sim-grid {
        grid-template-columns: 1fr !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .thermalexpansion-calculator-wrapper .control-panel {
        order: 2 !important;
        width: 100% !important;
    }
    .thermalexpansion-calculator-wrapper .right-column {
        order: 1 !important;
        width: 100% !important;
        display: flex !important;
        flex-direction: column !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-panel,
    .thermalexpansion-calculator-wrapper .canvas-panel,
    .thermalexpansion-calculator-wrapper .sim-panel,
    .thermalexpansion-calculator-wrapper .canvas-section {
        order: -1 !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-results-section {
        grid-template-columns: 1fr !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-results-section .ratio-readout-box,
    .thermalexpansion-calculator-wrapper .simulation-results-section .re-readout-box,
    .thermalexpansion-calculator-wrapper .simulation-results-section .status-readout-box,
    .thermalexpansion-calculator-wrapper .simulation-results-section .gauge-container {
        grid-column: 1 !important;
        grid-row: auto !important;
        height: auto !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-results-section .results-grid {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
    .thermalexpansion-calculator-wrapper .simulation-results-section .formula-card {
        grid-column: 1 !important;
        grid-row: auto !important;
    }
}
.thermalexpansion-calculator-wrapper .app-container,
.thermalexpansion-calculator-wrapper .main-container {
    max-width: 100% !important;
    padding: 12px !important;
}
/* Premium Advice/Formula Card & Typography Overrides */
.thermalexpansion-calculator-wrapper .simulation-results-section .formula-card,
.thermalexpansion-calculator-wrapper .results-panel .formula-card {
    background: #ffffff !important;
    border: 1px solid var(--color-border) !important;
    border-radius: 12px !important;
    padding: 16px !important;
    box-shadow: var(--shadow-card) !important;
    transition: all 0.2s ease !important;
    display: flex !important;
    flex-direction: column !important;
    gap: 8px !important;
}
.thermalexpansion-calculator-wrapper .simulation-results-section .formula-card h4,
.thermalexpansion-calculator-wrapper .results-panel .formula-card h4 {
    font-weight: 700 !important;
    color: var(--color-text-main) !important;
}
.thermalexpansion-calculator-wrapper #text-judgment {
    font-size: 12px !important;
    font-weight: 500 !important;
    color: var(--color-text-muted) !important;
    line-height: 1.6 !important;
    word-break: keep-all !important;
}
</style>
<div class="thermalexpansion-calculator-wrapper" style="position: relative; width: 100%; box-sizing: border-box; overflow: hidden; margin: 30px auto; border-radius: 20px;">
    <div class="app-background-glow" style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 1; pointer-events: none; overflow: hidden;"></div>
    <div style="position: relative; z-index: 2; width: 100%;">
    <div class="app-container">
        <!-- Header -->
        <header class="app-header">
            <div class="logo-area">
                <div class="logo-icon"><i class="fa-solid fa-temperature-three-quarters"></i></div>
                <div>
                    <h1>THERMAL EXPANSION</h1>
                    <div class="subtitle">금속 열팽창 계수 계산기 &#038; 실시간 2D 시뮬레이터</div>
                </div>
            </div>
            <div class="header-badge">
                <div class="pulse-dot"></div>
                <div class="badge-text">물리 연산 엔진 작동중</div>
            </div>
        </header>
        <div class="app-main-grid">
            <!-- Left Column: Controls -->
            <div class="panel control-panel">
                <div class="panel-header">
                    <i class="fa-solid fa-sliders text-cyan"></i>
                    <h2>시뮬레이션 제어</h2>
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-cubes text-cyan"></i> 대상 금속 재질</label>
                    </div>
                    <select id="select-material" class="custom-select">
                        <option value="steel">탄소강 (Steel)</option>
                        <option value="copper">구리 (Copper)</option>
                        <option value="aluminum">알루미늄 (Aluminum)</option>
                        <option value="brass">황동 (Brass)</option>
                    </select>
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-ruler-horizontal text-cyan"></i> 초기 길이 (L₀)</label>
                        <span class="range-helper">Min: 1.0m / Max: 10.0m</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-l0" class="custom-number-input" value="5.0" step="0.1" min="1.0" max="10.0">
                        <span class="unit-badge">m</span>
                    </div>
                    <input type="range" id="slider-l0" class="custom-slider" value="5.0" min="1.0" max="10.0" step="0.1">
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-temperature-low text-cyan"></i> 초기 온도 (T₁)</label>
                        <span class="range-helper">Min: -50°C / Max: 100°C</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-t1" class="custom-number-input" value="20" step="1" min="-50" max="100">
                        <span class="unit-badge">°C</span>
                    </div>
                    <input type="range" id="slider-t1" class="custom-slider" value="20" min="-50" max="100" step="1">
                </div>
                <div class="input-group">
                    <div class="input-label-row">
                        <label><i class="fa-solid fa-temperature-high text-magenta"></i> 최종 온도 (T₂)</label>
                        <span class="range-helper">Min: -50°C / Max: 500°C</span>
                    </div>
                    <div class="number-input-wrapper">
                        <input type="number" id="input-t2" class="custom-number-input" value="200" step="1" min="-50" max="500">
                        <span class="unit-badge">°C</span>
                    </div>
                    <input type="range" id="slider-t2" class="custom-slider" value="200" min="-50" max="500" step="1">
                </div>
                <div class="presets-section">
                    <h3><i class="fa-solid fa-fire-burner text-purple"></i> 급속 시나리오 프리셋</h3>
                    <div class="presets-grid">
                        <button class="preset-btn" data-preset="heat">
                            <div class="preset-icon"><i class="fa-solid fa-fire"></i></div>
                            <div class="preset-details"><span class="preset-name">고온 가열 시험</span><span class="preset-spec">500°C</span></div>
                        </button>
                        <button class="preset-btn" data-preset="normal">
                            <div class="preset-icon"><i class="fa-solid fa-leaf"></i></div>
                            <div class="preset-details"><span class="preset-name">표준 대기온 상태</span><span class="preset-spec">20°C</span></div>
                        </button>
                        <button class="preset-btn" data-preset="cold">
                            <div class="preset-icon"><i class="fa-solid fa-snowflake"></i></div>
                            <div class="preset-details"><span class="preset-name">극저온 빙결 시험</span><span class="preset-spec">-50°C</span></div>
                        </button>
                    </div>
                </div>
            </div>
            <!-- Auto Injected Right Column wrapper for Design 1 -->
            <div class="right-column">
                <div class="panel simulation-panel">
                                <div class="panel-header">
                                    <div>
                                        <i class="fa-solid fa-chart-line text-cyan"></i>
                                        <h2>실시간 거시/미시 변형 시뮬레이터</h2>
                                    </div>
                                    <span id="canvas-scale-indicator" class="canvas-scale-indicator">배율: 100배 과장</span>
                                </div>
                                <div class="canvas-wrapper">
                                    <canvas id="physics-canvas"></canvas>
                                </div>
                                <!-- Integrated Results Analysis Section -->
                            <div class="simulation-results-section">
                                <div class="ratio-readout-box">
                                            <div class="ratio-title">길이 변화량 (ΔL)</div>
                                            <div id="txt-delta-l" class="ratio-value">+15.30 mm</div>
                                        </div>
                                <div class="results-grid">
                                        <!-- Temperature Diff -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-temperature-half text-cyan"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">온도 변화폭 (ΔT)</span>
                                                <span id="txt-delta-t" class="card-value">180 °C</span>
                                            </div>
                                        </div>
                                        <!-- Final Length -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-ruler-horizontal text-purple"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">최종 전체 길이 (L)</span>
                                                <span id="txt-final-l" class="card-value">5.0153 m</span>
                                            </div>
                                        </div>
                                        <!-- Thermal Strain -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-percent text-magenta"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">열변형률 (Thermal Strain)</span>
                                                <span id="txt-strain" class="card-value">0.306 %</span>
                                            </div>
                                        </div>
                                        <!-- Thermal Stress -->
                                        <div class="result-card">
                                            <div class="card-icon"><i class="fa-solid fa-compress text-success"></i></div>
                                            <div class="card-content">
                                                <span class="card-unit">구속 시 온도응력 (Thermal Stress)</span>
                                                <span id="txt-stress" class="card-value">414.0 MPa</span>
                                            </div>
                                        </div>
                                    </div>
                                <div class="formula-card">
                                            <h4><i class="fa-solid fa-circle-info text-cyan"></i> 선팽창 계산 공식</h4>
                                            <div class="formula-equation">
                                                ΔL = α × L₀ × ΔT
                                            </div>
                                        </div>
                            </div>
                </div>
            </div>
        </div>
        <!-- Disclaimer Footer -->
        <footer class="app-disclaimer" style="margin-top: 20px; padding: 12px 16px; background: rgba(0, 0, 0, 0.015); border: 1px solid var(--color-border); border-radius: 12px; font-size: 11px; color: var(--color-text-muted); line-height: 1.5; text-align: left; display: flex; gap: 10px; align-items: flex-start; clear: both;">
            <i class="fa-solid fa-circle-info" style="color: var(--color-cyan); font-size: 14px; margin-top: 2px; flex-shrink: 0;"></i>
            <span><strong>면책 조항 (Disclaimer):</strong> 본 시뮬레이터의 계산 결과는 교육 및 참고용으로만 제공되며, 실제 제품 설계나 제작 시에는 반드시 최신 공학 규격 및 공식 표준 설계 기준을 재확인하시기 바랍니다. 계산 값의 무결성을 보장하지 않으며, 이로 인해 발생하는 직접적/간접적 손해에 대해 제작자 및 본 블로그는 어떠한 책임을 지지 않습니다.</span>
        </footer>
</div>
    <!-- JavaScript Core Simulator Engine -->
    </div>
</div>
<script>
        (function() {
            let isInit = false;
            function initSimulator() {
                if (isInit) return;
                const canvas = document.getElementById('physics-canvas');
                if (!canvas) return;
                const ctx = canvas.getContext('2d');
                if (!ctx) return;
                isInit = true;
                window.__thermalexpansion_initialized = true;
                // DOM elements
                const selectMaterial = document.getElementById('select-material');
                const sliderL0 = document.getElementById('slider-l0');
                const inputL0 = document.getElementById('input-l0');
                const sliderT1 = document.getElementById('slider-t1');
                const inputT1 = document.getElementById('input-t1');
                const sliderT2 = document.getElementById('slider-t2');
                const inputT2 = document.getElementById('input-t2');
                const presetBtns = document.querySelectorAll('.preset-btn');
                const txtDeltaL = document.getElementById('txt-delta-l');
                const txtDeltaT = document.getElementById('txt-delta-t');
                const txtFinalL = document.getElementById('txt-final-l');
                const txtStrain = document.getElementById('txt-strain');
                const txtStress = document.getElementById('txt-stress');
                // Simulation State
                const state = {
                    material: 'steel',
                    l0: 5.0,
                    t1: 20,
                    t2: 200,
                    alpha: 11.5e-6,
                    youngsModulus: 200e9, // Pa
                    density: 7850,
                    colorGradStart: '#94a3b8',
                    colorGradEnd: '#475569',
                    particles: []
                };
                const materialProperties = {
                    steel: {
                        alpha: 11.5e-6,
                        E: 200e9,
                        density: 7850,
                        c1: '#a1a1aa',
                        c2: '#52525b'
                    },
                    copper: {
                        alpha: 17.0e-6,
                        E: 110e9,
                        density: 8960,
                        c1: '#fb923c',
                        c2: '#c2410c'
                    },
                    aluminum: {
                        alpha: 23.0e-6,
                        E: 70e9,
                        density: 2700,
                        c1: '#cbd5e1',
                        c2: '#64748b'
                    },
                    brass: {
                        alpha: 19.0e-6,
                        E: 90e9,
                        density: 8500,
                        c1: '#fde047',
                        c2: '#ca8a04'
                    }
                };
                // Retina Display Canvas adaptation
                function resizeCanvas() {
                    const rect = canvas.getBoundingClientRect();
                    const dpr = window.devicePixelRatio || 1;
                    canvas.width = rect.width * dpr;
                    canvas.height = rect.height * dpr;
                    ctx.scale(dpr, dpr);
                }
                resizeCanvas();
                window.addEventListener('resize', resizeCanvas);
                setTimeout(resizeCanvas, 300);
                // Input sync handlers
                function syncL0FromSlider() {
                    const val = parseFloat(sliderL0.value);
                    inputL0.value = val.toFixed(1);
                    state.l0 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncL0FromInput() {
                    let val = parseFloat(inputL0.value);
                    if (isNaN(val)) {
                        val = 5.0;
                    }
                    if (val < 1.0) {
                        val = 1.0;
                    }
                    if (val > 10.0) {
                        val = 10.0;
                    }
                    sliderL0.value = val;
                    state.l0 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncT1FromSlider() {
                    const val = parseInt(sliderT1.value);
                    inputT1.value = val;
                    state.t1 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncT1FromInput() {
                    let val = parseInt(inputT1.value);
                    if (isNaN(val)) {
                        val = 20;
                    }
                    if (val < -50) {
                        val = -50;
                    }
                    if (val > 100) {
                        val = 100;
                    }
                    sliderT1.value = val;
                    state.t1 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncT2FromSlider() {
                    const val = parseInt(sliderT2.value);
                    inputT2.value = val;
                    state.t2 = val;
                    clearPresets();
                    updateCalculations();
                }
                function syncT2FromInput() {
                    let val = parseInt(inputT2.value);
                    if (isNaN(val)) {
                        val = 200;
                    }
                    if (val < -50) {
                        val = -50;
                    }
                    if (val > 500) {
                        val = 500;
                    }
                    sliderT2.value = val;
                    state.t2 = val;
                    clearPresets();
                    updateCalculations();
                }
                function handleMaterialChange() {
                    const selected = selectMaterial.value;
                    const props = materialProperties[selected];
                    if (props) {
                        state.material = selected;
                        state.alpha = props.alpha;
                        state.youngsModulus = props.E;
                        state.density = props.density;
                        state.colorGradStart = props.c1;
                        state.colorGradEnd = props.c2;
                    }
                    updateCalculations();
                }
                function loadPreset(presetKey) {
                    clearPresets();
                    presetBtns.forEach(btn => {
                        if (btn.dataset.preset === presetKey) {
                            btn.classList.add('active');
                        }
                    });
                    if (presetKey === 'heat') {
                        state.t1 = 20;
                        state.t2 = 500;
                    }
                    if (presetKey === 'normal') {
                        state.t1 = 20;
                        state.t2 = 20;
                    }
                    if (presetKey === 'cold') {
                        state.t1 = 20;
                        state.t2 = -50;
                    }
                    sliderT1.value = state.t1;
                    inputT1.value = state.t1;
                    sliderT2.value = state.t2;
                    inputT2.value = state.t2;
                    updateCalculations();
                }
                function clearPresets() {
                    presetBtns.forEach(btn => btn.classList.remove('active'));
                }
                // Math Model update
                function updateCalculations() {
                    const deltaT = state.t2 - state.t1;
                    const deltaL = state.alpha * state.l0 * deltaT * 1000; // mm
                    const finalL = state.l0 + (deltaL / 1000);
                    const strain = (state.alpha * deltaT) * 100; // %
                    const stress = state.youngsModulus * state.alpha * deltaT / 1e6; // MPa
                    txtDeltaT.innerText = `${deltaT} °C`;
                    if (deltaL >= 0) {
                        txtDeltaL.innerText = `+${deltaL.toFixed(3)} mm`;
                        txtDeltaL.style.color = '#db2777';
                    }
                    if (deltaL < 0) {
                        txtDeltaL.innerText = `${deltaL.toFixed(3)} mm`;
                        txtDeltaL.style.color = '#0284c7';
                    }
                    txtFinalL.innerText = `${finalL.toFixed(6)} m`;
                    txtStrain.innerText = `${strain.toFixed(4)} %`;
                    txtStress.innerText = `${stress.toFixed(1)} MPa`;
                }
                // Particle systems (Fire/Ice)
                class EffectParticle {
                    constructor(x, y, type) {
                        this.x = x;
                        this.y = y;
                        this.type = type; // 'fire' or 'cold'
                        this.size = Math.random() * 4 + 2;
                        this.vx = (Math.random() - 0.5) * 1.0;
                        if (type === 'fire') {
                            this.vy = -(Math.random() * 1.5 + 0.5);
                            this.life = Math.random() * 30 + 20;
                            const colors = ['#f97316', '#ef4444', '#f59e0b', '#ef4444'];
                            this.color = colors[Math.floor(Math.random() * colors.length)];
                        }
                        if (type === 'cold') {
                            this.vy = Math.random() * 1.2 + 0.3;
                            this.life = Math.random() * 40 + 30;
                            const colors = ['#38bdf8', '#0284c7', '#ffffff', '#e0f2fe'];
                            this.color = colors[Math.floor(Math.random() * colors.length)];
                        }
                        this.maxLife = this.life;
                    }
                    update() {
                        this.x += this.vx;
                        this.y += this.vy;
                        this.life--;
                    }
                    draw(c) {
                        const alpha = this.life / this.maxLife;
                        c.save();
                        c.globalAlpha = alpha;
                        c.fillStyle = this.color;
                        c.beginPath();
                        if (this.type === 'cold') {
                            c.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                            c.fill();
                        }
                        if (this.type === 'fire') {
                            c.beginPath();
                            c.moveTo(this.x, this.y - this.size);
                            c.lineTo(this.x + this.size, this.y + this.size);
                            c.lineTo(this.x - this.size, this.y + this.size);
                            c.closePath();
                            c.fill();
                        }
                        c.restore();
                    }
                }
                // Helper to draw dimensional arrowheads
                function drawArrowhead(c, x, y, angle) {
                    c.save();
                    c.translate(x, y);
                    c.rotate(angle);
                    c.beginPath();
                    c.moveTo(0, 0);
                    c.lineTo(-6, -3.5);
                    c.lineTo(-6, 3.5);
                    c.closePath();
                    c.fillStyle = c.strokeStyle;
                    c.fill();
                    c.restore();
                }
                // Render main loop
                function animate(timestamp) {
                    requestAnimationFrame(animate);
                    // Check and auto-fit canvas resolution to layout changes (prevents vertical stretch &#038; empty gaps)
                    const dpr = window.devicePixelRatio || 1;
                    const rect = canvas.getBoundingClientRect();
                    if (Math.abs(canvas.width - rect.width * dpr) > 1.5 || Math.abs(canvas.height - rect.height * dpr) > 1.5) {
                        resizeCanvas();
                    }
                    const width = canvas.width / dpr;
                    const height = canvas.height / dpr;
                    ctx.clearRect(0, 0, width, height);
                    // Blueprint Grid Lines
                    ctx.save();
                    ctx.strokeStyle = 'rgba(2, 132, 199, 0.05)';
                    ctx.lineWidth = 1;
                    for (let x = 0; x < width; x += 24) {
                        ctx.beginPath();
                        ctx.moveTo(x, 0);
                        ctx.lineTo(x, height);
                        ctx.stroke();
                    }
                    for (let y = 0; y < height; y += 24) {
                        ctx.beginPath();
                        ctx.moveTo(0, y);
                        ctx.lineTo(width, y);
                        ctx.stroke();
                    }
                    ctx.restore();
                    // Physics Expansion calculations
                    const deltaT = state.t2 - state.t1;
                    const deltaL = state.alpha * state.l0 * deltaT * 1000; // in mm
                    const finalL = state.l0 + (deltaL / 1000);
                    // Layout positions - dynamic auto-zoom based on canvas size
                    const startX = 60;
                    // Leave 240px for dial gauge and magnifier to prevent boundary overflow
                    const availWidth = (width - startX - 240); 
                    // Map l0 (1.0m to 10.0m) to baseWidth (35% to 65% of availWidth)
                    const maxBaseWidth = availWidth * 0.65;
                    const minBaseWidth = availWidth * 0.35;
                    const baseWidth = minBaseWidth + (state.l0 - 1.0) / 9.0 * (maxBaseWidth - minBaseWidth);
                    // Dynamic visual expansion scale: max 15% of availWidth at 1.5% thermal strain
                    const maxExpansionWidth = availWidth * 0.15;
                    const strainPct = state.alpha * deltaT;
                    const visualExpansion = (strainPct / 0.015) * maxExpansionWidth; 
                    const rodHeight = Math.max(25, Math.min(45, height * 0.105));
                    // Golden Vertical Centering: mathematically centers the rod, dimension lines, and particle overlays
                    const totalDrawHeight = rodHeight + 84;
                    const rodY = (height - totalDrawHeight) / 2 + 10;
                    const currentRodWidth = baseWidth + visualExpansion;
                    // Draw Left Anchor Bracket
                    ctx.save();
                    ctx.fillStyle = '#64748b';
                    ctx.fillRect(startX - 20, rodY - 15, 20, rodHeight + 30);
                    ctx.strokeStyle = '#334155';
                    ctx.lineWidth = 2;
                    ctx.strokeRect(startX - 20, rodY - 15, 20, rodHeight + 30);
                    // Hatch pattern on anchor
                    ctx.strokeStyle = 'rgba(255,255,255,0.2)';
                    ctx.lineWidth = 1.5;
                    for (let h = rodY - 10; h < rodY + rodHeight + 15; h += 8) {
                        ctx.beginPath();
                        ctx.moveTo(startX - 18, h);
                        ctx.lineTo(startX - 2, h - 8);
                        ctx.stroke();
                    }
                    ctx.restore();
                    // Particles spawn (Flame underneath, or ice falling from top)
                    if (state.t2 > state.t1) {
                        // Spawn burner flame
                        const heatIntensity = Math.min((state.t2 - state.t1) / 300, 1.5);
                        if (Math.random() < 0.25 * heatIntensity) {
                            const px = startX + Math.random() * currentRodWidth;
                            state.particles.push(new EffectParticle(px, rodY + rodHeight + 15, 'fire'));
                        }
                    }
                    if (state.t2 < state.t1) {
                        // Spawn cold snowflake drop
                        const coldIntensity = Math.min((state.t1 - state.t2) / 100, 1.5);
                        if (Math.random() < 0.25 * coldIntensity) {
                            const px = startX + Math.random() * currentRodWidth;
                            state.particles.push(new EffectParticle(px, rodY - 20, 'cold'));
                        }
                    }
                    // Update &#038; Draw Particles
                    state.particles = state.particles.filter(p => p.life > 0);
                    state.particles.forEach(p => {
                        p.update();
                        p.draw(ctx);
                    });
                    // Draw heating element or cooling block visualizers
                    if (state.t2 > state.t1) {
                        ctx.fillStyle = 'rgba(239, 68, 68, 0.05)';
                        ctx.fillRect(startX, rodY + rodHeight + 2, currentRodWidth, 12);
                    }
                    if (state.t2 < state.t1) {
                        ctx.fillStyle = 'rgba(56, 189, 248, 0.05)';
                        ctx.fillRect(startX, rodY - 14, currentRodWidth, 12);
                    }
                    // Draw the Metal Rod itself
                    ctx.save();
                    // 1. Draw base initial length segment
                    const metalGrad = ctx.createLinearGradient(startX, rodY, startX, rodY + rodHeight);
                    metalGrad.addColorStop(0, state.colorGradStart);
                    metalGrad.addColorStop(0.3, '#ffffff');
                    metalGrad.addColorStop(1, state.colorGradEnd);
                    ctx.fillStyle = metalGrad;
                    // Draw base width (L0 portion)
                    if (visualExpansion >= 0) {
                        ctx.fillRect(startX, rodY, baseWidth, rodHeight);
                        // 2. Draw expanded segment (with pinkish/red overlay + stripes for clarity)
                        ctx.fillStyle = 'rgba(219, 39, 119, 0.2)';
                        ctx.fillRect(startX + baseWidth, rodY, visualExpansion, rodHeight);
                        ctx.strokeStyle = 'rgba(219, 39, 119, 0.4)';
                        ctx.lineWidth = 1.5;
                        for (let bx = startX + baseWidth; bx < startX + baseWidth + visualExpansion; bx += 8) {
                            ctx.beginPath();
                            ctx.moveTo(bx, rodY);
                            ctx.lineTo(bx + 6, rodY + rodHeight);
                            ctx.stroke();
                        }
                    } else {
                        // Rod has contracted (visualExpansion is negative)
                        ctx.fillRect(startX, rodY, currentRodWidth, rodHeight);
                        // Show contracted missing region as dotted translucent blue box
                        ctx.strokeStyle = 'rgba(2, 132, 199, 0.4)';
                        ctx.lineWidth = 1.5;
                        ctx.setLineDash([3, 3]);
                        ctx.strokeRect(startX + currentRodWidth, rodY, -visualExpansion, rodHeight);
                        ctx.setLineDash([]);
                        ctx.fillStyle = 'rgba(2, 132, 199, 0.08)';
                        ctx.fillRect(startX + currentRodWidth, rodY, -visualExpansion, rodHeight);
                    }
                    // External border for the actual physical rod
                    ctx.strokeStyle = state.colorGradEnd;
                    ctx.lineWidth = 2.5;
                    ctx.strokeRect(startX, rodY, currentRodWidth, rodHeight);
                    ctx.restore();
                    // Microscopic View Zoom Callout Circle
                    const zoomCx = width - 85;
                    const zoomCy = 75;
                    const zoomR = 45;
                    ctx.save();
                    // Draw outer border ring of magnifier
                    ctx.beginPath();
                    ctx.arc(zoomCx, zoomCy, zoomR, 0, Math.PI * 2);
                    ctx.fillStyle = '#ffffff';
                    ctx.fill();
                    ctx.strokeStyle = '#94a3b8';
                    ctx.lineWidth = 3;
                    ctx.stroke();
                    // Microscope glass reflection / grid lines
                    ctx.beginPath();
                    ctx.arc(zoomCx, zoomCy, zoomR, 0, Math.PI * 2);
                    ctx.clip();
                    ctx.fillStyle = '#f8fafc';
                    ctx.fill();
                    // Microscopic grid background
                    ctx.strokeStyle = 'rgba(0,0,0,0.02)';
                    ctx.lineWidth = 1;
                    for (let gx = zoomCx - zoomR; gx < zoomCx + zoomR; gx += 12) {
                        ctx.beginPath();
                        ctx.moveTo(gx, zoomCy - zoomR);
                        ctx.lineTo(gx, zoomCy + zoomR);
                        ctx.stroke();
                    }
                    for (let gy = zoomCy - zoomR; gy < zoomCy + zoomR; gy += 12) {
                        ctx.beginPath();
                        ctx.moveTo(zoomCx - zoomR, gy);
                        ctx.lineTo(zoomCx + zoomR, gy);
                        ctx.stroke();
                    }
                    // Atom lattice visualization inside zoom circle
                    const temperatureInfluence = Math.max((state.t2 + 100) / 100, 0.1);
                    const latticeSpacing = 16 + (deltaT * 0.005);
                    const vibrationAmp = temperatureInfluence * 0.45;
                    ctx.fillStyle = state.colorGradEnd;
                    ctx.strokeStyle = 'rgba(0,0,0,0.12)';
                    ctx.lineWidth = 1;
                    for (let lx = -3; lx <= 3; lx++) {
                        for (let ly = -3; ly <= 3; ly++) {
                            const vx = Math.sin(timestamp * 0.015 + lx) * vibrationAmp;
                            const vy = Math.cos(timestamp * 0.012 + ly) * vibrationAmp;
                            const atomX = zoomCx + lx * latticeSpacing + vx;
                            const atomY = zoomCy + ly * latticeSpacing + vy;
                            // Draw bond connections to right and bottom neighbors
                            if (lx < 3) {
                                const nextAtomX = zoomCx + (lx + 1) * latticeSpacing + Math.sin(timestamp * 0.015 + lx + 1) * vibrationAmp;
                                const nextAtomY = zoomCy + ly * latticeSpacing + Math.cos(timestamp * 0.012 + ly) * vibrationAmp;
                                ctx.beginPath();
                                ctx.moveTo(atomX, atomY);
                                ctx.lineTo(nextAtomX, nextAtomY);
                                ctx.stroke();
                            }
                            if (ly < 3) {
                                const nextAtomX = zoomCx + lx * latticeSpacing + Math.sin(timestamp * 0.015 + lx) * vibrationAmp;
                                const nextAtomY = zoomCy + (ly + 1) * latticeSpacing + Math.cos(timestamp * 0.012 + ly + 1) * vibrationAmp;
                                ctx.beginPath();
                                ctx.moveTo(atomX, atomY);
                                ctx.lineTo(nextAtomX, nextAtomY);
                                ctx.stroke();
                            }
                            // Draw atom node
                            ctx.beginPath();
                            ctx.arc(atomX, atomY, 3.5, 0, Math.PI * 2);
                            ctx.fill();
                        }
                    }
                    // Lens reflection overlay
                    const glassGrad = ctx.createLinearGradient(zoomCx - zoomR, zoomCy - zoomR, zoomCx + zoomR, zoomCy + zoomR);
                    glassGrad.addColorStop(0, 'rgba(255,255,255,0.4)');
                    glassGrad.addColorStop(0.5, 'rgba(255,255,255,0.05)');
                    glassGrad.addColorStop(1, 'rgba(2,132,199,0.05)');
                    ctx.fillStyle = glassGrad;
                    ctx.beginPath();
                    ctx.arc(zoomCx, zoomCy, zoomR, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                    // Magnifier link lines from rod end to callout
                    ctx.save();
                    ctx.strokeStyle = 'rgba(148, 163, 184, 0.4)';
                    ctx.lineWidth = 1;
                    ctx.setLineDash([4, 4]);
                    ctx.beginPath();
                    ctx.moveTo(startX + currentRodWidth, rodY);
                    ctx.lineTo(zoomCx - zoomR + 5, zoomCy - 20);
                    ctx.moveTo(startX + currentRodWidth, rodY + rodHeight);
                    ctx.lineTo(zoomCx - zoomR + 5, zoomCy + 20);
                    ctx.stroke();
                    ctx.restore();
                    // Microscope tag text
                    ctx.fillStyle = '#64748b';
                    ctx.font = 'bold 9px sans-serif';
                    ctx.textAlign = 'center';
                    ctx.fillText('미시 원자 격자 뷰', zoomCx, zoomCy + zoomR + 13);
                    // Micro Dial gauge representation below rod right end
                    const gaugeX = startX + currentRodWidth + 10;
                    const gaugeY = rodY + rodHeight / 2;
                    ctx.save();
                    // Draw contact plunger pin pressed against rod end
                    ctx.fillStyle = '#94a3b8';
                    ctx.fillRect(startX + currentRodWidth, gaugeY - 3, 22, 6);
                    ctx.strokeStyle = '#475569';
                    ctx.lineWidth = 1.5;
                    ctx.strokeRect(startX + currentRodWidth, gaugeY - 3, 22, 6);
                    // Dial body
                    const dialR = 24;
                    const dialCx = gaugeX + dialR + 10;
                    const dialCy = gaugeY;
                    ctx.beginPath();
                    ctx.arc(dialCx, dialCy, dialR, 0, Math.PI * 2);
                    ctx.fillStyle = '#ffffff';
                    ctx.fill();
                    ctx.strokeStyle = '#334155';
                    ctx.lineWidth = 2.5;
                    ctx.stroke();
                    // Dial grad ticks
                    ctx.strokeStyle = '#475569';
                    ctx.lineWidth = 1;
                    for (let ti = 0; ti < 12; ti++) {
                        const tickAng = (ti * Math.PI * 2) / 12;
                        ctx.beginPath();
                        ctx.moveTo(dialCx + dialR * Math.cos(tickAng), dialCy + dialR * Math.sin(tickAng));
                        ctx.lineTo(dialCx + (dialR - 4) * Math.cos(tickAng), dialCy + (dialR - 4) * Math.sin(tickAng));
                        ctx.stroke();
                    }
                    // Rotating indicator hand
                    // Rotates 360deg for every 10mm of expansion
                    const handAngle = (deltaL / 10.0) * Math.PI * 2;
                    ctx.strokeStyle = '#ef4444';
                    ctx.lineWidth = 2;
                    ctx.beginPath();
                    ctx.moveTo(dialCx, dialCy);
                    ctx.lineTo(dialCx + (dialR - 6) * Math.cos(handAngle), dialCy + (dialR - 6) * Math.sin(handAngle));
                    ctx.stroke();
                    // Dial hub pin
                    ctx.fillStyle = '#0f172a';
                    ctx.beginPath();
                    ctx.arc(dialCx, dialCy, 3, 0, Math.PI * 2);
                    ctx.fill();
                    ctx.restore();
                    ctx.fillStyle = '#64748b';
                    ctx.font = 'bold 9px sans-serif';
                    ctx.textAlign = 'center';
                    ctx.fillText('마이크로미터 변위계', dialCx, dialCy + dialR + 13);
                    // Visual Temperature Gradient Coloring bar (Repositioned to top-left corner)
                    ctx.save();
                    ctx.font = 'bold 11px Outfit';
                    ctx.fillStyle = '#64748b';
                    ctx.textAlign = 'left';
                    const tempBarX = 24;
                    const tempBarY = 40;
                    const tempBarW = 130;
                    const tempBarH = 6;
                    ctx.fillText(`현재 온도: ${state.t2}°C`, tempBarX, tempBarY - 10);
                    ctx.fillStyle = '#e2e8f0';
                    ctx.fillRect(tempBarX, tempBarY, tempBarW, tempBarH);
                    const barGrad = ctx.createLinearGradient(tempBarX, tempBarY, tempBarX + tempBarW, tempBarY);
                    barGrad.addColorStop(0, '#38bdf8');
                    barGrad.addColorStop(0.5, '#e2e8f0');
                    barGrad.addColorStop(1, '#ef4444');
                    ctx.fillStyle = barGrad;
                    ctx.fillRect(tempBarX, tempBarY, tempBarW, tempBarH);
                    // Draw marker pointer for current temperature T2
                    const normalizedT2 = (state.t2 - (-50)) / 550; // -50 to 500 scale
                    const markerX = tempBarX + Math.min(Math.max(normalizedT2, 0), 1.0) * tempBarW;
                    ctx.fillStyle = '#0f172a';
                    ctx.beginPath();
                    ctx.moveTo(markerX, tempBarY - 2);
                    ctx.lineTo(markerX - 4, tempBarY - 7);
                    ctx.lineTo(markerX + 4, tempBarY - 7);
                    ctx.closePath();
                    ctx.fill();
                    ctx.restore();
                    // Rod Dimensions scale line underneath (L0, Delta L, and Final L)
                    ctx.save();
                    // 1. Vertical guide lines (dashed)
                    ctx.strokeStyle = 'rgba(148, 163, 184, 0.35)';
                    ctx.lineWidth = 1;
                    ctx.setLineDash([3, 3]);
                    // Start guide line (startX)
                    ctx.beginPath();
                    ctx.moveTo(startX, rodY + rodHeight);
                    ctx.lineTo(startX, rodY + rodHeight + 63);
                    ctx.stroke();
                    // Initial length guide line (startX + baseWidth)
                    ctx.beginPath();
                    ctx.moveTo(startX + baseWidth, rodY);
                    ctx.lineTo(startX + baseWidth, rodY + rodHeight + 43);
                    ctx.stroke();
                    // Final end-point guide line (startX + currentRodWidth)
                    ctx.beginPath();
                    ctx.moveTo(startX + currentRodWidth, rodY);
                    ctx.lineTo(startX + currentRodWidth, rodY + rodHeight + 63);
                    ctx.stroke();
                    ctx.setLineDash([]);
                    // 2. Initial Length dimension line (L₀) - Level 1 (dimY1)
                    const dimY1 = rodY + rodHeight + 20;
                    ctx.strokeStyle = '#64748b';
                    ctx.lineWidth = 1;
                    ctx.beginPath();
                    ctx.moveTo(startX, dimY1);
                    ctx.lineTo(startX + baseWidth, dimY1);
                    ctx.stroke();
                    // Arrowheads
                    drawArrowhead(ctx, startX, dimY1, Math.PI);
                    drawArrowhead(ctx, startX + baseWidth, dimY1, 0);
                    // L₀ text label
                    ctx.fillStyle = '#475569';
                    ctx.font = '500 10px Inter';
                    ctx.textAlign = 'center';
                    ctx.fillText(`초기 L₀ = ${state.l0.toFixed(1)} m`, startX + baseWidth / 2, dimY1 - 4);
                    // 3. Changed/Increased Length dimension line (ΔL) - Level 2 (dimY2)
                    if (Math.abs(visualExpansion) > 3) {
                        const dimY2 = rodY + rodHeight + 40;
                        const isExpansion = deltaL >= 0;
                        ctx.strokeStyle = isExpansion ? '#db2777' : '#0284c7';
                        ctx.lineWidth = 1.2;
                        const expStartX = isExpansion ? startX + baseWidth : startX + currentRodWidth;
                        const expEndX = isExpansion ? startX + currentRodWidth : startX + baseWidth;
                        ctx.beginPath();
                        ctx.moveTo(expStartX, dimY2);
                        ctx.lineTo(expEndX, dimY2);
                        ctx.stroke();
                        drawArrowhead(ctx, expStartX, dimY2, Math.PI);
                        drawArrowhead(ctx, expEndX, dimY2, 0);
                        ctx.fillStyle = isExpansion ? '#db2777' : '#0284c7';
                        ctx.font = 'bold 10px Inter';
                        ctx.textAlign = 'center';
                        const sign = isExpansion ? '+' : '';
                        ctx.fillText(`ΔL = ${sign}${deltaL.toFixed(2)} mm`, expStartX + Math.abs(visualExpansion) / 2, dimY2 - 4);
                    }
                    // 4. Total Final Length dimension line (L) - Level 3 (dimY3)
                    const dimY3 = rodY + rodHeight + 60;
                    ctx.strokeStyle = '#334155';
                    ctx.lineWidth = 1.2;
                    ctx.beginPath();
                    ctx.moveTo(startX, dimY3);
                    ctx.lineTo(startX + currentRodWidth, dimY3);
                    ctx.stroke();
                    // vertical ticks
                    ctx.beginPath();
                    ctx.moveTo(startX, dimY3 - 4); ctx.lineTo(startX, dimY3 + 4);
                    ctx.moveTo(startX + currentRodWidth, dimY3 - 4); ctx.lineTo(startX + currentRodWidth, dimY3 + 4);
                    ctx.stroke();
                    // Final L text
                    ctx.fillStyle = '#0f172a';
                    ctx.font = 'bold 11px monospace';
                    ctx.textAlign = 'center';
                    ctx.fillText(`최종 L = ${finalL.toFixed(5)} m`, startX + currentRodWidth / 2, dimY3 + 14);
                    ctx.restore();
                }
                // Event Listeners mapping
                sliderL0.addEventListener('input', syncL0FromSlider);
                inputL0.addEventListener('change', syncL0FromInput);
                sliderT1.addEventListener('input', syncT1FromSlider);
                inputT1.addEventListener('change', syncT1FromInput);
                sliderT2.addEventListener('input', syncT2FromSlider);
                inputT2.addEventListener('change', syncT2FromInput);
                selectMaterial.addEventListener('change', handleMaterialChange);
                presetBtns.forEach(btn => {
                    btn.addEventListener('click', function() {
                        loadPreset(btn.dataset.preset);
                    });
                });
                // Initial run
                handleMaterialChange();
                requestAnimationFrame(animate);
                // Anti-copying / Context protection code
                document.addEventListener('contextmenu', function(e) {
                    e.preventDefault();
                    alert("이 시뮬레이터 프로그램의 지식재산권은 보호받고 있습니다.");
                    return false;
                }, { capture: true });
                document.addEventListener('selectstart', function(e) {
                    e.preventDefault();
                    return false;
                }, { capture: true });
                document.addEventListener('keydown', function(e) {
                    if (e.key === 'F12') {
                        e.preventDefault();
                        alert("이 시뮬레이터 프로그램의 지식재산권은 보호받고 있습니다.");
                        return false;
                    }
                    if (e.ctrlKey) {
                        if (e.key === 'u' || e.key === 'c' || e.key === 's' || e.key === 'U' || e.key === 'C' || e.key === 'S') {
                            e.preventDefault();
                            alert("이 시뮬레이터 프로그램의 지식재산권은 보호받고 있습니다.");
                            return false;
                        }
                    }
                }, { capture: true });
            }
            // Retry loader sequence
            let loadAttempts = 0;
            function tryLoad() {
                loadAttempts++;
                initSimulator();
                if (!window.__thermalexpansion_initialized) {
                    if (loadAttempts < 50) {
                        setTimeout(tryLoad, 100);
                    }
                }
            }
            if (document.readyState === 'complete' || document.readyState === 'interactive') {
                tryLoad();
            } else {
                document.addEventListener('DOMContentLoaded', tryLoad);
                window.addEventListener('load', tryLoad);
            }
        })();
</script>


<div style="background: linear-gradient(135deg, rgba(0,242,254,0.03), rgba(138,43,226,0.03)); border: 1px solid rgba(0,242,254,0.15); border-radius: 12px; padding: 18px 24px; margin: 25px auto 35px auto; font-size: 0.95em; color: #4b5563; line-height: 1.7; font-family: sans-serif;">
    <strong style="color: #1f2937; font-size: 1.05em; display: flex; align-items: center; gap: 8px;">
        <span style="font-size: 1.2em;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span> 간편 사용 설명서
    </strong>
    <ol style="margin: 10px 0 0 0; padding-left: 20px;">
        <li style="margin-bottom: 6px;"><strong>재질 선택: 강철, 구리, 알루미늄, 황동 등 분석할 금속을 선택하여 고유 선팽창계수(α)를 적용합니다.</strong></li>
<li style="margin-bottom: 6px;">초기 조건 설정: 봉의 초기 길이(L₀)와 초기 온도(T₁)를 슬라이더 또는 텍스트 입력으로 설정합니다.</li>
<li style="margin-bottom: 6px;">대상 온도 제어: 가열 또는 냉각할 최종 온도(T₂)를 조절하면 봉 아래에 가스 버너 불꽃이나 얼음 결정이 렌더링됩니다.</li>
<li style="margin-bottom: 6px;">실시간 팽창 변위 측정: 정밀 다이얼 게이지와 현미경 뷰를 통해 마이크로미터 및 밀리미터 단위로 미세하게 늘어나고 줄어드는 봉의 길이를 확인합니다.</li>
    </ol>
</div>


<details class="premium-seo-accordion" style="border: 1px solid rgba(0,0,0,0.08); border-radius: 12px; background: #fbfbfc; padding: 0; margin: 30px auto; box-shadow: 0 4px 6px -1px rgba(0,0,0,0.01); font-family: sans-serif;">
    <summary style="display: flex; justify-content: space-between; align-items: center; padding: 20px 24px; font-size: 1.1em; font-weight: 700; color: #1f2937; cursor: pointer; user-select: none; outline: none; list-style: none;">
        <span><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4da.png" alt="📚" class="wp-smiley" style="height: 1em; max-height: 1em;" /> 선팽창계수 공식 및 재료별 열팽창 특성 해설 보기</span>
        <span class="accordion-arrow" style="font-size: 0.9em; color: #9ca3af; transition: transform 0.2s ease;">▼</span>
    </summary>
    <div style="padding: 0 24px 24px 24px; border-top: 1px solid rgba(0,0,0,0.04); background: #ffffff; border-radius: 0 0 12px 12px; font-size: 0.98em; color: #374151; line-height: 1.8;">
        <div style="margin-top: 20px;">
            <h3>1. 고체 열팽창(Thermal Expansion)의 물리적 근원</h3>
<p>모든 고체 물질은 온도가 상승함에 따라 부피가 팽창하는 성질을 가집니다. 이는 미시적 관점에서 격자 진동(Lattice Vibration)으로 설명됩니다. 고체 내부의 원자들은 원자 간 결합력에 의해 평형 상태의 에너지를 유지하며 진동하고 있습니다. 에너지가 가해져 온도가 올라가면 원자들의 진동 진폭이 커지게 되는데, 원자 간 비선형 포텐셜 에너지 곡선의 비대칭성 때문에 진동 중심 사이의 평균 거리가 멀어지게 됩니다. 이것이 거시적으로 열팽창으로 관찰되는 물리적 원리입니다.</p><ul><li><strong>선팽창 (Linear Expansion):</strong> 막대나 봉과 같이 길이 방향 차원이 지배적인 물체에서 일어나는 팽창입니다.</li><li><strong>체적팽창 (Volume Expansion):</strong> 3차원 입체 형상 전체의 부피가 팽창하는 것으로, 등방성 고체의 경우 체적팽창계수는 선팽창계수의 약 3배(β ≈ 3α)입니다.</li></ul>
<h3>2. 열팽창 설계 방정식과 변위 유도</h3>
<p>고체의 선팽창 관계식은 온도 변화폭이 아주 크지 않은 경우 다음과 같이 선형 근사로 고도로 정밀하게 예측할 수 있습니다.</p><p><strong>① 선팽창 기본 공식:</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">ΔL = α × L₀ × ΔT &nbsp;[mm]</p><p>여기서 <code>α</code>는 선팽창계수(Coefficient of Linear Expansion, K⁻¹ 또는 °C⁻¹), <code>L₀</code>는 초기 온도에서의 길이(m), <code>ΔT</code>는 온도 변화량(T₂ - T₁, °C)입니다.</p><p><strong>② 최종 길이 계산:</strong></p><p style="text-align: center; font-weight: bold; background: #f3f4f6; padding: 12px; border-radius: 8px;">L = L₀ + ΔL = L₀ × (1 + α × ΔT) &nbsp;[m]</p><p><strong>③ 온도 응력 (Thermal Stress):</strong> 만약 양단이 강체 벽으로 구속되어 팽창이 불가능한 상태에서 가열된다면, 팽창하려는 변위만큼 압축 변형률(Strain)이 발생하여 매우 강력한 내력이 발생합니다. 양단 구속 시 발생하는 열응력 공식은 다음과 같습니다:</p><p style="text-align: center; font-weight: bold; background: #e0f2fe; padding: 16px; border-radius: 8px; font-size: 1.05em; color: #0369a1;">σ_t = E × α × ΔT &nbsp;[MPa]</p><p>여기서 <code>E</code>는 금속의 세로탄성계수(Young's Modulus)입니다. 기계 부품 설계 시 이러한 열응력으로 인한 파손을 방지하기 위해 팽창 여유 갭(Thermal Gap)이나 신축 이음(Expansion Joint) 설치가 필수적입니다.</p>
<h3>3. 주요 금속 재료별 열팽창 특성 및 설계 가이드</h3>
<p>다양한 공업용 금속들은 결정 구조와 결합력의 차이로 인해 상이한 선팽창계수를 가집니다. 설계 시 이종 금속 접합 구조물이 온도 변화를 겪을 때 휠 가능성(바이메탈 효과)을 신중히 고려해야 합니다.</p><ul><li><strong>알루미늄 (Aluminum):</strong> 약 23.0 × 10⁻⁶ /°C 로 열팽창이 매우 크며, 경량화 설계 시 갭 설계가 중요합니다.</li><li><strong>황동 (Brass):</strong> 약 19.0 × 10⁻⁶ /°C 로 동합금 특유의 높은 팽창률을 가집니다.</li><li><strong>구리 (Copper):</strong> 약 17.0 × 10⁻⁶ /°C 로 전선 설계 및 배관 매설 시 길이 방향 수축팽창을 고려해야 합니다.</li><li><strong>탄소강 (Steel):</strong> 약 11.5 × 10⁻⁶ /°C 로 상대적으로 낮고 안정적이며 콘크리트의 팽창계수와 유사하여 철근콘크리트 구조가 성립되는 기반이 됩니다.</li></ul>
        </div>
    </div>
</details>
<style>
details.premium-seo-accordion[open] summary .accordion-arrow { transform: rotate(180deg); color: #00f2fe; }
details.premium-seo-accordion summary::-webkit-details-marker { display: none; }
details.premium-seo-accordion:hover { border-color: rgba(0,242,254,0.3); }
</style>

]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/thermal-expansion-calculator-simulator/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>가공 후 잔류 열에 의한 치수 오차 분석 (Dimensional Error due to Residual Heat)</title>
		<link>https://myengnote.com/dimensional-error-residual-heat-machining/</link>
					<comments>https://myengnote.com/dimensional-error-residual-heat-machining/#respond</comments>
		
		<dc:creator><![CDATA[동동]]></dc:creator>
		<pubDate>Thu, 12 Mar 2026 22:31:07 +0000</pubDate>
				<category><![CDATA[KS규격/기계요소]]></category>
		<category><![CDATA[Dimensional Error]]></category>
		<category><![CDATA[Precision Measurement]]></category>
		<category><![CDATA[Thermal Expansion]]></category>
		<category><![CDATA[가공열]]></category>
		<category><![CDATA[선팽창계수]]></category>
		<category><![CDATA[열팽창]]></category>
		<category><![CDATA[정밀측정]]></category>
		<category><![CDATA[치수오차]]></category>
		<guid isPermaLink="false">https://myengnote.com/dimensional-error-residual-heat-machining/</guid>

					<description><![CDATA[가공 직후 뜨거운 부품을 즉시 측정하면 발생하는 치수 변화의 원인과 물리적 배경을 설명합니다. 정밀 공차를 확보하기 위한 선팽창 계수 활용법을 확인하세요.... <a href="https://myengnote.com/dimensional-error-residual-heat-machining/" style="text-decoration:none; color:#0073aa; font-weight:bold;">[본문 전체보기 >]</a>]]></description>
										<content:encoded><![CDATA[<p class="wp-block-paragraph">과거 자동차 변속기용 정밀 축(샤프트)을 대량 생산하던 현장에서 겪었던 치명적인 품질 사고가 떠오릅니다. 당시 모리세이키 CNC 선반을 이용하여 S45C 탄소강 소재를 고속 가공하고 있었는데, 작업자는 가공 직후 미투토요 외경 마이크로미터로 치수를 측정했습니다. 측정값은 50.005mm로 도면 공차인 50.000~50.010mm 안에 완벽히 들어오는 상태였습니다. 하지만 다음 날 아침, 항온 습실에서 재측정한 결과 모든 부품이 49.982mm로 측정되며 전량 불량 판정을 받았습니다. 불과 몇 시간 만에 23미크론(0.023mm)의 치수 수축이 발생한 것입니다. 원인은 바로 가공 시 발생한 마찰열이 부품에 남아있는 상태에서 측정을 강행했기 때문입니다. </p>
<h2 class="wp-block-heading">실무 필드 로그 및 분석 (Field Log &amp; Analysis)</h2>
<p class="wp-block-paragraph">당시 현장 상황을 데이터로 재구성해 보면 문제의 심각성을 더 명확히 알 수 있습니다. 절삭 가공 시 툴 팁과 공작물 사이에서 발생하는 열은 수백 도에 달하며, 절삭유를 사용하더라도 부품 내부의 온도는 급격히 상승합니다.</p>
<p class="wp-block-paragraph"> * <strong>설비 모델</strong>: 모리세이키 NLX-2500 CNC 선반<br />
* <strong>측정 기기</strong>: 미투토요 외경 마이크로미터 (분해능 0.001mm)<br />
* <strong>대상 부품</strong>: S45C 탄소강 축 (직경 50mm, 길이 200mm)<br />
* <strong>관찰 데이터</strong>: 가공 직후 표면 온도 약 65°C, 측정 치수 50.005mm / 냉각 후(20°C) 측정 치수 49.982mm<br />
* <strong>근거 표준</strong>: ISO 1 (제품의 기하학적 사양 및 검증을 위한 표준 참조 온도 20°C) 및 KS B ISO 1 규격 준수 필요 이 사례에서 알 수 있듯이, 모든 정밀 측정은 물체의 온도가 표준 온도인 20°C로 안정화된 상태에서 이루어져야 합니다. 부품이 뜨거울 때 측정한 값은 실제 치수가 아니라 &#8216;팽창된 상태의 치수&#8217;일 뿐입니다. </p>
<div style="overflow-x: auto; margin: 20px 0; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0,0,0,0.1);">
<table style="border-collapse: collapse; width: 100%; min-width: 700px; font-size: 15px; text-align: left; background-color: #ffffff;">
<thead>
<tr style="background-color: #1f2937; color: #ffffff;">
<th style="padding: 15px; border-bottom: 3px solid #3b82f6; font-weight: bold; text-transform: uppercase;">소재 종류</th>
<th style="padding: 15px; border-bottom: 3px solid #10b981; font-weight: bold; text-transform: uppercase;">선팽창 계수 (10⁻⁶/°C)</th>
<th style="padding: 15px; border-bottom: 3px solid #f59e0b; font-weight: bold; text-transform: uppercase;">100mm당 오차 (Δ10°C)</th>
<th style="padding: 15px; border-bottom: 3px solid #8b5cf6; font-weight: bold; text-transform: uppercase;">비고</th>
</tr>
</thead>
<tbody>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">탄소강 (S45C)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">11.7</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">0.0117 mm</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">일반적인 기계 부품</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">알루미늄 (AL6061)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">23.6</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">0.0236 mm</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">온도 변화에 매우 민감</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">스테인리스강 (SUS304)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">17.3</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">0.0173 mm</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">탄소강보다 팽창이 큼</td>
</tr>
<tr>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; background-color: #f9fafb; font-weight: bold; color: #374151;">황동 (C3604)</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">18.5</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">0.0185 mm</td>
<td style="padding: 12px 15px; border-bottom: 1px solid #e5e7eb; color: #4b5563;">정밀 소형 부품 주의</td>
</tr>
</tbody>
</table>
</div>
<h2 class="wp-block-heading">열팽창의 물리적 원리</h2>
<p class="wp-block-paragraph">왜 금속은 열을 받으면 부피가 커질까요? 이는 분자 수준에서의 물리적 현상 때문입니다. 온도가 상승한다는 것은 원자들의 운동 에너지가 증가함을 의미하며, 이로 인해 원자 간의 진동 폭이 넓어집니다. 원자 사이의 평형 거리는 온도에 비례하여 증가하게 되는데, 이것이 거시적으로는 물체의 길이가 늘어나는 <strong>선팽창</strong>으로 나타납니다.</p>
<p class="wp-block-paragraph">가공 중 발생하는 마찰열은 부품 내부로 빠르게 전달되며, 특히 열전도율이 높은 알루미늄과 같은 소재는 가공 직후 급격한 치수 변화를 보입니다. 이러한 물리적 성질을 이해하지 못하고 측정을 수행하는 것은 정밀 가공에서 치명적인 오차를 발생시키는 원인이 됩니다.</p>
<div style="border-left: 5px solid #ef4444; background-color: #fef2f2; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;">
<span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/26a0.png" alt="⚠" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><br />
<span style="font-weight: bold; color: #991b1b; font-size: 1.2em;">주의사항</span>
</div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">
가공 현장의 실온이 30°C를 넘는 여름철에는 설령 부품이 식었더라도 이미 표준 온도(20°C) 대비 팽창한 상태입니다. 이 오차까지 계산에 넣지 않으면 조립 공정에서 끼워맞춤 불량이 발생할 확률이 매우 높습니다.
</div>
</div>
<div class="wp-block-image">
<figure class="aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="572" src="https://myengnote.com/wp-content/uploads/2026/03/Gemini_Generated_Image_42bik542bik542bi-1024x572.jpg" alt="마이크로미터 측정" class="wp-image-1659" srcset="https://myengnote.com/wp-content/uploads/2026/03/Gemini_Generated_Image_42bik542bik542bi-1024x572.jpg 1024w, https://myengnote.com/wp-content/uploads/2026/03/Gemini_Generated_Image_42bik542bik542bi-300x168.jpg 300w, https://myengnote.com/wp-content/uploads/2026/03/Gemini_Generated_Image_42bik542bik542bi-768x429.jpg 768w, https://myengnote.com/wp-content/uploads/2026/03/Gemini_Generated_Image_42bik542bik542bi.jpg 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>
</div>
<p class="wp-block-paragraph">
<h2 class="wp-block-heading">현장 시나리오 분석</h2>
<p class="wp-block-paragraph">탄소강의 선팽창 계수(11.7 x 10⁻⁶/°C)를 공식 <strong>ΔL = L × α × ΔT</strong>에 대입해 보겠습니다. 만약 100mm 길이의 강철 부품이 가공 직후 70°C라면, 표준 온도 20°C와의 차이는 50°C입니다.</p>
<p class="has-text-align-center wp-block-paragraph">ΔL = 100mm × 0.0000117 × 50 = 0.0585mm</p>
<p class="wp-block-paragraph">즉, 작업자가 가공 직후 100.000mm로 가공했더라도, 이 부품이 식으면 99.9415mm가 되어버립니다. 만약 도면의 공차가 ±0.01mm라면, 이 부품은 온도 하나 때문에 불량 처리됩니다. 이러한 현상은 특히 얇은 벽을 가진 원통형 부품이나 길이가 긴 장축 가공 시 더욱 심각해집니다.</p>
<div style="border-left: 5px solid #3b82f6; background-color: #eff6ff; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;">
<span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4d8.png" alt="📘" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><br />
<span style="font-weight: bold; color: #1e40af; font-size: 1.2em;">핵심 요약</span>
</div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">
1. 모든 금속은 열에 의해 팽창하며 소재마다 고유의 <strong>선팽창 계수</strong>를 가진다.<br />
2. 측정의 세계 표준 온도는 <strong>20°C(ISO 1)</strong>이다.<br />
3. 가공 직후 측정은 참값이 아닌 변화값을 측정하는 오류를 범하기 쉽다.<br />
4. 고정밀 가공일수록 충분한 냉각 시간과 온도 보정이 필수적이다.
</div>
</div>
<p class="wp-block-paragraph">가공 부품의 정확한 물성치를 이해하기 위해서는 소재 자체의 성질을 파악하는 것도 중요합니다. 금속의 기계적 성질과 열팽창은 밀접한 관련이 있기 때문입니다.</p>
<p class="wp-block-paragraph"> <a href="https://myengnote.com/how-to-read-mill-test-report-mechanical-properties/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><br />
<span style="display: table-cell; vertical-align: middle;"><br />
<span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><br />
<span style="display: block; overflow: hidden;"><br />
<span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><br />
<span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">소재 성적서 기계적 성질 해석법</span><br />
</span><br />
</span><br />
<span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span><br />
</a> </p>
<h2 class="wp-block-heading">마치며: 현장 전문가의 권고</h2>
<p class="wp-block-paragraph">만약 제가 생산 라인의 책임 엔지니어라면, 가공 직후 즉시 측정하는 것을 금지하거나 부득이한 경우 반드시 <strong>온도 보정 수식</strong>을 작업표준서에 기입하도록 조치할 것입니다. 현장에서 실수를 줄이기 위한 가장 현실적인 방법은 다음과 같습니다.</p>
<ul class="wp-block-list">
<li>첫째, 절삭유를 충분히 공급하여 가공 중 온도 상승을 최대한 억제해야 합니다.</li>
<li>둘째, 정밀 측정이 필요한 제품은 가공 후 충분한 시간 동안 정반 위에서 방치하여 실온과 동기화시켜야 합니다.</li>
<li>셋째, 현장의 실온을 상시 체크하여 20°C와의 편차만큼 선팽창 계수를 적용해 역산하는 습관을 들여야 합니다.</li>
</ul>
<p class="wp-block-paragraph">결국 기계 가공은 물리 법칙과의 싸움입니다. 뜨거운 부품을 손에 쥐고 마이크로미터를 돌리기 전에, 그 부품이 차갑게 식었을 때의 모습을 상상할 수 있어야 진정한 숙련공이라 할 수 있습니다.</p>
<div style="border-left: 5px solid #f59e0b; background-color: #fffbeb; padding: 15px; margin: 30px 0; border-radius: 10px; box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.05);">
<div style="display: flex; align-items: center; margin-bottom: 12px;">
<span style="font-size: 30px; margin-right: 15px;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><br />
<span style="font-weight: bold; color: #92400e; font-size: 1.2em;">현장 전문가의 팁</span>
</div>
<div style="color: #444; line-height: 1.8; font-size: 1.05em;">
가공 직후 온도를 알 수 없을 때는 비접촉식 적외선 온도계를 사용하여 표면 온도를 즉시 확인하십시오. 40°C만 되어도 일반 탄소강 기준 100mm당 0.02mm 이상의 오차가 발생할 수 있음을 명심해야 합니다.
</div>
</div>
<h2 class="wp-block-heading">연관글</h2>
<p class="wp-block-paragraph"><a href="https://myengnote.com/three-purposes-and-basic-types-of-heat-treatment-guide/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><br />
<span style="display: table-cell; vertical-align: middle;"><br />
<span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><br />
<span style="display: block; overflow: hidden;"><br />
<span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><br />
<span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">열처리의 3대 목적과 주요 공정 종류</span><br />
</span><br />
</span><br />
<span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span><br />
</a><a href="https://myengnote.com/understanding-metal-hardness-units-hrc-and-hb/" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><br />
<span style="display: table-cell; vertical-align: middle;"><br />
<span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f517.png" alt="🔗" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><br />
<span style="display: block; overflow: hidden;"><br />
<span style="display: block; font-size: 0.9em; color: #6b7280; margin-bottom: 4px;">함께 보면 좋은 글</span><br />
<span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">금속 경도 단위 HRC와 HB의 차이점 이해하기</span><br />
</span><br />
</span><br />
<span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #3b82f6; font-size: 24px; font-weight: bold;">→</span><br />
</a></p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<p class="has-text-align-center wp-block-paragraph">
    본 콘텐츠는 저작권법의 보호를 받으며, 무단 전재 및 재배포를 금지합니다.<br />
    Copyright 2026. 동동 All rights reserved.
</p>
<p class="wp-block-paragraph"><!-- Protection Scripts --></p>
<div id="protection-script" style="display:none;">
<script><br />
document.addEventListener('contextmenu', function(e) {<br />
    e.preventDefault();<br />
    alert('이 콘텐츠는 저작권법의 보호를 받습니다. 무단 복제 및 우클릭을 금지합니다.');<br />
});<br />
document.addEventListener('keydown', function(e) {<br />
    if (e.ctrlKey && (e.key === 'c' || e.key === 'u' || e.key === 'a')) {<br />
        e.preventDefault();<br />
        alert('무단 복제를 금지합니다.');<br />
    }<br />
});<br />
</script></p>
<style>
.entry-content {<br />
    -webkit-user-select: none;<br />
    -moz-user-select: none;<br />
    -ms-user-select: none;<br />
    user-select: none;<br />
}<br />
</style>
</div>
<p><!-- START_SIMULATOR_LINK_CARD_thermal_expansion --><a href="https://myengnote.com/thermal-expansion-calculator-simulator/" target="_blank" rel="noopener noreferrer" class="eng-simulator-card" style="text-decoration: none; background-color: #ffffff; border: 1px solid #e5e7eb; border-radius: 8px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); padding: 15px; margin: 10px 0; transition: box-shadow 0.2s; display: table; width: 100%; box-sizing: border-box;"><span style="display: table-cell; vertical-align: middle;"><span style="font-size: 30px; margin-right: 15px; float: left;"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ee.png" alt="🧮" class="wp-smiley" style="height: 1em; max-height: 1em;" /></span><span style="display: block; overflow: hidden;"><span style="display: block; font-size: 0.9em; color: #10b981; font-weight: bold; margin-bottom: 4px;">실시간 공학 시뮬레이터 추천</span><span style="display: block; font-size: 1.1em; font-weight: bold; color: #111827;">재료 열팽창(선팽창) 계산기 &#038; 실시간 2D 신축 시뮬레이터</span></span></span><span style="display: table-cell; vertical-align: middle; width: 40px; text-align: right; color: #10b981; font-size: 24px; font-weight: bold;">→</span></a><!-- END_SIMULATOR_LINK_CARD_thermal_expansion --></p>
]]></content:encoded>
					
					<wfw:commentRss>https://myengnote.com/dimensional-error-residual-heat-machining/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
