Вопрос по функции map

vvadim
Offline
Зарегистрирован: 23.05.2012

Функция map линейная. A какие есть возможности для создания нелинейной функции и как это делается.

Допустим по синусоиде от мин до макс.

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

Свою функцию преобразования написать ну так сложно, что просто пипец. Наверное кто то уже написал функцию которая возвращает то, что мне нужно. Как такой нет? Уфф, натуральное УГ.

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

kisoft пишет:
Свою функцию преобразования написать ну так сложно, что просто пипец.

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

А если, все-таки, потребуется "свою писать", то  "искать готовое" - не такая уж и плохая привычка.

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Любая нелинейная функция подразумевает написание своего алгоритма преобразования. Не согласны? Переубеждать не буду.

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

kisoft пишет:
Любая нелинейная функция подразумевает написание своего алгоритма преобразования. Не согласны? Переубеждать не буду.

А сможете? Вот я дал ссылку на функцию sin(). Которая не линейна. И не требует написание своего алгоритма преобразования. Если под условия задачи она пременима, то и дело с концом.Только не нужно расказывать что "внутри у нее алгоритм". Речь шла именно про "написание своего".

А если вспомнить еще, что бывает функциональное програмирование (и даже функциональные языки) и что "алгоритмическое мышление" не единственно возможное при решении задач (даже на C++).... Или познакомтесь, к примеру, с таким языком как Prolog. Там "алгоритмическое мышление" и попытки думать алгоритмами, а не предикатами - будет только мешать.

Так что осторожней со словом "любая".

kisoft
kisoft аватар
Offline
Зарегистрирован: 13.11.2012

Хотите скучать с синусом - не вопрос

vvadim
Offline
Зарегистрирован: 23.05.2012

Может я не совсем правильно сформулировал вопрос.

Читаю данные с потенциометра и перевожу через map в нужные мне параметры. Перевод идёт как линейная функция. 

val = map(val, 0, 1024, 650, 2400);

Меня интересует как сделать так, чтобы значения от 650 до 2400 менялись по логарифмической и обратнологарифмической шкале. Про синусоиду спросил как пример.

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

Правильно сформулированный вопрос содержит 70% ответа.

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

Если трудно, поможем. Но нужно давать больше исходных данных. Например, нужно знать, какая функция у Вашего резистора (она может быть не только линейной, но и логарифмической, обратнологарифмической, s-образной). В самом простом варианте Вам нужно написать "у меня в крайних положениях столько-то, в среднем столько-то, а нужно столько и столько" - то есть для задания логарифмической функции достаточно 3-х точек.

Andrey_Y_Ostanovsky
Offline
Зарегистрирован: 03.12.2012

AlexFisher пишет:

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

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

У товарища родственник работал инженером на "большой ЭВМ" и ему отдавались исходные тексты, а он приносил нам распечатки с результатами, все шло хорошо до того момента, пока мы не начали вводить реальные данные температур кипения компонентов, которых оказалось катастрофически мало (3-4 точки). Родственник посмотрел и сказал: "фигня это ваше по трем точкам, мы их сейчас рядами Фурье сведем с точностью до третьего знака после запятой"... Свели, после этого программа стала вылетать с сообщением "попытка деления на ноль". Сломали всю голову, пока кому-то на ВЦ не пришла умная мысль: вывести "кривую", рассчитанную рядами Фурье, на плоттер - получили даже не синусоиду, а частокол значений с переходом в некоторых местах ниже нуля... Этот случай показывает, что методы апроксимации надо очень внимательно выверять, иначе можно получить непредсказуемый результат.

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

Все зависит от точности исходных данных и необходимой точности результата. Резистор может оказаться весьма далек от заявленной характеристики, но мы же не смотрим на это, используя функцию map(), которая считается всего по двум точкам.

А топикастеру может даже и логарифма много, наверняка можно обойтись кусочно-линейной функцией на 2-3 диапазона - и памяти мало съест и вычисляться будет быстро.

Не пугайте его рядом Фурье :)))

vvadim
Offline
Зарегистрирован: 23.05.2012

Да, рядов Фурье и прочих незнакомых премудростей я боюсь. Но я и как сделать кусочно-линейную функцию не знаю.

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

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

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

vvadim пишет:

Да, рядов Фурье и прочих незнакомых премудростей я боюсь. Но я и как сделать кусочно-линейную функцию не знаю.

ну простейший вариант - два массива.

В один ложим X-сы, в другой Y-ки.

Когда потом, когда нам нужно  что-то конвертнуть - бежим по X-сам, смотрим в какой диапазон попадает наше значение и возвращаем соотвествующие ему и Y-ков.

Примерно так:

int X[]={2,5,7,12} ; // диапазоны входных значений
#define TOTAL sizeof(X)/sizeof(int) // подсчитываем сколько у нас диапазонов
int Y[TOTAL]={10,50,70,200}; // диапазоны выходных


// value=...-1,0,1,2  -> 10
// value=3,4  -> 50
// value=5,6  -> 70
// value=7,8,9,10,11  -> 200
// value=12,13,14.... ->200

int tabledMap(int value){
  
  // ищем подходящий диапазон
  for(byte i=0;i<TOTAL;i++){
    if(value<=X[i])return Y[i];  
  }
  
  return Y[TOTAL-1]; // если больше чем наши диапазоны - возвращаем последнее
}

Не проверял, но идея думаю ясна.

vvadim
Offline
Зарегистрирован: 23.05.2012

Спасибо. Попробую на милиметровке прорисовать кривую и снять значения.

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

Нет, не совсем. Это не кусочно-линейная, а табличная функция (моя очередь занудствовать). Вот примерно то, что я имел в виду:

Функция примерно такая:

int droplin(int x)
{
  if (x<512) return map(x, 0, 512, 0, 8);
  else return map(x, 512, 1024, 8, 10);
}

 

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

AlexFisher пишет:

Нет, не совсем. Это не кусочно-линейная, а табличная функция (моя очередь занудствовать). Вот примерно то, что я имел в виду:

Я знаю, но я показывал "идею", а не "конечную реализацию" :) Так как на "идее" можно построить уже различные реализации (в зависимости от того что же именно нужно ТС).  Думаю поняв идею "таблицы", добавить к ней "линейность" уже не составить труда, вместо

return Y[i]

return Y[i], делать что-то типа

return map(value,X[0],X[TOTAL-1],Y[i-1],Y[i]); 

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

vvadim
Offline
Зарегистрирован: 23.05.2012

Попробовал пример в посте #15 -  вполне устраивает.  И  для меня , как слабенького программиста, очень даже понятно.

Спасибо.