|
|
|
<!-- Copyright 2023 by Alexei Bezborodov <AlexeiBv+mirocod_wave_reflection@narod.ru> -->
|
|
|
|
<!-- public domain -->
|
|
|
|
|
|
|
|
<html lang="ru">
|
|
|
|
|
|
|
|
<head>
|
|
|
|
<meta charset="UTF-8">
|
|
|
|
<title>Переотражение волн</title>
|
|
|
|
|
|
|
|
<!--
|
|
|
|
Загрузка скриптов из интернета
|
|
|
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/brython@3.8.9/brython.min.js"></script>
|
|
|
|
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/brython@3.8.9/brython_stdlib.js"></script>
|
|
|
|
-->
|
|
|
|
|
|
|
|
<!--
|
|
|
|
Загрузка скриптов из локальной папки (рядом с файлом html)
|
|
|
|
-->
|
|
|
|
<script type="text/javascript" src="brython.min.js"></script>
|
|
|
|
<script type="text/javascript" src="brython_stdlib.js"></script>
|
|
|
|
|
|
|
|
|
|
|
|
</head>
|
|
|
|
|
|
|
|
<body onload="brython()">
|
|
|
|
|
|
|
|
<details open>
|
|
|
|
<summary>Расчётные данные</summary>
|
|
|
|
<div>
|
|
|
|
<p>
|
|
|
|
<input type="range" id="max_step_range" for="max_step" name="volume" min="10" max="1000" value="100"
|
|
|
|
oninput='document.getElementById("max_step").value = document.getElementById("max_step_range").value; recalculate();'>
|
|
|
|
<input id = "max_step" type="number" value="100" step="1"
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="max_step" alt="Количество расчётных точек на всю длину среды">Точность расчёта</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<input type="checkbox" id="right_refraction" checked
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="right_refraction" alt="">Отражения и переотражения справа</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<input type="range" id="max_right_refraction_range" for="max_step" name="volume" min="0" max="100" value="3"
|
|
|
|
oninput='document.getElementById("max_right_refraction").value = document.getElementById("max_right_refraction_range").value; recalculate();'>
|
|
|
|
<input id = "max_right_refraction" type="number" value="3" step="1"
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="max_right_refraction" alt="">Количество переотражений справа</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<input type="checkbox" id="left_refraction" checked
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="left_refraction" alt="">Отражения и переотражения слева</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<input type="range" id="max_left_refraction_range" for="max_step" name="volume" min="0" max="100" value="3"
|
|
|
|
oninput='document.getElementById("max_left_refraction").value = document.getElementById("max_left_refraction_range").value; recalculate();'>
|
|
|
|
<input id = "max_left_refraction" type="number" value="3" step="1"
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="max_left_refraction" alt="">Количество переотражений слева</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<input type="range" id="length_range" for="omega" name="volume" min="0" max="200" value="50"
|
|
|
|
oninput='document.getElementById("length").value = document.getElementById("length_range").value / 100; recalculate();'>
|
|
|
|
<input id = "length" type="number" value="0.5" step=".01"
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="length" alt="">Длина среды (в длинах волн)</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<input type="checkbox" id="invert_phase" checked
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="invert_phase" alt="">Инвертирование волны при отражении</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<input type="range" id="k_refraction_range" for="omega" name="volume" min="0" max="100" value="60"
|
|
|
|
oninput='document.getElementById("k_refraction").value = document.getElementById("k_refraction_range").value / 100; recalculate();'>
|
|
|
|
<input id = "k_refraction" type="number" value="0.6" step=".01"
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="k_refraction" alt="">Коэффициент отражения</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<p>
|
|
|
|
<input type="range" id="omega_range" for="omega" name="volume" min="-1000" max="1000" value="0"
|
|
|
|
oninput='document.getElementById("omega").value = document.getElementById("omega_range").value / 100; recalculate();'>
|
|
|
|
<input id = "omega" type="number" value="0" step=".01"
|
|
|
|
oninput='recalculate();'/>
|
|
|
|
<label for="omega" alt="">Начальная фаза главной функции</label>
|
|
|
|
</p>
|
|
|
|
|
|
|
|
<button id="recalculate">Пересчитать</button>
|
|
|
|
</div>
|
|
|
|
</details>
|
|
|
|
|
|
|
|
<h1 class="text-center">Графики волн</h1>
|
|
|
|
<canvas id="draw-board" width="1024" height="500"></canvas>
|
|
|
|
|
|
|
|
<script type="text/python">
|
|
|
|
|
|
|
|
from browser import document, html, window
|
|
|
|
import random, math
|
|
|
|
|
|
|
|
canvas = document["draw-board"]
|
|
|
|
ctx = canvas.getContext("2d")
|
|
|
|
|
|
|
|
x_border = 10
|
|
|
|
y_border = 10
|
|
|
|
|
|
|
|
# Чёрный экран
|
|
|
|
def DrawBlackScreen():
|
|
|
|
ctx.fillStyle = "black"
|
|
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height)
|
|
|
|
|
|
|
|
def DrawLine(x1, y1, x2, y2, lineWidth, style):
|
|
|
|
ctx.strokeStyle = style
|
|
|
|
ctx.lineWidth = lineWidth
|
|
|
|
ctx.beginPath()
|
|
|
|
ctx.moveTo(x1, y1)
|
|
|
|
ctx.lineTo(x2, y2)
|
|
|
|
ctx.stroke()
|
|
|
|
return
|
|
|
|
|
|
|
|
def DrawAxesScreen():
|
|
|
|
ctx.fillRect(0, 0, canvas.width, canvas.height)
|
|
|
|
x1 = x_border
|
|
|
|
x2 = canvas.width - x1
|
|
|
|
y1 = y_border
|
|
|
|
y2 = canvas.height - y1
|
|
|
|
ym = canvas.height/2
|
|
|
|
style = 'red'
|
|
|
|
lw = 2
|
|
|
|
DrawLine(x1, ym, x2, ym, lw, style)
|
|
|
|
DrawLine(x1, y1, x1, y2, lw, style)
|
|
|
|
DrawLine(x2, y1, x2, y2, lw, style)
|
|
|
|
|
|
|
|
|
|
|
|
def max_step_range(event):
|
|
|
|
#document["max_step"].value = document["max_step_range"].value
|
|
|
|
document["max_step"].value = 103
|
|
|
|
|
|
|
|
def base_func(x, omega):
|
|
|
|
return math.sin(x + omega)
|
|
|
|
|
|
|
|
def recalculate():
|
|
|
|
max_step = int(document["max_step"].value)
|
|
|
|
r = document["invert_phase"].checked
|
|
|
|
if r:
|
|
|
|
r = -1
|
|
|
|
else:
|
|
|
|
r = 1
|
|
|
|
k_refraction = float(document["k_refraction"].value)
|
|
|
|
omega = float(document["omega"].value)
|
|
|
|
|
|
|
|
right_refraction = document["right_refraction"].checked
|
|
|
|
max_right_refraction = int(document["max_right_refraction"].value)
|
|
|
|
|
|
|
|
left_refraction = document["left_refraction"].checked
|
|
|
|
max_left_refraction = int(document["max_left_refraction"].value)
|
|
|
|
|
|
|
|
length = float(document["length"].value)
|
|
|
|
|
|
|
|
DrawBlackScreen()
|
|
|
|
DrawAxesScreen()
|
|
|
|
|
|
|
|
right_refraction_last_values = [0.0] * max_right_refraction;
|
|
|
|
left_refraction_last_values = [0.0] * max_left_refraction;
|
|
|
|
|
|
|
|
result = 0.0
|
|
|
|
result_last_value = result
|
|
|
|
|
|
|
|
base_func_value = 0.0
|
|
|
|
base_func_last_value = result
|
|
|
|
|
|
|
|
pi = math.pi
|
|
|
|
|
|
|
|
x1 = x_border
|
|
|
|
x2 = canvas.width - x1
|
|
|
|
y1 = y_border
|
|
|
|
y2 = canvas.height - y1
|
|
|
|
ym = canvas.height/2
|
|
|
|
style = 'white'
|
|
|
|
style_right = '#FF0000'
|
|
|
|
style_left = '#00FF00'
|
|
|
|
style_result = '#00FFFF'
|
|
|
|
line_width_scale = 4.0
|
|
|
|
y_scale = 0.3
|
|
|
|
|
|
|
|
cur_x = 0
|
|
|
|
prev_x = cur_x
|
|
|
|
|
|
|
|
for i in range(max_step):
|
|
|
|
result = 0
|
|
|
|
x = i / max_step * 2.0 * pi * length + 0.0 * omega
|
|
|
|
|
|
|
|
cur_x = x1 + (x2 - x1) * i / max_step
|
|
|
|
|
|
|
|
omega1 = 1.0 * omega
|
|
|
|
|
|
|
|
base_func_value = base_func(x, omega1)
|
|
|
|
if i > 0:
|
|
|
|
base_y = ym - (ym - y1) * y_scale * base_func_value
|
|
|
|
base_y_last = ym - (ym - y1) * y_scale * base_func_last_value
|
|
|
|
|
|
|
|
DrawLine(prev_x, base_y_last, cur_x, base_y, 1.0 * line_width_scale, style)
|
|
|
|
base_func_last_value = base_func_value
|
|
|
|
result += base_func_value
|
|
|
|
|
|
|
|
for r_i in range(max_right_refraction * int(right_refraction) ):
|
|
|
|
cur_k = k_refraction ** (r_i + 1)
|
|
|
|
cur_r = r ** (r_i + 1)
|
|
|
|
cur_znak = (-1) ** r_i
|
|
|
|
func_value = cur_k * cur_r * base_func( ((r_i + 1) + (r_i + 1) % 2) * length * 2 * pi - cur_znak * x, omega1)
|
|
|
|
if i > 0:
|
|
|
|
base_y = ym - (ym - y1) * y_scale * func_value
|
|
|
|
base_y_last = ym - (ym - y1) * y_scale * right_refraction_last_values[r_i]
|
|
|
|
|
|
|
|
DrawLine(prev_x, base_y_last, cur_x, base_y, cur_k * line_width_scale, style_right)
|
|
|
|
right_refraction_last_values[r_i] = func_value
|
|
|
|
result += func_value
|
|
|
|
|
|
|
|
for r_i in range(max_left_refraction * int(left_refraction) ):
|
|
|
|
cur_k = k_refraction ** (r_i + 1)
|
|
|
|
cur_r = r ** (r_i + 1)
|
|
|
|
cur_znak = (-1) ** r_i
|
|
|
|
func_value = cur_k * cur_r * base_func( -((r_i + 1) - (r_i + 1) % 2) * length * 2 * pi - cur_znak * x, omega1)
|
|
|
|
if i > 0:
|
|
|
|
base_y = ym - (ym - y1) * y_scale * func_value
|
|
|
|
base_y_last = ym - (ym - y1) * y_scale * left_refraction_last_values[r_i]
|
|
|
|
|
|
|
|
DrawLine(prev_x, base_y_last, cur_x, base_y, cur_k * line_width_scale, style_left)
|
|
|
|
left_refraction_last_values[r_i] = func_value
|
|
|
|
result += func_value
|
|
|
|
|
|
|
|
if i > 0:
|
|
|
|
base_y = ym - (ym - y1) * y_scale * result
|
|
|
|
base_y_last = ym - (ym - y1) * y_scale * result_last_value
|
|
|
|
|
|
|
|
DrawLine(prev_x, base_y_last, cur_x, base_y, 2.0 * line_width_scale, style_result)
|
|
|
|
result_last_value = result
|
|
|
|
|
|
|
|
|
|
|
|
prev_x = cur_x
|
|
|
|
|
|
|
|
def recalculate_event(event):
|
|
|
|
recalculate()
|
|
|
|
|
|
|
|
|
|
|
|
window.recalculate = recalculate
|
|
|
|
document["recalculate"].bind("click", recalculate_event)
|
|
|
|
|
|
|
|
</script>
|
|
|
|
|
|
|
|
</body>
|
|
|
|
|
|
|
|
</html>
|