电磁波调制原理演示
互动演示,展示调幅(AM)、调频(FM)和调相(PM)的基本概念。(文末有下载链接)
这个演示将包括:
一个信号源(基带信号)和一个载波信号。
用户可以选择调制类型:AM、FM、PM。
用户可以调整一些参数,比如调制深度(AM)、频率偏移(FM)、相位偏移(PM)等。
显示原始信号、载波和调制后的信号。

以下是实现代码( 由 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_.html
目录 返回
首页
