Поперечные волны в струне — различия между версиями

Материал из Department of Theoretical and Applied Mechanics
Перейти к: навигация, поиск
Строка 26: Строка 26:
  
 
[[Медиа:OscSpring.rar|Скачать архив]]
 
[[Медиа:OscSpring.rar|Скачать архив]]
 +
<br />
 +
<br />
 +
<div class="mw-collapsible mw-collapsed" style="width:100%" >
 +
'''Текст программы на языке JavaScript (разработчик [[Александров Сергей]]):''' <div class="mw-collapsible-content">
 +
Файл '''"Test.js"'''
 +
function Main_Spring(canvas, slider_g, text_g, slider_nu, text_nu, slider_A, text_A, sinbutton) {
 +
var canvas, ctx, w, h, world, lineBody, lineBody1, mouseConstraint, s, s1; // переменные: канвас, содержимое канваса, ширина и высота канваса, создание "мира" p2, парвая и левая "стена", закрепление мыши, пружины для связи со стенами
 +
var scaleX = 50, scaleY = -50; //масштаб
 +
var circleBody2 = new Array(); //массив шариков
 +
var circleShape2 = new Array(); //массив форм шариков
 +
var ss = new Array();//массив пружин
 +
var num = 100; //общее кол-во частиц
 +
var k = 250; // жесткость пружин
 +
var B = 4; // вязкость
 +
var R = 0.05; //радиус шаров
 +
var dx = 0.01; // начальная длина пружин
 +
var g = 0; // сила тяжести
 +
var dtt = 0; // время для колебаний по sin
 +
var LA = 2; // смещение по вертикали для sin
 +
var dt = 0.03; // "скорость" для sin
 +
var sw = 0; // переключатель для кнопок
 +
 +
// Инициализируем канвал и действия маши
 +
canvas = document.getElementById("myCanvas");
 +
    w = canvas.width;
 +
    h = canvas.height;
 +
    ctx = canvas.getContext("2d");
 +
    ctx.lineWidth = 0.05;
 +
canvas.addEventListener("mousedown", doMouseDown, false);
 +
canvas.addEventListener("mousemove", doMouseMove, false);
 +
canvas.addEventListener("mouseup", doMouseUp, false);
 +
 +
// Ползунки и текстовые поля
 +
this.setSlider_g = function(new_g){g = new_g; world.gravity[1] = -g;};
 +
this.setSlider_nu = function(new_nu){dt = new_nu/10;};
 +
this.setSlider_A = function(new_A){LA = new_A*4;};
 +
this.setSlider_B = function(new_B){B = new_B*12; s.damping = B; s1.damping = B;
 +
for (var i = 0; i < num-1; i++){ss[i].damping = B;};
 +
for (var j = 0; j < num; j++){circleBody2[j].damping=B/24;};};
 +
 +
slider_g.min = 0;              slider_g.max = 1;
 +
    slider_g.step = 0.10;
 +
    slider_g.value = g;
 +
    text_g.value = g.toFixed(1);
 +
 +
slider_A.min = 0;              slider_A.max = 1;
 +
    slider_A.step = 0.10;
 +
    slider_A.value = LA/4;
 +
    text_A.value = (LA/4).toFixed(1);
 +
 +
 +
slider_B.min = 0;              slider_B.max = 1;
 +
    slider_B.step = 0.10;
 +
    slider_B.value = B/12;
 +
    text_B.value = (B/12).toFixed(1);
 +
 +
slider_nu.min = 0;              slider_nu.max = 1;
 +
    slider_nu.step = 0.10;
 +
    slider_nu.value = dt*10;          // начальное значение ползунка должно задаваться после min и max
 +
    text_nu.value = (dt*10).toFixed(1);
 +
 +
      init();
 +
      animate();
 +
 
 +
// Функция "переключения" кнопок
 +
this.sw = function(a)
 +
{
 +
if (a==-1) sw = a;
 +
else
 +
sw += a;
 +
}
 +
 +
// Функция движения левой границы по Sin
 +
function FSin()
 +
{
 +
sinbutton.value = "Стоп";
 +
sw = 1;
 +
dtt+=dt;
 +
s.localAnchorB[0] = 4-LA * (Math.sin(dtt)/2);
 +
return 0;
 +
}
 +
 +
function Stop()
 +
{
 +
sw = 0;
 +
sinbutton.value = "Sin";
 +
}
 +
 +
// Функция сброса
 +
function Reset()
 +
{
 +
if (sinbutton.value != "Sin") sinbutton.value = "Sin";
 +
dtt = 0;
 +
sw = 0;
 +
world.clear();
 +
init();
 +
 +
}
 +
 +
// Функция создания всех объектов
 +
      function init(){
 +
       
 +
// Создание мира p2
 +
        world = new p2.World();
 +
world.gravity[1] = -g;
 +
world.solver.iterations = 10;
 +
world.solver.frictionIterations = 0;
 +
 +
// Создаем левую границу
 +
lineShape = new p2.Line({ length: 6 });
 +
        lineBody = new p2.Body({
 +
          position: [-6,-4],
 +
          angle: Math.PI/2
 +
        });
 +
        lineBody.addShape(lineShape, [0,0], Math.PI );
 +
        world.addBody(lineBody);
 +
 +
// Создаем правую границу
 +
lineShape1 = new p2.Line({ length: 6 });
 +
        lineBody1 = new p2.Body({
 +
          position: [6,-4],
 +
          angle: Math.PI/2
 +
        });
 +
        lineBody1.addShape(lineShape1, [0,0], Math.PI );
 +
        world.addBody(lineBody1);
 +
 +
// Создаем все шарики
 +
for (var i = 0; i < num; i++)
 +
{
 +
circleShape2[i] = new p2.Circle({ radius: R });
 +
circleBody2[i] = new p2.Body({ mass:0.5, position:[(-6 + (12*(i+1)/(num+1))) ,0] , angularDamping:0, damping:B/24});
 +
circleBody2[i].addShape(circleShape2[i]);
 +
world.addBody(circleBody2[i]);
 +
};
 +
 +
//Создаем пружину для связи с левой границей
 +
s = new p2.LinearSpring(circleBody2[0], lineBody, {
 +
                restLength : dx,
 +
                stiffness : k,
 +
damping : B,
 +
                localAnchorB : [4,0],
 +
            });
 +
        world.addSpring(s);
 +
 +
// Создаем пружину для связи с правой границей
 +
s1 = new p2.LinearSpring(circleBody2[num-1], lineBody1, {
 +
                restLength : dx,
 +
                stiffness : k,
 +
damping : B,
 +
                localAnchorB : [4,0],
 +
            });
 +
        world.addSpring(s1);
 +
 +
// Создаем пружины для связи шариков вместе
 +
for (var i = 0; i < num-1; i++)
 +
{
 +
ss[i] = new p2.LinearSpring(circleBody2[i], circleBody2[i+1], {
 +
                restLength : dx,
 +
                stiffness : k,
 +
damping : B,
 +
                localAnchorA : [0,0],
 +
                localAnchorB : [0,0],
 +
            });
 +
world.addSpring(ss[i]);
 +
};
 +
 +
//Отключаем взаимодействие между пружинами и между шариками
 +
for (var i = 0; i < num-1; i++)
 +
{
 +
for (var j = i; j < num-1; j++)
 +
{
 +
world.disableBodyCollision(ss[i], ss[j]);
 +
}
 +
};
 +
 +
for (var i = 0; i < num; i++)
 +
{
 +
for (var j = i; j < num; j++)
 +
{
 +
world.disableBodyCollision(circleBody2[i], circleBody2[j]);
 +
world.disableBodyCollision(circleBody2[i], lineBody1);
 +
world.disableBodyCollision(circleBody2[i], lineBody);
 +
}
 +
};
 +
 +
// Создаем объект для мыши
 +
        mouseBody = new p2.Body();
 +
        world.addBody(mouseBody);
 +
 +
      }
 +
 
 +
  // Функция нажатия мыши вниз
 +
  function doMouseDown(event){
 +
          var position = getPhysicsCoord(event);
 +
          circleBody2.forEach(function(item, i, circleBody2)
 +
  {
 +
  var hitBodies = world.hitTest(position, [item]);
 +
          if(hitBodies.length){
 +
            mouseBody.position[0] = position[0];
 +
            mouseBody.position[1] = position[1];
 +
          mouseConstraint = new p2.LockConstraint(mouseBody, item);
 +
            world.addConstraint(mouseConstraint);
 +
  }
 +
          });
 +
        }
 +
 +
// Функция перемещения мыши
 +
  function doMouseMove(event){
 +
          var position = getPhysicsCoord(event);
 +
          mouseBody.position[0] = position[0];
 +
          mouseBody.position[1] = position[1];
 +
        }
 +
 +
// Функция отпуская клавиши мыши
 +
        function doMouseUp(event){
 +
          world.removeConstraint(mouseConstraint);
 +
        } 
 +
 +
// Перевод координат мыши в текущие координаты
 +
    function getPhysicsCoord(mouseEvent){
 +
          var rect = canvas.getBoundingClientRect();
 +
          var x = mouseEvent.clientX - rect.left;
 +
          var y = mouseEvent.clientY - rect.top;
 +
          x = (x - w / 2) / scaleX;
 +
          y = (y - h / 2) / scaleY;
 +
 +
          return [x, y];
 +
}
 +
 
 +
  // Функция рисования всех шаров
 +
  function drawAllCircle(){
 +
for (var i = 0; i < num; i++)
 +
{
 +
ctx.beginPath();
 +
        var x1 = circleBody2[i].position[0],
 +
            y1 = circleBody2[i].position[1],
 +
            radius1 = circleShape2[i].radius;
 +
        ctx.arc(x1,y1,radius1,0,2*Math.PI);
 +
ctx.fill();
 +
ctx.stroke();
 +
}
 +
ctx.strokeStyle = "black";
 +
      }
 +
 +
// Рисуем пол
 +
      function drawPlane(){
 +
        ctx.moveTo(-w, -4);
 +
        ctx.lineTo( w, -4);
 +
ctx.strokeStyle = "black";
 +
        ctx.stroke();
 +
      }
 +
 
 +
  // Рисуем правую стену
 +
  function drawRL(){
 +
        ctx.beginPath();
 +
        var x = lineBody.position[0],
 +
            y = lineBody.position[1];
 +
        ctx.moveTo(x, -y);
 +
        ctx.lineTo(x, y);
 +
        ctx.strokeStyle = "black";
 +
ctx.stroke();
 +
      }
 +
 
 +
 
 +
  // Рисуем левую стену
 +
  function drawLL(){
 +
        ctx.beginPath();
 +
        var x = lineBody1.position[0],
 +
            y = lineBody1.position[1];
 +
        ctx.moveTo(x, -y);
 +
        ctx.lineTo(x, y);
 +
ctx.strokeStyle = "black";
 +
        ctx.stroke();
 +
      }
 +
 
 +
  // Рисуем все пружины
 +
  function drawAllSpring(){
 +
for (var i = 0; i < num-1; i++)
 +
{
 +
ctx.beginPath();
 +
        var x = circleBody2[i].position[0],
 +
            y = circleBody2[i].position[1];
 +
var x1 = circleBody2[i+1].position[0],
 +
            y1 = circleBody2[i+1].position[1];
 +
            ctx.moveTo(x, y);
 +
ctx.lineTo(x1, y1);
 +
ctx.strokeStyle = "black";
 +
        ctx.stroke();
 +
}
 +
      }
 +
 
 +
  // Рисуем пружину для связи первого шарика со стеной
 +
  function draw1S(){
 +
ctx.beginPath();
 +
        var x = circleBody2[0].position[0],
 +
            y = circleBody2[0].position[1];
 +
ctx.moveTo(-6, (s.localAnchorB[0]-4));
 +
        ctx.lineTo(x, y);
 +
        ctx.strokeStyle = "black";
 +
ctx.stroke();
 +
      }
 +
 
 +
  // Рисуем пружину для связи последнего шарика со стеной
 +
  function draw2S(){
 +
        ctx.beginPath();
 +
        var x = circleBody2[num-1].position[0],
 +
            y = circleBody2[num-1].position[1];
 +
        ctx.moveTo(6, 0);
 +
        ctx.lineTo(x, y);
 +
        ctx.strokeStyle = "black";
 +
ctx.stroke();
 +
      }
 +
 
 +
      function render(){
 +
        ctx.clearRect(0,0,w,h);
 +
        ctx.save();
 +
        ctx.translate(w/2, h/2);  // Переводим начало в центр
 +
        ctx.scale(50, -50);      //Зумируем канвас
 +
        // Рисуем все тела на канвасе
 +
drawAllCircle();
 +
        drawRL();
 +
drawLL();
 +
drawPlane();
 +
drawAllSpring();
 +
draw1S();
 +
draw2S();
 +
        ctx.restore();
 +
      }
 +
 +
      function animate(){
 +
        requestAnimationFrame(animate);
 +
if (sw == 1) FSin();
 +
if (sw == 2) Stop();
 +
if (sw == -1) Reset();
 +
        world.step(1/60);
 +
        render();
 +
      }
 +
 
 +
}
 +
 +
</syntaxhighlight>
 +
</div>
 +
</div>

Версия 13:29, 22 декабря 2015

Виртуальная лаборатория > Динамика взаимодействия частиц произвольной формы
Движение струны, со скоростью 1200 кадров в секунду

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

Цель проекта

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


Решение

[math] m \ddot r=\sum -k \Delta r - B \dot r [/math]

r = r(x,y)
m - масса одной частицы
k - жесткость пружины
B - вязкость

Обе конца пружины закреплены

Результаты




Скачать архив

Текст программы на языке JavaScript (разработчик Александров Сергей):

Файл "Test.js" function Main_Spring(canvas, slider_g, text_g, slider_nu, text_nu, slider_A, text_A, sinbutton) { var canvas, ctx, w, h, world, lineBody, lineBody1, mouseConstraint, s, s1; // переменные: канвас, содержимое канваса, ширина и высота канваса, создание "мира" p2, парвая и левая "стена", закрепление мыши, пружины для связи со стенами var scaleX = 50, scaleY = -50; //масштаб var circleBody2 = new Array(); //массив шариков var circleShape2 = new Array(); //массив форм шариков var ss = new Array();//массив пружин var num = 100; //общее кол-во частиц var k = 250; // жесткость пружин var B = 4; // вязкость var R = 0.05; //радиус шаров var dx = 0.01; // начальная длина пружин var g = 0; // сила тяжести var dtt = 0; // время для колебаний по sin var LA = 2; // смещение по вертикали для sin var dt = 0.03; // "скорость" для sin var sw = 0; // переключатель для кнопок

// Инициализируем канвал и действия маши canvas = document.getElementById("myCanvas");

   w = canvas.width;
   h = canvas.height;
   ctx = canvas.getContext("2d");
   ctx.lineWidth = 0.05;

canvas.addEventListener("mousedown", doMouseDown, false); canvas.addEventListener("mousemove", doMouseMove, false); canvas.addEventListener("mouseup", doMouseUp, false);

// Ползунки и текстовые поля this.setSlider_g = function(new_g){g = new_g; world.gravity[1] = -g;}; this.setSlider_nu = function(new_nu){dt = new_nu/10;}; this.setSlider_A = function(new_A){LA = new_A*4;}; this.setSlider_B = function(new_B){B = new_B*12; s.damping = B; s1.damping = B; for (var i = 0; i < num-1; i++){ss[i].damping = B;}; for (var j = 0; j < num; j++){circleBody2[j].damping=B/24;};};

slider_g.min = 0; slider_g.max = 1;

   slider_g.step = 0.10;
   slider_g.value = g;
   text_g.value = g.toFixed(1);

slider_A.min = 0; slider_A.max = 1;

   slider_A.step = 0.10;
   slider_A.value = LA/4;
   text_A.value = (LA/4).toFixed(1);


slider_B.min = 0; slider_B.max = 1;

   slider_B.step = 0.10;
   slider_B.value = B/12;
   text_B.value = (B/12).toFixed(1);

slider_nu.min = 0; slider_nu.max = 1;

   slider_nu.step = 0.10;
   slider_nu.value = dt*10;          // начальное значение ползунка должно задаваться после min и max
   text_nu.value = (dt*10).toFixed(1);
     init();
     animate();

// Функция "переключения" кнопок this.sw = function(a)

	{

if (a==-1) sw = a; else sw += a; }

// Функция движения левой границы по Sin function FSin() { sinbutton.value = "Стоп"; sw = 1; dtt+=dt; s.localAnchorB[0] = 4-LA * (Math.sin(dtt)/2); return 0; }

function Stop() { sw = 0; sinbutton.value = "Sin"; }

// Функция сброса function Reset() { if (sinbutton.value != "Sin") sinbutton.value = "Sin"; dtt = 0; sw = 0; world.clear(); init();

}

// Функция создания всех объектов

     function init(){
       

// Создание мира p2

       world = new p2.World();

world.gravity[1] = -g; world.solver.iterations = 10; world.solver.frictionIterations = 0;

// Создаем левую границу lineShape = new p2.Line({ length: 6 });

       lineBody = new p2.Body({
         position: [-6,-4],
         angle: Math.PI/2 
       });
       lineBody.addShape(lineShape, [0,0], Math.PI );
       world.addBody(lineBody);

// Создаем правую границу lineShape1 = new p2.Line({ length: 6 });

       lineBody1 = new p2.Body({
         position: [6,-4],
         angle: Math.PI/2 
       });
       lineBody1.addShape(lineShape1, [0,0], Math.PI );
       world.addBody(lineBody1);

// Создаем все шарики for (var i = 0; i < num; i++) { circleShape2[i] = new p2.Circle({ radius: R }); circleBody2[i] = new p2.Body({ mass:0.5, position:[(-6 + (12*(i+1)/(num+1))) ,0] , angularDamping:0, damping:B/24}); circleBody2[i].addShape(circleShape2[i]); world.addBody(circleBody2[i]); };

//Создаем пружину для связи с левой границей s = new p2.LinearSpring(circleBody2[0], lineBody, {

               restLength : dx,
               stiffness : k,

damping : B,

               localAnchorB : [4,0],
           });
       world.addSpring(s);

// Создаем пружину для связи с правой границей s1 = new p2.LinearSpring(circleBody2[num-1], lineBody1, {

               restLength : dx,
               stiffness : k,

damping : B,

               localAnchorB : [4,0],
           });
       world.addSpring(s1);

// Создаем пружины для связи шариков вместе for (var i = 0; i < num-1; i++) { ss[i] = new p2.LinearSpring(circleBody2[i], circleBody2[i+1], {

               restLength : dx,
               stiffness : k,

damping : B,

               localAnchorA : [0,0],
               localAnchorB : [0,0],
           });

world.addSpring(ss[i]); };

//Отключаем взаимодействие между пружинами и между шариками for (var i = 0; i < num-1; i++) { for (var j = i; j < num-1; j++) { world.disableBodyCollision(ss[i], ss[j]); } };

for (var i = 0; i < num; i++) { for (var j = i; j < num; j++) { world.disableBodyCollision(circleBody2[i], circleBody2[j]); world.disableBodyCollision(circleBody2[i], lineBody1); world.disableBodyCollision(circleBody2[i], lineBody); } };

// Создаем объект для мыши

       mouseBody = new p2.Body();
       world.addBody(mouseBody);
     }

// Функция нажатия мыши вниз function doMouseDown(event){

         var position = getPhysicsCoord(event);
         circleBody2.forEach(function(item, i, circleBody2)

{ var hitBodies = world.hitTest(position, [item]);

         if(hitBodies.length){
           mouseBody.position[0] = position[0];
           mouseBody.position[1] = position[1];
          mouseConstraint = new p2.LockConstraint(mouseBody, item);
           world.addConstraint(mouseConstraint);

}

         });
       }

// Функция перемещения мыши function doMouseMove(event){

         var position = getPhysicsCoord(event);
         mouseBody.position[0] = position[0];
         mouseBody.position[1] = position[1];
       }

// Функция отпуская клавиши мыши

       function doMouseUp(event){
         world.removeConstraint(mouseConstraint);
       }  

// Перевод координат мыши в текущие координаты function getPhysicsCoord(mouseEvent){

         var rect = canvas.getBoundingClientRect();
         var x = mouseEvent.clientX - rect.left;
         var y = mouseEvent.clientY - rect.top;
         x = (x - w / 2) / scaleX;
         y = (y - h / 2) / scaleY;
         return [x, y];

}

// Функция рисования всех шаров function drawAllCircle(){ for (var i = 0; i < num; i++) { ctx.beginPath();

       var x1 = circleBody2[i].position[0],
           y1 = circleBody2[i].position[1],
           radius1 = circleShape2[i].radius;
       ctx.arc(x1,y1,radius1,0,2*Math.PI);

ctx.fill(); ctx.stroke(); } ctx.strokeStyle = "black";

     }

// Рисуем пол

     function drawPlane(){
       ctx.moveTo(-w, -4);
       ctx.lineTo( w, -4);

ctx.strokeStyle = "black";

       ctx.stroke();
     }

// Рисуем правую стену function drawRL(){

       ctx.beginPath();
       var x = lineBody.position[0],
           y = lineBody.position[1];
       ctx.moveTo(x, -y);
       ctx.lineTo(x, y);
       ctx.strokeStyle = "black";

ctx.stroke();

     }


// Рисуем левую стену function drawLL(){

       ctx.beginPath();
       var x = lineBody1.position[0],
           y = lineBody1.position[1];
       ctx.moveTo(x, -y);
       ctx.lineTo(x, y);

ctx.strokeStyle = "black";

       ctx.stroke();
     }

// Рисуем все пружины function drawAllSpring(){ for (var i = 0; i < num-1; i++) { ctx.beginPath();

       var x = circleBody2[i].position[0],
           y = circleBody2[i].position[1];

var x1 = circleBody2[i+1].position[0],

           y1 = circleBody2[i+1].position[1];
           ctx.moveTo(x, y);

ctx.lineTo(x1, y1); ctx.strokeStyle = "black";

       ctx.stroke();

}

     }

// Рисуем пружину для связи первого шарика со стеной function draw1S(){ ctx.beginPath();

       var x = circleBody2[0].position[0],
           y = circleBody2[0].position[1];

ctx.moveTo(-6, (s.localAnchorB[0]-4));

       ctx.lineTo(x, y);
       ctx.strokeStyle = "black";

ctx.stroke();

     }

// Рисуем пружину для связи последнего шарика со стеной function draw2S(){

       ctx.beginPath();
       var x = circleBody2[num-1].position[0],
           y = circleBody2[num-1].position[1];
       ctx.moveTo(6, 0);
       ctx.lineTo(x, y);
       ctx.strokeStyle = "black";

ctx.stroke();

     }
     function render(){
       ctx.clearRect(0,0,w,h);
       ctx.save();
       ctx.translate(w/2, h/2);  // Переводим начало в центр
       ctx.scale(50, -50);       //Зумируем канвас
       // Рисуем все тела на канвасе

drawAllCircle();

       drawRL();

drawLL(); drawPlane(); drawAllSpring(); draw1S(); draw2S();

       ctx.restore();
     }
     function animate(){
       requestAnimationFrame(animate);

if (sw == 1) FSin(); if (sw == 2) Stop(); if (sw == -1) Reset();

       world.step(1/60);
       render();
     }

}

</syntaxhighlight>