대화형 파동 실험실
인터랙티브 파동 실험실에 오신 것을 환영합니다! 여기에서 파동의 세 가지 주요 현상인 전파, 회절, 간섭을 학습할 수 있습니다.
실험을 선택하세요:
파동의 전파
파동은 소스로부터 일정한 속도로 모든 방향으로 퍼져 나갑니다.
🌐 파동 전파
파동은 물질의 이동 없이 에너지를 전달합니다. 소스로부터 동심원을 그리며 퍼져 나갑니다.
- 전파 속도는 매질에 따라 달라집니다
- 진폭은 파동의 세기를 결정합니다
- 전파되는 동안 주파수는 일정하게 유지됩니다
🌊 파동의 회절
회절은 파동이 장애물을 돌아가거나 좁은 틈을 통과하는 성질입니다.
- 장애물의 크기가 파장과 비슷할 때 더 뚜렷하게 나타납니다
- 틈을 통과한 파동은 부채꼴 모양으로 퍼집니다
- 모퉁이 너머로 소리가 들리는 이유를 설명해 줍니다
⚡ 파동의 간섭
간섭은 두 개의 일관된 소스에서 나온 파동이 겹치는 현상입니다 (영의 이중 슬릿).
- 밝은 띠 - 보강 간섭
- 어두운 띠 - 상쇄 간섭
- 띠 사이의 간격은 파장에 따라 달라집니다
📊 파동 프로필
측면도는 공간을 이동하는 사인파 형태의 파동을 보여줍니다.
- 진폭 - 평형점으로부터의 최대 변위
- 파장은 주파수와 속도에 따라 달라집니다
- 주파수가 높을수록 파장은 짧아집니다
🎯 실생활 응용
🎵 음향학
콘서트홀 설계 시 음파의 간섭을 고려합니다
📡 무선 통신
회절 덕분에 전파가 산이나 건물을 돌아갈 수 있습니다
🔬 광학
빛의 간섭은 레이저와 홀로그래피에 사용됩니다
🌊 해양학
파도 연구는 날씨 예측에 도움이 됩니다

0.5) {
ctx.globalAlpha = intensity * (amplitude / 40);
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
}
ctx.globalAlpha = 1;
// Дифрагированные волны справа от щели
const slitSource = { x: barrierX, y: slitY };
for (let angle = -Math.PI/2; angle <= Math.PI/2; angle += Math.PI/20) {
const maxDist = canvas.width - barrierX;
for (let dist = 0; dist < maxDist; dist += 3) {
const x = slitSource.x + dist * Math.cos(angle);
const y = slitSource.y + dist * Math.sin(angle);
if (x >= barrierX && x < canvas.width && y >= 0 && y < canvas.height) {
const wavePhase = (dist / waveLength - time * frequency) * 2 * Math.PI;
const waveValue = Math.sin(wavePhase);
const distanceFactor = Math.max(0, 1 - dist / maxDist);
const angleFactor = Math.cos(angle) * Math.cos(angle);
if (waveValue > 0.3) {
const intensity = waveValue * distanceFactor * angleFactor * (amplitude / 40);
if (intensity > 0.1) {
ctx.fillStyle = 'rgba(255, 152, 0, ' + intensity + ')';
ctx.fillRect(x-1, y-1, 2, 2);
}
}
}
}
}
// Подписи (отодвинули от краев)
ctx.fillStyle = '#fff';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText("\uc2ac\ub9bf", barrierX, Math.max(30, 20));
ctx.fillText("\ud68c\uc808", Math.min(barrierX + 80, canvas.width - 50), Math.max(slitY - 40, 30));
}
// Рисование интерференции от двух щелей с экраном
function drawInterference() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const barrierX = canvas.width * 0.25;
const screenX = canvas.width * 0.6; // Экран ближе к щелям
const slitDistance = 50;
const centerY = canvas.height / 2;
const slit1Y = centerY - slitDistance/2;
const slit2Y = centerY + slitDistance/2;
const slitWidth = 6;
const waveSpeed = 50;
const waveLength = waveSpeed / frequency;
// Рисуем барьер с двумя щелями
ctx.fillStyle = '#444';
ctx.fillRect(barrierX - 3, 0, 6, slit1Y - slitWidth/2);
ctx.fillRect(barrierX - 3, slit1Y + slitWidth/2, 6, slit2Y - slitWidth/2 - (slit1Y + slitWidth/2));
ctx.fillRect(barrierX - 3, slit2Y + slitWidth/2, 6, canvas.height - (slit2Y + slitWidth/2));
// Падающие волны слева
ctx.strokeStyle = 'rgba(33, 150, 243, 0.6)';
ctx.lineWidth = 1;
for (let x = 0; x < barrierX; x += waveLength/3) {
const wavePhase = (x / waveLength - time * frequency) * 2 * Math.PI;
const intensity = Math.sin(wavePhase);
if (intensity > 0.5) {
ctx.globalAlpha = intensity * 0.5;
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, canvas.height);
ctx.stroke();
}
}
ctx.globalAlpha = 1;
// Источники в щелях
ctx.fillStyle = '#ff4444';
ctx.beginPath();
ctx.arc(barrierX, slit1Y, 3, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(barrierX, slit2Y, 3, 0, 2 * Math.PI);
ctx.fill();
// Анимированные волны от источников
ctx.strokeStyle = 'rgba(76, 175, 80, 0.3)';
ctx.lineWidth = 1;
for (let i = 0; i < 5; i++) {
const radius = (time * 30 + i * 25) % 120; // Уменьшили радиус
if (radius > 5) {
const alpha = Math.max(0, 0.3 - radius / 400);
ctx.globalAlpha = alpha;
// От первой щели
ctx.beginPath();
ctx.arc(barrierX, slit1Y, radius, 0, 2 * Math.PI);
ctx.stroke();
// От второй щели
ctx.beginPath();
ctx.arc(barrierX, slit2Y, radius, 0, 2 * Math.PI);
ctx.stroke();
}
}
ctx.globalAlpha = 1;
// Экран справа
ctx.fillStyle = '#222';
ctx.fillRect(screenX - 2, 0, 4, canvas.height);
// Статичная интерференционная картина на экране
const pattern = createInterferencePattern();
pattern.forEach(stripe => {
const { y, color, alpha, width } = stripe;
ctx.fillStyle = 'rgba(' + color[0] + ', ' + color[1] + ', ' + color[2] + ', ' + alpha + ')';
ctx.fillRect(screenX + 2, y, width, 1);
});
// Подписи (размещены подальше от краев)
ctx.fillStyle = '#fff';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
// Подписи щелей
const labelX = Math.max(barrierX - 25, 40);
ctx.fillText("\uc2ac\ub9bf 1", labelX, Math.max(slit1Y - 10, 20));
ctx.fillText("\uc2ac\ub9bf 2", labelX, Math.min(slit2Y + 20, canvas.height - 10));
// Подпись экрана
ctx.fillText("\uc2a4\ud06c\ub9b0", screenX, Math.max(canvas.height - 15, canvas.height - 10));
// Подпись интерференции (размещена безопасно)
const interferenceX = Math.min(screenX + 30, canvas.width - 60);
const interferenceY = Math.max(35, 25);
ctx.font = '11px Arial';
ctx.fillText("\uac04\uc12d", interferenceX, interferenceY);
}
// Рисование бокового вида волны
function drawSideView() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
const centerY = canvas.height / 2;
const waveLength = 100 / frequency;
const maxAmplitude = Math.min(amplitude, canvas.height / 3);
// Ось X
ctx.strokeStyle = '#666';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(0, centerY);
ctx.lineTo(canvas.width, centerY);
ctx.stroke();
// Разметка оси
ctx.fillStyle = '#888';
ctx.font = '10px Arial';
ctx.textAlign = 'center';
for (let x = 0; x < canvas.width; x += waveLength) {
if (x > 20 && x < canvas.width - 20) { // Отступ от краев
ctx.beginPath();
ctx.moveTo(x, centerY - 5);
ctx.lineTo(x, centerY + 5);
ctx.stroke();
ctx.fillText('λ', x, centerY + 15);
}
}
// Волна
ctx.strokeStyle = '#4CAF50';
ctx.lineWidth = 3;
ctx.beginPath();
for (let x = 0; x < canvas.width; x += 2) {
const phase = (x / waveLength + time * frequency * 2) * 2 * Math.PI;
const y = centerY - maxAmplitude * Math.sin(phase);
if (x === 0) {
ctx.moveTo(x, y);
} else {
ctx.lineTo(x, y);
}
}
ctx.stroke();
// Стрелки амплитуды
ctx.strokeStyle = '#ff4444';
ctx.lineWidth = 2;
const arrowX = canvas.width * 0.25;
// Стрелка вверх
ctx.beginPath();
ctx.moveTo(arrowX, centerY);
ctx.lineTo(arrowX, centerY - maxAmplitude);
ctx.stroke();
// Стрелка вниз
ctx.beginPath();
ctx.moveTo(arrowX, centerY);
ctx.lineTo(arrowX, centerY + maxAmplitude);
ctx.stroke();
// Подписи (размещены с отступом от краев)
ctx.fillStyle = '#fff';
ctx.font = '14px Arial';
ctx.textAlign = 'left';
const labelY = Math.max(centerY - maxAmplitude - 10, 25);
ctx.fillText("\uc9c4\ud3ed", Math.max(arrowX - 20, 20), labelY);
ctx.fillText('A = ' + amplitude, Math.max(arrowX - 20, 20), Math.max(labelY - 15, 15));
ctx.textAlign = 'center';
ctx.fillText("\uc804\ud30c \ubc29\ud5a5 \u2192", canvas.width/2, Math.max(40, 30));
ctx.fillText("\uc8fc\ud30c\uc218 = " + frequency + " Hz", canvas.width/2, Math.min(canvas.height - 10, canvas.height - 20));
}
// Анимация
function animate() {
if (!isAnimating) return;
switch(currentExperiment) {
case 'propagation':
drawPropagation();
break;
case 'diffraction':
drawDiffraction();
break;
case 'interference':
drawInterference();
break;
case 'sideview':
drawSideView();
break;
}
time += 0.02;
animationFrame = requestAnimationFrame(animate);
}
// Управление экспериментами
window.switchExperiment = function(experiment) {
const buttons = document.querySelectorAll('.experiment-btn');
const cards = document.querySelectorAll('.theory-card');
const info = document.getElementById('experimentInfo');
buttons.forEach(btn => btn.classList.remove('active'));
cards.forEach(card => card.style.display = 'none');
currentExperiment = experiment;
time = 0;
const btnIds = {
'propagation': 'wavePropBtn',
'diffraction': 'diffractionBtn',
'interference': 'interferenceBtn',
'sideview': 'sideViewBtn'
};
const activeBtn = document.getElementById(btnIds[experiment]);
const activeCard = document.getElementById(experiment + 'Card');
if (activeBtn) activeBtn.classList.add('active');
if (activeCard) activeCard.style.display = 'block';
if (info) {
const titles = {
'propagation': "\ud30c\ub3d9\uc758 \uc804\ud30c",
'diffraction': "\ud30c\ub3d9 \ud68c\uc808",
'interference': "\ud30c\ub3d9 \uac04\uc12d",
'sideview': "\ud30c\ub3d9 \ud504\ub85c\ud544"
};
const descriptions = {
'propagation': "\ud30c\ub3d9\uc740 \uc18c\uc2a4\ub85c\ubd80\ud130 \ub3d9\uc2ec\uc6d0\uc744 \uadf8\ub9ac\uba70 \ud37c\uc838 \ub098\uac11\ub2c8\ub2e4.",
'diffraction': "\ud30c\ub3d9\uc774 \uc2ac\ub9bf\uc744 \ud1b5\uacfc\ud558\uba70 \ubd80\ucc44\uaf34\ub85c \ud37c\uc9d1\ub2c8\ub2e4.",
'interference': "\ub450 \uac1c\uc758 \uc2ac\ub9bf\uc774 \uc2a4\ud06c\ub9b0\uc5d0 \uc815\uc801\uc778 \uac04\uc12d \ubb34\ub2ac\ub97c \ub9cc\ub4ed\ub2c8\ub2e4.",
'sideview': "\uc0ac\uc778\ud30c\uac00 \uacf5\uac04\uc744 \uc774\ub3d9\ud569\ub2c8\ub2e4."
};
info.innerHTML = '
' + titles[experiment] + '
' + descriptions[experiment] + '
';
}
};
// Обновление параметров волн
window.updateWaveParams = function() {
const freqSlider = document.getElementById('frequencySlider');
const ampSlider = document.getElementById('amplitudeSlider');
const freqValue = document.getElementById('frequencyValue');
const ampValue = document.getElementById('amplitudeValue');
if (freqSlider && freqValue) {
frequency = parseFloat(freqSlider.value);
freqValue.textContent = frequency + " Hz";
}
if (ampSlider && ampValue) {
amplitude = parseFloat(ampSlider.value);
ampValue.textContent = amplitude;
}
// Пересчитать интерференционную картину при изменении параметров
interferencePattern = null;
};
// Управление анимацией
window.toggleWaveAnimation = function() {
const btn = document.getElementById('playPauseWaveBtn');
if (!btn) return;
if (isAnimating) {
isAnimating = false;
cancelAnimationFrame(animationFrame);
btn.textContent = "\u25b6\ufe0f \uc7ac\uc0dd";
} else {
isAnimating = true;
animate();
btn.textContent = "\u505c \uc77c\uc2dc\uc815\uc9c0";
}
};
window.resetWaveAnimation = function() {
time = 0;
if (!isAnimating) {
switch(currentExperiment) {
case 'propagation':
drawPropagation();
break;
case 'diffraction':
drawDiffraction();
break;
case 'interference':
drawInterference();
break;
case 'sideview':
drawSideView();
break;
}
}
};
// Запуск анимации
animate();
})()"
style="display: none;">