Поперечные волны в струне — различия между версиями
Материал из Department of Theoretical and Applied Mechanics
Строка 22: | Строка 22: | ||
g - сила тяжести<br/> | g - сила тяжести<br/> | ||
B - вязкость<br/> | B - вязкость<br/> | ||
− | &nu - частота колебания левой границы (работает только при "Sin")<br/> | + | ν - частота колебания левой границы (работает только при "Sin")<br/> |
A - амплитуда колебания левой границы (работает только при "Sin")<br/> | A - амплитуда колебания левой границы (работает только при "Sin")<br/> | ||
Версия 16:02, 9 января 2016
Виртуальная лаборатория > Динамика взаимодействия частиц произвольной формыСодержание
Курсовой проект по механике дискретных сред
- разработчик Богданов Дмитрий
- руководитель Кузькин Виталий
Цель проекта
Разработка программы моделирующая колебания струны
Математическая модель
-начальная длина пружины
m - масса одной частицы
k - жесткость пружины
B - вязкость
Возможности программы
Оба конца закреплены. Возможно задавать колебания, оттягивая один из элементов. По нажатию кнопки "Sin", левая граница движется по закону синуса. При повторном нажатии, левая граница останавливается. Кнопка "Reset" устанавливает систему в начальное положение. Ползунки:
g - сила тяжести
B - вязкость
ν - частота колебания левой границы (работает только при "Sin")
A - амплитуда колебания левой границы (работает только при "Sin")
Результаты
Текст программы на языке JavaScript (разработчик Богданов Дмитрий):
Файл "Test.js"
1 function Main_Spring(canvas, slider_g, text_g, slider_nu, text_nu, slider_A, text_A, sinbutton) {
2 var canvas, ctx, w, h, world, lineBody, lineBody1, mouseConstraint, s, s1; // переменные: канвас, содержимое канваса, ширина и высота канваса, создание "мира" p2, парвая и левая "стена", закрепление мыши, пружины для связи со стенами
3 var scaleX = 50, scaleY = -50; //масштаб
4 var circleBody2 = new Array(); //массив шариков
5 var circleShape2 = new Array(); //массив форм шариков
6 var ss = new Array();//массив пружин
7 var num = 100; //общее кол-во частиц
8 var k = 250; // жесткость пружин
9 var B = 4; // вязкость
10 var R = 0.05; //радиус шаров
11 var dx = 0.01; // начальная длина пружин
12 var g = 0; // сила тяжести
13 var dtt = 0; // время для колебаний по sin
14 var LA = 2; // смещение по вертикали для sin
15 var dt = 0.03; // "скорость" для sin
16 var sw = 0; // переключатель для кнопок
17
18 // Инициализируем канвал и действия маши
19 canvas = document.getElementById("myCanvas");
20 w = canvas.width;
21 h = canvas.height;
22 ctx = canvas.getContext("2d");
23 ctx.lineWidth = 0.05;
24 canvas.addEventListener("mousedown", doMouseDown, false);
25 canvas.addEventListener("mousemove", doMouseMove, false);
26 canvas.addEventListener("mouseup", doMouseUp, false);
27
28 // Ползунки и текстовые поля
29 this.setSlider_g = function(new_g){g = new_g; world.gravity[1] = -g;};
30 this.setSlider_nu = function(new_nu){dt = new_nu/10;};
31 this.setSlider_A = function(new_A){LA = new_A*4;};
32 this.setSlider_B = function(new_B){B = new_B*12; s.damping = B; s1.damping = B;
33 for (var i = 0; i < num-1; i++){ss[i].damping = B;};
34 for (var j = 0; j < num; j++){circleBody2[j].damping=B/24;};};
35
36 slider_g.min = 0; slider_g.max = 1;
37 slider_g.step = 0.10;
38 slider_g.value = g;
39 text_g.value = g.toFixed(1);
40
41 slider_A.min = 0; slider_A.max = 1;
42 slider_A.step = 0.10;
43 slider_A.value = LA/4;
44 text_A.value = (LA/4).toFixed(1);
45
46
47 slider_B.min = 0; slider_B.max = 1;
48 slider_B.step = 0.10;
49 slider_B.value = B/12;
50 text_B.value = (B/12).toFixed(1);
51
52 slider_nu.min = 0; slider_nu.max = 1;
53 slider_nu.step = 0.10;
54 slider_nu.value = dt*10; // начальное значение ползунка должно задаваться после min и max
55 text_nu.value = (dt*10).toFixed(1);
56
57 init();
58 animate();
59
60 // Функция "переключения" кнопок
61 this.sw = function(a)
62 {
63 if (a==-1) sw = a;
64 else
65 sw += a;
66 }
67
68 // Функция движения левой границы по Sin
69 function FSin()
70 {
71 sinbutton.value = "Стоп";
72 sw = 1;
73 dtt+=dt;
74 s.localAnchorB[0] = 4-LA * (Math.sin(dtt)/2);
75 return 0;
76 }
77
78 function Stop()
79 {
80 sw = 0;
81 sinbutton.value = "Sin";
82 }
83
84 // Функция сброса
85 function Reset()
86 {
87 if (sinbutton.value != "Sin") sinbutton.value = "Sin";
88 dtt = 0;
89 sw = 0;
90 world.clear();
91 init();
92
93 }
94
95 // Функция создания всех объектов
96 function init(){
97
98 // Создание мира p2
99 world = new p2.World();
100 world.gravity[1] = -g;
101 world.solver.iterations = 10;
102 world.solver.frictionIterations = 0;
103
104 // Создаем левую границу
105 lineShape = new p2.Line({ length: 6 });
106 lineBody = new p2.Body({
107 position: [-6,-4],
108 angle: Math.PI/2
109 });
110 lineBody.addShape(lineShape, [0,0], Math.PI );
111 world.addBody(lineBody);
112
113 // Создаем правую границу
114 lineShape1 = new p2.Line({ length: 6 });
115 lineBody1 = new p2.Body({
116 position: [6,-4],
117 angle: Math.PI/2
118 });
119 lineBody1.addShape(lineShape1, [0,0], Math.PI );
120 world.addBody(lineBody1);
121
122 // Создаем все шарики
123 for (var i = 0; i < num; i++)
124 {
125 circleShape2[i] = new p2.Circle({ radius: R });
126 circleBody2[i] = new p2.Body({ mass:0.5, position:[(-6 + (12*(i+1)/(num+1))) ,0] , angularDamping:0, damping:B/24});
127 circleBody2[i].addShape(circleShape2[i]);
128 world.addBody(circleBody2[i]);
129 };
130
131 //Создаем пружину для связи с левой границей
132 s = new p2.LinearSpring(circleBody2[0], lineBody, {
133 restLength : dx,
134 stiffness : k,
135 damping : B,
136 localAnchorB : [4,0],
137 });
138 world.addSpring(s);
139
140 // Создаем пружину для связи с правой границей
141 s1 = new p2.LinearSpring(circleBody2[num-1], lineBody1, {
142 restLength : dx,
143 stiffness : k,
144 damping : B,
145 localAnchorB : [4,0],
146 });
147 world.addSpring(s1);
148
149 // Создаем пружины для связи шариков вместе
150 for (var i = 0; i < num-1; i++)
151 {
152 ss[i] = new p2.LinearSpring(circleBody2[i], circleBody2[i+1], {
153 restLength : dx,
154 stiffness : k,
155 damping : B,
156 localAnchorA : [0,0],
157 localAnchorB : [0,0],
158 });
159 world.addSpring(ss[i]);
160 };
161
162 //Отключаем взаимодействие между пружинами и между шариками
163 for (var i = 0; i < num-1; i++)
164 {
165 for (var j = i; j < num-1; j++)
166 {
167 world.disableBodyCollision(ss[i], ss[j]);
168 }
169 };
170
171 for (var i = 0; i < num; i++)
172 {
173 for (var j = i; j < num; j++)
174 {
175 world.disableBodyCollision(circleBody2[i], circleBody2[j]);
176 world.disableBodyCollision(circleBody2[i], lineBody1);
177 world.disableBodyCollision(circleBody2[i], lineBody);
178 }
179 };
180
181 // Создаем объект для мыши
182 mouseBody = new p2.Body();
183 world.addBody(mouseBody);
184
185 }
186
187 // Функция нажатия мыши вниз
188 function doMouseDown(event){
189 var position = getPhysicsCoord(event);
190 circleBody2.forEach(function(item, i, circleBody2)
191 {
192 var hitBodies = world.hitTest(position, [item]);
193 if(hitBodies.length){
194 mouseBody.position[0] = position[0];
195 mouseBody.position[1] = position[1];
196 mouseConstraint = new p2.LockConstraint(mouseBody, item);
197 world.addConstraint(mouseConstraint);
198 }
199 });
200 }
201
202 // Функция перемещения мыши
203 function doMouseMove(event){
204 var position = getPhysicsCoord(event);
205 mouseBody.position[0] = position[0];
206 mouseBody.position[1] = position[1];
207 }
208
209 // Функция отпуская клавиши мыши
210 function doMouseUp(event){
211 world.removeConstraint(mouseConstraint);
212 }
213
214 // Перевод координат мыши в текущие координаты
215 function getPhysicsCoord(mouseEvent){
216 var rect = canvas.getBoundingClientRect();
217 var x = mouseEvent.clientX - rect.left;
218 var y = mouseEvent.clientY - rect.top;
219 x = (x - w / 2) / scaleX;
220 y = (y - h / 2) / scaleY;
221
222 return [x, y];
223 }
224
225 // Функция рисования всех шаров
226 function drawAllCircle(){
227 for (var i = 0; i < num; i++)
228 {
229 ctx.beginPath();
230 var x1 = circleBody2[i].position[0],
231 y1 = circleBody2[i].position[1],
232 radius1 = circleShape2[i].radius;
233 ctx.arc(x1,y1,radius1,0,2*Math.PI);
234 ctx.fill();
235 ctx.stroke();
236 }
237 ctx.strokeStyle = "black";
238 }
239
240 // Рисуем пол
241 function drawPlane(){
242 ctx.moveTo(-w, -4);
243 ctx.lineTo( w, -4);
244 ctx.strokeStyle = "black";
245 ctx.stroke();
246 }
247
248 // Рисуем правую стену
249 function drawRL(){
250 ctx.beginPath();
251 var x = lineBody.position[0],
252 y = lineBody.position[1];
253 ctx.moveTo(x, -y);
254 ctx.lineTo(x, y);
255 ctx.strokeStyle = "black";
256 ctx.stroke();
257 }
258
259
260 // Рисуем левую стену
261 function drawLL(){
262 ctx.beginPath();
263 var x = lineBody1.position[0],
264 y = lineBody1.position[1];
265 ctx.moveTo(x, -y);
266 ctx.lineTo(x, y);
267 ctx.strokeStyle = "black";
268 ctx.stroke();
269 }
270
271 // Рисуем все пружины
272 function drawAllSpring(){
273 for (var i = 0; i < num-1; i++)
274 {
275 ctx.beginPath();
276 var x = circleBody2[i].position[0],
277 y = circleBody2[i].position[1];
278 var x1 = circleBody2[i+1].position[0],
279 y1 = circleBody2[i+1].position[1];
280 ctx.moveTo(x, y);
281 ctx.lineTo(x1, y1);
282 ctx.strokeStyle = "black";
283 ctx.stroke();
284 }
285 }
286
287 // Рисуем пружину для связи первого шарика со стеной
288 function draw1S(){
289 ctx.beginPath();
290 var x = circleBody2[0].position[0],
291 y = circleBody2[0].position[1];
292 ctx.moveTo(-6, (s.localAnchorB[0]-4));
293 ctx.lineTo(x, y);
294 ctx.strokeStyle = "black";
295 ctx.stroke();
296 }
297
298 // Рисуем пружину для связи последнего шарика со стеной
299 function draw2S(){
300 ctx.beginPath();
301 var x = circleBody2[num-1].position[0],
302 y = circleBody2[num-1].position[1];
303 ctx.moveTo(6, 0);
304 ctx.lineTo(x, y);
305 ctx.strokeStyle = "black";
306 ctx.stroke();
307 }
308
309 function render(){
310 ctx.clearRect(0,0,w,h);
311 ctx.save();
312 ctx.translate(w/2, h/2); // Переводим начало в центр
313 ctx.scale(50, -50); //Зумируем канвас
314 // Рисуем все тела на канвасе
315 drawAllCircle();
316 drawRL();
317 drawLL();
318 drawPlane();
319 drawAllSpring();
320 draw1S();
321 draw2S();
322 ctx.restore();
323 }
324
325 function animate(){
326 requestAnimationFrame(animate);
327 if (sw == 1) FSin();
328 if (sw == 2) Stop();
329 if (sw == -1) Reset();
330 world.step(1/60);
331 render();
332 }
333
334 }