If you're seeing this message, it means we're having trouble loading external resources on our website.

Ако си зад уеб филтър, моля, увери се, че домейните *. kastatic.org и *. kasandbox.org са разрешени.

Основно съдържание

Закони на Нютон

В последния пример от миналия раздел видяхме как да изчислим динамичното ускорение, базирано на вектор, сочещ от кръг на екрана към позицията на мишката. Полученото движение наподобява магнитно привличане между кръга и мишката, сякаш някаква сила дърпа кръга към мишката.
В този раздел ще формализираме разбирането си за понятието "сила" и за връзката ѝ с ускорението. Целта ни е до края на урока да разберем как да накараме множество обекти да се движат по екрана и да отговарят на най-различни сили от околната среда.
Преди да започнем да разучаваме практическото симулиране на сили чрез кода, да разгледаме понятието за това какво означава "сила" в реалния свят. Както думата "вектор", "сила" често се използва за различни неща. Тя може да индикира силна напрегнатост, както е в изречението "Тя избута камъка с голяма сила" или "Той говори силно". Определението за сила, което ни интересува, е много по-формално и идва от законите за движението на Исак Нютон:
Силата е вектор, който кара един обект, който има маса, да се ускорява.
Добрите новини са, че познаваме първата част от определението: силата е вектор. Добре, че вече имахме цяла тема, в която научихме какво е вектор и как да го програмираме с PVector-и!
Да разгледаме трите закона на Нютон за движението във връзка с понятието за сила.

Първи закон на Нютон

Първият закон на Нютон обикновено се формулира по следния начин:
Един обект в покой остава в покой, а един обект, който се движи, продължава да се движи.
Тук обаче липсва важен елемент, свързани със силите. Бихме могли да го разширим, като посочим:
Един обект в покой остава в покой, а един обект, който се движи, продължава да се движи с постоянна скорост, освен ако върху него не се упражни небалансирана сила.
По времето на Нютон преобладаващата теория за движението – формулирана от Аристотел – е била на почти 2000 години. Според нея ако един обект се движи, се изисква някаква сила, за да продължи да се движи. Ако този движещ се обект не е отблъснат или привлечен, той просто ще се забави и ще спре. Нали така?
Това, разбира се, не е вярно. В отсъствието на сили, не се изисква допълнителна сила, за да продължи обектът да се движи. Един обект (например топка), хвърлен в земната атмосфера, се забавя заради съпротивлението на въздуха (което е сила). Скоростта на обекта ще остане постоянна, ако няма никакви сили, или ако силите, които въздействат върху него, се унищожават взаимно, т.е. сумарната сила е 0. Често това се нарича равновесие. Падащата топка ще достигне крайна скорост (която остава константна), когато силата на съпротивлението на въздуха е равна на силата на гравитацията.
Диаграма на двама души, разлюляващи махало.
Махалото не се движи, защото всички сили се унищожават взаимно (сумарната им сила е равна на 0)
В нашия свят на ProcessingJS можем да преизчислим първия закон на Нютон, както следва:
Скоростта на един PVector обект остава постоянна, ако е в състояние на равновесие.
За момент ще прескочим втория закон на Нютон (който се приема за най-важния за нашите цели) и ще минем към третия закон.

Трети закон на Нютон

Този закон често се формулира по следния начин:
За всяко действие съществува равно по големина и противоположно по посока противодействие.
Този закон често предизвиква объркване заради начина, по който е формулиран. Най-малкото, звучи сякаш една сила причинява друга. Да, ако бутнеш някого, той може да реши също да те бутне. Но това не е действието и реакцията, за които става дума в третия закон на Нютон.
Да речем, че буташ стена. Стената не решава активно да те отблъсне обратно. Няма "източник" на силата. Твоят натиск просто включва двете сили, които могат да се разгледат като двойка "действие/противодействие".
По-добър начин да формулираме закона би бил:
Силите винаги се проявяват по двойки. Двете сили са равни по големина, но са в противоположни сили.
Това все още предизвиква объркване, защото звучи все едно тези сили винаги ще се неутрализират. Това не е така. Не забравяй, че силите действат върху различни обекти. А това, че двете сили са равни, не означава, че движенията им са еднакви (или че обектите ще спрат да се движат).
Опитай се да буташ спрял камион. Въпреки че камионът е много по-силен от теб, за разлика от камион в движение, спрелият камион никога няма да превъзхожда силата ти и да те накара да излетиш назад. Силата, която оказваш върху него, е равна, но противоположна по посока на силата, която изпитват ръцете ти. Резултатът зависи от различни фактори. Ако камионът е малък и се намира върху заледен склон, вероятно ще успееш да го помръднеш. От друга страна, ако е много голям камион на кален път и буташ достатъчно силно (може би дори ако се засилиш), можеш да нараниш ръцете си.
Какво ще стане, ако буташ камион, докато си с ролкови кънки?
Един мъж, бута камион докато носи ролкови кънки
Да предефинираме третия закон на Нютон в света на ProcessingJ:
Ако изчислим PVector f, който е силата на обект А върху обект В, трябва да приложим силата – PVector.mult(f,-1);, която В упражнява върху обект А.
Ще видим, че в света на програмирането с ProcessingJS не винаги изпълняваме горното. Понякога, както е в случая на гравитационно привличане между телата, искаме да моделираме еднакви и противоположни сили. В други случаи, както когато просто казваме "Хей, има вятър в околната среда", няма да се опитваме да моделираме силата, която тялото упражнява върху въздуха. Всъщност ние изобщо не моделираме въздуха! Не забравяй, че просто взимаме вдъхновение от физиката на естествения свят, а не симулираме всичко с перфектна точност.

Втори закон на Нютон

Ето ни пред най-важния закон за един ProcessingJS програмист.
Традиционно този закон е формулиран така:
Силата е равна на масата по ускорението.
Или:
F=MA
Защо това е най-важният закон за нас? Нека го напишем по различен начин.
A=F/M
Ускорението е право пропорционално на силата и обратно пропорционално на масата. Това означава, че ако някой те бутне, колкото по-силно те бутне, толкова по-бързо ще се движиш (или ускоряваш). Колкото е по-голям бутнатият, толкова по-бавно ще се движи.
Тегло срещу Маса
Масата на един обект е мярка за количеството материя в обекта (измерено в килограми).
Теглото, въпреки че често се бърка с масата, технически представлява силата на гравитацията, която действа върху обекта. От втория закон на Нютон можем да изчислим теглото като масата по ускорението на гравитацията (w = m * g). Теглото се измерва в нютони.
Плътността се дефинира като количеството масата за единица обект (грама за кубичен сантиметър, например).
Забележи, че един обект, който има маса един килограм на Земята ще има маса един килограм на Луната. Обаче ще тежи само една шеста от теглото си на Земята.
Какво все пак е масата в света на ProcessingJS? Нали работим с пиксели? За начало да кажем, че в нашия измислен свят от пиксели всички обекти имат маса 1. F/1 = F. И така:
A=F
Ускорението на един обект е равно на силата. Това са чудесни новини. Все пак видяхме в раздела за вектори, че ускорението е ключът за контролирането на движението на нашите обекти по екрана. Позицията се настройва от скоростта, а скоростта – от ускорението. Ускорението беше това, с което всичко започва. Но сега научаваме, че всъщност силата е това, с което започва всичко.
Да разгледаме какво научихме, за да създадем своя Mover обект, който в момента има позиция, скорост и ускорение. Сега целта ни е да можем да добавим сили към този обект, например така:
mover.applyForce(wind);
или:
mover.applyForce(gravity);
където wind и gravity са PVector обекти. Според втория закон на Нютон можем да имплементираме тази функция както следва:
Mover.prototype.applyForce = function(force) {
    this.acceleration = force;
};

Натрупване на сили

Това изглежда много добре. В крайна сметка ускорението = силата е буквален превод на втория закон на Нютон (без масата). Въпреки това тук има един доста голям проблем. Да се върнем към това, което се опитвахме да направим: да създадем обект, който се движи по екрана и реагира на вятъра и на гравитацията.
mover.applyForce(wind);
mover.applyForce(gravity);
mover.update();
mover.display();
Добре, нека за момент да станем компютъри. Първо извикваме applyForce() с вятъра. Така на ускорението на обекта Mover се присвоява PVector обектът wind. След това извикваме applyForce() с гравитацията. Сега на ускорението на обекта Mover се присвоява PVector обектът gravity. И накрая извикваме метода update(). Какво се случва в update()? Ускорението се добавя към скоростта.
velocity.add(acceleration);
Няма да видим грешка в нашата програма, но тя е там! Имаме голям проблем. Каква е стойността на ускорението, когато се добави към скоростта? Равно е на силата на гравитацията. Няма го вятъра! Ако извикаме applyForce() повече от веднъж, стойността от всяко предно извикване се презаписва. Как ще се справим с повече от една сила?
Разковничето тук е в това, че започнахме с опростено твърдение за втория закон на Нютон. Ето и по-точен начин да го формулираме:
Общата сила е равна на масата по ускорението.
С други думи ускорението е равно на сумата на всички сили, разделена на масата. Това е напълно логично. В крайна сметка, както видяхме в първия закон на Нютон, ако сборът на всички сили е 0, обектът се намира в състояние на равновесие (т.е. няма ускорение). Нашата имплементация на това е чрез процес, известен като натрупване на сили. Той всъщност е много прост; всичко, което трябва да направим , е да съберем силите. Във всеки един момент може да има 1, 2, 6, 12 или 303 сили. Докато нашият обект знае как да събере силите, които му въздействат, техният брой няма значение.
Да променим метода applyForce(), така че да добавя всяка нова сила към ускорението и да ги натрупва:
Mover.prototype.applyForce = function(force) {
    this.acceleration.add(force);
};
Не сме приключили все още. За акумулирането на сила ни е нужно още нещо. Тъй като събираме всички сили във всеки един момент, трябва да сме сигурни, че изчистваме ускорението (т.е. зануляваме го) преди всяко извикване на update(). Да помислим за момент за вятъра. Понякога вятърът е много силен, понякога – слаб и понякога въобще няма вятър. Във всеки един момент може да задуха силен вятър, например, когато потребителят задържи бутона на мишката.
if (mouseIsPressed) {
  var wind = new PVector(0{,}5, 0);
  mover.applyForce(wind);
}
Когато потребителят освободи мишката, вятърът ще спре и според първия закон на Нютон, обектът ще продължи да се движи с постоянна скорост. Обаче, ако сме забравили да занулим ускорението, вятърът ще продължи да духа. Дори още по-лошо – ще се усили от предишния кадър, тъй като добавяме сили!
Ускорението в нашата симулация няма памет; то се изчислява просто на базата на силите на средата, налични в един определен момент. Това е различно от, да речем, позицията, която трябва да помни къде се е намирал обектът в предишния кадър, за да може да се придвижи успешно в следващия.
Най-лесният начин да имплементираме изчистване на ускорението за всеки кадър е като умножим PVector по 0 в края на update().
Mover.prototype.update = function() {
    this.velocity.add(this.acceleration);
    this.position.add(this.velocity);
    this.acceleration.mult(0);
};

Работа с маса

Добре, трябва да добавим нещо съвсем малко преди да привършим с включването на сили към нашия клас Mover и да сме готови за примерите. В крайна сметка вторият закон на Нютон е F=MA, а не A=F. Можем да включим масата толкова лесно, колкото бихме могли да добавим свойство към нашия обект, но тук трябва да отделим повече време, защото ще се появи леко усложнение.
Мерни единици
След като се запознахме с масата, е важно да отбележим и мерните единици. В реалния свят нещата се измерват с конкретни единици. Казваме, че два обекта са на 3 метра един от друг, че бейзболната топка се движи с 90 мили за час, или че топката за боулинг има маса 6 килограма. Както ще видим по-късно в този курс, понякога ще искаме да вземем предвид мерните единици от реалния свят. През по-голямата част на този раздел, обаче, ще ги игнорираме.
Нашите мерни единици са пикселите (“Тези две окръжности са на 100 пиксела една от друга") и кадрите на анимацията (“Тази окръжност се движи със скорост 2 пиксела в кадър"). В случая с масата няма мерна единица, която да можем да използваме. Ще си измислим нещо. В този пример избираме произволно числото 10. Тъй като няма мерна единица, можеш да си измислиш своя, например “1 муг” или “1 юркъл.”
За целите на демонстрацията ще обвържем масата на обекта към неговия размер, така че ако масата е равна на 10, ще нарисуваме окръжност с радиус 10. Това ще ни позволи да визуализираме масата на един обект и да разберем ефекта на масата в нашите програми. В реалния свят, обаче, размерът не винаги индикира маса. Едно малко метално топче може да има много по-голяма маса, отколкото голям балон, заради по-голямата си плътност.
Масата е скалар (число с плаваща запетая), а не вектор, тъй като е просто едно число, което описва количеството материя в един обект. Можем да решим да сме интересни и да изчислим площта на формата като нейна маса, но е много по-просто да кажем: "Хей, масата на този обект е... ами, не знам, ... какво ще кажеш за 1?"
var Mover = function() {
    this.mass = 10;
    this.position = new PVector(random(width), random(height));
    this.velocity = new PVector(0, 0);
    this.acceleration = new PVector(0, 0);
};
Това не е толкова интересно, колкото би било ако имаме обекти с различна маса, но е някакво начало. Къде отива масата? Ще я използваме, когато прилагаме втория закон на Нютон към нашия обект.
Mover.prototype.applyForce = function(force) {
  force.div(this.mass);
  this.acceleration.add(force);
};
Отново, въпреки че кодът ни изглежда правилен, имаме доста голям проблем. Представи си следния сценарий с два обекта Mover, и двата издухани от силата на вятъра.
var m1 = new Mover();
var m2 = new Mover();

var wind = new PVector(1, 0);

m1.applyForce(wind);
m2.applyForce(wind);
Нека отново станем компютър. m1.applyForce() приема силата на вятъра (1,0), разделя я по масата (10) и я добавя към ускорението.
кодвятър
var wind = new PVector(1, 0);(1, 0)
m1.applyForce(wind)(0.1, 0)
Добре. Продължаваме с обект m2. Той също приема силата на вятъра – (1,0). Почакай. Една секунда. Каква е стойността на силата на вятъра? Ако погледнем по-отблизо, ще видим, че силата на вятъра всъщност е (0,1,0)!
Помниш ли този дребен детайл от работата с обекти? В JavaScript променлива, която съхранява обект (като PVector) всъщност пази показалец към този обект в паметта. Когато подадеш обекта на функция, не подаваш копие, а самия показалец. Така че ако една функция направи промяна в този обект (както прави тук, като разделя на масата), тогава този обект остава перманентно променен!
Ето защо нещата тук се объркват. Ние не искаме m2 да приема силата, делена на масата на обекта m1. Искаме той да приеме тази сила в първоначалното си състояние – (1,0). Така че трябва да се защитим и да направим копие на PVector f преди да го разделим на масата.
За щастие обектът PVector има удобен метод за създаване на копие –get(). get() връща нов обект PVector със същите данни. Така че можем да преработим applyForce() по следния начин:
Mover.prototype.applyForce = function(force) {
    var f = force.get();
    f.div(this.mass);
    this.acceleration.add(f);
};
Алтернативно можем да пренапишем метода с помощта на статичната версия на div(), като използваме това, което научихме за статичните функции от предишния раздел:
Mover.prototype.applyForce = function(force) {
  var f = PVector.div(force, this.mass);
  this.acceleration.add(f);
};
Важното е да намерим начин да не засягаме първоначалния вектор на силата, за да можем да го приложим към много обекти Mover.

Създаване на сили

Ние знаем какво е сила (вектор) и знаем как да приложим сила върху обект (разделяме я на масата и я добавяме към вектора на ускорение на обекта). Какво изпускаме? Остава ни да открием как въобще получаваме силата. Откъде идват силите?
В този раздел ще разгледаме два метода за създаване на сили в нашия свят на ProcessingJS:
  • Измисляме си сила! В крайна сметка сме програмисти, които създават своя свят. Няма причина да не можеш да си измислиш сила и да я приложиш.
  • Моделираме сила! Да, силите съществуват в реалния свят. А учебниците по физика съдържат формули за тези сили. Ние можем да вземем тези формули, да ги преведем в код и да моделираме сили от истинския свят в ProcessingJS.
Най-лесният начин да си измислим сила, е да изберем число. Да започнем с идеята за симулиране на вятър. Какво ще кажеш за сила на вятъра, която сочи надясно и е сравнително слаба? Ако приемем, че имаме обект m от тип Mover, кодът ни може да изглежда така:
var wind = new PVector(0{,}01, 0);
m.applyForce(wind);
Резултатът не е особено интересен, но е добро начало. Създаваме обект PVector, инициализираме го и го подаваме на обект (който на свой ред ще го приложи към своето ускорение). Ако искаме да имаме две сили, например вятър и гравитация (малко по-силна, сочеща надолу), можем да го запишем така:
var wind = new PVector(0{,}01, 0);
var gravity = new PVector(0, 0{,}1);
m.applyForce(wind);
m.applyForce(gravity);
Сега имаме две сили, които сочат в различни посоки и имат различна големина, като и двете са приложени към обекта m. Започваме да виждаме резултат. Построихме свят за нашите обекти в ProcessingJS, среда, на която те реално могат да реагират.
Ето и как ще изглежда нашата програма, когато съберем всичко заедно:
Ура! Покрихме доста материал, но сега вече можем да правим толкова много неща. Продължаваме – научи се да използваш силата!

Курсът "Компютърни симулации на физични явления" е производeн на "Природата на кода" от Даниел Шифман, използвана от Creative Commons Attribution-NonCommercial 3,0 Unported License.

Искаш ли да се присъединиш към разговора?

Все още няма публикации.
Разбираш ли английски? Натисни тук, за да видиш още дискусии в английския сайт на Кан Академия.