Задача падающей цепочки — различия между версиями
(Новая страница: «'''Курсовой проект по Введение в механику дискретных сред''''' '''Исполнитель:''' Борисен…») |
|||
(не показана 1 промежуточная версия этого же участника) | |||
Строка 7: | Строка 7: | ||
'''Семестр:''' осень 2022 | '''Семестр:''' осень 2022 | ||
− | + | ==Постановка задачи== | |
В рамках проекта необходимо смоделировать движение одномерной цепочки: начальное положение (провисание) цепочки и дальнейшее ее падение при отпускании одного из концов под действием силы тяжести, а также исследовать зависимость ускорения крайней свободной частицы от времени. | В рамках проекта необходимо смоделировать движение одномерной цепочки: начальное положение (провисание) цепочки и дальнейшее ее падение при отпускании одного из концов под действием силы тяжести, а также исследовать зависимость ускорения крайней свободной частицы от времени. | ||
− | + | ==Математическая модель== | |
Изначально запишем закон движения: | Изначально запишем закон движения: | ||
<math> | <math> | ||
Строка 40: | Строка 40: | ||
X_{i+1} = X_i+V_{i+1}\Delta{t}, | X_{i+1} = X_i+V_{i+1}\Delta{t}, | ||
\end{cases} </math> | \end{cases} </math> | ||
− | + | ==Численное моделирование== | |
{{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/Falling_Chain/Chain2.html| width= 1200 | height = 600}} | {{#widget:Iframe |url = http://tm.spbstu.ru/htmlets/js2020/Borisenkov/Falling_Chain/Chain2.html| width= 1200 | height = 600}} | ||
− | + | ==Выводы== | |
− | В рамках решения задачи смоделировано движение цепочки под действием силы тяжести и | + | В рамках решения задачи смоделировано движение цепочки под действием силы тяжести и проиллюстрирован тот факт, что ускорение крайней массы цепочки больше, чем ускорение свободно падающего тела. Данный эффект объясняется начальным преднатяжением цепочки. |
+ | ==Ссылки== | ||
+ | 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
Содержание
Постановка задачи[править]
В рамках проекта необходимо смоделировать движение одномерной цепочки: начальное положение (провисание) цепочки и дальнейшее ее падение при отпускании одного из концов под действием силы тяжести, а также исследовать зависимость ускорения крайней свободной частицы от времени.
Математическая модель[править]
Изначально запишем закон движения:
где
- силы упругости действующие на -ую частицу со стороны и соответственно, а - сила тяжести.Далее распишем силу упругости как произведение модуля на соответствующий орт:
, где - коэффициент жесткости пружины. Аналогично записывается сила .Далее подставляя все силы в уравнение движения, получим:
Дальнейшее интегрирование уравнения производится с помощью явного симплектического метода Верле c нулевыми начальными условиями и условиями закрепления на концах.
Численное моделирование[править]
Выводы[править]
В рамках решения задачи смоделировано движение цепочки под действием силы тяжести и проиллюстрирован тот факт, что ускорение крайней массы цепочки больше, чем ускорение свободно падающего тела. Данный эффект объясняется начальным преднатяжением цепочки.
Ссылки[править]
http://tm.spbstu.ru/Курсовые_работы_по_ВМДС:_2022-2023 - курсовые работы студентов 4-го курса 2022-2023 года по курсу дискретной механики http://tm.spbstu.ru/Введение_в_механику_дискретных_сред - курс механики дискретных сред
Код программы[править]
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 }
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>