Задача падающей цепочки
Курсовой проект по Введение в механику дискретных сред
Исполнитель: Борисенков Богдан
Группа: 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>