电磁波调制原理演示

03 11月
作者:cinjep|分类:辅助教学

互动演示,展示调幅(AM)、调频(FM)和调相(PM)的基本概念。(文末有下载链接
这个演示将包括:

  1. 一个信号源(基带信号)和一个载波信号。

  2. 用户可以选择调制类型:AM、FM、PM。

  3. 用户可以调整一些参数,比如调制深度(AM)、频率偏移(FM)、相位偏移(PM)等。

  4. 显示原始信号、载波和调制后的信号。


电磁波.png


以下是实现代码( 由 deepseek 依据人工指令生成):

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>电磁波调制技术互动演示</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }
        
        body {
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            line-height: 1.6;
            background: linear-gradient(135deg, #1e3c72 0%, #2a5298 100%);
            color: #f0f8ff;
            min-height: 100vh;
            padding: 20px;
        }
        
        .container {
            display: flex;
            max-width: 1400px;
            margin: 0 auto;
            background-color: rgba(255, 255, 255, 0.08);
            border-radius: 15px;
            overflow: hidden;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
            backdrop-filter: blur(10px);
        }
        
        header {
            text-align: center;
            padding: 25px;
            background: rgba(30, 60, 114, 0.7);
            margin-bottom: 20px;
            border-radius: 10px;
        }
        
        h1 {
            font-size: 2.5rem;
            margin-bottom: 10px;
            color: #e6f7ff;
            text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
        }
        
        .description {
            font-size: 1.1rem;
            max-width: 800px;
            margin: 0 auto;
            color: #cce7ff;
        }
        
        .control-panel {
            flex: 0 0 320px;
            padding: 25px;
            background: rgba(25, 55, 109, 0.7);
            border-right: 1px solid rgba(255, 255, 255, 0.1);
            display: flex;
            flex-direction: column;
            gap: 25px;
        }
        
        .control-group {
            background: rgba(255, 255, 255, 0.1);
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }
        
        .control-group h3 {
            margin-bottom: 15px;
            color: #a3d9ff;
            font-size: 1.3rem;
            border-bottom: 1px solid rgba(255, 255, 255, 0.2);
            padding-bottom: 8px;
        }
        
        label {
            display: block;
            margin-bottom: 8px;
            font-weight: 600;
            color: #e6f7ff;
        }
        
        select, input[type="range"] {
            width: 100%;
            padding: 10px;
            margin-bottom: 15px;
            background: rgba(255, 255, 255, 0.15);
            border: 1px solid rgba(255, 255, 255, 0.3);
            border-radius: 6px;
            color: white;
            font-size: 1rem;
        }
        
        select option {
            background: #1a3a6b;
            color: white;
        }
        
        .value-display {
            display: inline-block;
            width: 60px;
            text-align: right;
            font-weight: bold;
            color: #7fc9ff;
        }
        
        .visualization {
            flex: 1;
            padding: 25px;
            display: flex;
            flex-direction: column;
            gap: 25px;
        }
        
        .canvas-container {
            display: flex;
            flex-direction: column;
            gap: 20px;
        }
        
        .signal-display {
            background: rgba(25, 55, 109, 0.5);
            border-radius: 10px;
            padding: 20px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
        }
        
        .signal-display h3 {
            margin-bottom: 15px;
            color: #a3d9ff;
            font-size: 1.3rem;
        }
        
        canvas {
            width: 100%;
            height: 180px;
            background-color: rgba(10, 30, 70, 0.5);
            border-radius: 8px;
            border: 1px solid rgba(255, 255, 255, 0.1);
        }
        
        .signal-legend {
            display: flex;
            justify-content: center;
            gap: 25px;
            margin-top: 15px;
            flex-wrap: wrap;
        }
        
        .legend-item {
            display: flex;
            align-items: center;
            gap: 8px;
        }
        
        .legend-color {
            width: 18px;
            height: 18px;
            border-radius: 4px;
        }
        
        .info-panels {
            display: flex;
            gap: 20px;
        }
        
        .explanation, .modulation-info {
            flex: 1;
            background: rgba(25, 55, 109, 0.5);
            padding: 20px;
            border-radius: 10px;
            box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
        }
        
        .explanation h3, .modulation-info h3 {
            margin-bottom: 15px;
            color: #a3d9ff;
            font-size: 1.3rem;
            border-bottom: 1px solid rgba(255, 255, 255, 0.2);
            padding-bottom: 8px;
        }
        
        .modulation-type {
            font-weight: bold;
            color: #7fc9ff;
        }
        
        .modulation-info p {
            margin-bottom: 12px;
        }
        
        @media (max-width: 1100px) {
            .container {
                flex-direction: column;
            }
            
            .control-panel {
                border-right: none;
                border-bottom: 1px solid rgba(255, 255, 255, 0.1);
            }
        }
        
        .button {
            background: linear-gradient(to right, #4a8fe7, #2a6fc9);
            color: white;
            border: none;
            padding: 12px 20px;
            border-radius: 6px;
            cursor: pointer;
            font-weight: 600;
            font-size: 1rem;
            transition: all 0.3s ease;
            box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
        }
        
        .button:hover {
            background: linear-gradient(to right, #5a9ff7, #3a7fd9);
            transform: translateY(-2px);
            box-shadow: 0 6px 12px rgba(0, 0, 0, 0.25);
        }
        
        .button:active {
            transform: translateY(0);
        }
        
        .envelope-control {
            display: flex;
            align-items: center;
            margin-top: 10px;
        }
        
        .envelope-control label {
            margin-bottom: 0;
            margin-right: 10px;
        }
        
        .envelope-control input {
            margin-bottom: 0;
            width: auto;
        }
    </style>
</head>
<body>
    <header>
        <h1>电磁波调制技术互动演示</h1>
        <div>
            <p>本演示展示了调幅(AM)、调频(FM)和调相(PM)三种基本的调制技术。</p>
            <p>通过调整左侧参数,观察不同调制方式下信号波形的变化。</p>
        </div>
    </header>
    
    <div>
        <div>
            <div>
                <h3>调制设置</h3>
                <label for="modulationType">调制类型:</label>
                <select id="modulationType">
                    <option value="am">调幅 (AM)</option>
                    <option value="fm">调频 (FM)</option>
                    <option value="pm">调相 (PM)</option>
                </select>
                
                <label for="signalType">基带信号:</label>
                <select id="signalType">
                    <option value="sine">正弦波</option>
                    <option value="triangle">三角波</option>
                    <option value="square">方波</option>
                </select>
                
                <div>
                    <label for="showEnvelope">显示包络线:</label>
                    <input type="checkbox" id="showEnvelope" checked>
                </div>
            </div>
            
            <div>
                <h3>参数调整</h3>
                <label for="modulationIndex">
                    调制指数: <span id="modIndexValue">0.5</span>
                </label>
                <input type="range" id="modulationIndex" min="0" max="1" step="0.01" value="0.5">
                
                <label for="carrierFreq">
                    载波频率: <span id="carrierFreqValue">50</span> Hz
                </label>
                <input type="range" id="carrierFreq" min="10" max="100" step="1" value="50">
                
                <label for="signalFreq">
                    信号频率: <span id="signalFreqValue">10</span> Hz
                </label>
                <input type="checkbox" id="showEnvelope" checked>
                <input type="range" id="signalFreq" min="5" max="30" step="0.5" value="10">
            </div>
            
            <div>
                <h3>操作</h3>
                <button id="resetButton">重置参数</button>
                <button id="randomButton">随机参数</button>
            </div>
        </div>
        
        <div>
            <div>
                <div>
                    <h3>基带信号</h3>
                    <canvas id="basebandCanvas"></canvas>
                </div>
                
                <div>
                    <h3>载波信号</h3>
                    <canvas id="carrierCanvas"></canvas>
                </div>
                
                <div>
                    <h3>调制信号</h3>
                    <canvas id="modulatedCanvas"></canvas>
                </div>
                
                <div>
                    <div>
                        <div style="background-color: #3498db;"></div>
                        <span>基带信号</span>
                    </div>
                    <div>
                        <div style="background-color: #e74c3c;"></div>
                        <span>载波信号</span>
                    </div>
                    <div>
                        <div style="background-color: #2ecc71;"></div>
                        <span>调制信号</span>
                    </div>
                    <div>
                        <div style="background-color: #f1c40f;"></div>
                        <span>包络线</span>
                    </div>
                </div>
            </div>
            
            <div>
                <div>
                    <h3>调制原理说明</h3>
                    <p id="modulationExplanation">
                        调幅(AM):通过改变载波的振幅来传输信息。基带信号的变化直接反映在载波振幅的变化上。
                    </p>
                    <p id="envelopeExplanation" style="margin-top: 10px;">
                        包络线显示了调制信号的幅度变化,在AM调制中,包络线形状与基带信号一致。
                    </p>
                </div>
                
                <div>
                    <h3>调制技术对比</h3>
                    <p><span>调幅(AM)</span>: 实现简单,抗干扰能力较弱,主要用于中短波广播。</p>
                    <p><span>调频(FM)</span>: 抗干扰能力强,保真度高,主要用于调频广播和电视伴音。</p>
                    <p><span>调相(PM)</span>: 与调频类似,但调制方式不同,常用于数字通信系统。</p>
                </div>
            </div>
        </div>
    </div>
    <script>
        // 获取DOM元素
        const modulationTypeSelect = document.getElementById('modulationType');
        const signalTypeSelect = document.getElementById('signalType');
        const modulationIndexSlider = document.getElementById('modulationIndex');
        const carrierFreqSlider = document.getElementById('carrierFreq');
        const signalFreqSlider = document.getElementById('signalFreq');
        const resetButton = document.getElementById('resetButton');
        const randomButton = document.getElementById('randomButton');
        const showEnvelopeCheckbox = document.getElementById('showEnvelope');
        
        const modIndexValue = document.getElementById('modIndexValue');
        const carrierFreqValue = document.getElementById('carrierFreqValue');
        const signalFreqValue = document.getElementById('signalFreqValue');
        
        const basebandCanvas = document.getElementById('basebandCanvas');
        const carrierCanvas = document.getElementById('carrierCanvas');
        const modulatedCanvas = document.getElementById('modulatedCanvas');
        
        const modulationExplanation = document.getElementById('modulationExplanation');
        const envelopeExplanation = document.getElementById('envelopeExplanation');
        
        // 设置Canvas上下文
        const basebandCtx = basebandCanvas.getContext('2d');
        const carrierCtx = carrierCanvas.getContext('2d');
        const modulatedCtx = modulatedCanvas.getContext('2d');
        
        // 设置Canvas尺寸
        function resizeCanvases() {
            const width = basebandCanvas.parentElement.clientWidth - 40;
            basebandCanvas.width = width;
            carrierCanvas.width = width;
            modulatedCanvas.width = width;
            basebandCanvas.height = 180;
            carrierCanvas.height = 180;
            modulatedCanvas.height = 180;
        }
        
        // 初始化
        window.addEventListener('load', () => {
            resizeCanvases();
            updateValues();
            drawSignals();
        });
        
        window.addEventListener('resize', () => {
            resizeCanvases();
            drawSignals();
        });
        
        // 更新显示值
        function updateValues() {
            modIndexValue.textContent = parseFloat(modulationIndexSlider.value).toFixed(2);
            carrierFreqValue.textContent = carrierFreqSlider.value;
            signalFreqValue.textContent = parseFloat(signalFreqSlider.value).toFixed(1);
            
            // 更新调制说明
            const modulationType = modulationTypeSelect.value;
            let explanation = '';
            let envelopeExp = '';
            
            switch(modulationType) {
                case 'am':
                    explanation = '调幅(AM):通过改变载波的振幅来传输信息。基带信号的变化直接反映在载波振幅的变化上。';
                    envelopeExp = '包络线显示了调制信号的幅度变化,在AM调制中,包络线形状与基带信号一致。';
                    break;
                case 'fm':
                    explanation = '调频(FM):通过改变载波的频率来传输信息。基带信号的变化反映在载波频率的变化上。';
                    envelopeExp = '在FM调制中,包络线显示的是载波频率相对于基带信号的变化。';
                    break;
                case 'pm':
                    explanation = '调相(PM):通过改变载波的相位来传输信息。基带信号的变化反映在载波相位的变化上。';
                    envelopeExp = '在PM调制中,包络线显示的是载波相位相对于基带信号的变化。';
                    break;
            }
            
            modulationExplanation.textContent = explanation;
            envelopeExplanation.textContent = envelopeExp;
        }
        
        // 监听输入变化
        modulationTypeSelect.addEventListener('change', () => {
            updateValues();
            drawSignals();
        });
        
        signalTypeSelect.addEventListener('change', () => {
            drawSignals();
        });
        
        modulationIndexSlider.addEventListener('input', () => {
            updateValues();
            drawSignals();
        });
        
        carrierFreqSlider.addEventListener('input', () => {
            updateValues();
            drawSignals();
        });
        
        signalFreqSlider.addEventListener('input', () => {
            updateValues();
            drawSignals();
        });
        
        showEnvelopeCheckbox.addEventListener('change', () => {
            drawSignals();
        });
        
        // 重置按钮
        resetButton.addEventListener('click', () => {
            modulationTypeSelect.value = 'am';
            signalTypeSelect.value = 'sine';
            modulationIndexSlider.value = 0.5;
            carrierFreqSlider.value = 50;
            signalFreqSlider.value = 10;
            showEnvelopeCheckbox.checked = true;
            updateValues();
            drawSignals();
        });
        
        // 随机按钮
        randomButton.addEventListener('click', () => {
            const modulationTypes = ['am', 'fm', 'pm'];
            const signalTypes = ['sine', 'triangle', 'square'];
            
            modulationTypeSelect.value = modulationTypes[Math.floor(Math.random() * modulationTypes.length)];
            signalTypeSelect.value = signalTypes[Math.floor(Math.random() * signalTypes.length)];
            modulationIndexSlider.value = (Math.random() * 0.8 + 0.2).toFixed(2);
            carrierFreqSlider.value = Math.floor(Math.random() * 91) + 10; // 10-100
            signalFreqSlider.value = (Math.random() * 25 + 5).toFixed(1); // 5-30
            
            updateValues();
            drawSignals();
        });
        
        // 生成基带信号
        function generateBasebandSignal(time, signalType, frequency) {
            switch(signalType) {
                case 'sine':
                    return Math.sin(2 * Math.PI * frequency * time);
                case 'triangle':
                    return 2 * Math.abs(2 * (time * frequency - Math.floor(time * frequency + 0.5))) - 1;
                case 'square':
                    return Math.sin(2 * Math.PI * frequency * time) > 0 ? 1 : -1;
                default:
                    return Math.sin(2 * Math.PI * frequency * time);
            }
        }
        
        // 绘制信号
        function drawSignals() {
            const width = basebandCanvas.width;
            const height = basebandCanvas.height;
            const timeRange = 2; // 2秒的时间范围
            
            // 获取参数
            const modulationType = modulationTypeSelect.value;
            const signalType = signalTypeSelect.value;
            const modulationIndex = parseFloat(modulationIndexSlider.value);
            const carrierFrequency = parseFloat(carrierFreqSlider.value);
            const signalFrequency = parseFloat(signalFreqSlider.value);
            const showEnvelope = showEnvelopeCheckbox.checked;
            
            // 清除画布
            basebandCtx.clearRect(0, 0, width, height);
            carrierCtx.clearRect(0, 0, width, height);
            modulatedCtx.clearRect(0, 0, width, height);
            
            // 绘制网格和坐标轴
            drawGridAndAxes(basebandCtx, width, height);
            drawGridAndAxes(carrierCtx, width, height);
            drawGridAndAxes(modulatedCtx, width, height);
            
            // 绘制基带信号
            drawSignal(basebandCtx, width, height, timeRange, 
                      (time) => generateBasebandSignal(time, signalType, signalFrequency), 
                      '#3498db');
            
            // 绘制载波信号
            drawSignal(carrierCtx, width, height, timeRange, 
                      (time) => Math.sin(2 * Math.PI * carrierFrequency * time), 
                      '#e74c3c');
            
            // 绘制调制信号
            let modulatedFunction;
            let envelopeFunction;
            
            switch(modulationType) {
                case 'am':
                    // 调幅: A(t) = A_c * [1 + m * m(t)] * cos(2πf_c t)
                    modulatedFunction = (time) => {
                        const baseband = generateBasebandSignal(time, signalType, signalFrequency);
                        const carrier = Math.sin(2 * Math.PI * carrierFrequency * time);
                        return (1 + modulationIndex * baseband) * carrier;
                    };
                    
                    // AM包络线
                    envelopeFunction = (time) => {
                        const baseband = generateBasebandSignal(time, signalType, signalFrequency);
                        return 1 + modulationIndex * baseband;
                    };
                    break;
                    
                case 'fm':
                    // 调频: A(t) = A_c * cos(2πf_c t + β * ∫m(τ)dτ)
                    // 简化版本: A(t) = A_c * cos(2πf_c t + β * m(t))
                    modulatedFunction = (time) => {
                        const baseband = generateBasebandSignal(time, signalType, signalFrequency);
                        return Math.sin(2 * Math.PI * carrierFrequency * time + 
                                       modulationIndex * baseband);
                    };
                    
                    // FM包络线(频率变化)
                    envelopeFunction = (time) => {
                        const baseband = generateBasebandSignal(time, signalType, signalFrequency);
                        return 0.5 + 0.5 * modulationIndex * baseband;
                    };
                    break;
                    
                case 'pm':
                    // 调相: A(t) = A_c * cos(2πf_c t + k_p * m(t))
                    modulatedFunction = (time) => {
                        const baseband = generateBasebandSignal(time, signalType, signalFrequency);
                        return Math.sin(2 * Math.PI * carrierFrequency * time + 
                                       modulationIndex * Math.PI * baseband);
                    };
                    
                    // PM包络线(相位变化)
                    envelopeFunction = (time) => {
                        const baseband = generateBasebandSignal(time, signalType, signalFrequency);
                        return 0.5 + 0.5 * modulationIndex * baseband;
                    };
                    break;
            }
            
            // 绘制调制信号
            drawSignal(modulatedCtx, width, height, timeRange, modulatedFunction, '#2ecc71');
            
            // 绘制包络线
            if (showEnvelope && envelopeFunction) {
                drawEnvelope(modulatedCtx, width, height, timeRange, envelopeFunction, '#f1c40f');
            }
        }
        
        // 绘制网格和坐标轴
        function drawGridAndAxes(ctx, width, height) {
            ctx.strokeStyle = 'rgba(255, 255, 255, 0.2)';
            ctx.lineWidth = 1;
            
            // 绘制水平网格线
            for (let y = 0; y <= height; y += height / 4) {
                ctx.beginPath();
                ctx.moveTo(0, y);
                ctx.lineTo(width, y);
                ctx.stroke();
            }
            
            // 绘制垂直网格线
            for (let x = 0; x <= width; x += width / 10) {
                ctx.beginPath();
                ctx.moveTo(x, 0);
                ctx.lineTo(x, height);
                ctx.stroke();
            }
            
            // 绘制零线
            ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.moveTo(0, height / 2);
            ctx.lineTo(width, height / 2);
            ctx.stroke();
        }
        
        // 绘制信号波形
        function drawSignal(ctx, width, height, timeRange, signalFunction, color) {
            ctx.strokeStyle = color;
            ctx.lineWidth = 2;
            ctx.beginPath();
            
            for (let x = 0; x < width; x++) {
                const time = (x / width) * timeRange;
                const signalValue = signalFunction(time);
                
                // 将信号值映射到画布坐标
                const y = height / 2 - (signalValue * height / 2.5);
                
                if (x === 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            }
            
            ctx.stroke();
        }
        
        // 绘制包络线
        function drawEnvelope(ctx, width, height, timeRange, envelopeFunction, color) {
            ctx.strokeStyle = color;
            ctx.lineWidth = 2;
            ctx.setLineDash([5, 5]); // 虚线样式
            
            // 上包络线
            ctx.beginPath();
            for (let x = 0; x < width; x++) {
                const time = (x / width) * timeRange;
                const envelopeValue = envelopeFunction(time);
                
                // 将包络值映射到画布坐标
                const y = height / 2 - (envelopeValue * height / 2.5);
                
                if (x === 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            }
            ctx.stroke();
            
            // 下包络线
            ctx.beginPath();
            for (let x = 0; x < width; x++) {
                const time = (x / width) * timeRange;
                const envelopeValue = envelopeFunction(time);
                
                // 将包络值映射到画布坐标
                const y = height / 2 - (-envelopeValue * height / 2.5);
                
                if (x === 0) {
                    ctx.moveTo(x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            }
            ctx.stroke();
            
            ctx.setLineDash([]); // 重置为实线
        }
    </script>
</body>
</html>

------------------------------------------------------------------------------------------------

电磁波_deepseek_html_.zip

电磁波发射调幅调频调相演示_deepseek_html_.html



浏览242
返回
目录
返回
首页
傅里叶变换互动演示HTML实现