Задача падающей цепочки — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
 
Строка 44: Строка 44:
 
==Выводы==
 
==Выводы==
  
В рамках решения задачи смоделировано движение цепочки под действием силы тяжести и проилюсстрирован тот факт, что ускорение крайней массы цепочки больше, чем ускорение свободно падающего тела. Данный эффект объясняется начальным преднатяжением цепочки.
+
В рамках решения задачи смоделировано движение цепочки под действием силы тяжести и проиллюстрирован тот факт, что ускорение крайней массы цепочки больше, чем ускорение свободно падающего тела. Данный эффект объясняется начальным преднатяжением цепочки.
 +
==Ссылки==
 +
http://tm.spbstu.ru/Курсовые_работы_по_ВМДС:_2022-2023 - курсовые работы студентов 4-го курса 2022-2023 года по курсу дискретной механики
 +
http://tm.spbstu.ru/Введение_в_механику_дискретных_сред - курс механики дискретных сред
 +
==Код программы==
 +
<div class="mw-collapsible mw-collapsed">
 +
'''Код программы на языке JavaScript (разработчик Богдан Борисенков):''' <div class="mw-collapsible-content">
 +
<syntaxhighlight lang="javascript" line start="1" enclose="div">
 +
window.addEventListener('load',main,false);
 +
function main() {
 +
 +
var N = document.getElementById('Num').value;
 +
var a = document.getElementById('DIST').value;
 +
var fps = document.getElementById('FPS').value;
 +
var COEF = document.getElementById('COEFF').value;
 +
var hop,g,b,dt,cm;
 +
// считаем, что у нас массы всех частиц и жесткости одинаковы
 +
 +
PRT = []; // частицы
 +
var l_akt1, l_akt2, vx_dot, vy_dot;
 +
var dt2;
 +
var sp = 1;
 +
var flag = 0;
 +
 +
var time = 0; // нужна для подсчета шагов по времени
 +
var time2 = 0;
 +
var M = [];
 +
M.m = 10;
 +
 +
 
 +
// канвасы
 +
var ctx = cnv.getContext('2d');
 +
var h = cnv.height;
 +
var w = cnv.width;
 +
var ctxG = cnv_graf.getContext('2d');
 +
var hG = cnv_graf.height;
 +
var wG = cnv_graf.width;
 +
var ctxG2 = cnv_graf2.getContext('2d');
 +
var hG2 = cnv_graf2.height;
 +
var wG2 = cnv_graf2.width;
 +
 +
// для рисования цепочки по центру канваса
 +
var SHIFT;
 +
var global_len;
 +
 +
// массив модуля ускорения
 +
var VDOT = [];
 +
dot_speed2 = dot_speed = 0;
 +
RAZN = RAZN2 = 0;
 +
x_step = 0;
 +
max_value = 1;
 +
max_value2 = 1;
 +
y_tick(5);
 +
y_tick2(5);
 +
MASSIVE = [];
 +
// кнопки старт, Обновить, пауза
 +
 +
// пауза
 +
function switchdt() {
 +
switch (flag) {
 +
case 0: {
 +
flag = 1;
 +
sp = 0;
 +
break;
 +
}
 +
case 1: {
 +
flag = 0;
 +
sp = 1;
 +
 
 +
}
 +
}
 +
}
 +
COEFF.oninput = function () {UpdCoeff();}
 +
function UpdCoeff() { COEF = parseFloat(document.getElementById('COEFF').value); SHIFT = (w - 0.65*(N-1)*COEF*parseFloat(a))/2;}
 +
Pause.onclick = function () { switchdt();}
 +
 +
// Обновить
 +
New.onclick = function() {
 +
clearInt(interv);
 +
Update();
 +
}
 +
 +
LET.onclick = function () {
 +
clearInt(interv);
 +
interv = setInterval(control2,1000/fps);
 +
}
 +
 +
Add.onclick = function () {
 +
// вносит изменения в данные
 +
UpdateCoeffs();
 +
}
 +
// Функция, которая обновляет данные и запускает расчет
 +
function Update() {
 +
// берем значение для N
 +
N = parseInt(document.getElementById('Num').value);
 +
cm = parseFloat(document.getElementById('CM').value);
 +
a = parseFloat(document.getElementById('DIST').value);
 +
dt0 = parseFloat(document.getElementById('DT').value);
 +
Betta = parseFloat(document.getElementById('B').value);
 +
g = parseFloat(document.getElementById('G').value);
 +
fps = parseInt(document.getElementById('FPS').value);
 +
hop = parseInt(document.getElementById('HOP').value);
 +
// вспомогательная константа
 +
dt2 = dt0*dt0/2;
 +
// теперь задаем параболу
 +
count(N,a);
 +
time = 0;
 +
time2 = 0;
 +
MASSIVE = [];
 +
a = Math.pow(Math.pow(PRT[2].y - PRT[1].y,2) + Math.pow(PRT[2].x - PRT[1].x,2),1/2)/2;
 +
interv = setInterval(control1,1000/fps);
 +
}
 +
 +
function count(NUM, dist) {
 +
var len = 0.65*(NUM-1)*dist;
 +
global_len = len;
 +
var distt = len/(NUM-1);
 +
var len_2 = len/2;
 +
var w_2 = w/2;
 +
var constt2 = 2*Math.pow(2,1/2);
 +
var constt = constt2/len;
 +
 +
for (var i = 0; i< NUM; i++) {
 +
b = [];
 +
b.x = distt*i;
 +
b.y = -constt*Math.pow(b.x-len,2) - constt2*(b.x-len);
 +
b.vx = 0;
 +
b.vy = 0;
 +
b.vx_dot = 0;
 +
b.vy_dot = 0;
 +
PRT[i] = b;
 +
}
 +
// на всякий
 +
PRT[0].y = 0;
 +
PRT[NUM-1].y = 0;
 +
// console.log(PRT);
 +
M.x = PRT[N-1].x;
 +
M.y = PRT[N-1].y;
 +
M.vy = 0;
 +
 +
// сместим цепочку в центр канваса
 +
UpdCoeff();
 +
}
 +
 +
 +
function phys_1() {  // когда последняя частица закреплена
 +
// первая частица у нас всегда закреплена и последняя!
 +
dt = dt0*sp;
 +
dot_speed = dot_speed2;
 +
for (var i = 1; i<N-1; i++) {
 +
 +
l_akt1 = Math.pow(Math.pow(PRT[i+1].x - PRT[i].x,2) + Math.pow(PRT[i+1].y - PRT[i].y,2),1/2);
 +
l_akt2 = Math.pow(Math.pow(PRT[i].x - PRT[i-1].x,2) + Math.pow(PRT[i].y - PRT[i-1].y,2),1/2);
 +
// занулим силы, если расстояние меньше а
 +
if (l_akt1 < a) {
 +
FR = 0;
 +
} else {
 +
FR = (l_akt1 - a);
 +
}
 +
if (l_akt2 < a) {
 +
FL = 0;
 +
} else {
 +
FL = (l_akt2 - a);
 +
}
 +
vx_dot = cm*(FR*(PRT[i+1].x - PRT[i].x)/l_akt1 - FL*(PRT[i].x - PRT[i-1].x)/l_akt2) - Betta*PRT[i].vx;
 +
vy_dot = (cm*(FR*(PRT[i+1].y - PRT[i].y)/l_akt1 - FL*(PRT[i].y - PRT[i-1].y)/l_akt2) + g) - Betta*PRT[i].vy;
 +
PRT[i].vx_dot = vx_dot;
 +
PRT[i].vy_dot = vy_dot;
 +
PRT[i].vx += vx_dot*dt ;
 +
PRT[i].vy += vy_dot*dt;
 +
 
 +
}
 +
for (var i = 1; i<N-1; i++) {
 +
PRT[i].x += PRT[i].vx*dt;
 +
PRT[i].y += PRT[i].vy*dt;
 +
}
 +
 +
}
 +
 +
function phys_2() { // когда последнюю частицу отпустили
 +
dt = dt0*sp;
 +
dot_speed = dot_speed2;
 +
RAZN = RAZN2;
 +
MASSIVE.push(RAZN);
 +
for (var i = 1; i<N-1; i++) {
 +
l_akt1 = Math.pow(Math.pow(PRT[i+1].x - PRT[i].x,2) + Math.pow(PRT[i+1].y - PRT[i].y,2),1/2);
 +
l_akt2 = Math.pow(Math.pow(PRT[i].x - PRT[i-1].x,2) + Math.pow(PRT[i].y - PRT[i-1].y,2),1/2);
 +
if (l_akt1 < a) {
 +
FR = 0;
 +
} else {
 +
FR = (l_akt1 - a);
 +
}
 +
if (l_akt2 < a) {
 +
FL = 0;
 +
} else {
 +
FL = (l_akt2 - a);
 +
}
 +
vx_dot = cm*(FR*(PRT[i+1].x - PRT[i].x)/l_akt1 - FL*(PRT[i].x - PRT[i-1].x)/l_akt2) - Betta*PRT[i].vx;
 +
vy_dot = (cm*(FR*(PRT[i+1].y - PRT[i].y)/l_akt1 - FL*(PRT[i].y - PRT[i-1].y)/l_akt2) + g) - Betta*PRT[i].vy;
 +
PRT[i].vx_dot = vx_dot;
 +
PRT[i].vy_dot = vy_dot;
 +
PRT[i].vx += vx_dot*dt ;
 +
PRT[i].vy += vy_dot*dt;
 +
 
 +
}
 +
// теперь для последней частицы
 +
l_akt2 = Math.pow(Math.pow(PRT[N-1].x - PRT[N-2].x,2) + Math.pow(PRT[N-1].y - PRT[N-2].y,2),1/2);
 +
if (l_akt2 < a) {
 +
FL = 0;
 +
} else {
 +
FL = (l_akt2 - a);
 +
}
 +
vx_dot =  -cm*FL*(PRT[N-1].x - PRT[N-2].x)/l_akt2 - Betta*PRT[N-1].vx;
 +
vy_dot =  -cm*FL*(PRT[N-1].y - PRT[N-2].y)/l_akt2 - Betta*PRT[N-1].vy;
 +
PRT[N-1].vx_dot = vx_dot;
 +
PRT[N-1].vy_dot = vy_dot;
 +
PRT[N-1].vx += vx_dot*dt ;
 +
PRT[N-1].vy += vy_dot*dt;
 +
 +
// теперь считаем новые координаты
 +
 
 +
for (var i = 1; i<N; i++) {
 +
PRT[i].x += PRT[i].vx*dt;
 +
PRT[i].y += PRT[i].vy*dt;
 +
}
 +
M.y = g*Math.pow(time2*dt0,2)/2;
 +
}
 +
 
 +
 +
function draw1() {
 +
ctx.clearRect(0,0,w,h);
 +
for (var i = 0; i<N; i++) {
 +
ctx.beginPath();
 +
ctx.arc(PRT[i].x*COEF + SHIFT,PRT[i].y*COEF + 50, 3, 0, 2*Math.PI);
 +
ctx.stroke();
 +
}
 +
ctx.beginPath();
 +
ctx.moveTo(0,50);
 +
ctx.lineTo(w,50);
 +
ctx.stroke();
 +
 +
}
 +
 +
function draw2() {
 +
ctx.clearRect(0,0,w,h);
 +
for (var i = 0; i<N; i++) {
 +
ctx.beginPath();
 +
ctx.arc(PRT[i].x*COEF + SHIFT,PRT[i].y*COEF + 50, 3, 0, 2*Math.PI);
 +
ctx.stroke();
 +
}
 +
ctx.beginPath();
 +
ctx.moveTo(0,50);
 +
ctx.lineTo(w,50);
 +
ctx.stroke();
 +
// свободно падающее тело
 +
ctx.beginPath();
 +
ctx.arc(M.x*COEF + SHIFT,M.y*COEF + 50, 5, 0, 2*Math.PI);
 +
ctx.fill();
 +
 +
}
 +
 +
function draw_graf() {
 +
// строим график ускорений
 +
dot_speed2 = Math.pow(Math.pow(PRT[N-1].vx_dot,2) + Math.pow(PRT[N-1].vy_dot,2),1/2)/g;
 +
RAZN2 = PRT[N-1].y - M.y;
 +
// надо понять масштаб графика по y
 +
if (dot_speed2/max_value > 0.9) { max_value = dot_speed2*1.5; y_tick(5);}
 +
if (RAZN2/max_value2 > 0.9) { max_value2 = RAZN2*1.5; y_tick2(5);}
 +
if (x_step == wG) { x_step = 0; ctxG.clearRect(0,0,wG,hG); ctxG2.clearRect(0,0,wG2,hG2); y_tick(5); y_tick2(5);}
 +
ctxG.beginPath();
 +
ctxG.moveTo(x_step, hG*(1 - dot_speed/max_value));
 +
x_step += 0.5;
 +
ctxG.lineTo(x_step,hG*(1 - dot_speed2/max_value));
 +
ctxG.stroke();
 +
// рисуем верх
 +
ctxG2.clearRect(0,0,wG2,hG2);
 +
y_tick2(5);
 +
xx_step = wG2/2/MASSIVE.length;
 +
for (var j = 1; j < MASSIVE.length; j++) {
 +
ctxG2.beginPath();
 +
ctxG2.moveTo(xx_step*(j-1), hG2*(1 - MASSIVE[j-1]/max_value2));
 +
ctxG2.lineTo(xx_step*j,hG2*(1 - MASSIVE[j]/max_value2));
 +
ctxG2.stroke();
 +
}
 +
 +
 
 +
 +
}
 +
function y_tick(num) {
 +
ctxG.clearRect(0,0,50,hG-10);
 +
ctxG.fillText(max_value.toFixed(2),5,0.05*hG);
 +
var step = hG/num;
 +
for (var i = 1; i< num; i++) {
 +
// рисуем засечку
 +
val = step*i;
 +
ctxG.beginPath();
 +
ctxG.moveTo(0,hG - val);
 +
ctxG.lineTo(3,hG - val);
 +
ctxG.fillText((val/hG*max_value).toFixed(2), 5, hG - val);
 +
ctxG.stroke();
 +
}
 +
ctxG.fillText('x"/G',40,0.05*hG);
 +
 +
 
 +
}
 +
function y_tick2(num) {
 +
ctxG2.clearRect(0,0,50,hG2-10);
 +
ctxG2.clearRect(0,0,80,20);
 +
ctxG2.fillText(max_value2.toFixed(2),5,0.05*hG2);
 +
var step = hG/num;
 +
for (var i = 1; i< num; i++) {
 +
// рисуем засечку
 +
val = step*i;
 +
ctxG2.beginPath();
 +
ctxG2.moveTo(0,hG - val);
 +
ctxG2.lineTo(3,hG - val);
 +
ctxG2.fillText((val/hG2*max_value2).toFixed(2), 5, hG2 - val);
 +
ctxG2.stroke();
 +
}
 +
ctxG2.fillText('y - yM',40,0.05*hG2);
 +
}
 +
function control1() {
 +
phys_1();
 +
if (time % hop == 0) {
 +
draw1();
 +
}
 +
draw_graf();
 +
time++;
 +
}
 +
function control2() {
 +
phys_2();
 +
if (time % hop == 0) {
 +
draw2();
 +
}
 +
draw_graf();
 +
time2 += sp;
 +
}
 +
 +
function clearInt(intrv) {
 +
clearInterval(intrv);
 +
}
 +
FPS.oninput = function () {
 +
fps = parseInt(document.getElementById('FPS').value);
 +
clearInt(interv);
 +
interv = setInterval(control2,1000/fps);
 +
}
 +
 +
function UpdateCoeffs() {
 +
cm = parseFloat(document.getElementById('CM').value);
 +
dt0 = parseFloat(document.getElementById('DT').value);
 +
Betta = parseFloat(document.getElementById('B').value);
 +
g = parseFloat(document.getElementById('G').value);
 +
hop = parseInt(document.getElementById('HOP').value);
 +
dt2 = dt0*dt0/2;
 +
}
 +
UpdateCoeffs();
 +
Update();
 +
 
 +
}
 +
</syntaxhighlight>
 +
</div>
 +
<div class="mw-collapsible mw-collapsed">
 +
'''html - файл:''' <div class="mw-collapsible-content">
 +
<syntaxhighlight lang="html" line start="1" enclose="div">
 +
<!DOCTYPE html>
 +
<html>
 +
<head>
 +
<title> Chain_2022 </title>
 +
<script src = 'Chain2.js'>
 +
</script>
 +
</head>
 +
<body>
 +
<div id = 'Canv'>
 +
<canvas id = 'cnv' width = 500 height = 500 style='border: 1px solid black;'></canvas>
 +
<canvas id = 'cnv_graf' width = 500 height = 250 style='border: 1px solid black;'></canvas>
 +
<canvas id = 'cnv_graf2' width = 500 height = 250 style='border: 1px solid black;'></canvas>
 +
<b>
 +
<br><label>C/M <input type = 'text' id = 'CM' value = '2000'></label>
 +
<label>DT <input type = 'text' id = 'DT' value = '0.01'></label>
 +
<label>FPS <input type = 'range' id = 'FPS' min = 10 step = 10 value = 120 max = 120></label>
 +
<input type = "button" id = "New" value = "Обновить"/>
 +
<input type="button" id = "Pause" value = "▶/||"/> <input type="button" id = "Add" value = "Внести правки"/>
 +
<label> Расстояние между частицами <input type = 'text' id = 'DIST' value = '1'>
 +
<br>
 +
<br><label>B <input type = 'text' id = 'B' value = '1'></label>
 +
<label>N <input type = 'text' id = 'Num' value = '100'></label>
 +
<label>G <input type = 'text' id = 'G' value = '50'></label>
 +
<label>Рисовать каждый <input type = 'text' id = 'HOP' value = 1> шаг</label>
 +
<input type = 'button' id = 'LET' value = 'Отпустить правый конец'>
 +
<label>Масштаб<input type = 'range' id = 'COEFF' min = 0.1 step = 0.01 value = 3 max = 20></label>
 +
<br>
 +
</b>
 +
</div>
 +
 +
<style type="text/css">
 +
#CM,#DT,#B,#G,#Num,#HOP {width:70px}
 +
<!-- #Canv{  -->
 +
<!-- width: 50%; -->
 +
<!-- margin: 0 auto; -->
 +
<!-- } -->
 +
#cnv_graf2 {position:absolute; left:514px;}
 +
#cnv_graf {position:absolute; left:514px; top:258px;}
 +
</style>
 +
 +
</body>
 +
</html>
 +
</syntaxhighlight>
 +
</div>

Текущая версия на 11:21, 25 января 2023

Курсовой проект по Введение в механику дискретных сред

Исполнитель: Борисенков Богдан

Группа: 5030103/90101

Семестр: осень 2022

Постановка задачи[править]

В рамках проекта необходимо смоделировать движение одномерной цепочки: начальное положение (провисание) цепочки и дальнейшее ее падение при отпускании одного из концов под действием силы тяжести, а также исследовать зависимость ускорения крайней свободной частицы от времени.

Математическая модель[править]

Изначально запишем закон движения: [math] m\underline{\ddot{r}}_i(t)=\underline{F}_{i-1}+\underline{F}_{i+1} + \underline{F}_{g}\\ \underline{r}_i(0)=\underline{r}_i^0,~\underline{v}_i(0)=0~~~i=1,\ldots,n [/math]

где [math] \underline{F}_{i-1}, \underline{F}_{i+1}\\ [/math] - силы упругости действующие на [math]i[/math]-ую частицу со стороны [math]i-1[/math] и [math]i+1[/math] соответственно, а [math] \underline{F}_{g}=-mg\underline{k} \\ [/math] - сила тяжести.

Далее распишем силу упругости как произведение модуля на соответствующий орт: [math] \underline{F}_{i+1}= c(|\underline{r}_{i+1}-\underline{r}_{i}| - l_0)\frac{(\underline{r}_{i+1}-\underline{r}_{i})}{|\underline{r}_{i+1}-\underline{r}_{i}|} [/math], где [math]c[/math] - коэффициент жесткости пружины. Аналогично записывается сила [math]\underline{F}_{i-1}[/math].

Далее подставляя все силы в уравнение движения, получим:

[math] m\underline{\ddot{r}}_i(t)= c(||\underline{r}_{i+1}-\underline{r}_i|| -l_0)\frac{(\underline{r}_{i+1}-\underline{r}_i)}{||\underline{r}_{i+1}-\underline{r}_i||} + c(||\underline{r}_{i-1}-\underline{r}_i|| - l_0)\frac{(\underline{r}_{i-1}-\underline{r}_i)}{||\underline{r}_{i-1}-\underline{r}_i||} - mg\underline{k}\\ [/math]

Дальнейшее интегрирование уравнения производится с помощью явного симплектического метода Верле c нулевыми начальными условиями и условиями закрепления на концах.

[math] \begin{cases} V_{i+1} = V_i+A_i\Delta{t}\\ X_{i+1} = X_i+V_{i+1}\Delta{t}, \end{cases} [/math]

Численное моделирование[править]

Выводы[править]

В рамках решения задачи смоделировано движение цепочки под действием силы тяжести и проиллюстрирован тот факт, что ускорение крайней массы цепочки больше, чем ускорение свободно падающего тела. Данный эффект объясняется начальным преднатяжением цепочки.

Ссылки[править]

http://tm.spbstu.ru/Курсовые_работы_по_ВМДС:_2022-2023 - курсовые работы студентов 4-го курса 2022-2023 года по курсу дискретной механики http://tm.spbstu.ru/Введение_в_механику_дискретных_сред - курс механики дискретных сред

Код программы[править]

Код программы на языке JavaScript (разработчик Богдан Борисенков):
  1 window.addEventListener('load',main,false);
  2 function main() { 
  3 	
  4 	var N = document.getElementById('Num').value;
  5 	var a = document.getElementById('DIST').value;
  6 	var fps = document.getElementById('FPS').value;
  7 	var COEF = document.getElementById('COEFF').value;
  8 	var hop,g,b,dt,cm;
  9 	// считаем, что у нас массы всех частиц и жесткости одинаковы
 10 	
 11 	PRT = []; // частицы
 12 	var l_akt1, l_akt2, vx_dot, vy_dot;
 13 	var dt2;
 14 	var sp = 1;
 15 	var flag = 0;
 16 	
 17 	var time = 0; // нужна для подсчета шагов по времени
 18 	var time2 = 0;
 19 	var M = [];
 20 	M.m = 10;
 21 	
 22 
 23 	// канвасы
 24 	var ctx = cnv.getContext('2d');
 25 	var h = cnv.height;
 26 	var w = cnv.width;
 27 	var ctxG = cnv_graf.getContext('2d');
 28 	var hG = cnv_graf.height;
 29 	var wG = cnv_graf.width;
 30 	var ctxG2 = cnv_graf2.getContext('2d');
 31 	var hG2 = cnv_graf2.height;
 32 	var wG2 = cnv_graf2.width;
 33 	
 34 	// для рисования цепочки по центру канваса
 35 	var SHIFT; 
 36 	var global_len;
 37 	
 38 	// массив модуля ускорения
 39 	var VDOT = [];
 40 	dot_speed2 = dot_speed = 0;
 41 	RAZN = RAZN2 = 0;
 42 	x_step = 0;
 43 	max_value = 1;
 44 	max_value2 = 1;
 45 	y_tick(5);
 46 	y_tick2(5);
 47 	MASSIVE = [];
 48 	// кнопки старт, Обновить, пауза
 49 	
 50 	// пауза
 51 	function switchdt() {
 52 		switch (flag) {
 53 			case 0: {
 54 				flag = 1;
 55 				sp = 0;
 56 				break;
 57 			}
 58 			case 1: {
 59 				flag = 0;
 60 				sp = 1;
 61 
 62 			}
 63 		}
 64 	}	
 65 	COEFF.oninput = function () {UpdCoeff();}
 66 	function UpdCoeff() { COEF = parseFloat(document.getElementById('COEFF').value); SHIFT = (w - 0.65*(N-1)*COEF*parseFloat(a))/2;}
 67 	Pause.onclick = function () { switchdt();}
 68 	
 69 	// Обновить 
 70 	New.onclick = function() {
 71 		clearInt(interv);
 72 		Update();
 73 	}
 74 	
 75 	LET.onclick = function () { 
 76 		clearInt(interv);
 77 		interv = setInterval(control2,1000/fps);	
 78 	}
 79 	
 80 	Add.onclick = function () { 
 81 		// вносит изменения в данные
 82 		UpdateCoeffs();
 83 	}
 84 	// Функция, которая обновляет данные и запускает расчет
 85 	function Update() { 
 86 		// берем значение для N
 87 		N = parseInt(document.getElementById('Num').value);
 88 		cm = parseFloat(document.getElementById('CM').value);
 89 		a = parseFloat(document.getElementById('DIST').value);
 90 		dt0 = parseFloat(document.getElementById('DT').value);
 91 		Betta = parseFloat(document.getElementById('B').value);
 92 		g = parseFloat(document.getElementById('G').value);
 93 		fps = parseInt(document.getElementById('FPS').value);
 94 		hop = parseInt(document.getElementById('HOP').value);
 95 		// вспомогательная константа
 96 		dt2 = dt0*dt0/2;
 97 		// теперь задаем параболу
 98 		count(N,a);
 99 		time = 0;
100 		time2 = 0;
101 		MASSIVE = [];
102 		a = Math.pow(Math.pow(PRT[2].y - PRT[1].y,2) + Math.pow(PRT[2].x - PRT[1].x,2),1/2)/2;
103 		interv = setInterval(control1,1000/fps);
104 	}
105 	
106 	function count(NUM, dist) {
107 		var len = 0.65*(NUM-1)*dist;
108 		global_len = len;
109 		var distt = len/(NUM-1);
110 		var len_2 = len/2;
111 		var w_2 = w/2;
112 		var constt2 = 2*Math.pow(2,1/2);
113 		var constt = constt2/len;
114 		
115 		for (var i = 0; i< NUM; i++) { 
116 			b = [];
117 			b.x = distt*i; 
118 			b.y = -constt*Math.pow(b.x-len,2) - constt2*(b.x-len);
119 			b.vx = 0;
120 			b.vy = 0;
121 			b.vx_dot = 0;
122 			b.vy_dot = 0;
123 			PRT[i] = b;
124 		}
125 		// на всякий
126 		PRT[0].y = 0;
127 		PRT[NUM-1].y = 0;
128 		// console.log(PRT);
129 		M.x = PRT[N-1].x;
130 		M.y = PRT[N-1].y;
131 		M.vy = 0;
132 		
133 		// сместим цепочку в центр канваса
134 		UpdCoeff();
135 	}
136 		
137 	
138 	function phys_1() {  // когда последняя частица закреплена
139 		// первая частица у нас всегда закреплена и последняя!
140 		dt = dt0*sp;
141 		dot_speed = dot_speed2;
142 		for (var i = 1; i<N-1; i++) { 
143 			
144 			l_akt1 = Math.pow(Math.pow(PRT[i+1].x - PRT[i].x,2) + Math.pow(PRT[i+1].y - PRT[i].y,2),1/2);
145 			l_akt2 = Math.pow(Math.pow(PRT[i].x - PRT[i-1].x,2) + Math.pow(PRT[i].y - PRT[i-1].y,2),1/2);
146 			// занулим силы, если расстояние меньше а
147 			if (l_akt1 < a) {
148 				FR = 0;
149 			} else { 
150 				FR = (l_akt1 - a);
151 			}
152 			if (l_akt2 < a) {
153 				FL = 0;
154 			} else { 
155 				FL = (l_akt2 - a);
156 			}
157 			vx_dot = cm*(FR*(PRT[i+1].x - PRT[i].x)/l_akt1 - FL*(PRT[i].x - PRT[i-1].x)/l_akt2) - Betta*PRT[i].vx;
158 			vy_dot = (cm*(FR*(PRT[i+1].y - PRT[i].y)/l_akt1 - FL*(PRT[i].y - PRT[i-1].y)/l_akt2) + g) - Betta*PRT[i].vy;
159 			PRT[i].vx_dot = vx_dot;
160 			PRT[i].vy_dot = vy_dot;
161 			PRT[i].vx += vx_dot*dt ;
162 			PRT[i].vy += vy_dot*dt;
163 
164 		}
165 		for (var i = 1; i<N-1; i++) { 
166 			PRT[i].x += PRT[i].vx*dt;
167 			PRT[i].y += PRT[i].vy*dt;
168 		}
169 		
170 	}
171 	
172 	function phys_2() { // когда последнюю частицу отпустили
173 		dt = dt0*sp;
174 		dot_speed = dot_speed2;
175 		RAZN = RAZN2;
176 		MASSIVE.push(RAZN);
177 		for (var i = 1; i<N-1; i++) { 
178 			l_akt1 = Math.pow(Math.pow(PRT[i+1].x - PRT[i].x,2) + Math.pow(PRT[i+1].y - PRT[i].y,2),1/2);
179 			l_akt2 = Math.pow(Math.pow(PRT[i].x - PRT[i-1].x,2) + Math.pow(PRT[i].y - PRT[i-1].y,2),1/2);
180 			if (l_akt1 < a) {
181 				FR = 0;
182 			} else { 
183 				FR = (l_akt1 - a);
184 			}
185 			if (l_akt2 < a) {
186 				FL = 0;
187 			} else { 
188 				FL = (l_akt2 - a);
189 			}
190 			vx_dot = cm*(FR*(PRT[i+1].x - PRT[i].x)/l_akt1 - FL*(PRT[i].x - PRT[i-1].x)/l_akt2) - Betta*PRT[i].vx;
191 			vy_dot = (cm*(FR*(PRT[i+1].y - PRT[i].y)/l_akt1 - FL*(PRT[i].y - PRT[i-1].y)/l_akt2) + g) - Betta*PRT[i].vy;
192 			PRT[i].vx_dot = vx_dot;
193 			PRT[i].vy_dot = vy_dot;
194 			PRT[i].vx += vx_dot*dt ;
195 			PRT[i].vy += vy_dot*dt;
196 
197 		}
198 		// теперь для последней частицы
199 		l_akt2 = Math.pow(Math.pow(PRT[N-1].x - PRT[N-2].x,2) + Math.pow(PRT[N-1].y - PRT[N-2].y,2),1/2);
200 		if (l_akt2 < a) {
201 				FL = 0;
202 			} else { 
203 				FL = (l_akt2 - a);
204 		}
205 		vx_dot =  -cm*FL*(PRT[N-1].x - PRT[N-2].x)/l_akt2 - Betta*PRT[N-1].vx;
206 		vy_dot =  -cm*FL*(PRT[N-1].y - PRT[N-2].y)/l_akt2 - Betta*PRT[N-1].vy;
207 		PRT[N-1].vx_dot = vx_dot;
208 		PRT[N-1].vy_dot = vy_dot;
209 		PRT[N-1].vx += vx_dot*dt ;
210 		PRT[N-1].vy += vy_dot*dt;
211 		
212 		// теперь считаем новые координаты
213 
214 		for (var i = 1; i<N; i++) { 
215 			PRT[i].x += PRT[i].vx*dt;
216 			PRT[i].y += PRT[i].vy*dt;
217 		}
218 		M.y = g*Math.pow(time2*dt0,2)/2;
219 	}
220 
221 	
222 	function draw1() { 
223 		ctx.clearRect(0,0,w,h);
224 		for (var i = 0; i<N; i++) { 
225 			ctx.beginPath();
226 			ctx.arc(PRT[i].x*COEF + SHIFT,PRT[i].y*COEF + 50, 3, 0, 2*Math.PI);
227 			ctx.stroke();
228 		}
229 		ctx.beginPath();
230 		ctx.moveTo(0,50);
231 		ctx.lineTo(w,50);
232 		ctx.stroke();
233 		
234 	}
235 	
236 	function draw2() { 
237 		ctx.clearRect(0,0,w,h);
238 		for (var i = 0; i<N; i++) { 
239 			ctx.beginPath();
240 			ctx.arc(PRT[i].x*COEF + SHIFT,PRT[i].y*COEF + 50, 3, 0, 2*Math.PI);
241 			ctx.stroke();
242 		}
243 		ctx.beginPath();
244 		ctx.moveTo(0,50);
245 		ctx.lineTo(w,50);
246 		ctx.stroke();
247 		// свободно падающее тело 
248 		ctx.beginPath();
249 		ctx.arc(M.x*COEF + SHIFT,M.y*COEF + 50, 5, 0, 2*Math.PI);
250 		ctx.fill();
251 		
252 	}
253 	
254 	function draw_graf() { 
255 		// строим график ускорений 
256 		dot_speed2 = Math.pow(Math.pow(PRT[N-1].vx_dot,2) + Math.pow(PRT[N-1].vy_dot,2),1/2)/g;
257 		RAZN2 = PRT[N-1].y - M.y;
258 		// надо понять масштаб графика по y
259 		if (dot_speed2/max_value > 0.9) { max_value = dot_speed2*1.5; y_tick(5);}
260 		if (RAZN2/max_value2 > 0.9) { max_value2 = RAZN2*1.5; y_tick2(5);}
261 		if (x_step == wG) { x_step = 0; ctxG.clearRect(0,0,wG,hG); ctxG2.clearRect(0,0,wG2,hG2); y_tick(5); y_tick2(5);}
262 		ctxG.beginPath();
263 		ctxG.moveTo(x_step, hG*(1 - dot_speed/max_value));
264 		x_step += 0.5;
265 		ctxG.lineTo(x_step,hG*(1 - dot_speed2/max_value));
266 		ctxG.stroke();
267 		// рисуем верх 
268 		ctxG2.clearRect(0,0,wG2,hG2);
269 		y_tick2(5);
270 		xx_step = wG2/2/MASSIVE.length;
271 		for (var j = 1; j < MASSIVE.length; j++) { 
272 			ctxG2.beginPath();
273 			ctxG2.moveTo(xx_step*(j-1), hG2*(1 - MASSIVE[j-1]/max_value2));
274 			ctxG2.lineTo(xx_step*j,hG2*(1 - MASSIVE[j]/max_value2));
275 			ctxG2.stroke();
276 		}
277 		
278 
279 		
280 	}
281 	function y_tick(num) { 
282 		ctxG.clearRect(0,0,50,hG-10);
283 		ctxG.fillText(max_value.toFixed(2),5,0.05*hG);
284 		var step = hG/num;
285 		for (var i = 1; i< num; i++) { 
286 			// рисуем засечку
287 			val = step*i;
288 			ctxG.beginPath();
289 			ctxG.moveTo(0,hG - val); 
290 			ctxG.lineTo(3,hG - val);
291 			ctxG.fillText((val/hG*max_value).toFixed(2), 5, hG - val);
292 			ctxG.stroke();
293 		}
294 		ctxG.fillText('x"/G',40,0.05*hG);
295 		
296 
297 	}
298 	function y_tick2(num) { 
299 		ctxG2.clearRect(0,0,50,hG2-10);
300 		ctxG2.clearRect(0,0,80,20);
301 		ctxG2.fillText(max_value2.toFixed(2),5,0.05*hG2);
302 		var step = hG/num;
303 		for (var i = 1; i< num; i++) { 
304 			// рисуем засечку
305 			val = step*i;
306 			ctxG2.beginPath();
307 			ctxG2.moveTo(0,hG - val); 
308 			ctxG2.lineTo(3,hG - val);
309 			ctxG2.fillText((val/hG2*max_value2).toFixed(2), 5, hG2 - val);
310 			ctxG2.stroke();
311 		}
312 		ctxG2.fillText('y - yM',40,0.05*hG2);
313 	}
314 	function control1() { 
315 		phys_1();
316 		if (time % hop == 0) { 
317 			draw1();
318 		}
319 		draw_graf();
320 		time++;
321 	}
322 	function control2() { 
323 		phys_2();
324 		if (time % hop == 0) { 
325 			draw2();
326 		}
327 		draw_graf();
328 		time2 += sp;
329 	}
330 	
331 	function clearInt(intrv) { 
332 		clearInterval(intrv);
333 	}
334 	FPS.oninput = function () { 
335 		fps = parseInt(document.getElementById('FPS').value);
336 		clearInt(interv);
337 		interv = setInterval(control2,1000/fps);
338 	}
339 	
340 	function UpdateCoeffs() {
341 		cm = parseFloat(document.getElementById('CM').value);
342 		dt0 = parseFloat(document.getElementById('DT').value);
343 		Betta = parseFloat(document.getElementById('B').value);
344 		g = parseFloat(document.getElementById('G').value);
345 		hop = parseInt(document.getElementById('HOP').value);
346 		dt2 = dt0*dt0/2;
347 	}
348 	UpdateCoeffs();
349 	Update();
350 
351 }
html - файл:
 1 <!DOCTYPE html>
 2 <html>
 3 	<head>
 4 		<title> Chain_2022 </title>
 5 		<script src = 'Chain2.js'>
 6 		</script>
 7 	</head>
 8 	<body>
 9 		<div id = 'Canv'>
10 		<canvas id = 'cnv' width = 500 height = 500 style='border: 1px solid black;'></canvas>
11 		<canvas id = 'cnv_graf' width = 500 height = 250 style='border: 1px solid black;'></canvas>
12 		<canvas id = 'cnv_graf2' width = 500 height = 250 style='border: 1px solid black;'></canvas>
13 		<b>
14 		<br><label>C/M <input type = 'text' id = 'CM' value = '2000'></label>
15 		<label>DT <input type = 'text' id = 'DT' value = '0.01'></label>
16 		<label>FPS <input type = 'range' id = 'FPS' min = 10 step = 10 value = 120 max = 120></label>
17 		 <input type = "button" id = "New" value = "Обновить"/>
18 		 <input type="button" id = "Pause" value = "▶/||"/> <input type="button" id = "Add" value = "Внести правки"/>
19 		 <label> Расстояние между частицами <input type = 'text' id = 'DIST' value = '1'>
20 		<br>
21 		<br><label>B <input type = 'text' id = 'B' value = '1'></label>
22 		<label>N <input type = 'text' id = 'Num' value = '100'></label>
23 		<label>G <input type = 'text' id = 'G' value = '50'></label>
24 		<label>Рисовать каждый <input type = 'text' id = 'HOP' value = 1> шаг</label> 
25 		<input type = 'button' id = 'LET' value = 'Отпустить правый конец'>
26 		<label>Масштаб<input type = 'range' id = 'COEFF' min = 0.1 step = 0.01 value = 3 max = 20></label>
27 		<br> 
28 		</b>
29 		</div>
30 		
31 		<style type="text/css">
32 			#CM,#DT,#B,#G,#Num,#HOP {width:70px}
33 			<!-- #Canv{  -->
34 				<!-- width: 50%; -->
35 				<!-- margin: 0 auto; -->
36 				<!-- } -->
37 			#cnv_graf2 {position:absolute; left:514px;}
38 			#cnv_graf {position:absolute; left:514px; top:258px;}
39 		</style>
40 		
41 	</body>
42 </html>