Вопросы по преобразованию диапазонов
- Войдите на сайт для отправки комментариев
Здравствуйте. Помогите, пожалуйста, советом.
Задача: с аналогового датчика (софтпот https://www.sparkfun.com/products/8681, управляю выходными значениями пальцем) я читаю сигнал и преобразую его в диапазон для 37 значений функцией map для последующей передачи по миди. В общем-то, код простейший:
int val = analogRead (0); byte pitch = map (val, 0, 1023, 60, 96);
Собственно 60 и 96 - это границы высоты тонов, с которыми я работаю по миди. Сам потенциометр я стабилизировал конденсатором на 0,1 мкФ. Но возникает проблема, когда на потенциометре я держу палец на "пограничных" зонах. И например между 65 и 66 на мониторе серийного порта мне выдает нечто вроде:
66< 65 < 65> 66 <
И так далее совершенно рандомно. Как с этим бороться - не представляю, перепробовал разные варианты. Один из них - это написать 37 условий с разрывом диапазона такого типа:
if (val>=0 && val<=25) pitch=60; if (val>=30 && val<=54) pitch=61; ..... if (val>=998 && val<=1023) pitch=96;
Но не хочется перегружать код таким количеством условий (у меня будет 2 потенциометра) и к тому же скачок все равно есть, пусть и меньший. Ускорится ли выполнение кода, если засунуть эти условия в библиотеку? Или есть решение проще? Изучал подобные проекты, но ответа там для себя не нашел.
не понял, в чем ваша проблема - в том что данные прыгают с 65 на 66 и обратно? Или то что в мониторе появляется символ ">"
ПРосто когда я подключаюсь уже через конвертор к компу, в секвенсоре в этих положения пальца, соответственно, жуткий треск и перегруз. Дополню, что условия выполнения миди у меня такие:
byte pitch; byte prpitch = 96; void Setup () { MIDI.begin() } void loop () { int val = analogRead(0); pitch = map(val,0,1023,60,96); if (pitch != prpitch) { MIDI.sendNoteOn (pitch,60,1); MIDI.sendNoteOn(prpitch,0,1); prpitch = pitch; } }Пишу не из своего скетча, могут быть синтаксические ошибки.
Соответственно в эти моменты мой код не может переназначить prpitch на pitch(чтобы замолчала предыдущая нота) и постоянно отсылает миди-сигнал, перегружая все и вся
IMHO, map функция тут не причем и 36 IF вам не помогут. У вас скачут исходные значения. Можно попробовать бороться с этим так же - как и с дребезкгом - переключать диапазоны только когда исходная величина находится в новом питче некоторое время
Вы имеете в виду сделать скользящее среднее значений аналогового сигнала до функции map? Я об этом и не подумал. Спасибо, попробую вечером.
Alex_Bryl, нужно делать гистерезис.
Покажу, как реализоваго у меня:
byte control[46]; // состояние органов управления по стандарту MIDI: 0-127 unsigned int ADC_data[46]; // ADC data 10 bit: 0-1023 unsigned int oldCtrl_i[46]; // предыдущее запомненное состояние данных АЦП - для устранения шума (порог шума - 6 единиц младшего разряда) void CheckControl(byte index){ // проверка вновь полученных от АЦП данных - а не изменились ли они? CheckMIDIserial(); unsigned int newCtrl_i = ADC_data[index]; byte newCtrl_b = newCtrl_i/8; if(newCtrl_b != control[index]) { if(abs((int)newCtrl_i - (int)oldCtrl_i[index]) >= 6) { // не реагируем, пока разница в сырых 10-битных значениях не превзойдет 6 control[index] = newCtrl_b; oldCtrl_i[index] = newCtrl_i; lcd.setString(0, index + 1024 + 128); lcd.setString(1, newCtrl_b); } } }В MIDI используется 128 уровней, поэтому у меня сигналы от всех аналоговых органов управления приводятся из дмапазона 0-1023 к диапазону 0-127. Величина гистерезиса 6. Т.е. изменения менее чем на 6 единиц не фиксируются.
Всего используется 46 аналоговых регуляторов, подключенных к внешним АЦП MCP3008. Текущие значения заносятся в массив unsigned int ADC_data[46]; в функции, которая не приведена. В Вашем случае это будет просто analogRead().
Функция CheckControl(byte index) обрабатывает значение одного регулятора с номером index.
В результате обработки выходное значение помещается в массив byte control[46]; - это уже очищенное от дрожания значение, приведенное к диапазона MIDI.
В функции также проверяется, не пришло ли что-нибудт в MIDI-порт (функция CheckMIDIserial()) и при наличии изменения инициализируется вывод на экран (самого вывода на экран здесь нет по соображениям скорости реакции на сообщения). На экран выводится название изменившегося параметра и его новое значение.
Ускорится ли выполнение кода, если засунуть эти условия в библиотеку?
Ага, в Ленинскую засуньте - тогда ардуинка сразу на бздячей тяге к Марсу полетит.
З.Ы. Библиотека - такой же код на С++, как сам факт, что вы запрячете код туда, повлияет на его (кода) быстродействие?
Отчитываюсь по результатам.
Лучше всего помог вариат с гистерезизом. Вот как я его реализовал в простом варианте:
#include <MIDI.h> #include <midi_Defs.h> #include <midi_Message.h> #include <midi_Namespace.h> #include <midi_Settings.h> MIDI_CREATE_DEFAULT_INSTANCE(); byte pitch; byte prpitch = 96; int val; int oldval; void setup () { MIDI.begin(); } void loop () { val = analogRead(0); if (abs(val-oldval)>=10) {pitch = map(val,0,1023,60,96); oldval = val; } if (pitch != prpitch) { MIDI.sendNoteOn(pitch,60,1); MIDI.sendNoteOff(prpitch,0,1); prpitch = pitch; } }Звук на выходе получается четким и без дрожания, на мониторе порта еще попадается строчка с символами ">" или "<" при перемещении по датчику, но всего одна и видимо от нее не избавится, на результат уже не влияет.
Выглдит все очень просто и мне стыдно, что сам не догадался, так что спасибо за советы