помогите с функцией сдвига массива

ku-ku
Offline
Зарегистрирован: 14.11.2018

Нарыл код для циклического сдвига массива. То есть было 1-2-3-4, сдвинули на единицу, получили 4-1-2-3

Программер из меня паршивый. Накидал для проверки такой вот код:

int shiftingArray[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

int sizeOfArray = 10;
int shiftingPoint = 1;


void shiftk(int *shiftingArray, int n, int k) {

  if (n <= 1)     // Degenerated case
    return;

  // Reduce k to the interval 0..n-1
  // using the periodicity
  k %= n;
  if (k == 0)
    return;

  if (k < 0)  // Shift to the left on k
    k += n; // == shift to the right on n-k

  int i = 0;  // Index of the first element of orbit
  int nod = gcd(n, k);
  while (i < nod) {   // Loop for each orbit
    //   i is the first element of orbit
    int j = i - k;  //   j is the last element of orbit
    if (j < 0)
      j += n;
    int x = shiftingArray[j];   // Save the value of the last element of orbit

    while (j != i) { // Loop for each element j of orbit
      int l = j - k; //    l is the previous element to j
      if (l < 0)
        l += n;
      shiftingArray[j] = shiftingArray[l]; //    copy previous element to current
      j = l;       //    go to the previous element
    }
    shiftingArray[i] = x;        // copy the last element of orbit to the first
    ++i;             // go to the next orbit
  }
}

int gcd(int x, int y) {
  while (y != 0) {
    int r = x % y;
    x = y; y = r;
  }
  return x;
}


void setup() {
  Serial.begin(115200);
}

void loop() {
  int r = random(-9, 9);

  shiftk(shiftingArray, 10, r);
  for (int z = 0; z < 10; z++) {
    Serial.print(shiftingArray[z]);
    Serial.print(", ");
  }
  Serial.print("   shift by: ");
  Serial.println(r);
  delay(1200);

  for (int k = 0; k < 10; k++) {  //return to basic order
    shiftingArray[k] = k + 1;
  }
}

Коротко - задаем массив значений подряд,  от 1 до 10-ти. Потом сдвигаем его на рандомное количество шагов либо влево, либо - вправо. Ну и серем в ком-порт сдвинутым массивом и значением сдвига.

Все работает! Вывод идет как надо:

1, 2, 3, 4, 5, 6, 7, 8, 9, 10,    shift by: 0
4, 5, 6, 7, 8, 9, 10, 1, 2, 3,    shift by: -3
3, 4, 5, 6, 7, 8, 9, 10, 1, 2,    shift by: 8
7, 8, 9, 10, 1, 2, 3, 4, 5, 6,    shift by: -6
7, 8, 9, 10, 1, 2, 3, 4, 5, 6,    shift by: 4
4, 5, 6, 7, 8, 9, 10, 1, 2, 3,    shift by: 7
6, 7, 8, 9, 10, 1, 2, 3, 4, 5,    shift by: 5
10, 1, 2, 3, 4, 5, 6, 7, 8, 9,    shift by: 1
9, 10, 1, 2, 3, 4, 5, 6, 7, 8,    shift by: -8
8, 9, 10, 1, 2, 3, 4, 5, 6, 7,    shift by: 3
8, 9, 10, 1, 2, 3, 4, 5, 6, 7,    shift by: 3
7, 8, 9, 10, 1, 2, 3, 4, 5, 6,    shift by: 4
4, 5, 6, 7, 8, 9, 10, 1, 2, 3,    shift by: 7
2, 3, 4, 5, 6, 7, 8, 9, 10, 1,    shift by: -1

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



void shiftk(int *shiftingArray, int n, int k) {

Я не совсем понимаю указатели и прочие высокие вещи. Могут ли быть грабли из-за этого принципа ссылочности на массив (или как там это правильно сказать)? - вот в чем вопрос!

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

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

Сам алгоритм сдвига - отсюда, лекция 6
 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015
ku-ku пишет:
что за вот та звездочка перед массивом при вызове  shiftk?
Ответ есть по Вашей же ссылке - лекция 4.
 
b707
Offline
Зарегистрирован: 26.05.2017

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

ku-ku
Offline
Зарегистрирован: 14.11.2018

кольцевой буфер для меня - более страшно, чем указатели )

А есть пример простой, для дошкольников? )

ku-ku
Offline
Зарегистрирован: 14.11.2018

ЕвгенийП пишет:
Ответ есть по Вашей же ссылке - лекция 4.

а без указателей - никак?

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Ну, почему никак? Можно индексами.

ku-ku
Offline
Зарегистрирован: 14.11.2018

пытался прямо скормить массив, но компилятор обызвается (

Как его обмануть? (добвить себе ума - не предлагать, то моветон )) )

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

Правильный: самый простой и самый быстрый вариант Вам предложили - кольцевой буфер.

ku-ku
Offline
Зарегистрирован: 14.11.2018

Там дело в следующем: используется FastLED. В loop идет непрерывная функция засветки ленты. Процедуры там себе чего-то считают, шевелят цветом и яркостью, а она - постоянно выводит что имеется (насколько я понимаю).

Я пробовал вызывать сдвиг непрерывно, рядом с FastLED.show - на ленте ахинея по итогу.

Щас сделал сдвиг каждые shiftEvery-секунд:

if ( millis() > shiftTimeout) {  //коль пришла пора
    shiftThem(coordsHeat, 35, 1);  //двигаем наши 35 значений на единичку
    shiftTimeout = millis() + (shiftEvery * 1000);
}

И хоть я задаю shiftEvery единицей, хоть сотней (динамически есть возможность), то на ленте все равно ахинея.

Сама процедура, которая использует массив, насколько я понимаю, она ведь сначала нагенерит чего ей положено и после должен идти сдвиг.

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

Непойму из-за чего этот сыр-бор.

Массив объявлен перед всеми функциями, я так понимаю виден отовсюду. Мож из-за этого беда?

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

b707
Offline
Зарегистрирован: 26.05.2017

ku-ku пишет:

кольцевой буфер для меня - более страшно, чем указатели )

А есть пример простой, для дошкольников? )

Пример для дошкольников

Есть массив с десятью элементами от 0 до 9. Начало этого массива, очевидно - элемент 0

Потом вам приходит команда "подвиньте массив влево на 3 позиции". - Но вы хитрый, вы ничего не двигаете. Вы просто запоминаете -теперь у меня начало массива на позиции 3. И когда вам придет команда "выдайте нам массив на печать" - вы напечатаете массив, как он есть, без копирований элементов -  только начнете не с элемента 0, а с элемента 3. Потом 4, 5. 6... Главное - отслеживать конец массива. Как дошли до последнего элемента - перешли к нулевому и продолжаете, пока не напечатаете все 10.

Понятно?

 

b707
Offline
Зарегистрирован: 26.05.2017

ku-ku пишет:

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

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

sadman41
Онлайн
Зарегистрирован: 19.10.2016

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

А грабли вы себе, скорее всего, находите потому что в фастледе цвет задается не int-ом, соответсвенно - сдвигаете с нарушением разрядности числа. Сделайте сдвиг на 2, к примеру.

UPD: со сдвигом на 2 тоже не выйдет, там массив трехбайтовых структур используется.

ku-ku
Offline
Зарегистрирован: 14.11.2018

b707 пишет:

 Как дошли до последнего элемента - перешли к нулевому и продолжаете, пока не напечатаете все 10.

Понятно?

понятно-то понятно! Но был бы я кодером.... Ладно, то уже маловажно!
Суть в том, что я пока что лишь приобщаюсь к коду. Я беру готовый проект и пытаюсь его слегка поменять. Оттуда кусочек сюда - и мне радость )

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

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

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

Беру готовую процедуру и говорю - ты, милая, считай на половинку ленты! Она себе считает! А я беру, и просто копирую каждый кадр на вторую половинку ленты, да еще и отзеркалив. А могу и не зеркалить, и не на половинку, а на всю! Да еще и когда захочу или в зависимости от погоды на Марсе!

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

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

 в фастледе цвет задается не int-ом, соответсвенно - сдвигаете с нарушением разрядности числа.

та я и юинты пробовал ) Спасибо, камрад! Первым делом я его CRGB, конечно, пытался пошевелить. Но там засада сразу!

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

Но и тут - облом вышел (

кстати, если чо - со мной можно на "ты". То вас - много, а я bool (еще и false, похоже :D )

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

Или я чего не понимаю, или - тривиальный linked list, реализация на С++ гуглится минут за пять. И не надо ничего никуда двигать - просто перемещай указатель чтения туда-сюда на сколько нужно позиций, и всё.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Вобщем, той функцией, что в первом сообщении двигать только массивы 2-байтных чисел можно. Для фастледа ее или переписывать под CRGB или на memmove заменить.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Фастлед со списками не работает, у него массив из структур применяется для задания цветов пикселей. На show() он тупо выстреливает его битстримом в страйп и был таков. 

Просто человек решил применить методику из интернетов без учета специфики используемой библиотеки.

ku-ku
Offline
Зарегистрирован: 14.11.2018

подумалось, а как быстро оно мне массив сдвинет? Можете подсказать кто-нибудь!

Судя по ТТХ алгоритма,  оно занимает

т.е. всего число операций копирования равняется длине массива плюс число орбит:
     num = n + gcd(n, k)
В частности, если числа n и k взаимно просты, то число копирований равно n+1

А сколько это циклов процессора или как там правильно сказать это займет, допустим для массива в сотню элементов и сдвигом на единичку (раз в секунду)? Моя лента работает на 800КГц. А сколько примерно от этого отожрет сдвиг массива? Хоть примерно?

На ESP встроенная функция подсчета fps для анимации показывает ~200. То есть 200 кадров она генерит примерно. Понятное дело, что это не совсем правильно соотносить частоту работы микрух в диодах и кадры, да еще и со сдвигом, но в целом - сильно много оно отжирает процессорного времени?

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

Фастлед со списками не работает...

Просто человек решил применить методику из интернетов без учета специфики используемой библиотеки.

несовсем верно! Я его решил применить в специфическом ракурсе. Я не встроенные массивы шевелю, а координаты.

вот берем известную готовую процедурку:

void sinelon1(){
  fadeToBlackBy( leds, NUM_LEDS, 20);
  int pos = beatsin16(13*256, 0, NUM_LEDS);
  leds[hitriyOrder[pos]] += CHSV( gHue, 255, 192);

Которая использует заранее заданные координаты из массива:

uint8_t hitriyOrder[NUM_LEDS] = { 0, 158, 60, 218, 120, 23, 181, 83, , 87, 244, 147, 49, 207, 110, 12, 239, 142, 44, 202}

И я (теоретически, по факу тут нет смысла) могу сдвигать эту анимацию по ленте.

Это не самый лучший пример! Я лишь показать вариант применимости.  Я пробовал на примере процедуры огня. Хотел, чтобы он у меня бродил по ленте. Там ведь начало светится постоянно, а "языки" пламени наверху - периодически. И если бы двигать его по ленте, которую свернуть в кольцо - должно бы выглядеть неплохо! Но, ума не хватает, сдвиг массива координат не пашет как надо, а буферы и мемсеты - то для меня сильно мудро.

Ладно, благодарю за помощь, камрады ;)

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Оно - это что? А вообще - в ардуине есть micros(). Запомнил текущее значение, цикл из тыщи функций копирования прокрутил, вычел из конечного времени начальное и поделил на кол-во циклов. Результат - в Serial вывел. Вот и будет самая, что ни на есть правдивая информация о быстродействии. 

Одно скажу - на елку хватает мощи у 328-го МК для 50-60 фпс вместе с IR-управлением.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

ku-ku пишет:
число операций копирования равняется длине массива плюс число орбит:
Та-а-ак! Понеслась ... по кочкам! :))))

sadman41
Онлайн
Зарегистрирован: 19.10.2016

В модифицированной известной процедуре проще random применять, как мне кажется - эффект тот же ;)

Logik
Offline
Зарегистрирован: 05.08.2014

ku-ku пишет:

А сколько это циклов процессора или как там правильно сказать это займет, допустим для массива в сотню элементов и сдвигом на единичку (раз в секунду)?

В грубой оценке - десяток тактов на байт. При 16МГц считайте грубо 1мксек на байт. Итого сотня мксек плюс/минус лапоть разумеется

ku-ku пишет:

 Моя лента работает на 800КГц. А сколько примерно от этого отожрет сдвиг массива? Хоть примерно?

 

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

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

на елку хватает мощи у 328-го МК для 50-60 фпс

та то я в курсе! ) копирование это - сильно тугое или нет? Вон, уже ответили, спасибо! Вроде не сильно тупое, раз в секунду для анимаций типа "пускать сопли из точки" - юзать можно! Как сопля приземлилась - двигаем!

Надо грызть гранит дальше! А зубки-то уже не те! Об фотошопы с иллюстраторами и прочей прикладнючестью всё пообламал. Тогда с полуслова понимал, сейчас с этим программированием - ниче не задерживается (

Но кой-чего таки впитал!

ku-ku
Offline
Зарегистрирован: 14.11.2018

Logik пишет:

как выпихнули - пауза

а как узнать что оно невыпихует? на FastLED'е реально? или там хитрые обработчики писать нужно?

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

В модифицированной известной процедуре проще random применять, как мне кажется - эффект тот же ;)

та то ж код не рабочий, а абы-було! Я скопипастил, да выкинул побольше лишнего, чтобы экран не загромождать читающим. Это я проект один мучал, а там своя математика филотаксиса. И координаты проще просчитать заранее и задать в массиве, чем вычислять налету!

https://www.youtube.com/watch?v=PDc_siO9afY вот он! много крови попил, но я раздуплил как он координаты считал и сделал на 200 диодов)) (могу и больше, но оно и 200- оверпрайс вышел)

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Знатная гипножаба.

Про обработчики непонятно - что имеется в виду? Считайте, что МК однозадачный - или готовит данные или посылает. Чем быстрее готовит, тем чаще посылает. Отседа и FPS. И узнавать там про отправку нечего - пока все не уйдет, новая сцена считаться не начнет.

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

 И узнавать там про отправку нечего - пока все не уйдет, новая сцена считаться не начнет.

вот про эту отправку и хотел уточнить )

Я думал, что оно постоянно передает. Понятное дело, что там нет мультизадачности, но в целом, мол параллельно почти идет расчет процедур и вывода на ленту.

А Вы не в курсе, FastLED.show там флагов никаких не поднимает, мол "порция ленте скормлена, жду добавки"?

Можно как-то снаружи увидеть, что оно закончило ленту дергать и решило передохнуть, чтобы в этот момент заняться своими черными делами? Вплоть до того, чтобы заставить его подождать. Хотя там окошко мизерное, но для общего развития интересно )

DIYMan
DIYMan аватар
Offline
Зарегистрирован: 23.11.2015

ku-ku пишет:

А Вы не в курсе, FastLED.show там флагов никаких не поднимает, мол "порция ленте скормлена, жду добавки"?

Чой-то сходу ничего подобного не видно:

void CFastLED::show(uint8_t scale) {
	// guard against showing too rapidly
	while(m_nMinMicros && ((micros()-lastshow) < m_nMinMicros));
	lastshow = micros();

	// If we have a function for computing power, use it!
	if(m_pPowerFunc) {
		scale = (*m_pPowerFunc)(scale, m_nPowerData);
	}

	CLEDController *pCur = CLEDController::head();
	while(pCur) {
		uint8_t d = pCur->getDither();
		if(m_nFPS < 100) { pCur->setDither(0); }
		pCur->showLeds(scale);
		pCur->setDither(d);
		pCur = pCur->next();
	}
	countFPS();
}

 

sadman41
Онлайн
Зарегистрирован: 19.10.2016

ku-ku пишет:

вот про эту отправку и хотел уточнить )

Я думал, что оно постоянно передает. Понятное дело, что там нет мультизадачности, но в целом, мол параллельно почти идет расчет процедур и вывода на ленту.

Передает всё сразу, когда вызовут. Никаких вычислений, пока из функции не вернется управление, МК делать не будет.  Ритмичность вызова show() определяете самостоятельно в соответствии со сценой. Если на елке огоньки бегут со сдвигом на позицию раз в секунду - вызываете show() раз в секунду, чаще смысла нет никакого. В перерывах можно майнить.

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

вызываете show() раз в секунду, чаще смысла нет никакого. В перерывах можно майнить.

ну сколько проектов я перечитал на этой либе (а из годных, наверно все и еще трошечки)  и сколько перепробовал, то будь там вызов FastLED.show в самой процедуре анимации, или в loop, то разницы особо нема.

Мож канеш из-за моих слабых пониманий процессов я не так понимаю, но судя по своему опыту, разницы особо нет.

Вот та "гипножаба": там вывод на ленту идет в лупе ну и прочий перебор анимаций, палитр и прочего. Так вот, на сотне диодов на ESP оно давало ~210 fps, а когда расширил до двух сотен, то фпс упал вдвое. Это не отразилось на отображении анимаций. Ну, на визуальном восприятии. Так что если оно чрезмерно много фпс генерит, то это не особо страшно.

Кстати, я настолько непонимаю как работает контроллер, что для меня остается загадкой как это одни и те же процедуры одинаково отображаются что на ардуине, что на более шустром ЕСП. Совпадение? Ну, то есть ЕСП там еще и нутрянокй управляет и остается почти как в голой ардуине под пользу?

ФПС больше, а скорость анимации на вид - почти одинаковая. Вот щас задумался ) Вроде должны метеорчики во много раз быстрее бегать, ан-нет! Молодец Крейгсман, годную либу запилил )

upd: майнить нельзя, это подрывает обороноспособость страны! ))

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

Никаких вычислений, пока из функции не вернется управление, МК делать не будет. 

правильно ли я понимаю, что если: у меня вывод на ленту идет в луп. Если я этот вывод на ленту запилю в отдельную процедуру, оставив в лупе на том месте вызов той самой отдельной процедуры, то после вывода на ленту я могу двигать массив, и это не отобразится во время сдвига на ленте никак?

Или каким образом можно гарантировано что-то делать, чтобы это действие не пришлось на момент вывода на ленту? Вызывать FaslLED.show в отдельной процедуре, и после него в той же процедуре творить свои делишки?

sadman41
Онлайн
Зарегистрирован: 19.10.2016

Еще раз: МК - однозадачный. Если идет вывод на страйп - ничего более из пользовательского кода гарантированно не исполняется. Как только вывод закончен и управление передано обратно из функции show() - можете крутить CRGB-массивом, как хотите и в течении любого времени. Трансформировали его под новую сцену - вызвали show(), которая зашлет в контроллеры пикселей новые цвета.  

Вызывать show() можете в любой процедуре - хоть в лупе, хоть в сетапе, хоть в superEffect(). Задача этой функции - выкинуть в страйп данные.  Перемешиваете несколько раз CRGB-массив, но не вызываете show() - картинка не обновляется. Вызвали - на ленту ушла последняя модификация.

Смысла лупить в страйп избыточный FPS нет никакого. Чем быстрее ваша функция модифицирует массив - тем больший потенциальный FPS можете получить, сразу вызывая за ней show(). Но нужен ли FPS 200, если вы не пчела - вопрос философский.

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

Но нужен ли FPS 200, если вы не пчела - вопрос философский.

нужен! А чего ж не нужен, если он есть. В луп его засадил, и пусть работает!

А ты знай себе - пиши процедуры засветки!

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

Не для спору пишу. Просто так уже заведено. Не изменять же специально! Но Ваше пояснение мне добавило экспириентса, честно! теперь я более четко понимаю вывод, более уверен в нем! Спасибо Вам и всем, всем, всем!

ku-ku
Offline
Зарегистрирован: 14.11.2018

Если позволите, камрады, то чтобы не плодить новые темы - объясните, пожалуйста, о битовых сдвигах!

Вот процедура:

CRGB Color( uint8_t temperature) {
  CRGB color;  // Scale 'heat' down from 0-255 to 0-191, which can then be easily divided into three
  // equal 'thirds' of 64 units each.
  uint8_t t192 = scale8_video( temperature, 192);
  // calculate a value that ramps up from zero to 255 in each 'third' of the scale.
  uint8_t heatramp = t192 & 0x3F; // 0..63
  heatramp <<= 2; // scale up to 0..252
  // now figure out which third of the spectrum we're in:
  if ( t192 & 0x80)
  {    // we're in the hottest third
    color.b = 255; // full red
    color.r = 255; // full green
    color.g = heatramp; // ramp up blue
  }  else if ( t192 & 0x40 )  {
    // we're in the middle third
    color.b = 255; // full red
    color.r = heatramp; // ramp up green
    color.g = 0; // no blue
  }  else  {    // we're in the coolest third
    color.b = heatramp; // ramp up red
    color.r = 0; // no green
    color.g = 0; // no blue
  }  return color; }

В ней идет деление на три куска и кускам назначается цвет!

Можно ли тут задать 4 или 5 кусков и как делать сдвиг на другие значения?

Я выделил строки, которые мне крайне непонятны. Читал про битовый сдвиг, но не особо понял. Мож у кого есть годная ссылка, где объяснено поближе к этому примеру, чтобы понятней было? Притом сдвиг вроде делают как >> или <<, а тут логическим И, да еще и сдвигают десятичное - двоичным. Нипанятна!

Спасибо! не сочтите за офтоп.

sadman41
Онлайн
Зарегистрирован: 19.10.2016

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

Берется некий индекс "жары" и для него вычисляется цвет, соответствующий ощущению температуры. Например - для высокого уровня жары берется full red + full green (кстати, индексы в структуре под другую цветовую модель - в моем фастледе они соответствуют комментариям), что дает full yellow. Потом, через подмешивание blue цвет начинает выводится в full white. Т.е. на максимальном жаре сформируется белый цвет. Сдвигом тут реализовано "усиление" цвета вчетверо, т.е. с 63 он увеличивается до 252, что дает full blue и, при последующем подмесе, - full white. Остальные варианты смешивают цвета как-то иначе. Тут я не копенгаген. Здесь есть картинки со спектрумом, может они пояснят принцип: https://github.com/FastLED/FastLED/wiki/Pixel-reference

Разбиение же устроено следующим образом:

1) N = 0..255 масштабируется к N = 0..191, потому что 192 делится на три без остатка, т.е. удобно три группы разбиения сформировать
2) N & 63 => B00111111 - этот фокус мне непонятен
3) Положим, что N вышло 63, 63 * 4 = 252 => B00111111 << 2 => B11111100 - усиливаем один раз, чтобы не делать это в каждой ветке if-а
4) 252 & 0x80 => B11111100 & B10000000 => B10000000 - максимальный жар
5) 252 & 0x40 => B11111100 & B01000000 => B01000000 - средний жар
6) остальные варианты - малый жар

 

 

andriano
andriano аватар
Offline
Зарегистрирован: 20.06.2015

ku-ku пишет:

объясните, пожалуйста, о битовых сдвигах!

...

Я выделил строки, которые мне крайне непонятны.

Из четырех выделенных строк три не имеют к битовым сдвигам никакого отношения.

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

Возьмите какое-либо число, запишите его в клеточки внутри колонки в двоичном виде.

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

Вообще, логический сдвиг влево эквивалентен операции умножения на степень двойки. Т.е. сдвиг на 1 эквивалентен умножению на 2^1, сдвиг на 2 эквивалентен умножению на 2^2, на 3 - умножению на 2^3 и т.д. Разумеется, с потерей разрядов, выходящих за пределы разрядности числа.

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41, кажись я понял твой ник: многие знания - многие печали, да? ))

Пасиб! четко рассказал!

Как я понял из буржуйских пояснений, этот хётмап - что-то типа индекса цвета в инфракрасном изображении. Ну как на видео, когда чучмеков по пустыням гоняют с вертолетов. Там, канеш, градации серого, но в кино прикрашают цветным.

Далее, фастлед умеет интерполировать промежутки! Задаем : начало - белый, середина - синий, конец - красный. И фастлед автоматом нам сгенерирует градиент от белого в синий и после в красный.

Мне, собственно, нужно сделать хётмап, но не для красного, а для синего. Попробовал тупо объявить последовательность при инициализации не GRB (как у 2812), a BGR. Если в картинке огня переназначить таким образом цвета - я получаю примерно то, что мне нужно.

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

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

Ладно, что ж, попробую это победить )

Спасибо, ребята, за разъяснения. Стало чуть понятнее колдовство!

ku-ku
Offline
Зарегистрирован: 14.11.2018

andriano пишет:

Из четырех выделенных строк три не имеют к битовым сдвигам никакого отношения.

А Вы ждали, чтобы малограмотный человек четко обозначил Вам "диагноз" своих непоняток?

Ну да, не сдвиг, а булева алгебра. А может и еще что-то такое. Я для того и спрашиваю, что не совсем понятно что там за шаманство!

Спасибо за потраченное время, не обессудьте, я признателен за Ваши пояснения. Но от них мало проку. sadman41 понял о чем речь и пояснил более полезно! Мне и без сдвигов нужно в голову многое накласть, боюсь даже устану сильно, а тут еще и Ваша наука ))

sadman41
Онлайн
Зарегистрирован: 19.10.2016

ku-ku пишет:

Мне, собственно, нужно сделать хётмап, но не для красного, а для синего. Попробовал тупо объявить последовательность при инициализации не GRB (как у 2812), a BGR. Если в картинке огня переназначить таким образом цвета - я получаю примерно то, что мне нужно.

Может Fire2012WithPalette что-то подскажет. В принципе - тоже на индекс "жары" повязано, только цвета из палитры берутся. Там уже математика не попортит картинку.

Некоторые вещи мне приходилось через CHSV делать, а потом его уже в CRGB гнать. Накладно (двойной объем данных держать), но профит есть - например повышение яркости/оттенка с черного до заданного делается элементарно. В CRGB устанешь вычисления проводить и, порой, артефакты на некоторых оттенках всё равно проскакивают.

ku-ku
Offline
Зарегистрирован: 14.11.2018

sadman41 пишет:

Может Fire2012WithPalette что-то подскажет.

та я его уже примудрил )) даже нашел способ как вот те Gradient Color Palette засунуть и использовать в виде простого CRGBPalette16.

Даже цветовые профиля прикрутил на всякий случай )) Могу в любое время поставить галогенку, флуорисцентку или еще какой-то цветовой профиль из 20-ти имеющихся. Оно ж когда коту делать нечего - он яйцы лижет! А я прикручую всякий мотлох, который в состоянии прикрутить, а вдруг чего полезного с него выйдет )

Если бы палитры можно было бы динамически изменять, чтобы наблюдать результат, то это было бы здорово. Там я бы себе быстро подобрал бы. Но я не могу так сделать, поэтому через костыльки подбираюсь к решению задачи )) Даже делал разные процедуры, чтобы можно было задать 4-хцветную палитру и динамически менять цвета на каждой позиции. Но в идеале еще и позицию самой позиции цвета нужно менять! Ну, то есть половина чтобы была не на 50%, а 40 или 60 например. А то уже для меня сложно! Хётмап этот - он же не просто как палитра, где цвет растянут на оттенки и оттенки выгребаются по координатам своим. Оно ж динамическое и выглядит замечательно! Вот под себя настрою и успокоюсь ) Пойду дальше чего-то расколупывать на сях этих ваших ))