Интерактивная модель простейшей колебательной системы — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Денис (обсуждение | вклад) (Новая страница: «Виртуальная лаборатория > Интерактивная модель простейшей колебательной системы <HR> ...») |
Денис (обсуждение | вклад) |
||
Строка 3: | Строка 3: | ||
Левая клавиша мыши по грузу - перетаскивание. | Левая клавиша мыши по грузу - перетаскивание. | ||
− | + | {{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/Tcvetkov/Spring/Spring_v2-1_release/Spring.html |width=645 |height=565 |border=0 }} | |
− | {{# | ||
− | |||
− | |||
− | Текст программы на языке JavaScript (разработчики [[Цветков Денис]], [[Кривцов Антон]], использована библиотека [http:// | + | Скачать [[Медиа:Spring_v2-1_release.zip|Spring_v2-1_release.zip]]. |
− | Файл '''" | + | |
+ | Текст программы на языке JavaScript (разработчики [[Цветков Денис]], [[Кривцов Антон]], использована библиотека для построения графиков [http://www.flotcharts.org/ Flot]): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default"> | ||
+ | Файл '''"Spring.js"''' | ||
<source lang="javascript" first-line="1"> | <source lang="javascript" first-line="1"> | ||
− | function | + | window.addEventListener("load", Main_Spring, true); |
+ | function Main_Spring() { | ||
− | // | + | var canvas = spring_canvas; |
+ | canvas.onselectstart = function () {return false;}; // запрет выделения canvas | ||
+ | var ctx = canvas.getContext("2d"); // на ctx происходит рисование | ||
+ | var w = canvas.width; // ширина окна в расчетных координатах | ||
+ | var h = canvas.height; // высота окна в расчетных координатах | ||
− | var | + | var Pi = 3.1415926; // число "пи" |
− | + | var m0 = 1; // масштаб массы | |
+ | var T0 = 1; // масштаб времени (период колебаний исходной системы) | ||
− | + | var k0 = 2 * Pi / T0; // масштаб частоты | |
− | + | var C0 = m0 * k0 * k0; // масштаб жесткости | |
− | + | var B0 = 2 * m0 * k0; // масштаб вязкости | |
− | |||
− | |||
− | |||
// *** Задание физических параметров *** | // *** Задание физических параметров *** | ||
Строка 31: | Строка 33: | ||
var C = 1 * C0; // жесткость | var C = 1 * C0; // жесткость | ||
var B = .1 * B0; // вязкость | var B = .1 * B0; // вязкость | ||
+ | slider_m.value = (m / m0).toFixed(1); number_m.value = (m / m0).toFixed(1); | ||
+ | slider_C.value = (C / C0).toFixed(1); number_C.value = (C / C0).toFixed(1); | ||
+ | slider_B.value = (B / B0).toFixed(1); number_B.value = (B / B0).toFixed(1); | ||
// *** Задание вычислительных параметров *** | // *** Задание вычислительных параметров *** | ||
− | + | var fps = 60; // frames per second - число кадров в секунду (качечтво отображения) | |
− | + | var spf = 10; // steps per frame - число шагов интегрирования между кадрами (edtkbxbdftn скорость расчета) | |
− | + | var dt = 0.05 * T0 / fps; // шаг интегрирования (качество расчета) | |
− | |||
var steps = 0; // количество шагов интегрирования | var steps = 0; // количество шагов интегрирования | ||
− | + | function setM(new_m) {m = new_m * m0;} | |
− | + | function setC(new_C) {C = new_C * C0;} | |
− | + | function setB(new_B) {B = new_B * B0;} | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | slider_m.oninput = function() {number_m.value = slider_m.value; setM(slider_m.value);}; | ||
+ | number_m.oninput = function() {slider_m.value = number_m.value; setM(number_m.value);}; | ||
+ | slider_C.oninput = function() {number_C.value = slider_C.value; setC(slider_C.value);}; | ||
+ | number_C.oninput = function() {slider_C.value = number_C.value; setC(number_C.value);}; | ||
+ | slider_B.oninput = function() {number_B.value = slider_B.value; setB(slider_B.value);}; | ||
+ | number_B.oninput = function() {slider_B.value = number_B.value; setB(number_B.value);}; | ||
var count = true; // проводить ли расчет системы | var count = true; // проводить ли расчет системы | ||
var v = 0; // скорость тела | var v = 0; // скорость тела | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
var rw = canvas.width / 30; var rh = canvas.height / 1.5; | var rw = canvas.width / 30; var rh = canvas.height / 1.5; | ||
− | var x0 = 15 * rw - rw / 2; var y0 = rh/1.33 - rh / 2; | + | var x0 = 15 * rw - rw / 2; var y0 = rh / 1.33 - rh / 2; |
− | // | + | // параметры пружины |
− | + | var coil = 10; // количество витков | |
− | + | var startX = 0; // закрепление пружины | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | // создаем прямоугольник | + | // создаем прямоугольник-грузик |
− | var rect = | + | var rect = { |
− | x: x0, width: rw, | + | x: x0, width: rw, |
− | + | y: y0, height: rh, | |
− | + | fill: "rgba(0, 0, 255, 1)" // цвет | |
− | } | + | }; |
// захват прямоугольника мышью | // захват прямоугольника мышью | ||
− | + | var mx_; // буфер позиции мыши (для расчета скорости при отпускании шара) | |
− | + | document.onmousedown = function(e) { // функция при нажатии клавиши мыши | |
− | + | var m = mouseCoords(e); // получаем расчетные координаты курсора мыши | |
− | + | ||
− | + | var x = rect.x; | |
− | } | + | var xw = rect.x + rect.width; |
+ | var y = rect.y; | ||
+ | var yh = rect.y + rect.height; | ||
+ | if (x <= m.x && xw >= m.x && y <= m.y && yh >= m.y) { | ||
+ | if (e.which == 1) { // нажата левая клавиша мыши | ||
+ | rect.xPlus = rect.x - m.x; // сдвиг курсора относительно грузика по x | ||
+ | rect.yPlus = rect.y - m.y; // сдвиг курсора относительно грузика по y | ||
+ | mx_ = m.x; | ||
+ | count = false; | ||
+ | document.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения | ||
+ | } | ||
+ | } | ||
+ | }; | ||
+ | |||
+ | document.onmouseup = function(e) { // функция при отпускании клавиши мыши | ||
+ | document.onmousemove = null; // когда клавиша отпущена - функции перемещения нету | ||
+ | count = true; | ||
+ | }; | ||
+ | |||
+ | function mouseMove(e) { // функция при перемещении мыши, работает только с зажатой ЛКМ | ||
+ | var m = mouseCoords(e); // получаем расчетные координаты курсора мыши | ||
+ | rect.x = m.x + rect.xPlus; | ||
+ | // v = 6.0 * (m.x - mx_) / dt / fps; // сохранение инерции | ||
+ | v = 0; | ||
+ | mx_ = m.x; | ||
+ | } | ||
− | + | function mouseCoords(e) { // функция возвращает расчетные координаты курсора мыши | |
+ | var m = []; | ||
+ | var rect = canvas.getBoundingClientRect(); | ||
+ | m.x = (e.clientX - rect.left); | ||
+ | m.y = (e.clientY - rect.top); | ||
+ | return m; | ||
+ | } | ||
+ | // график | ||
var vGraph = new TM_graph( // определить график | var vGraph = new TM_graph( // определить график | ||
"#vGraph", // на html-элементе #vGraph | "#vGraph", // на html-элементе #vGraph | ||
− | |||
250, // сколько шагов по оси "x" отображается | 250, // сколько шагов по оси "x" отображается | ||
-1, 1, 0.2); // мин. значение оси Y, макс. значение оси Y, шаг по оси Y | -1, 1, 0.2); // мин. значение оси Y, макс. значение оси Y, шаг по оси Y | ||
+ | function control() { | ||
+ | calculate(); | ||
+ | draw(); | ||
+ | requestAnimationFrame(control); | ||
+ | } | ||
+ | control(); | ||
+ | // setInterval(control, 1000 / fps); // Запуск системы | ||
− | function | + | function calculate() { |
− | + | if (!count) return; | |
− | + | for (var s=1; s<=spf; s++) { | |
var f = - C * (rect.x - x0) - B * v; | var f = - C * (rect.x - x0) - B * v; | ||
v += f / m * dt; | v += f / m * dt; | ||
− | + | rect.x += v * dt; | |
steps++; | steps++; | ||
if (steps % 80 == 0) vGraph.graphIter(steps, (rect.x-x0)/canvas.width*2); // подать данные на график | if (steps % 80 == 0) vGraph.graphIter(steps, (rect.x-x0)/canvas.width*2); // подать данные на график | ||
− | + | } | |
− | + | ||
} | } | ||
− | function | + | function draw() { |
− | for (var i = | + | ctx.clearRect(0, 0, w, h); |
− | + | ||
− | + | ctx.strokeStyle = "#0aa"; | |
− | + | ctx.beginPath(); | |
− | + | ctx.moveTo(0, y0+rh/2); | |
− | + | for (var i = 1; i <= coil + 1; i++ ) { | |
− | + | var x; | |
+ | var y; | ||
+ | if (i != coil + 1) { | ||
+ | x = startX + ((rect.x - startX))/coil*i - ((rect.x - startX))/coil/2; | ||
+ | y = y0+rh/2 + ((i%2==0)?1:-1)*30; | ||
+ | } else { | ||
+ | x = startX + ((rect.x - startX))/coil*i - ((rect.x - startX))/coil; | ||
+ | y = y0+rh/2; | ||
+ | } | ||
+ | |||
+ | ctx.lineTo(x, y); | ||
} | } | ||
+ | ctx.stroke(); | ||
+ | |||
+ | ctx.fillStyle = "#0000ff"; | ||
+ | ctx.fillRect(rect.x, rect.y, rect.width, rect.height); | ||
} | } | ||
− | |||
− | |||
} | } | ||
</source> | </source> | ||
− | Файл '''" | + | Файл '''"Spring.html"''' |
<source lang="html" first-line="1"> | <source lang="html" first-line="1"> | ||
<!DOCTYPE html> | <!DOCTYPE html> | ||
<html> | <html> | ||
<head> | <head> | ||
− | < | + | <meta charset="UTF-8" /> |
− | < | + | <title>Пружина</title> |
− | <script src=" | + | <script src="Spring.js"></script> |
<script src="jquery.min.js"></script> | <script src="jquery.min.js"></script> | ||
− | + | <script src="jquery.flot.js"></script> | |
− | <script src=" | + | <script src="TM_v2-1.js"></script> |
− | |||
− | |||
− | |||
− | <script | ||
</head> | </head> | ||
<body> | <body> | ||
− | + | <canvas id="spring_canvas" width="600" height="100" style="border:1px solid #000000;"></canvas><br> | |
− | + | <input type="range" id="slider_m" min="0.01" max="10" step=0.01 style="width: 150px;" /> | |
− | + | m = <input type="number" id="number_m" min="0.01" max="10" step=0.01 style="width: 50px;" /><br> | |
− | < | + | <input type="range" id="slider_C" min="0" max="10" step=0.01 style="width: 150px;" /> |
− | + | C = <input type="number" id="number_C" min="0" max="10" step=0.01 style="width: 50px;" /><br> | |
− | + | <input type="range" id="slider_B" min="0" max="10" step=0.01 style="width: 150px;" /> | |
− | + | B = <input type="number" id="number_B" min="0" max="10" step=0.01 style="width: 50px;" /><br><br> | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | <table> | ||
+ | <tr><td>x</td> | ||
+ | <td><div id="vGraph" style="width:600px; height:300px; clear:both;"></div></td> | ||
+ | </tr> | ||
+ | <tr><td></td><td style="text-align: center">steps</td></tr> | ||
+ | </table> | ||
</body> | </body> | ||
</html> | </html> | ||
Строка 180: | Строка 198: | ||
</toggledisplay> | </toggledisplay> | ||
− | |||
== Предлагаемые направления развития стенда == | == Предлагаемые направления развития стенда == |
Версия 19:30, 5 ноября 2014
Виртуальная лаборатория > Интерактивная модель простейшей колебательной системыЛевая клавиша мыши по грузу - перетаскивание.
Скачать Spring_v2-1_release.zip.
Текст программы на языке JavaScript (разработчики Цветков Денис, Кривцов Антон, использована библиотека для построения графиков Flot): <toggledisplay status=hide showtext="Показать↓" hidetext="Скрыть↑" linkstyle="font-size:default"> Файл "Spring.js"
window.addEventListener("load", Main_Spring, true);
function Main_Spring() {
var canvas = spring_canvas;
canvas.onselectstart = function () {return false;}; // запрет выделения canvas
var ctx = canvas.getContext("2d"); // на ctx происходит рисование
var w = canvas.width; // ширина окна в расчетных координатах
var h = canvas.height; // высота окна в расчетных координатах
var Pi = 3.1415926; // число "пи"
var m0 = 1; // масштаб массы
var T0 = 1; // масштаб времени (период колебаний исходной системы)
var k0 = 2 * Pi / T0; // масштаб частоты
var C0 = m0 * k0 * k0; // масштаб жесткости
var B0 = 2 * m0 * k0; // масштаб вязкости
// *** Задание физических параметров ***
var m = 1 * m0; // масса
var C = 1 * C0; // жесткость
var B = .1 * B0; // вязкость
slider_m.value = (m / m0).toFixed(1); number_m.value = (m / m0).toFixed(1);
slider_C.value = (C / C0).toFixed(1); number_C.value = (C / C0).toFixed(1);
slider_B.value = (B / B0).toFixed(1); number_B.value = (B / B0).toFixed(1);
// *** Задание вычислительных параметров ***
var fps = 60; // frames per second - число кадров в секунду (качечтво отображения)
var spf = 10; // steps per frame - число шагов интегрирования между кадрами (edtkbxbdftn скорость расчета)
var dt = 0.05 * T0 / fps; // шаг интегрирования (качество расчета)
var steps = 0; // количество шагов интегрирования
function setM(new_m) {m = new_m * m0;}
function setC(new_C) {C = new_C * C0;}
function setB(new_B) {B = new_B * B0;}
slider_m.oninput = function() {number_m.value = slider_m.value; setM(slider_m.value);};
number_m.oninput = function() {slider_m.value = number_m.value; setM(number_m.value);};
slider_C.oninput = function() {number_C.value = slider_C.value; setC(slider_C.value);};
number_C.oninput = function() {slider_C.value = number_C.value; setC(number_C.value);};
slider_B.oninput = function() {number_B.value = slider_B.value; setB(slider_B.value);};
number_B.oninput = function() {slider_B.value = number_B.value; setB(number_B.value);};
var count = true; // проводить ли расчет системы
var v = 0; // скорость тела
var rw = canvas.width / 30; var rh = canvas.height / 1.5;
var x0 = 15 * rw - rw / 2; var y0 = rh / 1.33 - rh / 2;
// параметры пружины
var coil = 10; // количество витков
var startX = 0; // закрепление пружины
// создаем прямоугольник-грузик
var rect = {
x: x0, width: rw,
y: y0, height: rh,
fill: "rgba(0, 0, 255, 1)" // цвет
};
// захват прямоугольника мышью
var mx_; // буфер позиции мыши (для расчета скорости при отпускании шара)
document.onmousedown = function(e) { // функция при нажатии клавиши мыши
var m = mouseCoords(e); // получаем расчетные координаты курсора мыши
var x = rect.x;
var xw = rect.x + rect.width;
var y = rect.y;
var yh = rect.y + rect.height;
if (x <= m.x && xw >= m.x && y <= m.y && yh >= m.y) {
if (e.which == 1) { // нажата левая клавиша мыши
rect.xPlus = rect.x - m.x; // сдвиг курсора относительно грузика по x
rect.yPlus = rect.y - m.y; // сдвиг курсора относительно грузика по y
mx_ = m.x;
count = false;
document.onmousemove = mouseMove; // пока клавиша нажата - работает функция перемещения
}
}
};
document.onmouseup = function(e) { // функция при отпускании клавиши мыши
document.onmousemove = null; // когда клавиша отпущена - функции перемещения нету
count = true;
};
function mouseMove(e) { // функция при перемещении мыши, работает только с зажатой ЛКМ
var m = mouseCoords(e); // получаем расчетные координаты курсора мыши
rect.x = m.x + rect.xPlus;
// v = 6.0 * (m.x - mx_) / dt / fps; // сохранение инерции
v = 0;
mx_ = m.x;
}
function mouseCoords(e) { // функция возвращает расчетные координаты курсора мыши
var m = [];
var rect = canvas.getBoundingClientRect();
m.x = (e.clientX - rect.left);
m.y = (e.clientY - rect.top);
return m;
}
// график
var vGraph = new TM_graph( // определить график
"#vGraph", // на html-элементе #vGraph
250, // сколько шагов по оси "x" отображается
-1, 1, 0.2); // мин. значение оси Y, макс. значение оси Y, шаг по оси Y
function control() {
calculate();
draw();
requestAnimationFrame(control);
}
control();
// setInterval(control, 1000 / fps); // Запуск системы
function calculate() {
if (!count) return;
for (var s=1; s<=spf; s++) {
var f = - C * (rect.x - x0) - B * v;
v += f / m * dt;
rect.x += v * dt;
steps++;
if (steps % 80 == 0) vGraph.graphIter(steps, (rect.x-x0)/canvas.width*2); // подать данные на график
}
}
function draw() {
ctx.clearRect(0, 0, w, h);
ctx.strokeStyle = "#0aa";
ctx.beginPath();
ctx.moveTo(0, y0+rh/2);
for (var i = 1; i <= coil + 1; i++ ) {
var x;
var y;
if (i != coil + 1) {
x = startX + ((rect.x - startX))/coil*i - ((rect.x - startX))/coil/2;
y = y0+rh/2 + ((i%2==0)?1:-1)*30;
} else {
x = startX + ((rect.x - startX))/coil*i - ((rect.x - startX))/coil;
y = y0+rh/2;
}
ctx.lineTo(x, y);
}
ctx.stroke();
ctx.fillStyle = "#0000ff";
ctx.fillRect(rect.x, rect.y, rect.width, rect.height);
}
}
Файл "Spring.html"
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Пружина</title>
<script src="Spring.js"></script>
<script src="jquery.min.js"></script>
<script src="jquery.flot.js"></script>
<script src="TM_v2-1.js"></script>
</head>
<body>
<canvas id="spring_canvas" width="600" height="100" style="border:1px solid #000000;"></canvas><br>
<input type="range" id="slider_m" min="0.01" max="10" step=0.01 style="width: 150px;" />
m = <input type="number" id="number_m" min="0.01" max="10" step=0.01 style="width: 50px;" /><br>
<input type="range" id="slider_C" min="0" max="10" step=0.01 style="width: 150px;" />
C = <input type="number" id="number_C" min="0" max="10" step=0.01 style="width: 50px;" /><br>
<input type="range" id="slider_B" min="0" max="10" step=0.01 style="width: 150px;" />
B = <input type="number" id="number_B" min="0" max="10" step=0.01 style="width: 50px;" /><br><br>
<table>
<tr><td>x</td>
<td><div id="vGraph" style="width:600px; height:300px; clear:both;"></div></td>
</tr>
<tr><td></td><td style="text-align: center">steps</td></tr>
</table>
</body>
</html>
</toggledisplay>
Предлагаемые направления развития стенда
- Моделирование двумерной системы, в которой груз закреплен пружинами с четырех сторон.
- Моделирование более сложных конфигураций, например, несколько пружин подряд с разной жесткостью.
- Возможность определения, является ли система апериодичной при заданных условиях.