Измерение координаты, скорости и ускорения тела

lev39
Offline
Зарегистрирован: 14.08.2012

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

leshak
Offline
Зарегистрирован: 29.09.2011

 Дополню "предысторию". Тема была отпочкованна от http://arduino.ru/forum/programmirovanie/izmerenie-vremeni-soudareniya-metallicheskikh-sharov#comment-14011

leshak
Offline
Зарегистрирован: 29.09.2011

lev39 пишет:

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

Мне кажется что примешивание сюда слова "проекции" - только запутывает (хотя формально и правильно). Сразу всплывает "проекции куда?" и т.п. IMHO раз мы программим, то проще будет пользоваться чисто алгебраическими терминами. "Больше нуля/меньше  нуля".

То есть задача сводится к "есть дискретная функция S(t)".  Нужно посчитать ее первую и вторую производные. Все.

А уж потом, глядя на получившиеся знаки производных будем пытатся понять что у нас происходит ускорение,торможение, вправо едем или влево.

P.S. Как "действующему учителю" вам, возможно и видней. Я не настаиваю на сказанном выше. Можете считать это отголосками моих школьных воспоминаний. Возможно уже ошибочных :(

lev39
Offline
Зарегистрирован: 14.08.2012

Приятно, что Вы все правильно поняли. А выводить конечно можно и в EXEL и в Dephi и VC. но моя мечта сделать вывод в LabWiev, ведь она управляет Адронным коллайдером. Я уже смотрел - виртуальный СОМ порт она определяет. Вот эти проблемы решу и займусь ей. Может и Вас с агитирую.

А вообще-то Вы правы. Для нешкольных пользователей проекции ни к чему. А в школе решения всех задач на механику связаны с проекциями на координатные оси. Без этого не решишь практическини ни одной задачи, в том числе и в ЕГЭ по физике. А поскольку мне это нужно для демонстраций знаков проекций и создания проблемных ситуаций на уроках, то я и делаю акцент на проекции на ось ОХ. 

И программа по идее, может выдавать комментарий  вроде этого. "Тело движется равноускоренно против оси ОХ". Как только характер движения изменится, то изменится и комментарий.

Вот такая конфетка мне и нужна. Чтобы обучение было с увлечением.

leshak
Offline
Зарегистрирован: 29.09.2011

lev39 пишет:

Приятно, что Вы все правильно поняли.

"Чай, не лаптем щи хлебаю, Соображаю что к чему." (С) Л.Филатов

lev39 пишет:

А выводить конечно можно и в EXEL и в Dephi и VC. но моя мечта сделать вывод в LabWiev, ведь она управляет Адронным коллайдером. Я уже смотрел - виртуальный СОМ порт она определяет. Вот эти проблемы решу и займусь ей. Может и Вас с агитирую.

Это вряд ли. Год назад с ним игрался. Лично мне он плохо подходит. Монстрячий. Да и не люблю я эти "визуальные программирования". Лично для меня любую обработку/логику намного быстрее на языке програмирования сделать каком-нибудь. Текст он все-таки намного "компактней-выразительней". То есть данные-то я в нем, в итоге вывел, но сколько это времени заняло :( 

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

Конечно это дело вкуса. Человеку привыкшему "мыслить аналогово" может он и удобней будет. Тут скорее речь идет уже про мои личные вкусы. И владения альтернативными инструментами.

А вот "для школьников", возможно он и "в тему будет". Все-таки "большое и красивое" и "выглядит как колайдер" в этом случае вполне может играть очень большое значение.

Только.... А разве он не стоит хороших денег? Дело Поносова не пугает?

Так что на LabView вы меня вряд ли убедите (за других говорить не буду). Мне намного больше простор для творчества в комбинации C#+WPF. Ну максимум, возможно, Processing все-таки решусь пощупать :) Для расширения кругозора :)  (хотя тоже не нравится его Java-базированность)

lev39 пишет:

А вообще-то Вы правы. Для нешкольных пользователей проекции ни к чему. А в школе решения всех задач на механику связаны с проекциями на координатные оси. Без этого не решишь практическини ни одной задачи, в том числе и в ЕГЭ по физике. А поскольку мне это нужно для демонстраций знаков проекций и создания проблемных ситуаций на уроках, то я и делаю акцент на проекции на ось ОХ. 

Ну дык в коде-то у вас все равно нет никаких проекций быть не может :). Все равно тут "алгеброй" работать нужно. А уж "в финале" можно и геометрическую интерпетацию дать.

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

lev39 пишет:

И программа по идее, может выдавать комментарий  вроде этого. "Тело движется равноускоренно против оси ОХ". Как только характер движения изменится, то изменится и комментарий.

Вот такая конфетка мне и нужна. Чтобы обучение было с увлечением.

Ну если цифра посчитанная есть, то вывести разный текст в зависимости от знака - это не есть проблема :)

Что-бы от "лирики" перейти к "конкретике" давайте выясним с какой же частью проекта вы испытываете затруднения:

  1. Как это все регистрирова-отсылать из Arduin-ы
  2. Как это принимать на процессинге
  3. Как обрабатывать дискретные данные (считать производные)
  4. Как все это вывести на экран

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Кстати, по третьему пункту теория-лекция  1. Лекция: Задачи численного дифференцирования и алгебраической интерполяции

Не знаю насколько оно "для уровня школы" (школы разные бывают), но если очень захотеть imho в общих чертах подход уловить можно.

lev39
Offline
Зарегистрирован: 14.08.2012

Ситуация такая. Я знаю дифференцирование и интегрирование. Проблема вот в чем. Как это реализовать в скетче.

Итак изменяется величина, допустим увеличивается расстояние. Эта величина передается например в процессинг.  Как должен выглядеть кусочек скетча по взятию первой производной ( скорость) и как от скорости опять взять производную ( ускорение).

Мне кажется что кусок скетча для взятия производных лучше писать в процессинге. А Вы как думаете ?

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

lev39 пишет:

Ситуация такая. Я знаю дифференцирование и интегрирование.

Никто в этом не сомневался. Даже уверен что лучше меня знаете. У меня оно от "не использования" - изрядно подзабылось. Так что не удивляйтесь глупым вопросам :) 

lev39 пишет:

Проблема вот в чем. Как это реализовать в скетче.

OK. То есть с пунктами 1,2,4 - затруднений нет? Только с 3-тим?

lev39 пишет:

Мне кажется что кусок скетча для взятия производных лучше писать в процессинге. А Вы как думаете ?

Ну я уже говорил что мое мнение - лучше делать это на стороне компьютера. Хотя, в случае с процессингом, сам код расчета,писать его на арудине или процессинге - будет практически идентичным.

lev39 пишет:

Итак изменяется величина, допустим увеличивается расстояние. Эта величина передается например в процессинг.  Как должен выглядеть кусочек скетча по взятию первой производной ( скорость) и как от скорости опять взять производную ( ускорение).

Нет. Давайте с другого конца. Раз мы решаем "проблему три", то четко отбросим все интерпретации и "откуда данные взялись". Предположим они у нас уже есть. Нам нужно посчитать дискретную производную абстрактной функции. Пусть у нас даны пары значений x,y. Табличка. Для простоты, предположим что шаг по x -  постоянный.

X=10,Y=4319
X=15,Y=15329
X=20,Y=37239
X=25,Y=73799
X=30,Y=128759
X=35,Y=205869
X=40,Y=308879
X=45,Y=441539
X=50,Y=607599
X=55,Y=810809

Как бы вы на бумаге, не скетчем, а "по русски" описали процесс составление второй таблички, X,YY , де иксы - те же самые, а вот YY - это уже значение первой производной?

Давайте вы попробуете выступить "экспертом предметной области", а я попробую это потом перевести на "комьютерный язык".

Жаль что тут мат символы невозможно вставлять. Трудно понимать друг-друга будет :(

Предлагаю такую символику использовать X[1], X[2],X[3] - это значения иксов из соотвесвующей строки. То есть X[1]=10,X[4]=25

Аналогично для Y[1],Y[2],Y[3] - исходные значения нашей функции (4319,15329,37239)

YY[1], YY[2],YY[3] - значения производной которые нужно расчитать (для X[1],X[2],X[3])

 

 

 

lev39
Offline
Зарегистрирован: 14.08.2012

Логично. Но, как говорится я старый стал, плохой стал.

Производные от Х1. Х2, Х3 и т.д. будут нули так как они константы.

Иля я в чем то не прав ?

 

leshak
Offline
Зарегистрирован: 29.09.2011

lev39 пишет:

Но, как говорится я старый стал, плохой стал.

Ничего подобного. До тех пор пока вас интересует новое - вы не старый. А знания всегда ограничены, просто с возрастом это признавать трудней :) .

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

К сожалению ардуина не может "непрерывно", мерять какие-то значения. Только в определенные моменты времени. То есть на входе для расчетов у нас будет именно подобная "табличка" (или ее кусочек). И нам нужно научится ее считать.

Вначале на бумажке. Мы не сможем объяснить компьютеру "как это посчитать" (написать скетч), пока сами не знает как это делать. "Компьютер должен работать, а человек - думать". Так что, в данный момент "затык", у нас не с программированием, а с математикой.

Ну ничего страшного. Будем вместе разбиратся/вспоминать. Может кто-нибудь поделитится ссылочкой где численные методы объяснены более школьным языком, чем в линке на лекцию что я выше давал. Без "страшных" рядов тейлора и определителей матриц (мне не удалось найти).

В крайнем случае - сами выведем. Изобретем велосипед.  Смог же Цилковский переизобрести диф.исчесление. Из-за того что не мог получит образование. Значит и мы сможем. :)

lev39 пишет:

Производные от Х1. Х2, Х3 и т.д. будут нули так как они константы.

Иля я в чем то не прав ? 

Давайте подумаем. А какую физическую интерпретацию  будет иметь подобный ответ? Первая производная от пути - равна нулю. Значить "мы стоим". Получили аппорию "Стрела Зенона". Вряд ли нас устроит ответ "скорость равна нулю при любых показаниях датчика". Значит прийдется считать что вы не правы и искать в чем.

Вернемся в "математику". Почему же получился такой ответ? А потому что вы рассмотрели таблицу не как одну функцию заданную в определенных точках, а как множество функций-констант. И от каждой взяли производную "независимо". То есть "подменили задачу" на не эквивалентную. Потеряли информацию о связи точек между собой.

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

А по-моему все просто. Что есть производная? Это dY/dX при стремлении dX к нулю. то есть dX должно быть минимальным, но ненулевым. Для дискретной функции минимум dX - это один дискрет. Приходим к YY(X[n]) = (Y[n]-Y[n-1]) / (X[n]-X[n-1])

Аналогично со второй производной.

Считайте функцию кусочно-линейной, или сглаживайте (хоть сплайнами, хоть степенной функцией, тогда производная эмпирически извесна)

P.S. Производную можно обозначит Y', а вторую Y" :) Но это только для текста. Для программы можно dY и ddY или dY2

leshak
Offline
Зарегистрирован: 29.09.2011

 А посчитать нужно :) Итого на данный момент мы умеем брать производные от непрерывных функций, но не умеем брать производные от дискретных. Выход очевиден. "Подменить" дискретную похожей на нее непрерывной и взять производную от нее.

Что значит "похожей"? Значит, как минимум, проходящей через те же точки. То есть найти апроксимирующую функцию и дальше работать с ней.

Этот подход "не идеален" для нашего случая, но все равно вначале пройдем его. Будем данные полученые через него использовать для "самопроверки".

Проще всего, естественно апроксимировать полиномом вида:

 (1)

 Апроксимировать - значит найти такие коэфициенты a0,a1...aN, что-бы функция p(x), проходила через все точки нашей таблицы.
Сделать это можно составив и решив систему n уравнений, в которой каждое уранение это  .  

 

Проделав это с нашей табличкой получим такую апроксимирующую функцию:

(2)

А вот от нее, к счастью, мы уже умеем взять производную в рамках школьной математики.

(3)

Подставляем в нее наши x1,x2..xN и находим искомые yy1,yy2..yyN

X=10,Y'=1362
X=15,Y'=3167
X=20,Y'=5722
X=25,Y'=9027
X=30,Y'=13082
X=35,Y'=17887
X=40,Y'=23442
X=45,Y'=29747
X=50,Y'=36802
X=55,Y'=44607

 

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

Тогда мы должны помнить 4 последних отсчета (для полинома 3 степени) и с приходом нового отсчета считать каждый раз решать систему. Еще можно брать больше отсчетов, сглаживать по методу минимальных квадратов, потом решать систему... Для медленной системы прокатит, иначе - может нехватить вычислительных мощностей.

Одно ясно - сначала ищется маематическое решение, потом оно алгоритмизуется и кодируется.

leshak
Offline
Зарегистрирован: 29.09.2011

 

AlexFisher пишет:

А по-моему все просто. Что есть производная?

Ну само-собой. Но я же "просто" - не умею. Должен издалека к этому приехать :) Занудить всех в усмерть. Пошагово. С объяснением "что же было неправильно в изначальном подходе" :)

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

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

Естественно и ваш подход сделаем.

>Производную можно обозначит Y', а вторую Y"

Согласен. Когда набирал предыдущий пост сам к этому пришел ;) Че-то перемудрил :(

leshak
Offline
Зарегистрирован: 29.09.2011

 

AlexFisher пишет:

Одно ясно - сначала ищется маематическое решение, потом оно алгоритмизуется и кодируется.

Вот. Вот. Этим я и занимаюсь. Апроксимирующую функцию я взял что-бы иметь "тестовые данные", с которыми можно будет сравнивать реализацию предложенного вами подхода.

 

leshak
Offline
Зарегистрирован: 29.09.2011

 >Тогда мы должны помнить 4 последних отсчета (для полинома 3 степени)

Вы правы. Но то что он получился третий степени (все остальные a - нули). Это просто "повезло" на конкретно этих данных.

На реальных данных он будет степени N. 

Что привод нас к главному его недостатку: для расчета нужно знать все точки заранее. Невозможно, без потери точности, вычислять "на ходу". Это не критично если мы делаем расчеты по какому-то сохраненому логу, но "немного не то" для эксперемента в реальном времени.

И все-таки я, для начала "дожму его" :) Буду использовать его в качестве "эталона".

Счас буду ставить процессинг и раскуривать его. 

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

А еще в "Матанализе" есть много интересного про интегрирование и дифференцирование функций, заданных дискретными отсчетами. Вот нужная статья. Если ее "вкурить", как выражаются некоторые ;) то сильно сокращается объем расчетов, потому что при расчете производной используются только имеющиеся данные :) Типичная ситуация "все украдено до нас" :)))

leshak
Offline
Зарегистрирован: 29.09.2011

AlexFisher пишет:

 Вот нужная статья

Спасибо. Именно подобную ссылку я и имел ввиду когда говорил что "может кто-то даст". Почему-то не смог сам нагуглить.

Зато сейчас сразу нашел Лекция 10. Численное дифференцирование

То же самое, только для конкретных N. Готовое - бери и подставляй ;)

leshak
Offline
Зарегистрирован: 29.09.2011

 Сам не выношу слов "просьба не пинать", но видать это "заразно" ;).

Вообщем "просьба не пинать", так как я этот процессинг перый раз в глаза вижу :)

final static int N=10; // размер нашей талицы данных

float[] X=new float[N];
float[] Y=new float[N];
float[] dY1=new float[N];  // первая производная методом апроксимирующей функции.

void setup(){
// массивы для хранения данных
 

fillTestData(); // заполняем входный данные
calculate(); // считаем производные разными методами
printTable(); // выводим результаты

exit(); // и закрываем окно
}

void fillTestData(){
   //заполняем массив тестовыми данными
 for(int n=0;n<N;n++){
   X[n]=(n+1)*5+5;
   Y[n]=5*pow(X[n],3)-7*pow(X[n],2)+2*X[n]-1; // f(x)=5*x^2-7*x^2+2*x-1
 }
}

// считаем производные
void calculate(){

  for(int i=0;i<N;i++)  {
    float x=X[i];
    // первый. "проверочный способ"
    //f'(x)=15*x^2-14*x+2
    dY1[i]= 15*pow(x,2)-14*x+2;
    
  }

}

void  printTable(){
  println("X \t Y \t f'(x)");
   for(int i=0;i<N;i++){
     print(X[i]);
     print(" \t "+Y[i]);
     print(" \t "+dY1[i]); // первый способ
     
     println();
   }
   

}

Выводит 

X 	     Y 	         f'(x)
10.0 	 4319.0 	 1362.0
15.0 	 15329.0 	 3167.0
20.0 	 37239.0 	 5722.0
25.0 	 73799.0 	 9027.0
30.0 	 128759.0 	 13082.0
35.0 	 205869.0 	 17887.0
40.0 	 308879.0 	 23442.0
45.0 	 441539.0 	 29747.0
50.0 	 607599.0 	 36802.0
55.0 	 810809.0 	 44607.0

 

leshak
Offline
Зарегистрирован: 29.09.2011

Теперь попробуем реализовать метод предложенный AlexFisher в msg#10.

Он же "метод #2" из этой лекции http://www.toehelp.ru/theory/informat/lecture10.html

Вообщем воспользуемся формулой

 (как видим это практически "голое" определение что такое производная).

Скетч:

final static int N=10; // размер нашей талицы данных
final static float STEP=5;

float[] X=new float[N];
float[] Y=new float[N];
float[] dY1=new float[N];  // первая производная методом апроксимирующей функции.
float[] dY2=new float[N]; // первая производная методом конечной разности

void setup(){
// массивы для хранения данных
 

fillTestData(); // заполняем входный данные
calculate(); // считаем производные разными методами
printTable(); // выводим результаты

exit(); // и закрываем окно
}

void fillTestData(){
   //заполняем массив тестовыми данными
 for(int n=0;n<N;n++){
   X[n]=(n+1)*STEP+5;
   Y[n]=5*pow(X[n],3)-7*pow(X[n],2)+2*X[n]-1; // f(x)=5*x^2-7*x^2+2*x-1
 }
}

// считаем производные
void calculate(){

  for(int i=0;i<N;i++)  {
    float x=X[i];
    // первый. "проверочный способ"
    //f'(x)=15*x^2-14*x+2
    dY1[i]= 15*pow(x,2)-14*x+2;
    
    //метод конечной разности. 
    // для первой точки посчитать не можем, так как отсусвует предыдущая точка
    if(i>0)dY2[i]=(Y[i]-Y[i-1])/(X[i]-X[i-1]);
    
  }

}

void  printTable(){
  println("X \t\t Y \t\t f'(x) \t\t f'(x)");
   for(int i=0;i<N;i++){
     print(nfc(X[i],3));
     print(" \t\t "+nfc(Y[i],3));
     print(" \t\t "+nfc(dY1[i],3)); // первый способ
     print(" \t\t "+nfc(dY2[i],3)); // второй способ
     
     println();
   }
   

}

 

Вывод будет таким:

X 	     Y 	      	    f'(x) 	       f'(x)
10,000 	 4 319,000 	 1 362,000 	 0,000
15,000 	 15 329,000 	 3 167,000 	 2 202,000
20,000 	 37 239,000 	 5 722,000 	 4 382,000
25,000 	 73 799,000 	 9 027,000 	 7 312,000
30,000 	 128 759,000 	 13 082,000 	 10 992,000
35,000 	 205 869,000 	 17 887,000 	 15 422,000
40,000 	 308 879,000 	 23 442,000 	 20 602,000
45,000 	 441 539,000 	 29 747,000 	 26 532,000
50,000 	 607 599,000 	 36 802,000 	 33 212,000
55,000 	 810 809,000 	 44 607,000 	 40 642,000

Как видим. "Теоретически значения" (предпоследняя колонка) и расчетные (последняя) не совпадают весьма значительно. Почему? Смотрим на формулу и видим что производная у на _приблизительно_ равна разнице дельт. И чем меньше у нас дельта X тем более она равна (ближе к определению что такое производная).

А, на этих данных, у нас икс "шагает довольно широко". Когда же дельта по иксу (на больших значениях) становится существенно меньше значения самой функции - мы видим что ошибка уменшается. Проверим это. Снизим размер шага по иксу на несколько порядков. Возьмем STEP=0.01, вместо STEP=5

Получим:

X 	     Y 	      	 f'(x) 	      f'(x)
5,010 	 462,077 	 308,362 	 0,000
5,020 	 465,167 	 309,726 	 309,047
5,030 	 468,271 	 311,094 	 310,405
5,040 	 471,389 	 312,464 	 311,778
5,050 	 474,521 	 313,838 	 313,158
5,060 	 477,666 	 315,214 	 314,522
5,070 	 480,825 	 316,594 	 315,902
5,080 	 483,998 	 317,976 	 317,290
5,090 	 487,184 	 319,362 	 318,663
5,100 	 490,385 	 320,750 	 320,055

Как видим последние две колонки стали гораздо более похожими. Ошибка пришла к "тепрмимому" уровню.

На сегодня, наверное, это все. 

lev39
Offline
Зарегистрирован: 14.08.2012

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

Спасибо. Разобрался. Но, если я правильно понял, то вы берете конкретную функцию и берете от нее производную.

Но у меня задача другая. Идет от Ардуино поток данных - допустим работает датчик расстояния и он выдает 1 см, 2 см, .....

Если делаем в Processng ( Delphi,  VC, SmailBasic .... в чем угодно, что принимает данные с Ардуино).

то в него с датчика расстояния поступает непрерывно изменяющуюся величина расстояния S.

И мне представляется алгоритм в цикле таким :

Запоминаем S

Запоминаем новое расстояние S1

Находим разность S1 - S, делим ее на dx, допустим 0.01

Получаем V = (S1 - S)/ dx

Запоминаем V

Запомнаем новую скорость V1

Находим а = (V1 - V)/dx

Мне кажется должно быть так.

Или я в чем-то неправ. Рассудите люди добрые.

lev39
Offline
Зарегистрирован: 14.08.2012

Если я прав и Вы бы набросали скетч, то лучшего подарка учителю к Новому учебному году и желать не стоит.

leshak
Offline
Зарегистрирован: 29.09.2011

 >Но, если я правильно понял, то вы берете конкретную функцию и берете от нее производную.

Близко но не совсем. В сообщение #11 - я описал принцип превращения  "данные с датчика" можно превратить в "конкретную функцию" и дальше работать с ней (решить систему уравнений).

AlexFisher упомянул что для перехода от "показаний датчика" к конкретной функции - можно использовать, например, еще и для "метод наименьших квадратов" (тогда еще произойдет и сглаживание показаний).

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

Действительно получил, как вы правильно заметили "конкретную функцию". Но, только с целью "использовать ее в качестве эталона". Что-бы на данных полученные этой функцией посчитать методом про который упомянули вы "Находим разность S1 - S, делим ее на dx, допустим 0.01,Получаем V = (S1 - S)/ dx" и сравнить полученный результат с "эталонными значенями". И только после того как увидим что "алгоритм работает" и точность достаточно - его можно применять на реальных данных полученных с ардуины.

В данные момент эта "конкретная фунция" выступает в качестве "заменителя датчика". Для отладки алгоритма. Если мы сразу возьмем настоящий датчик, то не сможем узнать "правильно ли у нас все работает". Прокатите вы датчик (причем каждый раз по другому), получите какие-то цифры, что-то на что-то поделите... и что? Как узнать их правильность?

Более того подход "V = (S1-S)/dx" - уже тоже реализован в скетче. В сообщении #19. Вы нажимали на надпись "показать код"? Строку 39 скетчка смотрели? Она даже  выделена. Это же и есть ваше V=(S1-S)/dx.

И показанные результаты. Можно сравнить как отличаеют значения V постчитанные "аналитически" (через "конретную фунции") и "численно" (вашим методом).

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

>Но у меня задача другая.

У вас задача не другая. Перечитайте сообщение #4 в конца там есть четыре пункта. На которые имеет смысл "разбить вашу задачу", что-бы решить ее. По частям. 

В данные момент эти скетчи и описания решают подзадачу 3. Естественно часть задачи не равна задаче в целом. Это все равно что вы пришли к автомастеру со словами "мне нужно поехать в село, а машина не заводится", он посмотрел и  говорит "нужно отрегулировать карбюратор", а вы "не... у меня другая задача, мне поехать нужно, а не карбюратор разбирать". Что-бы поехать в село нужно решить "почистить карбюратор", "заправить бензин", "наметить маршрут", "взять документы"....

 

 

lev39
Offline
Зарегистрирован: 14.08.2012

Спасибо. Еще раз внимательно просмотрю все сообщения. Их так много, что я возможно что-то пропустил.

Еще раз спасибо.

 

leshak
Offline
Зарегистрирован: 29.09.2011

 

lev39 пишет:

Их так много

Это месть :) За воспоминания детства типа "на завтра задаю 160 задач по Сканави". ;)

Шучу. На самом деле мне очень повезло, в свое время, встретить Настоящего Учителя Математики. Шмигевского Николай Васильевича.

Многословность - есть у меня такая болезнь. Но тут уж вам выбирать. Либо искать кого-друго или "брать что есть".

Я не люблю делать "подарок" и давать сразу готовый ответ. Это не подарок, а медвежья услуга (постараюсь удержатся от трех страниц описания почему ;). Хотя дать сразу "готовый ответ" зачастую в разы проще и быстрее, чем подталкивать кого-то к самостоятельному его нахождению или расписыванию пошагово "как мы к этому пришли".

По поводу "перечитаю". У меня сложилось впечатление, еще по предыдущей теме, что вы не замечаете или не знаете как посмотреть "свернутый код". Вот например в сообщении #19 вы сам код скетча смогли увидеть? (номер сообщения есть в правом верхнем углу каждого поста).

Если нет - скажите об этом, если да - попробуйте его запустить у себя в процессинге. "Поигратся с ним". Самому увидеть как он что-то выводит. А то мы "приползем" к конечному варианту, а в конце окажется что он у вас вообще не запускается. Подобные проблемы лучше всего выявлять на самых ранних "прототипах". Они для того и предназначены. 

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Ладно. Поехали дальше. В принципе мы уже умеем считать производную. Но нет предела совершеству :)  Попробуем улучшить точность расчета. Использовать для расчета производной информацию не о двух точках, а о трех.

Опять смотрим лекцию http://www.toehelp.ru/theory/informat/lecture10.html раздел "Вычисление первых производных по трёхточечным схемам."

 

Расчетные формулы для указанной трехточечной схемы имеют вид:

(откуда "взялись" эти формулы можно понять если почитать линк который давал AlexFisher).

Нам, так как мы планируем считать производную в real-time самой удобной будет третья формула. То есть будем считать производную по "точке" и двум ее предыдущим точкам. Только чуток сменим наименование-индексацию.  Будем считать для правой точки с картинки. Обзовем ее i-той, а не Y1, а две предыдущий i-1 и i-2.  Ну их вместо 2h - возьмем разницу иксов. Тогда "в нашей индексации формула примет вид":

 Осталось только реализовать эту формулу в скетче и вывести результат. 

Скетч:

final static int N=10; // размер нашей талицы данных
final static float STEP=0.01;

float[] X=new float[N];
float[] Y=new float[N];
float[] dY1=new float[N];  // первая производная методом апроксимирующей функции.
float[] dY2=new float[N]; // первая производная методом конечной разности
float[] dY3=new float[N]; // первая производная по трем точкам

void setup(){
// массивы для хранения данных
 

fillTestData(); // заполняем входный данные
calculate(); // считаем производные разными методами
printTable(); // выводим результаты

exit(); // и закрываем окно
}

void fillTestData(){
   //заполняем массив тестовыми данными
 for(int n=0;n<N;n++){
   X[n]=(n+1)*STEP+5;
   Y[n]=5*pow(X[n],3)-7*pow(X[n],2)+2*X[n]-1; // f(x)=5*x^2-7*x^2+2*x-1
 }
}

// считаем производные
void calculate(){

  for(int i=0;i<N;i++)  {
    float x=X[i];
    // первый. "проверочный способ"
    //f'(x)=15*x^2-14*x+2
    dY1[i]= 15*pow(x,2)-14*x+2;
    
    //метод конечной разности. 
    // для первой точки посчитать не можем, так как отсусвует предыдущая точка
    if(i>0)dY2[i]=(Y[i]-Y[i-1])/(X[i]-X[i-1]);
    
    //считем производную по трем точкам, поэтому "для первых двух" - посчитать не сможем
    if(i>1)dY3[i]= (Y[i-2]-4*Y[i-1]+3*Y[i])/ (X[i]-X[i-2]);
    
  }

}

void  printTable(){
  println("X \t\t Y \t\t f'(x) \t\t f'(x) \t\t f'(x)");
   for(int i=0;i<N;i++){
     print(nfc(X[i],3));
     print(" \t\t "+nfc(Y[i],3));
     print(" \t\t "+nfc(dY1[i],3)); // первый способ
     
     print(" \t\t "+nfc(dY2[i],3)); // второй способ
     print( " ("+ nfc(dY1[i]-dY2[i],3) +")" ); // выводим "ошибку", насколько отличается от расчетноего 
     
     print(" \t\t "+nfc(dY3[i],3)); // третий способ,&nbsp;по трем точкам
     print( " ("+ nfc(dY1[i]-dY3[i],3) +")" ); // выводим "ошибку", насколько отличается от расчетноего 
     
     println();
   }
   

}

 Результат:

X 		 Y 		 "f'(x)" 		 "f'(x)" 		 "f'(x)"
5,010 		 462,077 		 308,362 		 0,000 (308,362) 		 0,000 (308,362)
5,020 		 465,167 		 309,726 		 309,047 (0,679) 		 0,000 (309,726)
5,030 		 468,271 		 311,094 		 310,405 (0,688) 		 311,103 (-0,009)
5,040 		 471,389 		 312,464 		 311,778 (0,686) 		 312,451 (0,013)
5,050 		 474,521 		 313,838 		 313,158 (0,679) 		 313,861 (-0,024)
5,060 		 477,666 		 315,214 		 314,522 (0,692) 		 315,186 (0,028)
5,070 		 480,825 		 316,594 		 315,902 (0,692) 		 316,608 (-0,014)
5,080 		 483,998 		 317,976 		 317,290 (0,686) 		 317,969 (0,007)
5,090 		 487,184 		 319,362 		 318,663 (0,698) 		 319,367 (-0,005)
5,100 		 490,385 		 320,750 		 320,055 (0,695) 		 320,734 (0,016)

 

 В круглых скобках я вывел насколько отличается цифра полученная численным методом от "теоретической". Как видим "новый способ" дает результаты точнее почти на два порядка чем  "лобовой подход" V=(S1-S)/dx

Удовлетворимся полученным результатом и, в дальнейшем будем использовать именно его.

leshak
Offline
Зарегистрирован: 29.09.2011

 Что-бы дальше было удобней считать "поток данных" и пользоватся той же функцией для расчета второй производной вынесем строку 43 (предыдущего скетча) в отдельную функцию

// первая производная по трем точкам. 
// (x,y) - точка в которой считаем производную
// (x1,y1) - предыдущая точка (на шаг назад)
// (x2,y2) - пред.предыдущая (на два шага назад)
float diff1(float x2,float y2,float x1,float y1,float x,float y){
  return (y2-4*y1+3*y)/(x-x2);
}

а строке 43 будем просто ее вызывать.

    //считем производную по трем точкам, поэтому "для первых двух" - посчитать не сможем

     if(i>1)dY3[i]= diff1( X[i-2],Y[i-2],  X[i-1],Y[i-1], X[i],Y[i]); // считаем первую производную по трем точкам

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Теперь займемся расчетом "вторых производных".

Для начала опять-таки, посчитаем ее "аналитически". Возьмем нашу формулу первой производной (для этих данных)

и возьмем от нее производную

Получили "ориентир" с которым будем сверятся. 

А для "численного расчета" воспользуемся выделенной на прошлом шаге функцией diff1(...). Только вместо Y-ков передадим ей то что мы насчитали ей раньше. То есть получится diff1(diff1(...)). Тоже "производная от производной.

Скетч считающий вторые производные "двумя способами" будет таким:

final static int N=10; // размер нашей талицы данных
final static float STEP=0.01;



float[] X=new float[N];
float[] Y=new float[N];
float[] dY1=new float[N];  // первая производная методом апроксимирующей функции.
float[] dY2=new float[N]; // первая производная методом конечной разности
float[] dY3=new float[N]; // первая производная по трем точкам

float[] ddY1=new float[N]; // вторая производная апроксимирующей функцией (аналитический метод).
float[] ddY2=new float[N]; // вторая производная как "производная производной".


void setup(){
// массивы для хранения данных
 

fillTestData(); // заполняем входный данные
calculate(); // считаем производные разными методами
printTable(); // выводим результаты

exit(); // и закрываем окно
}

void fillTestData(){
   //заполняем массив тестовыми данными
 for(int n=0;n<N;n++){
   X[n]=(n+1)*STEP+5;
   Y[n]=5*pow(X[n],3)-7*pow(X[n],2)+2*X[n]-1; // f(x)=5*x^2-7*x^2+2*x-1
 }
}



// считаем производные
void calculate(){

  for(int i=0;i<N;i++)  {
    float x=X[i];
    // первый. "проверочный способ"
    //f'(x)=15*x^2-14*x+2
    dY1[i]= 15*pow(x,2)-14*x+2;
    
    //метод конечной разности. 
    // для первой точки посчитать не можем, так как отсусвует предыдущая точка
    if(i>0)dY2[i]=(Y[i]-Y[i-1])/(X[i]-X[i-1]);
    
    //считем производную по трем точкам, поэтому "для первых двух" - посчитать не сможем
     if(i>1)dY3[i]= diff1( X[i-2],Y[i-2],  X[i-1],Y[i-1], X[i],Y[i]); // считаем первую производную по трем точкам
     
    // ==== вторые производные ===========
    
    //аналитический способ, для самопроверки
    ddY1[i]=30*X[i]-14;
    
    //второй способ, считаем как "производную от производной. поэтому считать можем начать только с пятой точки, 
    // до этого мы просто не знаем трех значение первой производной
    if(i>4) ddY2[i]=diff1(X[i-2],dY3[i-2],  X[i-1],dY3[i-1], X[i],dY3[i]); // считаем вторую производную. только вместо Y-ков даем dY3 которые посчитали раньше (первая производная третим методом)

    
  }

}

// первая производная по трем точкам. 
// (x,y) - точка в которой считаем производную
// (x1,y1) - предыдущая точка (на шаг назад)
// (x2,y2) - пред.предыдущая (на два шага назад)
float diff1(float x2,float y2,float x1,float y1,float x,float y){
  return (y2-4*y1+3*y)/(x-x2);
}


void  printTable(){
//  println("X \t\t Y \t\t f'(x) \t\t f'(x) \t\t f''(x)");
  println("X \t\t Y \t\t f'(x) \t\t f''(x) \t\t f''(x)");
   for(int i=0;i<N;i++){
     print(nfc(X[i],3));
     print(" \t\t "+nfc(Y[i],3));
     
     /*
     // Пока закоментим вывод первыми двумя способами "в работу" у нас пошел третий.
     print(" \t\t "+nfc(dY1[i],3)); // первый способ
     
     print(" \t\t "+nfc(dY2[i],3)); // второй способ
     print( " ("+ nfc(dY1[i]-dY2[i],3) +")" ); // выводим "ошибку", насколько отличается от расчетноего 
     
     
     */
     
     print(" \t\t "+nfc(dY3[i],3)); // теритий способ
 //    print( " ("+ nfc(dY1[i]-dY3[i],3) +")" ); // выводим "ошибку", насколько отличается от расчетноего 
 
     // выводим вторый производные
     print(" \t\t "+nfc(ddY1[i],3)); // первый способ
     
     print(" \t\t "+nfc(ddY2[i],3)); // второй способ
     print( " ("+ nfc(ddY1[i]-ddY2[i],3) +")" ); // выводим "ошибку", насколько отличается от расчетноего 
     
     println();
   }
   

}

 Резульатат таким:

X 		 Y 		 f'(x) 		 f''(x) 		 f''(x)
5,010 		 462,077 		 0,000 		 136,300 		 0,000 (136,300)
5,020 		 465,167 		 0,000 		 136,600 		 0,000 (136,600)
5,030 		 468,271 		 311,103 		 136,900 		 0,000 (136,900)
5,040 		 471,389 		 312,451 		 137,200 		 0,000 (137,200)
5,050 		 474,521 		 313,861 		 137,500 		 0,000 (137,500)
5,060 		 477,666 		 315,186 		 137,800 		 128,174 (9,626)
5,070 		 480,825 		 316,608 		 138,100 		 147,095 (-8,995)
5,080 		 483,998 		 317,969 		 138,400 		 133,057 (5,343)
5,090 		 487,184 		 319,367 		 138,700 		 141,602 (-2,902)
5,100 		 490,385 		 320,734 		 139,000 		 135,193 (3,807)

 

 

lev39
Offline
Зарегистрирован: 14.08.2012

Хорошо. Буду внимательно разбираться и крутить скетчи в Процесснге.

Будут проблемы - выдам SOS !

leshak
Offline
Зарегистрирован: 29.09.2011

lev39 пишет:

Хорошо. Буду внимательно разбираться и крутить скетчи в Процесснге.

Будут проблемы - выдам SOS !

Вы так и не ответили. Скетч который "свернут" вы смогли увидеть?

leshak
Offline
Зарегистрирован: 29.09.2011

 Теперь займемся "рефакторингом" (делаем код "более вменяемым", не меняя сути того что он делает):

  1. Выкинем всякие "способы" которые мы использовали для перепроверки. Оставим только один способ для первой производной (по трем точкам) и для второй (по трем первым производным).
  2. Избавимся от тучи массивов. Введем объек-класс DataPoint который будет представлять каждую точку (ее координаты и производные).
// наш класс для хранения данных и расчетов "в одной коробке"
class DataPoint{
   
   // входные данные
   float x;
   float y;
   
   
   // результаты расчетов
   float dY; // первая производная
   float ddY; // вторая производная
   
   // конструктор
   DataPoint(float X, float Y){
     x=X;y=Y;
     dY=0;ddY=0; // по умолчанию считаем производными равными нулю
   }
}



// наша главная, на данный момент, функция
void setup(){
  
  fillTestData(); // заполнили тестовые данные

  calculate(); // посчитали производные
  
  printAllTestData(); //вывели

  
}

// заполняем тестовые данные
final static int N=10; // размер нашей талицы данных
final static float STEP=0.01;
DataPoint[] TestDataPoints=new DataPoint[N]; // массив тестовых данных
void fillTestData(){


  
   //заполняем массив тестовыми данными
 for(int n=0;n<N;n++){
   float x=(n+1)*STEP+5;
   float y=5*pow(x,3)-7*pow(x,2)+2*x-1; // Y=f(x)=5*x^2-7*x^2+2*x-1
   
   TestDataPoints[n]=new DataPoint(x,y);

 }
}



// выводит все тестовые данные
void printAllTestData(){
  for(int i=0;i<TestDataPoints.length;i++)printDataPoint(TestDataPoints[i]);
}

// выводит одну точку
void printDataPoint(DataPoint p){
  println(
    "x="+nfc(p.x,3)
    + ";\t y="+nfc(p.y,3)
    + ";\t y'="+nfc(p.dY,3)
    + ";\t y''="+nfc(p.ddY,3)
    );
}

// первая производная по трем точкам. 
// (x,y) - точка в которой считаем производную
// (x1,y1) - предыдущая точка (на шаг назад)
// (x2,y2) - пред.предыдущая (на два шага назад)
float diff1(float x2,float y2,float x1,float y1,float x,float y){
  return (y2-4*y1+3*y)/(x-x2);
}


// считаем производные для тестовых данных
void calculate(){
  for(int i=2;i<TestDataPoints.length;i++){ // начинаем с третей точки, только она имеет "две предыдущие
  
    DataPoint p=TestDataPoints[i]; // текущая точка
    DataPoint p1=TestDataPoints[i-1]; // предыдущая
    DataPoint p2=TestDataPoints[i-2]; // пред.предыдущая
    
    // первая производная
    p.dY=diff1( p2.x,p2.y,  p1.x,p1.y,  p.x,p.y);
    
    // вторая производная
    p.ddY=diff1(p2.x,p2.dY,  p1.x,p1.dY,  p.x,p.dY); // для первых точек будет "врать", так как на вход поступят дефолтные нули первой производной.
   
  }
}

 

leshak
Offline
Зарегистрирован: 29.09.2011

 Продожим "причесывать" скетч. Вынесем все расчетную логику в отдельный класс DiffCalculator который будет считать производные и "запоминать" прошлые значения. Что-бы отвязать логику расчетов от использования таблицы TestDataPoints и можно было, в дальнешем работать с данными поступающими "откуда угодно".

Скетч: (что-бы увидеть его нажмите на "показать код". 

DiffCalculator calc=new DiffCalculator(); // наш калькулятор производных

// наша главная, на данный момент, функция
void setup(){
  
  fillTestData(); // заполнили тестовые данные

  // считаем и выводим тестовые данные
  for(int i=0;i<TestDataPoints.length;i++){
    DataPoint calculatedPoint=calc.CalculateDiffs(TestDataPoints[i]); // посчитали
    printDataPoint(calculatedPoint); // вывели
    
  }

  
}

// выводит одну точку
void printDataPoint(DataPoint p){
  println(
    "x="+nfc(p.x,3)
    + ";\t y="+nfc(p.y,3)
    + ";\t y'="+nfc(p.dY,3)
    + ";\t y''="+nfc(p.ddY,3)
    );
}



// ==================================   Описание классов ===============================


// наш класс для хранения данных и расчетов "в одной коробке"
class DataPoint{
   
   // входные данные
   float x;
   float y;
   
   
   // результаты расчетов
   float dY; // первая производная
   float ddY; // вторая производная
   
   // конструктор
   DataPoint(float X, float Y){
     x=X;y=Y;
     dY=0;ddY=0; // по умолчанию считаем производными равными нулю
   }
}



// этот клас будет может считать первую и вторую производную для точки, при этом "хранит в себе" две предыдущие, для расчетов
class DiffCalculator{
   private  DataPoint p=new DataPoint(0,0); // текущая точка
   private DataPoint p1=new DataPoint(0,0);; // предыдущая
   private DataPoint p2=new DataPoint(0,0);; // пред.предыдущая
   

   // возвращает точку с посчитанными производными (делае новые экземпляр точки)
   // и "запоиминает" ее для дальнеших вычисление
   public DataPoint CalculateDiffs(DataPoint inputPoint){

     // вначале "сдвигаем" старые точки
     p2=p1;
     p1=p;
     
     // запоминаем новую
     p=new DataPoint(inputPoint.x,inputPoint.y);
     
     // вычисляем производные
     calculate();
     
     return p; // возвращаем точку с посчитанными значениями
   }
   
   // считает производные для текущей точки
   //для первых точек будет "врать", так как на вход поступят дефолтные нули первой производной.
   private void calculate(){
      
     
     // первая производная
    p.dY=diff1( p2.x,p2.y,  p1.x,p1.y,  p.x,p.y);
    
    // вторая производная
    p.ddY=diff1(p2.x,p2.dY,  p1.x,p1.dY,  p.x,p.dY); 
   }
   
       // первая производная по трем точкам. 
    // (x,y) - точка в которой считаем производную
    // (x1,y1) - предыдущая точка (на шаг назад)
    // (x2,y2) - пред.предыдущая (на два шага назад)
    private float diff1(float x2,float y2,float x1,float y1,float x,float y){
      return (y2-4*y1+3*y)/(x-x2);
    }

}

// ==================================   Тестовый регион ===============================
// заполняем тестовые данные
final static int N=10; // размер нашей талицы данных
final static float STEP=0.01;
DataPoint[] TestDataPoints=new DataPoint[N]; // массив тестовых данных
void fillTestData(){

 //заполняем массив тестовыми данными
 for(int n=0;n<N;n++){
   float x=(n+1)*STEP+5;
   float y=5*pow(x,3)-7*pow(x,2)+2*x-1; // Y=f(x)=5*x^2-7*x^2+2*x-1
   
   TestDataPoints[n]=new DataPoint(x,y);

 }
}

 На всякий случай напоминю, что что-бы попробовать скетч у себя - не обязательно его "перенабирать руками".

Прочитайте http://arduino.ru/forum/obshchii/vstavka-programmnogo-koda-v-temukommentarii#comment-13011 сообщение #2

С этим подходом "попробовать скетч у себя" у вас займет 10-15 секунд.

leshak
Offline
Зарегистрирован: 29.09.2011

 Ну и последние "усилие". Отделим получение данных от логики главной программы.

Введем функцию getNextDataPoint() задачей которй будет "вернуть новую точку для расчета". Откуда она ее взяла, из тестовых данных или от ардуины -  будет знать только она. 

DiffCalculator calc=new DiffCalculator(); // наш калькулятор производных

// настройка
void setup(){
  // тут можно будет настроить размеры окна, открыть соединение с ардуиной ит.п.
}

// главный цикл программы, который получает, обрабатывает и выводит данные
void draw(){
  DataPoint newPoint=getNextDataPoint(); // получаем новую точку
  if(newPoint!=null){ // удалось получить
    DataPoint calculatedPoint=calc.CalculateDiffs(newPoint); // посчитали
    printDataPoint(calculatedPoint); // вывели
  };
  
  
}

// возвращает следующую точку для обработки.
// пока берет их "из тестовой таблицы"
// в конечном варианте будет получать их от ардуины
DataPoint getNextDataPoint(){
  if(TestDataPoints==null)fillTestData(); // если тестовые данные пусты - заполняем их
  
  if(currentTestIndex==N)return null; // больше нет тестовых данных, возвращаем "ничего".
  
  DataPoint newPoint=TestDataPoints[currentTestIndex]; // вернем эту точку
  currentTestIndex++; // увеличили индекс что-бы в следующий раз вернуть следующую точку
  
  return newPoint;
}



// выводит одну точку
void printDataPoint(DataPoint p){
  println(
    "x="+nfc(p.x,3)
    + ";\t y="+nfc(p.y,3)
    + ";\t y'="+nfc(p.dY,3)
    + ";\t y''="+nfc(p.ddY,3)
    );
}



// ==================================   Описание классов ===============================


// наш класс для хранения данных и расчетов "в одной коробке"
class DataPoint{
   
   // входные данные
   float x;
   float y;
   
   
   // результаты расчетов
   float dY; // первая производная
   float ddY; // вторая производная
   
   // конструктор
   DataPoint(float X, float Y){
     x=X;y=Y;
     dY=0;ddY=0; // по умолчанию считаем производными равными нулю
   }
}



// этот клас будет может считать первую и вторую производную для точки, при этом "хранит в себе" две предыдущие, для расчетов
class DiffCalculator{
   private  DataPoint p=new DataPoint(0,0); // текущая точка
   private DataPoint p1=new DataPoint(0,0);; // предыдущая
   private DataPoint p2=new DataPoint(0,0);; // пред.предыдущая
   

   // возвращает точку с посчитанными производными (делае новые экземпляр точки)
   // и "запоиминает" ее для дальнеших вычисление
   public DataPoint CalculateDiffs(DataPoint inputPoint){

     // вначале "сдвигаем" старые точки
     p2=p1;
     p1=p;
     
     // запоминаем новую
     p=new DataPoint(inputPoint.x,inputPoint.y);
     
     // вычисляем производные
     calculate();
     
     return p; // возвращаем точку с посчитанными значениями
   }
   
   // считает производные для текущей точки
   //для первых точек будет "врать", так как на вход поступят дефолтные нули первой производной.
   private void calculate(){
      
     
     // первая производная
    p.dY=diff1( p2.x,p2.y,  p1.x,p1.y,  p.x,p.y);
    
    // вторая производная
    p.ddY=diff1(p2.x,p2.dY,  p1.x,p1.dY,  p.x,p.dY); 
   }
   
       // первая производная по трем точкам. 
    // (x,y) - точка в которой считаем производную
    // (x1,y1) - предыдущая точка (на шаг назад)
    // (x2,y2) - пред.предыдущая (на два шага назад)
    private float diff1(float x2,float y2,float x1,float y1,float x,float y){
      return (y2-4*y1+3*y)/(x-x2);
    }

}

// ==================================   Тестовый регион, потом выкинем его ===============================
// заполняем тестовые данные
final static int N=10; // размер нашей талицы данных
DataPoint[] TestDataPoints; // тестовые даннные
int currentTestIndex=0;

void fillTestData(){
  

final  float STEP=0.01;

  if(TestDataPoints==null)TestDataPoints=new DataPoint[N]; // инициализируем массив

 //заполняем массив тестовыми данными
 for(int n=0;n<N;n++){
   float x=(n+1)*STEP+5;
   float y=5*pow(x,3)-7*pow(x,2)+2*x-1; // Y=f(x)=5*x^2-7*x^2+2*x-1
   
   TestDataPoints[n]=new DataPoint(x,y);

 }
}

 Ну вот. По прежнему думаете что у вас "другая задача"?  Теперь достаточно заменить функцию getNextDataPoint() так что-бы данные она получала из ардуины, а не готовой таблицы и задача будет выглядить как "вылитая ваша"? :) Уже проглядывается?  Ну и выкинуть, в финале "Тестовый регион".

 

 

leshak
Offline
Зарегистрирован: 29.09.2011

Теперь пришло время опять "оглядеть задачу целиком".

leshak пишет:

Что-бы от "лирики" перейти к "конкретике" давайте выясним с какой же частью проекта вы испытываете затруднения:

  1. Как это все регистрировать-отсылать из Arduin-ы
  2. Как это принимать на процессинге
  3. Как обрабатывать дискретные данные (считать производные)
  4. Как все это вывести на экран

Пункт 3 мы вроде как выполнили (жду от вас подтвержения).

Какой пункт пойдет "следующим на реализацию"? Справитесь сами или тоже есть затруднения?

 

lev39
Offline
Зарегистрирован: 14.08.2012

Добрый вечер. Мне уже неудобно. Я отнял у Вас кучу времени. Я думал, что все намного проще.

Свернутые скетчи я конечно увидел сразу как пришел на форум.

А теперь, дайте мне время. Ваш темп я просто не выдерживаю. Я попробую на днях разобраться сам во всем что Вы мне написали. Сейчас совсем нет времени, идет подготовка к новому учебному году - кабинет, куча бумаг, дали новую интерактивную доску, систему для голосования ( тестирование учащихся в режиме on-line)  и т.д. и т.л..

О всех результатах, как положительных, так и отрицательных, которые у меня появятся -  сообщу на форуме.

Если получится, то на первых уроках в 10 классе запущу скетч на уроках, где пойдет речь о пути, скорости и ускорении.

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

 

AlexFisher
AlexFisher аватар
Offline
Зарегистрирован: 20.12.2011

lev39 пишет:

А теперь, дайте мне время. Ваш темп я просто не выдерживаю. Я попробую на днях разобраться сам во всем что Вы мне написали. Сейчас совсем нет времени, идет подготовка к новому учебному году - кабинет, куча бумаг, дали новую интерактивную доску, систему для голосования ( тестирование учащихся в режиме on-line)  и т.д. и т.л..

Нет, надо успевать, "гонка за лидером" - это такой вид спорта, когда если отстал - то отстал навсегда :)

2 leshak - респект!!! Мне было очень интересно. Думаю, не мне одному :) У меня не нашлось столько времени, чтобы из имеющихся материалов сварить кашу ;) А тема сама-по себе интересная.