Вопросы по преобразованию диапазонов

Alex_Bryl
Offline
Зарегистрирован: 12.02.2018

Здравствуйте. Помогите, пожалуйста, советом. 

Задача: с аналогового датчика (софтпот 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 потенциометра) и к тому же скачок все равно есть, пусть и меньший. Ускорится ли выполнение кода, если засунуть эти условия в библиотеку? Или есть решение проще? Изучал подобные проекты, но ответа там для себя не нашел. 

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

не понял, в чем ваша проблема - в том что данные прыгают с 65 на 66 и обратно? Или то что в мониторе появляется символ ">"

Alex_Bryl
Offline
Зарегистрирован: 12.02.2018

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

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(чтобы замолчала предыдущая нота) и постоянно отсылает миди-сигнал, перегружая все и вся

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

IMHO, map функция тут не причем и 36 IF вам не помогут. У вас скачут исходные значения. Можно попробовать бороться с этим так же - как и с дребезкгом - переключать диапазоны только когда исходная величина находится в новом питче некоторое время

Alex_Bryl
Offline
Зарегистрирован: 12.02.2018

Вы имеете в виду сделать скользящее среднее значений аналогового сигнала до функции map? Я об этом и не подумал. Спасибо, попробую вечером.

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

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()) и при наличии изменения инициализируется вывод на экран (самого вывода на экран здесь нет по соображениям скорости реакции на сообщения). На экран выводится название изменившегося параметра и его новое значение.

 

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

Alex_Bryl пишет:

Ускорится ли выполнение кода, если засунуть эти условия в библиотеку?

Ага, в Ленинскую засуньте - тогда ардуинка сразу на бздячей тяге к Марсу полетит.

З.Ы. Библиотека - такой же код на С++, как сам факт, что вы запрячете код туда, повлияет на его (кода) быстродействие?

Alex_Bryl
Offline
Зарегистрирован: 12.02.2018

Отчитываюсь по результатам. 

Лучше всего помог вариат с гистерезизом. Вот как я его реализовал в простом варианте:

#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;
      }
}

Звук на выходе получается четким и без дрожания, на мониторе порта еще попадается строчка с символами ">" или "<" при перемещении по датчику, но всего одна и видимо от нее не избавится, на результат уже не влияет.

Выглдит все очень просто и мне стыдно, что сам не догадался, так что спасибо за советы