Поперечные волны в струне

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
Виртуальная лаборатория > Поперечные волны в струне
Движение струны, со скоростью 1200 кадров в секунду

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

Цель проекта

Разработка программы моделирующая колебания струны

Математическая модель

[math] m\begin{pmatrix} {\ddot x_i} \\ {\ddot y_i} \end{pmatrix}= -k (|\vec{r}_{i,i-1}|-l_0)\frac{\vec{r}_{i,i-1}}{|\vec{r}_{i,i-1}|} - B (\begin{pmatrix} {\dot x_i} \\ {\dot y_i} \end{pmatrix}-\begin{pmatrix} {\dot x_{i-1}} \\ {\dot y_{i-1}} \end{pmatrix}) [/math]

[math]\vec{r}_{i,i-1} = \begin{pmatrix} {x_i} \\ {y_i} \end{pmatrix}-\begin{pmatrix} {x_{i-1}} \\ {y_{i-1}} \end{pmatrix} [/math]
[math]l_0[/math]-начальная длина одной пружины
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 }

Ссылки