Иллюзия зависания пружины

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

Описание физического эксперимента

Падение пружины

Длинная пружина растянута и находиться в статическом положении. После чего отпускаем верхний конец пружины и видим, что нижний конец пружины находится в неподвижном состоянии в течение продолжительного времени.
Ниже будет представлена математическая модель и программа, демонстрирующая данный эффект, называемый "иллюзией зависания".

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

Задана система пружин с жесткостью [math]{С}[/math] и грузиков с массой [math]{m}[/math], подвешенных на креплении. На систему действует сила тяжести [math]{mg}[/math]. Рассчитываются статические координаты такой системы. После чего убирается верхняя пружина, что приводит систему в движение.

Цель - описать "зависание" нижнего грузика во время падения пружины.

Основные уравнения

1)Расчет статических координат:

[math]{y}_{i}=i{l}_{0}+\sum^{i}_{k=1} {\Delta l_k}[/math]

[math]\Delta{l_k} = \frac{(n-k+1)mg}{C} [/math]

где [math]{n}[/math] — количество грузиков ; [math]{i}[/math] — текущий грузик ; [math]{l_0}[/math] — длина не растянутой пружины; [math]\Delta{l_k}[/math] — статическое удлинение пружины.

2) Уравнение движения грузиков при отсутствии верхней пружины:

[math]\ddot y_i = - \frac{C}{m} ({y}_{i+1} - 2{y}_{i}+{y}_{i-1}) + g [/math]

при [math]i = n [/math] :
[math] \ddot y_n = - \frac{C}{m}(y_n - {y}_{n-1} - l_0) + g[/math]

Программа (лучше всего смотреть ее в Mozilla Firefox)


Скачать программу Spring_illusion.rar.

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

Файл "Spring_illusin.js"

  1 window.addEventListener("load", Main_Spring, true);
  2 function Main_Spring() {
  3 
  4 	// *** Некие исходные данные ***
  5 
  6 	var canvas = spring_canvas;
  7 	canvas.onselectstart = function () {return false;}; // запрет выделения canvas
  8 	var ctx = canvas.getContext("2d"); // на ctx происходит рисование
  9 	var w = canvas.width; // ширина окна в расчетных координатах
 10 	var h = canvas.height; // высота окна в расчетных координатах
 11 
 12 	var Pi = 3.1415926; // число "пи"
 13 	var g = 9.8; // гравитационная постоянная
 14 
 15 	var T0 = 0.01; // масштаб времени (период колебаний исходной системы)
 16 
 17 	var m0 = 0.15; // масштаб массы маятника
 18 	var C0 = 1; // масштаб жесткости пружины
 19 
 20 	var count = true; // проводить ли расчет системы
 21 	var v = 0; // скорость тела
 22 	var t = 0;
 23 
 24 	// параметры полученные из размеров холста
 25 	var rw = canvas.width / 4;
 26 	var rh = canvas.height / 100;
 27 
 28 	// параметры грузиков
 29 	var x0 = 0;
 30 	var y0 = 0;
 31 	var vy0 = 0;
 32 	var rad0 = 7;
 33 	var sTime = 0;
 34 	// параметры пружины
 35 	var Lp = 30; //длина пружины
 36 
 37 
 38 	// *** Задание вычислительных параметров ***
 39 
 40 	var fps = 60; // frames per second - число кадров в секунду (качечтво отображения)
 41 	var spf = 5; // steps per frame   - число шагов интегрирования между кадрами
 42 	var dt = 50 * T0 / fps; // шаг интегрирования (качество расчета)
 43 	var steps = 0; // количество шагов интегрирования
 44 
 45 
 46 	// *** Задание физических параметров ***
 47 	var m = 1 * m0; // масса грузика
 48 	var C = 1 * C0; // жесткость пружины
 49 	var L0 = 0; // изначальное удлинение пружины
 50 	var n = 5; // количество тел
 51 	var circle; // круглые тела
 52 
 53 	// *** Установка слайдеров для переменных величин ***
 54 	slider_m.value = (m / m0).toFixed(1);
 55 	number_m.value = (m / m0).toFixed(1);
 56 	slider_spf.value = (spf).toFixed(1);
 57 	number_spf.value = (spf).toFixed(1);
 58 	slider_n.value = parseInt(n);
 59 	number_n.value = parseInt(n);
 60 
 61 	function setM(new_m) {
 62 		m = new_m * m0;
 63 	}
 64 
 65 	function setSpf(new_spf) {
 66 		spf = new_spf;
 67 	}
 68 	function setN(new_n) {
 69 		n = new_n;
 70 		StaticStart();
 71 	}
 72 
 73 	slider_m.oninput = function () {
 74 		number_m.value = slider_m.value;
 75 		setM(slider_m.value);
 76 	};
 77 	number_m.oninput = function () {
 78 		slider_m.value = number_m.value;
 79 		setM(number_m.value);
 80 	};
 81 
 82 
 83 	slider_spf.oninput = function () {
 84 		number_spf.value = slider_spf.value;
 85 		setSpf(slider_spf.value);
 86 	};
 87 	number_spf.oninput = function () {
 88 		slider_spf.value = number_spf.value;
 89 		setSpf(number_spf.value);
 90 	};
 91 
 92 	slider_n.oninput = function () {
 93 		number_n.value = slider_n.value;
 94 		setN(slider_n.value);
 95 	};
 96 	number_n.oninput = function () {
 97 		slider_n.value = number_n.value;
 98 		setN(number_n.value);
 99 	};
100 
101 	// *** Условие падения тела ***
102 	var spring_dropped = false;
103 	drop_spring.onclick = function () {
104 		spring_dropped = true;
105 	};
106 
107 	// *** Пересчет статических координат
108 	new_static.onclick = function () {
109 		StaticStart()
110 	};
111 
112 	// *** Создание массива элементов ***
113 	function StaticStart() {
114 		spring_dropped = false;
115 		circle = [];
116 		for (var i = 0; i < n; i++) {
117 			var circ = {};
118 			circ.x = x0;
119 			circ.y = y0;
120 			circ.vy = vy0;
121 			circ.rad = rad0;
122 			circ.L = L0;
123 
124 			var rgb = HSVtoRGB(i / n * 2, 1, 1);
125 
126 			circ.fill = "rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ", 1)";
127 			circle[i] = circ;
128 		}
129 		for (var i = 0; i < n; i++) {
130 			if (i == 0) {
131 				circle[i].x = w / 2;
132 				circle[i].y0 = Lp + (n - i) * m * g / C;
133 				circle[i].y = circle[i].y0;
134 
135 			} else {
136 				circle[i].x = w / 2;
137 				circle[i].y0 = circle[i - 1].y0 + Lp + (n - i) * m * g / C;
138 				circle[i].y = circle[i].y0;
139 				console.log(circle[i].y0);
140 
141 			}
142 		}
143 	}
144 	
145 // *** функция разукрашивания объектов
146 function HSVtoRGB(h, s, v) {              
147     var r, g, b, i, f, p, q, t;
148     i = Math.floor(h * 6);
149     f = h * 6 - i;
150     p = v * (1 - s);
151     q = v * (1 - f * s);
152     t = v * (1 - (1 - f) * s);
153     switch (i % 6) {
154         case 0: r = v, g = t, b = p; break;
155         case 1: r = q, g = v, b = p; break;
156         case 2: r = p, g = v, b = t; break;
157         case 3: r = p, g = q, b = v; break;
158         case 4: r = t, g = p, b = v; break;
159         case 5: r = v, g = p, b = q; break;
160     }
161     return {
162         r: Math.floor(r * 255),
163         g: Math.floor(g * 255),
164         b: Math.floor(b * 255)
165     };
166 }
167 
168 	    // график
169     var vGraph1 = new TM_graph(                  // определить график
170         "#vGraph1",                              // на html-элементе #vGraph
171         250,                                    // сколько шагов по оси "x" отображается
172         0, 100, 5);                            // мин. значение оси Y, макс. значение оси Y, шаг по оси Y
173 
174 // *** Функция обеспечивающая "жизнь" пружин ***
175 function control() {
176 	calculate();
177 	draw();
178 	requestAnimationFrame(control);
179 }
180 StaticStart();
181 control();
182 
183 
184 
185 // *** Функция расчетов координат ***
186 function calculate() {
187 
188 	for (var s = 1; s <= spf; s++) {
189 	var k = n;
190 		for (var i = 1; i < n; i++) {
191 			if (spring_dropped)
192 				circle[0].L = 0;
193 			else
194 				circle[0].L = circle[0].y - Lp;
195 			circle[i].L = circle[i].y - circle[i - 1].y - Lp;
196 		}
197 
198 		for (var i = 0; i < n; i++) {
199 			if (i == n - 1)
200 				circle[i].vy += ((-1) * C * (circle[i].L) / m + g) * dt;
201 			else
202 				circle[i].vy += ((-1) * C * (circle[i].L - circle[i + 1].L) / m + g) * dt;
203 				
204 			
205 			circle[i].y += circle[i].vy * dt;
206 
207 		}
208 		steps++;
209 
210 		if (spring_dropped)
211 		{ sTime ++;
212 		if (sTime % 50 == 0) vGraph1.graphIter(sTime/50, (circle[n-1].y-circle[n-1].y0)) ;
213 		};
214 	}
215 }
216 
217 
218 // *** Функция рисования объектов ***
219 function draw() {
220 	ctx.clearRect(0, 0, w, h);
221 
222 	// Рисование закрепления
223 	ctx.lineWidth = 6;
224 	ctx.strokeStyle = "#7394cb";
225 	ctx.beginPath();
226 	ctx.moveTo(200, 0);
227 	ctx.lineTo(300, 0);
228 	ctx.stroke();
229 
230 	for (var i = 0; i < n; i++) {
231 
232 		// Рисование пружинок
233 		if (i == 0) {
234 			if (!spring_dropped)
235 				draw_spring(0, circle[i].y, w / 2, 10, 40);
236 		} else
237 			draw_spring(circle[i - 1].y, circle[i].y, w / 2, 10, 40);
238 
239 
240 	}
241 	for (var i = 0; i < n; i++) {
242 	
243 		// Рисование грузиков	
244 		ctx.lineWidth = 6;
245 		ctx.strokeStyle = "#8B008B";
246 		ctx.beginPath();
247 		ctx.moveTo(circle[i].x-20, circle[i].y);
248 		ctx.lineTo(circle[i].x+20, circle[i].y);
249 		ctx.stroke();
250 	}
251 
252 }
253 
254 // *** Функция рисования пружины ***
255 function draw_spring(x_start, x_end, y, n, h) {
256 	ctx.lineWidth = 1;
257 
258 	var L = x_end - x_start;
259 	for (var i = 0; i < n; i++) {
260 		var rgb = HSVtoRGB(i / n * 0.5, 1, 1);
261 		ctx.strokeStyle = "rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ", 1)";
262 
263 		var x_st = x_start + L / n * i;
264 		var x_end = x_start + L / n * (i + 1);
265 		var l = x_end - x_st;
266 		ctx.beginPath();
267 		ctx.bezierCurveTo(y, x_st, y + h, x_st + l / 4, y, x_st + l / 2);
268 		ctx.bezierCurveTo(y, x_st + l / 2, y - h, x_st + 3 * l / 4, y, x_st + l);
269 		ctx.stroke();
270 	}
271 }
272 }

Физическое объяснение

Мы наблюдаем иллюзию "зависания" нижнего грузика потому, что до него должна дойти волна возмущений верхней пружины, прежде чем он придет в движение.

Ссылки