Текущая версия |
Ваш текст |
Строка 1: |
Строка 1: |
− | [[Виртуальная лаборатория]] > [[Поперечные волны в струне]] <HR> | + | [[Виртуальная лаборатория]] > [[Динамика взаимодействия частиц произвольной формы]] <HR> |
| [[Файл:1449683138190745365.gif|thumb|600px|right|Движение струны, со скоростью 1200 кадров в секунду]] | | [[Файл:1449683138190745365.gif|thumb|600px|right|Движение струны, со скоростью 1200 кадров в секунду]] |
| | | |
Строка 10: |
Строка 10: |
| Разработка программы моделирующая колебания струны | | Разработка программы моделирующая колебания струны |
| | | |
− | ===Математическая модель=== | + | |
− | <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><br /> | + | ===Решение=== |
− | <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><br /> | + | <math> m \ddot r=\sum -k \Delta r - B \dot r </math><br /> |
− | <math>l_0</math>-начальная длина одной пружины <br/>
| + | r = r(x,y)<br /> |
| m - масса одной частицы<br /> | | m - масса одной частицы<br /> |
| k - жесткость пружины<br /> | | k - жесткость пружины<br /> |
| B - вязкость | | B - вязкость |
− | | + | Обе конца пружины закреплены |
− | ===Интерфейс программы===
| |
− | Оба конца закреплены. Возможно задавать колебания, оттягивая один из элементов. По нажатию кнопки "Sin", левая граница движется по закону синуса. При повторном нажатии, левая граница останавливается. Кнопка "Reset" устанавливает систему в начальное положение. Ползунки:<br/>
| |
− | g - сила тяжести<br/>
| |
− | B - вязкость<br/>
| |
− | ν - частота колебания левой границы (работает только при "Sin")<br/>
| |
− | A - амплитуда колебания левой границы (работает только при "Sin")<br/>
| |
| | | |
| ===Результаты=== | | ===Результаты=== |
Строка 31: |
Строка 25: |
| <br /> | | <br /> |
| | | |
− | [[Медиа:OscSpring.rar|Скачать архив]] | + | [[Медиа:Discrete_mechanics.zip|Скачать архив]] |
− | <br />
| |
− | <br />
| |
− | <div class="mw-collapsible mw-collapsed" style="width:100%" >
| |
− | '''Текст программы на языке JavaScript (разработчик [[Богданов Дмитрий]]):''' <div class="mw-collapsible-content">
| |
− | Файл '''"Test.js"'''
| |
− | <syntaxhighlight lang="javascript" line start="1" enclose="div">
| |
− | 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>
| |
− | | |
− | == Ссылки ==
| |
− | *[https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D1%83%D0%B6%D0%B8%D0%BD%D0%BD%D1%8B%D0%B9_%D0%BC%D0%B0%D1%8F%D1%82%D0%BD%D0%B8%D0%BA Пружинный маятник]
| |
− | *[[Курсовые работы по ВМДС: 2015-2016]]
| |
− | *[[Введение в механику дискретных сред]]
| |
− | * [[VirtLab| Виртуальная лаборатория]]
| |