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

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

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

Цель проекта[править]

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

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

$ 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}) $

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

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