Текущая версия |
Ваш текст |
Строка 1: |
Строка 1: |
| [[Виртуальная лаборатория]]>[[Иллюзия зависания пружины]] <HR> | | [[Виртуальная лаборатория]]>[[Иллюзия зависания пружины]] <HR> |
− |
| |
− | == '''Описание физического эксперимента''' ==
| |
− | [[Файл: DropSpringShort.gif|600px|right|Падение пружины]]
| |
− | Длинная пружина растянута и находиться в статическом положении. После чего отпускаем верхний конец пружины и видим, что нижний конец пружины находится в неподвижном состоянии в течение продолжительного времени.
| |
− | <br/>
| |
− | Ниже будет представлена математическая модель и программа, демонстрирующая данный эффект, называемый "иллюзией зависания".
| |
| | | |
− | == '''Математическая модель''' ==
| + | '''Постановка задачи'''<br /> Задана система пружин с жесткостью <math>{С}</math> и грузиков с массой <math>{m}</math>, подвешенных на креплении. На систему действует сила тяжести <math>{mg}</math>. Рассчитываются статические координаты такой системы. После чего убираем верхнюю пружину. |
− | Задана система пружин с жесткостью <math>{С}</math> и грузиков с массой <math>{m}</math>, подвешенных на креплении. На систему действует сила тяжести <math>{mg}</math>. Рассчитываются статические координаты такой системы. После чего убирается верхняя пружина, что приводит систему в движение. | |
| | | |
− | Цель - описать "зависание" нижнего грузика во время падения пружины. | + | '''Цель'''<br /> |
− | | + | Наблюдать "зависание" нижнего при грузика во время падения пружины. |
− | =='''Основные уравнения'''==
| |
− | <div style="font-size: 16px;">1)''Расчет статических координат:''</div>
| |
| | | |
| + | '''Основные уравнения'''<br/> |
| + | 1)''Расчет статических координат:'' |
| + | <br/> |
| + | <br/> |
| <math>{y}_{i}=i{l}_{0}+\sum^{i}_{k=1} {\Delta l_k}</math> | | <math>{y}_{i}=i{l}_{0}+\sum^{i}_{k=1} {\Delta l_k}</math> |
| <br/> | | <br/> |
Строка 21: |
Строка 16: |
| <br/> | | <br/> |
| <br/> | | <br/> |
− | где <math>{n}</math> — количество грузиков ; <math>{i}</math> — текущий грузик ; <math>{l_0}</math> — длина не растянутой пружины; <math>\Delta{l_k}</math> — статическое удлинение пружины. | + | где <math>{n}</math> - количество грузиков ; <math>{i}</math> - текущий грузик ; <math>{l_0}</math> - длина не растянутой пружины. |
| | | |
− | <div style="font-size: 16px;">2) ''Уравнение движения грузиков при отсутствии верхней пружины:''</div>
| + | 2)''Уравнение движения грузиков при падении пружины:'' |
− | <math>\ddot y_i = - \frac{C}{m} ({y}_{i+1} - 2{y}_{i}+{y}_{i-1}) + g </math>
| |
| <br/> | | <br/> |
| <br/> | | <br/> |
− | при <math>i = n </math> :
| + | <math>\ddot y_i = - \frac{C}{m} (\Delta l_i - \Delta {l}_{i+1}) + g </math> |
| <br/> | | <br/> |
− | <math> \ddot y_n = - \frac{C}{m}(y_n - {y}_{n-1} - l_0) + g</math>
| |
| <br/> | | <br/> |
− | <br/>'''Программа (лучше всего смотреть ее в Mozilla Firefox)''' | + | при <math>i = n </math> : |
| <br/> | | <br/> |
− | {{#widget:Iframe |url=http://tm.spbstu.ru/htmlets/Alexandrov_S_D/Spring_illusion.html |width=800|height=800 |border=0 }}
| + | <math> \ddot y_n = - \frac{C}{m} \Delta l_n + g</math> |
− | <br />
| |
− | <br /> | |
− | Скачать программу [[Медиа:Spring_illusion.rar|Spring_illusion.rar]].
| |
− | <br />
| |
− | <br />
| |
− | <div class="mw-collapsible mw-collapsed" style="width:100%" >
| |
− | '''Текст программы на языке JavaScript (разработчик [[Александров Сергей]]):''' <div class="mw-collapsible-content">
| |
− | Файл '''"Spring_illusin.js"'''
| |
− | <syntaxhighlight lang="javascript" line start="1" enclose="div">
| |
− | window.addEventListener("load", Main_Spring, true);
| |
− | function Main_Spring() {
| |
− | | |
− | // *** Некие исходные данные ***
| |
− | | |
− | var canvas = spring_canvas;
| |
− | canvas.onselectstart = function () {return false;}; // запрет выделения canvas
| |
− | var ctx = canvas.getContext("2d"); // на ctx происходит рисование
| |
− | var w = canvas.width; // ширина окна в расчетных координатах
| |
− | var h = canvas.height; // высота окна в расчетных координатах
| |
− | | |
− | var Pi = 3.1415926; // число "пи"
| |
− | var g = 9.8; // гравитационная постоянная
| |
− | | |
− | var T0 = 0.01; // масштаб времени (период колебаний исходной системы)
| |
− | | |
− | var m0 = 0.15; // масштаб массы маятника
| |
− | var C0 = 1; // масштаб жесткости пружины
| |
− | | |
− | var count = true; // проводить ли расчет системы
| |
− | var v = 0; // скорость тела
| |
− | var t = 0;
| |
− | | |
− | // параметры полученные из размеров холста
| |
− | var rw = canvas.width / 4;
| |
− | var rh = canvas.height / 100;
| |
− | | |
− | // параметры грузиков
| |
− | var x0 = 0;
| |
− | var y0 = 0;
| |
− | var vy0 = 0;
| |
− | var rad0 = 7;
| |
− | var sTime = 0;
| |
− | // параметры пружины
| |
− | var Lp = 30; //длина пружины
| |
− | | |
− | | |
− | // *** Задание вычислительных параметров ***
| |
− | | |
− | var fps = 60; // frames per second - число кадров в секунду (качечтво отображения)
| |
− | var spf = 5; // steps per frame - число шагов интегрирования между кадрами
| |
− | var dt = 50 * T0 / fps; // шаг интегрирования (качество расчета)
| |
− | var steps = 0; // количество шагов интегрирования
| |
− | | |
− | | |
− | // *** Задание физических параметров ***
| |
− | var m = 1 * m0; // масса грузика
| |
− | var C = 1 * C0; // жесткость пружины
| |
− | var L0 = 0; // изначальное удлинение пружины
| |
− | var n = 5; // количество тел
| |
− | var circle; // круглые тела
| |
− | | |
− | // *** Установка слайдеров для переменных величин ***
| |
− | slider_m.value = (m / m0).toFixed(1);
| |
− | number_m.value = (m / m0).toFixed(1);
| |
− | slider_spf.value = (spf).toFixed(1);
| |
− | number_spf.value = (spf).toFixed(1);
| |
− | slider_n.value = parseInt(n);
| |
− | number_n.value = parseInt(n);
| |
− | | |
− | function setM(new_m) {
| |
− | m = new_m * m0;
| |
− | }
| |
− | | |
− | function setSpf(new_spf) {
| |
− | spf = new_spf;
| |
− | }
| |
− | function setN(new_n) {
| |
− | n = new_n;
| |
− | StaticStart();
| |
− | }
| |
− | | |
− | slider_m.oninput = function () {
| |
− | number_m.value = slider_m.value;
| |
− | setM(slider_m.value);
| |
− | };
| |
− | number_m.oninput = function () {
| |
− | slider_m.value = number_m.value;
| |
− | setM(number_m.value);
| |
− | };
| |
− | | |
| | | |
− | slider_spf.oninput = function () {
| + | '''Программа'''<br/> |
− | number_spf.value = slider_spf.value;
| |
− | setSpf(slider_spf.value);
| |
− | };
| |
− | number_spf.oninput = function () {
| |
− | slider_spf.value = number_spf.value;
| |
− | setSpf(number_spf.value);
| |
− | };
| |
− | | |
− | slider_n.oninput = function () {
| |
− | number_n.value = slider_n.value;
| |
− | setN(slider_n.value);
| |
− | };
| |
− | number_n.oninput = function () {
| |
− | slider_n.value = number_n.value;
| |
− | setN(number_n.value);
| |
− | };
| |
− | | |
− | // *** Условие падения тела ***
| |
− | var spring_dropped = false;
| |
− | drop_spring.onclick = function () {
| |
− | spring_dropped = true;
| |
− | };
| |
− | | |
− | // *** Пересчет статических координат
| |
− | new_static.onclick = function () {
| |
− | StaticStart()
| |
− | };
| |
− | | |
− | // *** Создание массива элементов ***
| |
− | function StaticStart() {
| |
− | spring_dropped = false;
| |
− | circle = [];
| |
− | for (var i = 0; i < n; i++) {
| |
− | var circ = {};
| |
− | circ.x = x0;
| |
− | circ.y = y0;
| |
− | circ.vy = vy0;
| |
− | circ.rad = rad0;
| |
− | circ.L = L0;
| |
− | | |
− | var rgb = HSVtoRGB(i / n * 2, 1, 1);
| |
− | | |
− | circ.fill = "rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ", 1)";
| |
− | circle[i] = circ;
| |
− | }
| |
− | for (var i = 0; i < n; i++) {
| |
− | if (i == 0) {
| |
− | circle[i].x = w / 2;
| |
− | circle[i].y0 = Lp + (n - i) * m * g / C;
| |
− | circle[i].y = circle[i].y0;
| |
− | | |
− | } else {
| |
− | circle[i].x = w / 2;
| |
− | circle[i].y0 = circle[i - 1].y0 + Lp + (n - i) * m * g / C;
| |
− | circle[i].y = circle[i].y0;
| |
− | console.log(circle[i].y0);
| |
− | | |
− | }
| |
− | }
| |
− | }
| |
− |
| |
− | // *** функция разукрашивания объектов
| |
− | function HSVtoRGB(h, s, v) {
| |
− | var r, g, b, i, f, p, q, t;
| |
− | i = Math.floor(h * 6);
| |
− | f = h * 6 - i;
| |
− | p = v * (1 - s);
| |
− | q = v * (1 - f * s);
| |
− | t = v * (1 - (1 - f) * s);
| |
− | switch (i % 6) {
| |
− | case 0: r = v, g = t, b = p; break;
| |
− | case 1: r = q, g = v, b = p; break;
| |
− | case 2: r = p, g = v, b = t; break;
| |
− | case 3: r = p, g = q, b = v; break;
| |
− | case 4: r = t, g = p, b = v; break;
| |
− | case 5: r = v, g = p, b = q; break;
| |
− | }
| |
− | return {
| |
− | r: Math.floor(r * 255),
| |
− | g: Math.floor(g * 255),
| |
− | b: Math.floor(b * 255)
| |
− | };
| |
− | }
| |
− | | |
− | // график
| |
− | var vGraph1 = new TM_graph( // определить график
| |
− | "#vGraph1", // на html-элементе #vGraph
| |
− | 250, // сколько шагов по оси "x" отображается
| |
− | 0, 100, 5); // мин. значение оси Y, макс. значение оси Y, шаг по оси Y
| |
− | | |
− | // *** Функция обеспечивающая "жизнь" пружин ***
| |
− | function control() {
| |
− | calculate();
| |
− | draw();
| |
− | requestAnimationFrame(control);
| |
− | }
| |
− | StaticStart();
| |
− | control();
| |
− | | |
− | | |
− | | |
− | // *** Функция расчетов координат ***
| |
− | function calculate() {
| |
− | | |
− | for (var s = 1; s <= spf; s++) {
| |
− | var k = n;
| |
− | for (var i = 1; i < n; i++) {
| |
− | if (spring_dropped)
| |
− | circle[0].L = 0;
| |
− | else
| |
− | circle[0].L = circle[0].y - Lp;
| |
− | circle[i].L = circle[i].y - circle[i - 1].y - Lp;
| |
− | }
| |
− | | |
− | for (var i = 0; i < n; i++) {
| |
− | if (i == n - 1)
| |
− | circle[i].vy += ((-1) * C * (circle[i].L) / m + g) * dt;
| |
− | else
| |
− | circle[i].vy += ((-1) * C * (circle[i].L - circle[i + 1].L) / m + g) * dt;
| |
− |
| |
− |
| |
− | circle[i].y += circle[i].vy * dt;
| |
− | | |
− | }
| |
− | steps++;
| |
− | | |
− | if (spring_dropped)
| |
− | { sTime ++;
| |
− | if (sTime % 50 == 0) vGraph1.graphIter(sTime/50, (circle[n-1].y-circle[n-1].y0)) ;
| |
− | };
| |
− | }
| |
− | }
| |
− | | |
− | | |
− | // *** Функция рисования объектов ***
| |
− | function draw() {
| |
− | ctx.clearRect(0, 0, w, h);
| |
− | | |
− | // Рисование закрепления
| |
− | ctx.lineWidth = 6;
| |
− | ctx.strokeStyle = "#7394cb";
| |
− | ctx.beginPath();
| |
− | ctx.moveTo(200, 0);
| |
− | ctx.lineTo(300, 0);
| |
− | ctx.stroke();
| |
− | | |
− | for (var i = 0; i < n; i++) {
| |
− | | |
− | // Рисование пружинок
| |
− | if (i == 0) {
| |
− | if (!spring_dropped)
| |
− | draw_spring(0, circle[i].y, w / 2, 10, 40);
| |
− | } else
| |
− | draw_spring(circle[i - 1].y, circle[i].y, w / 2, 10, 40);
| |
− | | |
− | | |
− | }
| |
− | for (var i = 0; i < n; i++) {
| |
− |
| |
− | // Рисование грузиков
| |
− | ctx.lineWidth = 6;
| |
− | ctx.strokeStyle = "#8B008B";
| |
− | ctx.beginPath();
| |
− | ctx.moveTo(circle[i].x-20, circle[i].y);
| |
− | ctx.lineTo(circle[i].x+20, circle[i].y);
| |
− | ctx.stroke();
| |
− | }
| |
− | | |
− | }
| |
− | | |
− | // *** Функция рисования пружины ***
| |
− | function draw_spring(x_start, x_end, y, n, h) {
| |
− | ctx.lineWidth = 1;
| |
− | | |
− | var L = x_end - x_start;
| |
− | for (var i = 0; i < n; i++) {
| |
− | var rgb = HSVtoRGB(i / n * 0.5, 1, 1);
| |
− | ctx.strokeStyle = "rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ", 1)";
| |
− | | |
− | var x_st = x_start + L / n * i;
| |
− | var x_end = x_start + L / n * (i + 1);
| |
− | var l = x_end - x_st;
| |
− | ctx.beginPath();
| |
− | ctx.bezierCurveTo(y, x_st, y + h, x_st + l / 4, y, x_st + l / 2);
| |
− | ctx.bezierCurveTo(y, x_st + l / 2, y - h, x_st + 3 * l / 4, y, x_st + l);
| |
− | ctx.stroke();
| |
− | }
| |
− | }
| |
− | }
| |
− | </syntaxhighlight>
| |
− | </div>
| |
− | </div>
| |
− | | |
− | =='''Физическое объяснение'''==
| |
− | Мы наблюдаем иллюзию "зависания" нижнего грузика потому, что до него должна дойти волна возмущений верхней пружины, прежде чем он придет в движение.
| |
− | | |
− | =='''Ссылки'''==
| |
− | * [[Виртуальная лаборатория]]
| |
− | <br/> | |
− | [[Category: Виртуальная лаборатория]]
| |
− | [[Category: Программирование]]
| |
− | [[Category: JavaScript]]
| |