メインコンテンツへスキップ
見出し画像
Photo byroute75th

AIチップを作る「光の工場」



    半導体工場の真ん中に、「光の工場」を置く。

    巨大な工場の中央に、巨大なリングがある。

    画像

    そこでは、ただ機械が回っているわけではない。

    電子を加速する。

    光速に限りなく近い速度まで電子を加速し、その電子を強力な磁場の中へ送り込む。

    そして電子を周期的に「蛇行」させる。

    すると――

    電子の運動から、光が生まれる。

    しかも、その光は普通の光ではない。

    半導体の最先端を切り拓く、極端紫外線――EUVだ。

    これが、イーロン・マスクが構想する巨大半導体工場「Terafab」をめぐって注目されている、自由電子レーザー(FEL)という発想である。

    現在のEUVリソグラフィーでは、レーザーで微小な錫の液滴をプラズマ化し、13.5 nmのEUVを作り出す方式が使われている。EUVは半導体の微細なパターンを形成するための重要な光だ。

    一方、FELはまったく違う。

    電子を加速する。

    磁場で電子を揺さぶる。

    その電子から生まれる光を利用する。

    しかも、電子のエネルギーやアンジュレータの条件を変えることで、発生する光の波長を制御できる。

    ここには、とても美しい物理がある。


    一つの巨大な光源から、無数の露光装置へ

    そして、私がこの構想で特に面白いと思ったのが、光源そのものよりも**「配置」**だ。

    普通に考えれば、露光装置があれば、その装置ごとに光源が必要になる。

    一台。

    また一台。

    さらに一台。

    露光装置を増やせば、光源も増えていく。

    ところが巨大なFEL光源を工場の中央に置いたらどうだろう。

    中央に、

    巨大な「光の発電所」

    を作る。

    そこからEUVを取り出し、複数の露光設備へ供給する。


    つまり、

    一つの巨大な光源で、工場全体を動かす。

    これは発電所と電力網に少し似ている。

    一軒一軒に発電所を置くのではない。

    巨大な発電所を作り、そこから必要な場所へエネルギーを配る。

    同じように、

    一つの巨大な「光の源」を作り、そこから大量の半導体製造ラインへ光を配る。

    この発想が、ものすごく面白い。


    そして、ここからが本当のSFだ

    もしこの考え方が量産工場で成立したら、半導体工場の姿そのものが変わるかもしれない。

    工場の中央には加速器。

    その中を電子が走る。

    アンジュレータの磁石列を通過する。

    そして、

    13.5 nmの光が生まれる。

    その光が巨大な工場の中へ供給される。

    その先では、何台もの露光装置が一斉に動く。

    シリコンウェハーが流れる。

    回路が刻まれる。

    さらに次の工程へ進む。

    そしてまた、次のウェハーへ。

    電子を走らせる。

    光を作る。

    その光で半導体を刻む。

    なんとも不思議な製造工程だ。

    物質を削るだけではない。

    巨大な加速器で作った「光」を使って、ナノメートルの世界に回路を書き込んでいく。


    FELによるEUV光源は非常に魅力的な可能性を持っている一方、量産半導体工場で実証済みの技術ではない。FELをEUVリソグラフィーの光源として使う研究・開発は進んでいるものの、商用量産で必要となる信頼性、安定性、コスト、光学系との統合など、越えるべき壁はまだ残っている。実際、米国では2026年にFEL-EUVプロトタイプ開発への1.5億ドルの支援が正式化された段階だ。

    だからこそ、面白い。

    これは完成した未来の話ではない。

    「こんな方法で、半導体を作ることができるのか?」

    という、巨大な技術実験でもある。


    そして私は、この発想を見て一つの実験を作ってみた。

    電子のエネルギーを変える。

    アンジュレータの周期を変える。

    磁場を変える。

    すると、

    発生する光の波長が変わる。

    赤。

    緑。

    青。

    紫外線。

    そして――

    EUV。

    13.5 nm。

    普段、私たちがスマートフォンやAIコンピューターの中で当たり前のように使っている半導体。

    その極小の回路を生み出すために、実はその背後では、

    電子を加速し、磁場で揺さぶり、光を作る。

    そんな壮大な物理が働いている。

    今回は、その「光が生まれる瞬間」を、ブラウザの中で実験できるシミュレーターにしてみた。

    電子を走らせてみよう。

    磁場を変えてみよう。

    アンジュレータを調整してみよう。

    そして、自分の手で――

    「光を作ってみよう」。 ⚡️🔬

    半導体の未来を考えるとき、見るべきものは巨大な工場だけではない。

    その工場の中心で走る、

    一筋の電子と、一筋の光

    なのかもしれない。


    ついに完成!アンジュレータ放射シミュレーターで「光を作る感動」を体験しよう!


    🎉 物理の美しさを、あなたの指先で!

    ついに、ついに完成しました!

    画像

    自由電子レーザー(FEL)の基本原理を、あなたの指先で直感的に体験できる画期的なWebシミュレーターが誕生しました!

    「加速器」と聞くと、なんだか難しそう…と思うかもしれません。でも、このシミュレーターを使えば、電子を加速して、磁場で曲げて、光を作るという壮大な物理現象を、まるでゲームのように楽しめるんです!


    💡 なぜこのアプリを作ったのか?

    私は常々思っていました。

    「アンジュレータ放射の原理は、実はすごく美しいのに、数式だけじゃ伝わらない!」

    • 電子を光速近くまで加速する

    • 周期磁場で電子を蛇行させる

    • すると、驚くべきことに電磁波が放射される

    • 電子エネルギーや磁場を調整することで、狙った波長の光を作れる

    このプロセス、本当はすごくドラマチックなんです!

    でも、従来の教材では数式が並ぶだけで、「実際にどうなるのか」がイメージしにくい。

    だったら、作ってしまおう!

    そう思って開発したのが、このシミュレーターです。


    🚀 このアプリの最大のアピールポイント!

    1. 物理計算をサボらない!


    画像

    多くのシミュレーターは「それっぽいアニメーション」だけで終わってしまいます。でも、このアプリは本気で物理計算しています!

    • ローレンツ因子 γ

    • 相対論的速度 β

    • アンジュレータパラメータ K

    • 放射波長 λ_r

    • 光子エネルギー E_γ

    すべて実際の物理式で計算し、リアルタイムで表示します。

    「適当な数値を表示しているだけ」なんてことではありません!

    2. スライダーを動かすと、即座に結果が変化!


    画像
    アンジュレータ磁場

    電子エネルギーを変えると…

    「あ、波長が短くなった!」

    アンジュレータ周期を変えると…

    「おっ、Kが変わった!波長も変わった!」

    アンジュレータ磁場を変えると…

    画像

    「13.5 nmになった!EUVだ!」

    こんな発見の喜びを、あなたも体験できます!

    3. 13.5 nm EUVを「作る」体験!

    半導体リソグラフィで使われる13.5 nmの極端紫外線(EUV)。

    このアプリなら、「13.5 nm EUVを狙う」ボタンを押すだけで、その条件を自動設定!

    実際にどうすれば13.5 nmの光が作れるのか、実験的に探求できるんです!

    4. 可視光からX線まで、光のスペクトルを体感!

    パラメータを調整すると、発生する光が変化します。

    • 赤外線

    • 可視光(赤・橙・黄・緑・青・紫)

    • 紫外線

    • EUV

    • X線

    「電子を速くしたら、波長が短くなって、紫外線になった!」

    こんな体験、他ではできません!

    5. 計算過程もすべて見える!

    「計算を見る」ボタンを押せば、どの数値からどの結果が導かれたのかを詳細に表示。

    「γ = 1 + 1000 / 0.511 ≈ 1957」

    といった具合に、物理の因果関係を明確に追えます!


    📖 シミュレーターの使い方:完全ガイド

    ステップ1:アプリを起動

    HTMLファイルを開くだけ!インターネット接続不要で、すぐに使えます。

    ステップ2:パラメータを設定

    左側のコントロールパネルで、以下のパラメータを調整できます。

    電子エネルギー(0.1 ~ 20 GeV)

    電子をどれだけのエネルギーで加速するか。

    初期値:1.0 GeV

    → 大きくするほど、電子は光速に近づき、放射波長は短くなります!

    アンジュレータ周期(5 ~ 100 mm)

    磁石の配置周期。

    初期値:20 mm

    → 小さくするほど、波長は短くなります!

    アンジュレータ磁場(0.1 ~ 2.0 T)

    磁石の強さ。

    初期値:1.0 T

    → 強くするほど、アンジュレータパラメータ K が大きくなり、波長に影響します!

    アンジュレータ周期数(5 ~ 50)

    磁石がいくつ並んでいるか。

    初期値:20

    → 多いほど、電子は長く蛇行運動を続けます!

    ステップ3:計算結果を確認

    右側のパネルに、以下の結果がリアルタイム表示されます。

    初心者モード:

    • 電子エネルギー

    • アンジュレータ磁場

    • アンジュレータ周期

    • 発生波長

    • 光の種類

    上級モード:

    • ローレンツ因子 γ

    • 速度比 β

    • 電子速度 v

    • アンジュレータパラメータ K

    • 放射波長 λ_r

    • 光子エネルギー E_γ

    • 周波数 f

    • 光の分類

    ステップ4:アニメーションで確認

    「実験開始」ボタンを押すと、電子がアンジュレータを通過する様子をアニメーションで確認できます!

    • 電子が左から飛んできます

    • アンジュレータ内部で蛇行運動

    • 電磁波を放射

    • 右側へ出ていきます

    「停止」「リセット」ボタンで、いつでもコントロール可能!

    ステップ5:軌道グラフで理解

    下部のグラフで、電子の軌道 x(z) と磁場 B(z) を同時に表示。

    「電子が磁場の周期に合わせて蛇行している」 ことが一目瞭然!


    🎯 おすすめの遊び方

    遊び方1:13.5 nm EUVを作ろう!

    「13.5 nm EUVを狙う」ボタンを押してみましょう。

    すると、13.5 nmのEUVを作るためのパラメータが自動設定されます。

    「へえ、この条件で13.5 nmになるんだ!」

    と、実感できます!

    遊び方2:可視光を作ってみよう!

    電子エネルギーを下げたり、アンジュレータ周期を大きくしたりして、可視光領域を目指してみましょう。

    「450 nmになった!青い光だ!」

    と、実際に青い色で表示されます!

    遊び方3:逆算モードで実験!

    「目標波長から設定を求める」 機能を使えば、「10 nmの光を作るには、どんな条件が必要?」 といった逆算実験も可能!

    あなたの**「もしも」を実験**できます!

    遊び方4:計算過程を追おう!

    「計算を見る」 を開いて、スライダーを動かしてみてください。

    「γが変わると、波長がこう変わるんだ!」

    と、物理の因果関係が手に取るように分かります!

    画像

    ⚠️ 重要な注意点

    このシミュレーターは、教育用に簡略化しています。

    • 実際のFELの完全な自己増幅過程は計算していません

    • 「電子が光る」は教育的な比喩です

    • 実際には、加速された電子の運動によって電磁波が放射されます

    でも、基本原理を理解するには最適です!


    🌟 さあ、あなたも物理学者になろう!

    このシミュレーターを使えば、あなたも今日から「光を作る研究者」 です!

    • 電子を加速して

    • 磁場で曲げて

    • 光を作る


    画像

    この壮大なプロセスを、あなたの指先で体験してください!

    「電子を速くしたら、波長が短くなった!」

    「13.5 nmにすると、EUVになった!」

    こんな発見の喜びを、ぜひ味わってください!


    物理は、楽しい。

    光を作る感動を、あなたに。




    <!DOCTYPE html>
    <html lang="ja">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>アンジュレータ放射シミュレーター</title>
        <style>
            * {
                margin: 0;
                padding: 0;
                box-sizing: border-box;
            }
    
            body {
                font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
                background: #f5f5f5 ;
                color: #333 ;
                line-height: 1.6;
            }
    
            .container {
                max-width: 1400px;
                margin: 0 auto;
                padding: 20px;
            }
    
            header {
                text-align: center;
                margin-bottom: 30px;
                background: white;
                padding: 20px;
                border-radius: 8px;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
    
            h1 {
                font-size: 1.8em;
                color: #2c3e50 ;
                margin-bottom: 10px;
            }
    
            .subtitle {
                color: #7f8c8d ;
                font-size: 0.95em;
            }
    
            .main-content {
                display: grid;
                grid-template-columns: 1fr 350px;
                gap: 20px;
                margin-bottom: 20px;
            }
    
            @media (max-width: 1024px) {
                .main-content {
                    grid-template-columns: 1fr;
                }
            }
    
            .canvas-container {
                background: white;
                border-radius: 8px;
                padding: 20px;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
    
            #simCanvas  {
                width: 100%;
                height: 400px;
                border: 2px solid #34495e ;
                border-radius: 4px;
                background: #1a1a2e ;
            }
    
            .controls {
                background: white;
                border-radius: 8px;
                padding: 20px;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
            }
    
            .control-group {
                margin-bottom: 20px;
            }
    
            .control-group label {
                display: block;
                font-weight: bold;
                margin-bottom: 5px;
                color: #2c3e50 ;
            }
    
            .control-group input[type="range"] {
                width: 100%;
                margin-bottom: 5px;
            }
    
            .control-group .value-display {
                text-align: right;
                font-size: 0.9em;
                color: #7f8c8d ;
            }
    
            .results {
                background: white;
                border-radius: 8px;
                padding: 20px;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                margin-bottom: 20px;
            }
    
            .result-item {
                margin-bottom: 15px;
                padding: 10px;
                background: #ecf0f1 ;
                border-radius: 4px;
            }
    
            .result-item .label {
                font-size: 0.85em;
                color: #7f8c8d ;
                margin-bottom: 5px;
            }
    
            .result-item .value {
                font-size: 1.4em;
                font-weight: bold;
                color: #2c3e50 ;
            }
    
            .result-item .unit {
                font-size: 0.9em;
                color: #7f8c8d ;
                margin-left: 5px;
            }
    
            .wavelength-display {
                text-align: center;
                padding: 20px;
                background: linear-gradient(135deg, #667eea  0%, #764ba2  100%);
                color: white;
                border-radius: 8px;
                margin-bottom: 20px;
            }
    
            .wavelength-display .wavelength-value {
                font-size: 2.5em;
                font-weight: bold;
                margin: 10px 0;
            }
    
            .wavelength-display .region {
                font-size: 1.2em;
                background: rgba(255,255,255,0.2);
                padding: 5px 15px;
                border-radius: 20px;
                display: inline-block;
                margin-top: 10px;
            }
    
            .buttons {
                display: flex;
                gap: 10px;
                flex-wrap: wrap;
                margin-bottom: 20px;
            }
    
            button {
                padding: 10px 20px;
                border: none;
                border-radius: 4px;
                cursor: pointer;
                font-size: 1em;
                transition: all 0.3s;
            }
    
            .btn-primary {
                background: #3498db ;
                color: white;
            }
    
            .btn-primary:hover {
                background: #2980b9 ;
            }
    
            .btn-secondary {
                background: #95a5a6 ;
                color: white;
            }
    
            .btn-secondary:hover {
                background: #7f8c8d ;
            }
    
            .btn-success {
                background: #27ae60 ;
                color: white;
            }
    
            .btn-success:hover {
                background: #229954 ;
            }
    
            .mode-toggle {
                display: flex;
                gap: 10px;
                margin-bottom: 20px;
            }
    
            .mode-toggle button {
                flex: 1;
            }
    
            .mode-toggle button.active {
                background: #2c3e50 ;
                color: white;
            }
    
            .calculation-details {
                background: white;
                border-radius: 8px;
                padding: 20px;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                margin-bottom: 20px;
            }
    
            .calculation-details summary {
                cursor: pointer;
                font-weight: bold;
                color: #2c3e50 ;
                padding: 10px;
                background: #ecf0f1 ;
                border-radius: 4px;
            }
    
            .calculation-content {
                margin-top: 15px;
                font-family: 'Courier New', monospace;
                font-size: 0.9em;
                line-height: 1.8;
            }
    
            .calculation-content .formula {
                background: #f8f9fa ;
                padding: 10px;
                border-radius: 4px;
                margin: 10px 0;
                border-left: 3px solid #3498db ;
            }
    
            .explanation {
                background: white;
                border-radius: 8px;
                padding: 20px;
                box-shadow: 0 2px 4px rgba(0,0,0,0.1);
                margin-bottom: 20px;
            }
    
            .explanation h3 {
                color: #2c3e50 ;
                margin-bottom: 15px;
            }
    
            .explanation .step {
                padding: 10px;
                margin: 10px 0;
                background: #e8f4f8 ;
                border-radius: 4px;
                border-left: 3px solid #3498db ;
            }
    
            .warning {
                background: #fff3cd ;
                border-left: 4px solid #ffc107 ;
                padding: 15px;
                margin: 15px 0;
                border-radius: 4px;
            }
    
            .info {
                background: #d1ecf1 ;
                border-left: 4px solid #17a2b8 ;
                padding: 15px;
                margin: 15px 0;
                border-radius: 4px;
            }
    
            .hidden {
                display: none;
            }
    
            .preset-buttons {
                display: flex;
                gap: 10px;
                flex-wrap: wrap;
                margin-bottom: 20px;
            }
    
            .inverse-calc {
                background: #f8f9fa ;
                padding: 15px;
                border-radius: 8px;
                margin-bottom: 20px;
            }
    
            .inverse-calc h4 {
                margin-bottom: 10px;
                color: #2c3e50 ;
            }
    
            .inverse-calc input {
                width: 100%;
                padding: 8px;
                border: 1px solid #ddd ;
                border-radius: 4px;
                margin-bottom: 10px;
            }
    
            #trajectoryCanvas  {
                width: 100%;
                height: 200px;
                border: 1px solid #ddd ;
                border-radius: 4px;
                background: white;
                margin-top: 10px;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <header>
                <h1>🔬 アンジュレータで光を作ってみよう</h1>
                <p class="subtitle">高速電子を周期磁場に通すと、電子は蛇行運動をしながら電磁波を放射します。</p>
            </header>
    
            <div class="mode-toggle">
                <button id="beginnerMode" class="active">初心者モード</button>
                <button id="advancedMode">上級モード</button>
            </div>
    
            <div class="main-content">
                <div class="canvas-container">
                    <canvas id="simCanvas"></canvas>
                    <canvas id="trajectoryCanvas"></canvas>
                </div>
    
                <div class="controls">
                    <h3 style="margin-bottom: 15px; color: #2c3e50 ;">パラメータ設定</h3>
                    
                    <div class="control-group">
                        <label>電子エネルギー</label>
                        <input type="range" id="energySlider" min="0.1" max="20" step="0.1" value="1.0">
                        <div class="value-display"><span id="energyValue">1.0</span> GeV</div>
                    </div>
    
                    <div class="control-group">
                        <label>アンジュレータ周期 (λ<sub>u</sub>)</label>
                        <input type="range" id="periodSlider" min="5" max="100" step="1" value="20">
                        <div class="value-display"><span id="periodValue">20</span> mm</div>
                    </div>
    
                    <div class="control-group">
                        <label>アンジュレータ磁場 (B)</label>
                        <input type="range" id="fieldSlider" min="0.1" max="2.0" step="0.01" value="1.0">
                        <div class="value-display"><span id="fieldValue">1.00</span> T</div>
                    </div>
    
                    <div class="control-group">
                        <label>アンジュレータ周期数 (N)</label>
                        <input type="range" id="numPeriodsSlider" min="5" max="50" step="1" value="20">
                        <div class="value-display"><span id="numPeriodsValue">20</span></div>
                    </div>
    
                    <div class="control-group">
                        <label>アニメーション速度</label>
                        <input type="range" id="speedSlider" min="0.5" max="5" step="0.5" value="1">
                        <div class="value-display"><span id="speedValue">1.0</span>x</div>
                    </div>
    
                    <div class="buttons">
                        <button id="startBtn" class="btn-primary">▶ 実験開始</button>
                        <button id="pauseBtn" class="btn-secondary">⏸ 停止</button>
                        <button id="resetBtn" class="btn-secondary">↺ リセット</button>
                    </div>
    
                    <div class="preset-buttons">
                        <button id="preset13_5" class="btn-success">🎯 13.5 nm EUVを狙う</button>
                    </div>
    
                    <div class="inverse-calc">
                        <h4>目標波長から設定を求める</h4>
                        <input type="number" id="targetWavelength" placeholder="目標波長 (nm)" step="0.1">
                        <button id="inverseCalcBtn" class="btn-primary" style="width: 100%;">逆算実行</button>
                    </div>
                </div>
            </div>
    
            <div class="wavelength-display" id="wavelengthDisplay">
                <div style="font-size: 0.9em;">発生した光</div>
                <div class="wavelength-value" id="wavelengthValue">--</div>
                <div id="photonEnergy">光子エネルギー: -- eV</div>
                <div class="region" id="wavelengthRegion">--</div>
            </div>
    
            <div class="results" id="resultsPanel">
                <h3 style="margin-bottom: 15px; color: #2c3e50 ;">計算結果</h3>
                <div id="beginnerResults">
                    <div class="result-item">
                        <div class="label">電子エネルギー</div>
                        <div class="value"><span id="resultEnergy">1.0</span><span class="unit">GeV</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">アンジュレータ磁場</div>
                        <div class="value"><span id="resultField">1.00</span><span class="unit">T</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">アンジュレータ周期</div>
                        <div class="value"><span id="resultPeriod">20</span><span class="unit">mm</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">発生波長</div>
                        <div class="value"><span id="resultWavelength">--</span><span class="unit" id="wavelengthUnit">nm</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">光の種類</div>
                        <div class="value"><span id="resultRegion">--</span></div>
                    </div>
                </div>
    
                <div id="advancedResults" class="hidden">
                    <div class="result-item">
                        <div class="label">ローレンツ因子 (γ)</div>
                        <div class="value"><span id="resultGamma">--</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">速度比 (β = v/c)</div>
                        <div class="value"><span id="resultBeta">--</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">電子速度 (v)</div>
                        <div class="value"><span id="resultVelocity">--</span><span class="unit">m/s</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">アンジュレータパラメータ (K)</div>
                        <div class="value"><span id="resultK">--</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">放射波長 (λ<sub>r</sub>)</div>
                        <div class="value"><span id="resultWavelengthAdv">--</span><span class="unit" id="wavelengthUnitAdv">nm</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">光子エネルギー (E<sub>γ</sub>)</div>
                        <div class="value"><span id="resultPhotonEnergy">--</span><span class="unit">eV</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">周波数 (f)</div>
                        <div class="value"><span id="resultFrequency">--</span><span class="unit" id="frequencyUnit">Hz</span></div>
                    </div>
                    <div class="result-item">
                        <div class="label">光の分類</div>
                        <div class="value"><span id="resultRegionAdv">--</span></div>
                    </div>
                </div>
            </div>
    
            <details class="calculation-details">
                <summary>📊 計算を見る</summary>
                <div class="calculation-content" id="calculationContent">
                    <!-- 計算過程がここに表示される -->
                </div>
            </details>
    
            <div class="explanation">
                <h3>💡 なぜ光が出るの?</h3>
                <div class="step">
                    <strong>1. 電子は磁場によって進行方向を曲げられます。</strong><br>
                    アンジュレータのN極とS極が交互に配置された磁場中を電子が通過すると、ローレンツ力によって電子の進行方向が左右に曲げられます。
                </div>
                <div class="step">
                    <strong>2. 方向が変化する電子は電磁波を放射します。</strong><br>
                    加速度運動する荷電粒子は電磁波を放射します(加速度放射)。電子が曲げられることは、つまり加速度運動をしていることを意味します。
                </div>
                <div class="step">
                    <strong>3. アンジュレータでは、この曲げを周期的に繰り返します。</strong><br>
                    N-S-N-S...と磁石を並べることで、電子は蛇行運動を繰り返しながら、各周期で電磁波を放射します。
                </div>
                <div class="step">
                    <strong>4. 電子から出た電磁波が条件を満たすと、強く揃った光になります。</strong><br>
                    特定の条件(共鳴条件)を満たすと、各周期で放射された電磁波が強め合い、波長の揃った強い光が発生します。
                </div>
                <div class="step">
                    <strong>5. これが自由電子レーザー(FEL)につながります。</strong><br>
                    実際のFELでは、多数の電子が電磁場と相互作用し、コヒーレントな放射が自己増幅されます。
                </div>
    
                <div class="info">
                    <strong>注意:</strong> この簡易シミュレーションはFELの完全な自己増幅過程を計算しているわけではありません。教育用に、電子の相対論的運動とアンジュレータ磁場による共鳴波長の計算を可視化しています。
                </div>
    
                <div class="warning">
                    <strong>教育的注意:</strong> 「電子が光る」という表現は比喩です。実際には、加速された電子の運動によって電磁波が放射されます。また、実際のFELでは多数の電子と電磁場の相互作用により光が増幅されます。
                </div>
            </div>
    
            <div class="info">
                <strong>表示倍率について:</strong> 実際の放射波長(例:13.5 nm)を物理スケールそのままに描画すると肉眼で見えないため、教育用に拡大表示しています。波面の間隔は実際の波長に対応していますが、画面上のスケールは誇張されています。
            </div>
        </div>
    
        <script>
            // ============================================
            // 物理定数の定義
            // ============================================
            const C = 299792458; // 光速 [m/s]
            const M_E = 9.1093837e-31; // 電子質量 [kg]
            const E_CHARGE = 1.602176634e-19; // 電子電荷 [C]
            const M_E_C2 = 0.511; // 電子静止エネルギー [MeV]
            const H_PLANCK = 6.62607015e-34; // プランク定数 [J·s]
    
            // ============================================
            // グローバル変数
            // ============================================
            let isRunning = false;
            let animationId = null;
            let electronPosition = 0;
            let time = 0;
            let currentMode = 'beginner'; // 'beginner' or 'advanced'
    
            // Canvas要素
            const simCanvas = document.getElementById('simCanvas');
            const simCtx = simCanvas.getContext('2d');
            const trajCanvas = document.getElementById('trajectoryCanvas');
            const trajCtx = trajCanvas.getContext('2d');
    
            // Canvasサイズ設定
            function resizeCanvases() {
                simCanvas.width = simCanvas.offsetWidth;
                simCanvas.height = simCanvas.offsetHeight;
                trajCanvas.width = trajCanvas.offsetWidth;
                trajCanvas.height = trajCanvas.offsetHeight;
            }
            resizeCanvases();
            window.addEventListener('resize', () => {
                resizeCanvases();
                updateSimulation();
            });
    
            // ============================================
            // 物理計算関数
            // ============================================
    
            // ローレンツ因子γを計算
            // 入力:電子エネルギー [GeV]
            // γ = 1 + E[MeV] / (m_e c² [MeV])
            function calculateGamma(energyGeV) {
                const energyMeV = energyGeV * 1000; // GeV → MeV
                return 1 + energyMeV / M_E_C2;
            }
    
            // 速度比βを計算
            // β = sqrt(1 - 1/γ²)
            function calculateBeta(gamma) {
                return Math.sqrt(1 - 1 / (gamma * gamma));
            }
    
            // 電子速度を計算
            // v = βc
            function calculateVelocity(beta) {
                return beta * C;
            }
    
            // アンジュレータパラメータKを計算
            // K = 0.934 × B[T] × λ_u[cm]
            function calculateK(fieldTesla, periodMm) {
                const periodCm = periodMm / 10; // mm → cm
                return 0.934 * fieldTesla * periodCm;
            }
    
            // 放射波長を計算
            // λ_r = λ_u / (2γ²) × (1 + K²/2)
            // 入力:λ_u [m], γ, K
            // 出力:λ_r [m]
            function calculateRadiationWavelength(periodM, gamma, K) {
                return (periodM / (2 * gamma * gamma)) * (1 + (K * K) / 2);
            }
    
            // 光子エネルギーを計算
            // E = hc/λ
            // 入力:λ [m]
            // 出力:E [eV]
            function calculatePhotonEnergy(wavelengthM) {
                const energyJ = (H_PLANCK * C) / wavelengthM;
                return energyJ / E_CHARGE; // J → eV
            }
    
            // 周波数を計算
            // f = c/λ
            function calculateFrequency(wavelengthM) {
                return C / wavelengthM;
            }
    
            // 波長から光の分類を判定
            function classifyWavelength(wavelengthM) {
                const wavelengthNm = wavelengthM * 1e9;
                
                if (wavelengthNm >= 750) return { region: '赤外線', visible: false };
                if (wavelengthNm >= 620) return { region: '可視光(赤)', visible: true, color: 'red' };
                if (wavelengthNm >= 590) return { region: '可視光(オレンジ)', visible: true, color: 'orange' };
                if (wavelengthNm >= 570) return { region: '可視光(黄)', visible: true, color: 'yellow' };
                if (wavelengthNm >= 495) return { region: '可視光(緑)', visible: true, color: 'green' };
                if (wavelengthNm >= 450) return { region: '可視光(青)', visible: true, color: 'blue' };
                if (wavelengthNm >= 380) return { region: '可視光(紫)', visible: true, color: 'violet' };
                if (wavelengthNm >= 121) return { region: '紫外線', visible: false };
                if (wavelengthNm >= 10) return { region: 'EUV(極端紫外線)', visible: false };
                if (wavelengthNm >= 0.01) return { region: 'X線', visible: false };
                return { region: 'ガンマ線', visible: false };
            }
    
            // 波長を適切な単位に変換して表示
            function formatWavelength(wavelengthM) {
                const wavelengthNm = wavelengthM * 1e9;
                const wavelengthPm = wavelengthM * 1e12;
                const wavelengthUm = wavelengthM * 1e6;
    
                if (wavelengthPm < 1000) {
                    return { value: wavelengthPm.toFixed(2), unit: 'pm' };
                } else if (wavelengthNm < 1000) {
                    return { value: wavelengthNm.toFixed(2), unit: 'nm' };
                } else {
                    return { value: wavelengthUm.toFixed(2), unit: 'μm' };
                }
            }
    
            // 周波数を適切な単位に変換して表示
            function formatFrequency(frequencyHz) {
                if (frequencyHz >= 1e15) {
                    return { value: (frequencyHz / 1e15).toFixed(2), unit: 'PHz' };
                } else if (frequencyHz >= 1e12) {
                    return { value: (frequencyHz / 1e12).toFixed(2), unit: 'THz' };
                } else if (frequencyHz >= 1e9) {
                    return { value: (frequencyHz / 1e9).toFixed(2), unit: 'GHz' };
                } else {
                    return { value: frequencyHz.toFixed(2), unit: 'Hz' };
                }
            }
    
            // 可視光の波長からRGB色を計算
            function wavelengthToRGB(wavelengthNm) {
                let r, g, b;
    
                if (wavelengthNm >= 380 && wavelengthNm < 440) {
                    r = -(wavelengthNm - 440) / (440 - 380);
                    g = 0;
                    b = 1;
                } else if (wavelengthNm >= 440 && wavelengthNm < 490) {
                    r = 0;
                    g = (wavelengthNm - 440) / (490 - 440);
                    b = 1;
                } else if (wavelengthNm >= 490 && wavelengthNm < 510) {
                    r = 0;
                    g = 1;
                    b = -(wavelengthNm - 510) / (510 - 490);
                } else if (wavelengthNm >= 510 && wavelengthNm < 580) {
                    r = (wavelengthNm - 510) / (580 - 510);
                    g = 1;
                    b = 0;
                } else if (wavelengthNm >= 580 && wavelengthNm < 645) {
                    r = 1;
                    g = -(wavelengthNm - 645) / (645 - 580);
                    b = 0;
                } else if (wavelengthNm >= 645 && wavelengthNm <= 750) {
                    r = 1;
                    g = 0;
                    b = 0;
                } else {
                    r = 0;
                    g = 0;
                    b = 0;
                }
    
                // 輝度補正
                let factor;
                if (wavelengthNm >= 380 && wavelengthNm < 420) {
                    factor = 0.3 + 0.7 * (wavelengthNm - 380) / (420 - 380);
                } else if (wavelengthNm >= 420 && wavelengthNm <= 700) {
                    factor = 1.0;
                } else if (wavelengthNm > 700 && wavelengthNm <= 750) {
                    factor = 0.3 + 0.7 * (750 - wavelengthNm) / (750 - 700);
                } else {
                    factor = 0;
                }
    
                return {
                    r: Math.round(255 * Math.pow(r * factor, 0.8)),
                    g: Math.round(255 * Math.pow(g * factor, 0.8)),
                    b: Math.round(255 * Math.pow(b * factor, 0.8))
                };
            }
    
            // ============================================
            // UI更新関数
            // ============================================
    
            function updateSimulation() {
                // スライダーから値を取得
                const energyGeV = parseFloat(document.getElementById('energySlider').value);
                const periodMm = parseFloat(document.getElementById('periodSlider').value);
                const fieldTesla = parseFloat(document.getElementById('fieldSlider').value);
                const numPeriods = parseInt(document.getElementById('numPeriodsSlider').value);
    
                // 物理計算
                const gamma = calculateGamma(energyGeV);
                const beta = calculateBeta(gamma);
                const velocity = calculateVelocity(beta);
                const K = calculateK(fieldTesla, periodMm);
                const periodM = periodMm / 1000; // mm → m
                const wavelengthM = calculateRadiationWavelength(periodM, gamma, K);
                const photonEnergyEv = calculatePhotonEnergy(wavelengthM);
                const frequencyHz = calculateFrequency(wavelengthM);
                const classification = classifyWavelength(wavelengthM);
                const wavelengthFormatted = formatWavelength(wavelengthM);
                const frequencyFormatted = formatFrequency(frequencyHz);
    
                // 表示更新
                document.getElementById('energyValue').textContent = energyGeV.toFixed(1);
                document.getElementById('periodValue').textContent = periodMm.toFixed(0);
                document.getElementById('fieldValue').textContent = fieldTesla.toFixed(2);
                document.getElementById('numPeriodsValue').textContent = numPeriods;
                document.getElementById('speedValue').textContent = document.getElementById('speedSlider').value;
    
                // 結果表示
                document.getElementById('resultEnergy').textContent = energyGeV.toFixed(1);
                document.getElementById('resultField').textContent = fieldTesla.toFixed(2);
                document.getElementById('resultPeriod').textContent = periodMm.toFixed(0);
                document.getElementById('resultWavelength').textContent = wavelengthFormatted.value;
                document.getElementById('wavelengthUnit').textContent = wavelengthFormatted.unit;
                document.getElementById('resultRegion').textContent = classification.region;
    
                // 上級モード表示
                document.getElementById('resultGamma').textContent = gamma.toFixed(2);
                document.getElementById('resultBeta').textContent = beta.toFixed(6);
                document.getElementById('resultVelocity').textContent = velocity.toExponential(3);
                document.getElementById('resultK').textContent = K.toFixed(3);
                document.getElementById('resultWavelengthAdv').textContent = wavelengthFormatted.value;
                document.getElementById('wavelengthUnitAdv').textContent = wavelengthFormatted.unit;
                document.getElementById('resultPhotonEnergy').textContent = photonEnergyEv.toFixed(2);
                document.getElementById('resultFrequency').textContent = frequencyFormatted.value;
                document.getElementById('frequencyUnit').textContent = frequencyFormatted.unit;
                document.getElementById('resultRegionAdv').textContent = classification.region;
    
                // 波長表示
                document.getElementById('wavelengthValue').textContent = 
                    wavelengthFormatted.value + ' ' + wavelengthFormatted.unit;
                document.getElementById('photonEnergy').textContent = 
                    '光子エネルギー: ' + photonEnergyEv.toFixed(2) + ' eV';
                document.getElementById('wavelengthRegion').textContent = classification.region;
    
                // 波長表示の背景色
                if (classification.visible && classification.color) {
                    const rgb = wavelengthToRGB(wavelengthM * 1e9);
                    document.getElementById('wavelengthDisplay').style.background = 
                        `linear-gradient(135deg, rgb(${rgb.r},${rgb.g},${rgb.b}) 0%, rgb(${Math.max(0,rgb.r-50)},${Math.max(0,rgb.g-50)},${Math.max(0,rgb.b-50)}) 100%)`;
                } else {
                    document.getElementById('wavelengthDisplay').style.background = 
                        'linear-gradient(135deg, #667eea  0%, #764ba2  100%)';
                }
    
                // 計算詳細を更新
                updateCalculationDetails(energyGeV, gamma, beta, velocity, K, wavelengthM, photonEnergyEv, frequencyHz);
    
                // Canvas描画
                drawSimulation(energyGeV, periodMm, fieldTesla, numPeriods, gamma, beta, K, wavelengthM);
                drawTrajectory(periodMm, numPeriods, K);
    
                // 物理的に非現実的な設定の警告
                checkPhysicalValidity(energyGeV, fieldTesla, periodMm);
            }
    
            function updateCalculationDetails(energyGeV, gamma, beta, velocity, K, wavelengthM, photonEnergyEv, frequencyHz) {
                const energyMeV = energyGeV * 1000;
                const wavelengthFormatted = formatWavelength(wavelengthM);
                const frequencyFormatted = formatFrequency(frequencyHz);
    
                const html = `
                    <div class="formula">
                        <strong>ローレンツ因子 γ:</strong><br>
                        γ = 1 + E / (m<sub>e</sub>c²)<br>
                        γ = 1 + ${energyMeV.toFixed(1)} MeV / 0.511 MeV<br>
                        γ ≈ ${gamma.toFixed(4)}
                    </div>
    
                    <div class="formula">
                        <strong>速度比 β:</strong><br>
                        β = √(1 - 1/γ²)<br>
                        β = √(1 - 1/${gamma.toFixed(4)}²)<br>
                        β ≈ ${beta.toFixed(8)}<br>
                        v = βc = ${velocity.toExponential(4)} m/s<br>
                        v/c = ${beta.toFixed(8)}
                    </div>
    
                    <div class="formula">
                        <strong>アンジュレータパラメータ K:</strong><br>
                        K = 0.934 × B[T] × λ<sub>u</sub>[cm]<br>
                        K = 0.934 × ${document.getElementById('fieldSlider').value} × ${(parseFloat(document.getElementById('periodSlider').value) / 10).toFixed(2)}<br>
                        K ≈ ${K.toFixed(4)}
                    </div>
    
                    <div class="formula">
                        <strong>放射波長 λ<sub>r</sub>:</strong><br>
                        λ<sub>r</sub> = λ<sub>u</sub> / (2γ²) × (1 + K²/2)<br>
                        λ<sub>r</sub> = ${(parseFloat(document.getElementById('periodSlider').value) / 1000).toExponential(4)} / (2 × ${gamma.toFixed(4)}²) × (1 + ${K.toFixed(4)}²/2)<br>
                        λ<sub>r</sub> = ${wavelengthM.toExponential(4)} m<br>
                        λ<sub>r</sub> ≈ ${wavelengthFormatted.value} ${wavelengthFormatted.unit}
                    </div>
    
                    <div class="formula">
                        <strong>光子エネルギー E<sub>γ</sub>:</strong><br>
                        E<sub>γ</sub> = hc / λ<sub>r</sub><br>
                        E<sub>γ</sub> = (6.626×10⁻³⁴ × 2.998×10⁸) / ${wavelengthM.toExponential(4)}<br>
                        E<sub>γ</sub> ≈ ${photonEnergyEv.toFixed(4)} eV
                    </div>
    
                    <div class="formula">
                        <strong>周波数 f:</strong><br>
                        f = c / λ<sub>r</sub><br>
                        f = 2.998×10⁸ / ${wavelengthM.toExponential(4)}<br>
                        f ≈ ${frequencyFormatted.value} ${frequencyFormatted.unit}
                    </div>
                `;
    
                document.getElementById('calculationContent').innerHTML = html;
            }
    
            function checkPhysicalValidity(energyGeV, fieldTesla, periodMm) {
                // 実際のFEL装置として現実的な範囲をチェック
                const warnings = [];
                
                if (energyGeV > 10) {
                    warnings.push('電子エネルギーが10 GeVを超えています。これは大型加速器施設レベルのエネルギーです。');
                }
                
                if (fieldTesla > 1.5) {
                    warnings.push('磁場が1.5 Tを超えています。通常の永久磁石アンジュレータでは実現が困難です。');
                }
    
                if (periodMm < 10) {
                    warnings.push('アンジュレータ周期が10 mm未満です。技術的に製作が困難な場合があります。');
                }
    
                // 警告表示は既存の警告要素を更新
                // (簡易化のため、ここではコンソールに出力するのみ)
                if (warnings.length > 0) {
                    console.log('物理的警告:', warnings);
                }
            }
    
            // ============================================
            // Canvas描画関数
            // ============================================
    
            function drawSimulation(energyGeV, periodMm, fieldTesla, numPeriods, gamma, beta, K, wavelengthM) {
                const ctx = simCtx;
                const width = simCanvas.width;
                const height = simCanvas.height;
    
                // 背景
                ctx.fillStyle = '#1a1a2e';
                ctx.fillRect(0, 0, width, height);
    
                // アンジュレータ領域
                const undulatorStart = width * 0.2;
                const undulatorEnd = width * 0.8;
                const undulatorWidth = undulatorEnd - undulatorStart;
                const centerY = height / 2;
    
                // 磁石の描画
                const magnetWidth = undulatorWidth / (numPeriods * 2);
                const magnetHeight = 60;
    
                for (let i = 0; i < numPeriods * 2; i++) {
                    const x = undulatorStart + i * magnetWidth;
                    const isNorth = i % 2 === 0;
    
                    // 磁石の色
                    ctx.fillStyle = isNorth ? '#e74c3c' : '#3498db';
                    ctx.fillRect(x, centerY - magnetHeight - 20, magnetWidth - 2, magnetHeight);
                    ctx.fillRect(x, centerY + 20, magnetWidth - 2, magnetHeight);
    
                    // 磁極ラベル
                    ctx.fillStyle = 'white';
                    ctx.font = 'bold 14px sans-serif';
                    ctx.textAlign = 'center';
                    ctx.fillText(isNorth ? 'N' : 'S', x + magnetWidth / 2, centerY - magnetHeight / 2 - 10);
                    ctx.fillText(isNorth ? 'S' : 'N', x + magnetWidth / 2, centerY + magnetHeight / 2 + 30);
    
                    // 磁場ベクトル(矢印)
                    ctx.strokeStyle = isNorth ? '#e74c3c' : '#3498db';
                    ctx.lineWidth = 2;
                    const arrowX = x + magnetWidth / 2;
                    const arrowStartY = centerY - magnetHeight - 30;
                    const arrowEndY = isNorth ? arrowStartY - 15 : arrowStartY + 15;
                    
                    ctx.beginPath();
                    ctx.moveTo(arrowX, arrowStartY);
                    ctx.lineTo(arrowX, arrowEndY);
                    ctx.stroke();
    
                    // 矢じり
                    ctx.beginPath();
                    ctx.moveTo(arrowX, arrowEndY);
                    ctx.lineTo(arrowX - 4, arrowEndY + (isNorth ? -6 : 6));
                    ctx.lineTo(arrowX + 4, arrowEndY + (isNorth ? -6 : 6));
                    ctx.closePath();
                    ctx.fill();
                }
    
                // 電子の軌道
                if (isRunning || electronPosition > 0) {
                    const amplitude = 30 * K; // Kに比例して振幅変化
                    const electronX = undulatorStart + (electronPosition / 100) * undulatorWidth;
    
                    // 軌跡を描画
                    ctx.strokeStyle = '#00ff88';
                    ctx.lineWidth = 3;
                    ctx.shadowBlur = 10;
                    ctx.shadowColor = '#00ff88';
                    ctx.beginPath();
    
                    for (let i = 0; i <= electronPosition; i += 0.5) {
                        const x = undulatorStart + (i / 100) * undulatorWidth;
                        const z = (i / 100) * numPeriods * periodMm;
                        const y = centerY + amplitude * Math.sin(2 * Math.PI * z / periodMm);
    
                        if (i === 0) {
                            ctx.moveTo(x, y);
                        } else {
                            ctx.lineTo(x, y);
                        }
                    }
                    ctx.stroke();
                    ctx.shadowBlur = 0;
    
                    // 電子本体
                    const electronY = centerY + amplitude * Math.sin(2 * Math.PI * electronPosition / 100 * numPeriods);
                    ctx.fillStyle = '#00ff88';
                    ctx.shadowBlur = 15;
                    ctx.shadowColor = '#00ff88';
                    ctx.beginPath();
                    ctx.arc(electronX, electronY, 8, 0, 2 * Math.PI);
                    ctx.fill();
                    ctx.shadowBlur = 0;
    
                    // 電子ラベル
                    ctx.fillStyle = 'white';
                    ctx.font = 'bold 12px sans-serif';
                    ctx.textAlign = 'center';
                    ctx.fillText('e⁻', electronX, electronY - 15);
    
                    // 放射波面(教育用の拡大表示)
                    if (electronPosition > 10) {
                        const wavelengthDisplay = wavelengthM * 1e9; // nm
                        const waveSpacing = Math.max(20, Math.min(80, wavelengthDisplay / 2)); // 表示用の波長間隔
                        
                        ctx.strokeStyle = 'rgba(255, 255, 100, 0.3)';
                        ctx.lineWidth = 2;
                        
                        for (let w = 0; w < 5; w++) {
                            const waveRadius = 30 + w * waveSpacing;
                            if (waveRadius < 200) {
                                ctx.beginPath();
                                ctx.arc(electronX, electronY, waveRadius, 0, 2 * Math.PI);
                                ctx.stroke();
                            }
                        }
                    }
                }
    
                // ラベル
                ctx.fillStyle = 'white';
                ctx.font = '14px sans-serif';
                ctx.textAlign = 'center';
                ctx.fillText('電子入射', undulatorStart - 40, centerY);
                ctx.fillText('光取出し', undulatorEnd + 40, centerY);
    
                // アンジュレータ領域の枠
                ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
                ctx.lineWidth = 2;
                ctx.strokeRect(undulatorStart, centerY - magnetHeight - 40, undulatorWidth, magnetHeight * 2 + 80);
            }
    
            function drawTrajectory(periodMm, numPeriods, K) {
                const ctx = trajCtx;
                const width = trajCanvas.width;
                const height = trajCanvas.height;
    
                // 背景
                ctx.fillStyle = 'white';
                ctx.fillRect(0, 0, width, height);
    
                const margin = 40;
                const plotWidth = width - 2 * margin;
                const plotHeight = height - 2 * margin;
                const centerY = margin + plotHeight / 2;
    
                // 軸
                ctx.strokeStyle = '#333';
                ctx.lineWidth = 1;
                ctx.beginPath();
                ctx.moveTo(margin, centerY);
                ctx.lineTo(margin + plotWidth, centerY);
                ctx.moveTo(margin, margin);
                ctx.lineTo(margin, margin + plotHeight);
                ctx.stroke();
    
                // 軸ラベル
                ctx.fillStyle = '#333';
                ctx.font = '12px sans-serif';
                ctx.textAlign = 'center';
                ctx.fillText('アンジュレータ位置 z', width / 2, height - 5);
                ctx.textAlign = 'right';
                ctx.fillText('x', margin - 10, centerY + 5);
    
                // 電子軌道
                const amplitude = plotHeight / 3 * (K / 2); // Kに比例
                ctx.strokeStyle = '#00ff88';
                ctx.lineWidth = 2;
                ctx.beginPath();
    
                for (let i = 0; i <= plotWidth; i++) {
                    const z = (i / plotWidth) * numPeriods * periodMm;
                    const x = amplitude * Math.sin(2 * Math.PI * z / periodMm);
                    const canvasX = margin + i;
                    const canvasY = centerY - x;
    
                    if (i === 0) {
                        ctx.moveTo(canvasX, canvasY);
                    } else {
                        ctx.lineTo(canvasX, canvasY);
                    }
                }
                ctx.stroke();
    
                // 磁場(背景)
                ctx.strokeStyle = 'rgba(231, 76, 60, 0.3)';
                ctx.lineWidth = 1;
                ctx.beginPath();
    
                for (let i = 0; i <= plotWidth; i++) {
                    const z = (i / plotWidth) * numPeriods * periodMm;
                    const B = Math.sin(2 * Math.PI * z / periodMm);
                    const canvasX = margin + i;
                    const canvasY = centerY - B * plotHeight / 4;
    
                    if (i === 0) {
                        ctx.moveTo(canvasX, canvasY);
                    } else {
                        ctx.lineTo(canvasX, canvasY);
                    }
                }
                ctx.stroke();
    
                // 凡例
                ctx.fillStyle = '#00ff88';
                ctx.fillRect(margin + 10, margin + 10, 20, 3);
                ctx.fillStyle = '#333';
                ctx.textAlign = 'left';
                ctx.fillText('電子軌道 x(z)', margin + 35, margin + 15);
    
                ctx.fillStyle = 'rgba(231, 76, 60, 0.5)';
                ctx.fillRect(margin + 10, margin + 25, 20, 3);
                ctx.fillStyle = '#333';
                ctx.fillText('磁場 B(z)', margin + 35, margin + 30);
            }
    
            // ============================================
            // アニメーション制御
            // ============================================
    
            function animate() {
                if (!isRunning) return;
    
                const speed = parseFloat(document.getElementById('speedSlider').value);
                electronPosition += speed * 0.5;
    
                if (electronPosition >= 100) {
                    electronPosition = 100;
                    isRunning = false;
                }
    
                updateSimulation();
                animationId = requestAnimationFrame(animate);
            }
    
            function startAnimation() {
                if (electronPosition >= 100) {
                    electronPosition = 0;
                }
                isRunning = true;
                animate();
            }
    
            function pauseAnimation() {
                isRunning = false;
                if (animationId) {
                    cancelAnimationFrame(animationId);
                }
            }
    
            function resetAnimation() {
                pauseAnimation();
                electronPosition = 0;
                updateSimulation();
            }
    
            // ============================================
            // プリセットと逆算
            // ============================================
    
            function setPreset13_5nm() {
                // 13.5 nm EUVを目指す設定
                // λ_r = λ_u / (2γ²) × (1 + K²/2)
                // 目標:λ_r = 13.5 nm = 13.5e-9 m
                
                const targetWavelength = 13.5e-9; // m
                const energyGeV = 1.0; // GeV
                const fieldTesla = 1.0; // T
                
                // γを計算
                const gamma = calculateGamma(energyGeV);
                
                // Kを計算(仮の周期で)
                let periodMm = 20;
                let K = calculateK(fieldTesla, periodMm);
                
                // λ_uを逆算
                // λ_r = λ_u / (2γ²) × (1 + K²/2)
                // λ_u = λ_r × 2γ² / (1 + K²/2)
                const periodM = targetWavelength * 2 * gamma * gamma / (1 + (K * K) / 2);
                periodMm = periodM * 1000; // m → mm
    
                // スライダーを更新
                document.getElementById('energySlider').value = energyGeV;
                document.getElementById('fieldSlider').value = fieldTesla;
                document.getElementById('periodSlider').value = Math.max(5, Math.min(100, periodMm));
                
                updateSimulation();
            }
    
            function inverseCalculation() {
                const targetWavelengthNm = parseFloat(document.getElementById('targetWavelength').value);
                if (isNaN(targetWavelengthNm) || targetWavelengthNm <= 0) {
                    alert('有効な波長を入力してください');
                    return;
                }
    
                const targetWavelengthM = targetWavelengthNm * 1e-9;
                const energyGeV = parseFloat(document.getElementById('energySlider').value);
                const fieldTesla = parseFloat(document.getElementById('fieldSlider').value);
    
                // γを計算
                const gamma = calculateGamma(energyGeV);
    
                // Kを計算(現在の周期で)
                const periodMm = parseFloat(document.getElementById('periodSlider').value);
                let K = calculateK(fieldTesla, periodMm);
    
                // λ_uを逆算
                // λ_u = λ_r × 2γ² / (1 + K²/2)
                const periodM = targetWavelengthM * 2 * gamma * gamma / (1 + (K * K) / 2);
                const newPeriodMm = periodM * 1000;
    
                // 範囲チェック
                if (newPeriodMm < 5 || newPeriodMm > 100) {
                    alert(`計算されたアンジュレータ周期 ${newPeriodMm.toFixed(2)} mm は設定範囲外です。\n電子エネルギーまたは磁場を変更してください。`);
                    return;
                }
    
                // スライダーを更新
                document.getElementById('periodSlider').value = newPeriodMm;
                updateSimulation();
    
                alert(`目標波長 ${targetWavelengthNm} nm に基づき、アンジュレータ周期を ${newPeriodMm.toFixed(2)} mm に設定しました。`);
            }
    
            // ============================================
            // モード切替
            // ============================================
    
            function setMode(mode) {
                currentMode = mode;
                
                if (mode === 'beginner') {
                    document.getElementById('beginnerMode').classList.add('active');
                    document.getElementById('advancedMode').classList.remove('active');
                    document.getElementById('beginnerResults').classList.remove('hidden');
                    document.getElementById('advancedResults').classList.add('hidden');
                } else {
                    document.getElementById('advancedMode').classList.add('active');
                    document.getElementById('beginnerMode').classList.remove('active');
                    document.getElementById('advancedResults').classList.remove('hidden');
                    document.getElementById('beginnerResults').classList.add('hidden');
                }
            }
    
            // ============================================
            // イベントリスナー
            // ============================================
    
            // スライダー
            document.getElementById('energySlider').addEventListener('input', updateSimulation);
            document.getElementById('periodSlider').addEventListener('input', updateSimulation);
            document.getElementById('fieldSlider').addEventListener('input', updateSimulation);
            document.getElementById('numPeriodsSlider').addEventListener('input', updateSimulation);
            document.getElementById('speedSlider').addEventListener('input', updateSimulation);
    
            // ボタン
            document.getElementById('startBtn').addEventListener('click', startAnimation);
            document.getElementById('pauseBtn').addEventListener('click', pauseAnimation);
            document.getElementById('resetBtn').addEventListener('click', resetAnimation);
            document.getElementById('preset13_5').addEventListener('click', setPreset13_5nm);
            document.getElementById('inverseCalcBtn').addEventListener('click', inverseCalculation);
    
            // モード切替
            document.getElementById('beginnerMode').addEventListener('click', () => setMode('beginner'));
            document.getElementById('advancedMode').addEventListener('click', () => setMode('advanced'));
    
            // ============================================
            // 初期化
            // ============================================
    
            updateSimulation();
    
            // バリデーション:既知のケースで計算を確認
            console.log('=== 計算バリデーション ===');
            
            // ケース1: 1 GeV, 20 mm, 1.0 T
            const testGamma = calculateGamma(1.0);
            const testBeta = calculateBeta(testGamma);
            const testK = calculateK(1.0, 20);
            const testWavelength = calculateRadiationWavelength(0.02, testGamma, testK);
            console.log('ケース1 (1 GeV, 20 mm, 1.0 T):');
            console.log('  γ =', testGamma.toFixed(2));
            console.log('  β =', testBeta.toFixed(6));
            console.log('  K =', testK.toFixed(3));
            console.log('  λ_r =', (testWavelength * 1e9).toFixed(2), 'nm');
    
            // ケース2: 13.5 nm EUV設定
            setPreset13_5nm();
            const presetWavelength = calculateRadiationWavelength(
                parseFloat(document.getElementById('periodSlider').value) / 1000,
                calculateGamma(parseFloat(document.getElementById('energySlider').value)),
                calculateK(
                    parseFloat(document.getElementById('fieldSlider').value),
                    parseFloat(document.getElementById('periodSlider').value)
                )
            );
            console.log('13.5 nmプリセット結果:');
            console.log('  λ_r =', (presetWavelength * 1e9).toFixed(2), 'nm');
            console.log('========================');
        </script>
    </body>
    </html>
    

    この記事が参加している募集

    あなたへのおすすめ