ARDUINO Цветомузыка на Arduino. Обсуждение проекта

novvel

★★★✩✩✩✩
29 Сен 2018
568
192
какая функция конденсатора на частотном входе. почему входов два у нас. я думал что отрезается частота. теперь я понимаю, что это не так.
На частоту он там точно не влияет, прогонял генератором и рзницы не было с 10нФ и с 50мкф, в схеме анализатора вообще отказался от конденсатора и подключил напрямую, компенсировав смещение в коде (правда я не знаю работает оно на самом деле или нет, но анализатор стал работать заметно лучше и меньше реагирует на гармоники при перемещении по частоте )

@Slenk, странное объяснение назначение кондера там) я переделал ту схему в такую и работать стало зааметно четче с микрофоном, от линейного входа не проверял к сожалению, лень провода тянуть и делители лепить:
1609410305915.png

 
Изменено:

Евгений Л

★✩✩✩✩✩✩
21 Июл 2020
34
11
Общение с technotrasher сподвигло на на некоторые мысли и заставило засунуть лень подальше. Посмотрев кино Гайвера меня посетила мысль почему в цветомузыке заливает все НЧ. Посмотрев скетч ( в котором я нихрена не понимаю) я понял, что делается по 100 замеров в каждой из частот и если в этих замерах амплитуда сигнала превышает пороговое значение, то информация отправляется на ленточку. НО при этом частота опросов и НЧ и СЧ и ВЧ одинаковая. Таким образом шанс попадания при замере НЧ на высокое значение амплитуды в десятки раз выше чем такой же шанс попадания на СЧ и ВЧ. Так как Период синусоиды НЧ в разы больше больше периода СЧ и уж тем более ВЧ. Если проще то на НЧ пики очень широкие а на ВЧ очень узкие. Можент я и не прав. Второе мое исследование - если запустить генератор и гонять туда сюда частоту то все реагирует более или мене правильно, но если уйти за частоту 12 кГЦ опять начинает светится НЧ канал. Почему не понял. Третье исследование - если оставить частоту генератора на каком то значении и не гонять его - погорев секунд 5 ленточка тухнет . Почему то же не понял. Тут явно вопрос к программе.
 
  • Лойс +1
Реакции: technotrasher

novvel

★★★✩✩✩✩
29 Сен 2018
568
192
@Евгений Л, У меня эти режимы вообще толком не пашут, бегущие частоты сейчас вообще просто моргают периодом и все, иногда они работают, но это очень редко)) обычно выглядит вот так:
И там после 10кгц примерно спектр стремится в обратную сторону по ленте к НЧ в цветомузыке, это верно.
 

kDn

★★★★★✩✩
18 Ноя 2019
1,103
437
На частоту он там точно не влияет, прогонял генератором и рзницы не было с 10нФ и с 50мкф, в схеме анализатора вообще отказался от конденсатора и подключил напрямую, компенсировав смещение в коде (правда я не знаю работает оно на самом деле или нет, но анализатор стал работать заметно лучше и меньше реагирует на гармоники при перемещении по частоте )
Все правильно, конденсаторы по аналоговому входу нахрен не нужны и даже вредны. Я это объяснял в нашей теме с полгода назад пару раз. Зачем убирать постоянную составляющую и ломать FFT анализ этом для меня загадка. Предположу что изначально автор делал по аналогии с аналоговой техникой, там действительно нужно постоянную составляющую вырезать перед выводом на динамик иначе будет фигня. Но тут же не динамик, а АЦП, и фигня как раз получается, если постоянную составляющую убрать. Программное выравнивание средней точки - подход верный, у себя я еще калибровку добавил - где выясняется как средняя точка относительно постоянной составляющей, так и уровень шума. Далее обе эти величины используются для компенсации.

Второе мое исследование - если запустить генератор и гонять туда сюда частоту то все реагирует более или мене правильно, но если уйти за частоту 12 кГЦ опять начинает светится НЧ канал
Разложение частот по FFT выделяет главную гармонику, если частота семплирования недостаточная, а присуствуют верхние частоты большой амплитуды, то будут выделяться другие гармоники и как следствие вы увидите то, что видите :). Вывод - нужно либо увеличивать верхнюю частоту семплирования, а она должна быть в ДВА раза больше чем целевая, т.е. для 20кГц нужно 40кГц, либо же смириться, либо делать фильтр программный.
Третье исследование - если оставить частоту генератора на каком то значении и не гонять его - погорев секунд 5 ленточка тухнет . Почему то же не понял. Тут явно вопрос к программе.
Ну так баг АРУ программного походу.

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

technotrasher

★★★★✩✩✩
14 Ноя 2019
508
227
Все правильно, конденсаторы по аналоговому входу нахрен не нужны и даже вредны. Я это объяснял в нашей теме с полгода назад пару раз. Зачем убирать постоянную составляющую и ломать FFT анализ этом для меня загадка. Предположу что изначально автор делал по аналогии с аналоговой техникой, там действительно нужно постоянную составляющую вырезать перед выводом на динамик иначе будет фигня. Но тут же не динамик, а АЦП, и фигня как раз получается, если постоянную составляющую убрать. Программное выравнивание средней точки - подход верный, у себя я еще калибровку добавил - где выясняется как средняя точка относительно постоянной составляющей, так и уровень шума. Далее обе эти величины используются для компенсации.


Разложение частот по FFT выделяет главную гармонику, если частота семплирования недостаточная, а присуствуют верхние частоты большой амплитуды, то будут выделяться другие гармоники и как следствие вы увидите то, что видите :). Вывод - нужно либо увеличивать верхнюю частоту семплирования, а она должна быть в ДВА раза больше чем целевая, т.е. для 20кГц нужно 40кГц, либо же смириться, либо делать фильтр программный.

Ну так баг АРУ программного походу.

--------------------
Я понимаю, что немного некорректно влезать в разговор о варианте который я не только не прошивал, но даже и не глядел... Но просто из вашего разговора настолько очевидны грабли по которым прошлись при разработке, что трудно удержаться от комментирования. :)
Но если что - могу пойти лесом и не мешать :)
Отлично. наоборот подсакзывайте!!! 10нФ - на входе есть везде у всех на схемах!!! даже на входе MSGEQ7 есть. если можно - укажите в своём скетче где обрабатываете спектр. точнее - можно ли Ваш кусочек кода. :) а то реально мы решаем, то что уже было решено.
 

kDn

★★★★★✩✩
18 Ноя 2019
1,103
437
Отлично. наоборот подсакзывайте!!! 10нФ - на входе есть везде у всех на схемах!!! даже на входе MSGEQ7 есть. если можно - укажите в своём скетче где обрабатываете спектр. точнее - можно ли Ваш кусочек кода. :) а то реально мы решаем, то что уже было решено.
В нашем варианте работает сразу несколько частей.
Библиотека: arduinoFFT - но версии из /dev-ветки, где были существенные изменения, поэтому библиотека лежит в проекте отдельно
Основной движок по работе с микрофоном (ну или линейным входом, тут без разницы) два файла - micFFT.h и micFFT.cpp - в них реализован класс-обертка над чтением аналогового входа и всеми необходимыми преобразованиями.
Ну а в самой лампе есть нечто подобное:

C++:
#ifdef MIC_EFFECTS
void LAMP::micHandler()
{
  static uint8_t counter=0;
  if(effects.getEn()==EFF_ENUM::EFF_NONE)
    return;
  if(mw==nullptr && !iflags.isCalibrationRequest){ // обычный режим
    mw = new MICWORKER(mic_scale,mic_noise);
    if(!mw) {
      mw=nullptr;
      return; // не удалось выделить память, на выход
    }
    //delete mw; mw = nullptr; return;
   
    samp_freq = mw->process(noise_reduce); // возвращаемое значение - частота семплирования
    last_min_peak = mw->getMinPeak();
    last_max_peak = mw->getMaxPeak();

    if(!counter) // раз на N измерений берем частоту, т.к. это требует обсчетов
      last_freq = mw->analyse(); // возвращаемое значение - частота главной гармоники
    if(iflags.micAnalyseDivider)
      counter = (counter+1)%(0x01<<(iflags.micAnalyseDivider-1)); // как часто выполнять анализ
    else
      counter = 1; // при micAnalyseDivider == 0 - отключено

    // EVERY_N_SECONDS(1){
    //   LOG(println, counter);
    // }

    //LOG(println, last_freq);
    //mw->debug();
    delete mw;
    mw = nullptr;
  } else if(iflags.isCalibrationRequest) {
    if(mw==nullptr){ // калибровка начало
      mw = new MICWORKER();
      mw->calibrate();
    } else { // калибровка продолжение
      mw->calibrate();
    }
    if(!mw->isCaliblation()){ // калибровка конец
      mic_noise = mw->getNoise();
      mic_scale = mw->getScale();
      iflags.isCalibrationRequest = false; // завершили
      delete mw;
      mw = nullptr;

      remote_action(RA::RA_MIC, NULL);
    }
  }
}
#endif
Сам эффект частотного (спектрального анализатора) написан так:
C++:
#ifdef MIC_EFFECTS
class EffectFreq : public EffectCalc {
private:
    uint8_t type=1;
    int8_t peakX[2][WIDTH];
    float samp_freq;
    double last_freq = 0;
    uint8_t last_min_peak, last_max_peak;
    float x[WIDTH+1];
    float maxVal;
    uint8_t freqDiv = 2U-scale/128; //1...2
    bool freqAnalyseRoutine(CRGB *leds, EffectWorker *param);
    void load() override;
public:
    bool run(CRGB *ledarr, EffectWorker *opt=nullptr) override;
    void setDynCtrl(UIControl*_val) override;
};
#endif

//-------------------------------------------------
   
// Частотный (спектральный) анализатор
#ifdef MIC_EFFECTS
void EffectFreq::load()
{
  palettesload();    // подгружаем дефолтные палитры
  memset(peakX,0,sizeof(peakX));
  memset(x,0,sizeof(x));
}

void EffectFreq::setDynCtrl(UIControl*_val){
  EffectCalc::setDynCtrl(_val);
  if(_val->getId()==4){
    if(isRandDemo()){
      type = random(_val->getMin().toInt(),_val->getMax().toInt()+1);
    } else {
      type = _val->getVal().toInt();
    }
  }
}

bool EffectFreq::run(CRGB *ledarr, EffectWorker *opt){
  myLamp.setMicAnalyseDivider(0); // отключить авто-работу микрофона, т.к. тут все анализируется отдельно, т.е. не нужно выполнять одну и ту же работу дважды
  if (dryrun(3.0))
    return false;
  return freqAnalyseRoutine(*&ledarr, &*opt);
}

bool EffectFreq::freqAnalyseRoutine(CRGB *leds, EffectWorker *param)
{
  if(isMicOn())
  { // вот этот блок медленный, особенно нагружающим будет вызов заполенния массива
    MICWORKER *mw = new MICWORKER(myLamp.getMicScale(),myLamp.getMicNoise());

    if(mw!=nullptr){
      samp_freq = mw->process(myLamp.getMicNoiseRdcLevel()); // частота семплирования
      last_min_peak = mw->getMinPeak();
      last_max_peak = mw->getMaxPeak()*2;

      EVERY_N_MILLIS(MIC_POLLRATE){
        maxVal=mw->fillSizeScaledArray(x,WIDTH/freqDiv); // массив должен передаваться на 1 ед. большего размера, т.е. для 16 полос его размер 17!!!
      }
      samp_freq = samp_freq; last_min_peak=last_min_peak; last_freq=last_freq; // давим варнинги
    }
    delete mw;
  } else {
    EVERY_N_MILLIS(random(50,300)){
      last_max_peak=random(0,128);
      maxVal=random(0,last_max_peak)/10.0;
      for(uint16_t i=0; i<(sizeof(x)/sizeof(float))-1U;i++){
        x[i] = random(0,128)/100.0;
      }
      x[sizeof(x)/sizeof(float)-1] = random(60,20000);
    }
  }

  float _scale = (maxVal==0? 0 : last_max_peak/maxVal);
  _scale = _scale * ((scale%128)/127.0);
  freqDiv = 2U-scale/128; //1...2

// #ifdef LAMP_DEBUG
// EVERY_N_SECONDS(1){
//   for(uint8_t i=0; i<WIDTH/freqDiv; i++)
//     LOG(printf_P,PSTR("%5.2f "),x[i]);
//   LOG(printf_P,PSTR("F: %8.2f SC: %5.2f\n"),x[WIDTH/freqDiv], scale);
// }
// #endif

  TProgmemRGBPalette16 const *_curPalette;
  float _ptPallete; // сколько пунктов приходится на одну палитру; 255.1 - диапазон ползунка, не включая 255, т.к. растягиваем только нужное :)
  uint8_t _pos; // позиция в массиве указателей паллитр
  uint8_t _curVal; // curVal == либо var как есть, либо getScale
  if(paletteIdx){
    _ptPallete = ptPallete;
    _pos = palettepos;
    _curVal = paletteIdx;
  } else {
    _ptPallete = ptPallete/2.0;
    _pos = (uint8_t)((float)(scale%128)/_ptPallete);
    _curVal = scale%128;
  }

  // EVERY_N_SECONDS(1){
  //   LOG(printf_P,PSTR("palettepos: %d\n"),_pos);
  // }

  _curPalette = palettes.at(_pos); // выбираем из доп. регулятора

  for(uint8_t xpos=0; xpos<WIDTH/freqDiv; xpos++){
    for(uint8_t ypos=0; ypos<HEIGHT; ypos++){
      uint32_t color = (x[xpos]*_scale*(1.0/(ypos+1)))>5?255:0;
      if(color==255 && peakX[1][xpos] < ypos){
        peakX[1][xpos]=ypos;
        peakX[0][xpos]=10;
      }
      if(ypos>(1.5*HEIGHT/2.0)){
        color=color<<16;
      } else if(ypos>(HEIGHT/2.0)){
        color=(color<<8)|(color<<16);
      } else {
        //color=color<<8;
        if(color){
          CRGB tColor;
          if(!(_curVal%(uint8_t)(_ptPallete*(_pos+1)))) // для крайней точки рандом, иначе возьмем по индексу/2
            tColor = ColorFromPalette(*_curPalette,random8(15)); // sizeof(TProgmemRGBPalette16)/sizeof(uint32_t)
          else
            tColor = ColorFromPalette(*_curPalette,constrain(ypos,0,15)); // sizeof(TProgmemRGBPalette16)/sizeof(uint32_t)
          color=((unsigned long)tColor.r<<16)+((unsigned long)tColor.g<<8)+(unsigned long)tColor.b; // извлекаем и конвертируем цвет :)
        }
      }
      if(!(type>=2)){
        color = 0;
      }
        EffectMath::setLed(myLamp.getPixelNumber(freqDiv*xpos,ypos), color);
        if(freqDiv>1)
          EffectMath::setLed(myLamp.getPixelNumber(freqDiv*xpos+1,ypos), color);
      //}
    }
  }


  bool isfall=false;
  EVERY_N_MILLISECONDS(70){
    isfall = true;
  }

  for (size_t i = 0; i < WIDTH/freqDiv; i++)
  {
    uint32_t color = 255;
    int8_t &ypos=peakX[1][i];
    if(peakX[0][i])
      peakX[0][i]--;
    if(isfall && ypos>0 && !peakX[0][i]) ypos--;

    if(ypos>(1.5*HEIGHT/2.0)){
      color=color<<16;
    } else if(ypos>(HEIGHT/2.0)){
      color=(color<<8)|(color<<16);
    } else {
      //color=color<<8;
      if(color){
          CRGB tColor;
          if(!(_curVal%(uint8_t)(_ptPallete*(_pos+1)))) // для крайней точки рандом, иначе возьмем по индексу/2
            tColor = ColorFromPalette(*_curPalette,random8(15)); // sizeof(TProgmemRGBPalette16)/sizeof(uint32_t)
          else
            tColor = ColorFromPalette(*_curPalette,constrain(ypos,0,15)); // sizeof(TProgmemRGBPalette16)/sizeof(uint32_t)
          color=((unsigned long)tColor.r<<16)+((unsigned long)tColor.g<<8)+(unsigned long)tColor.b; // извлекаем и конвертируем цвет :)
      }
    }
    if(type<=2){
      EffectMath::setLed(myLamp.getPixelNumber(freqDiv*i,ypos), color);
      if(freqDiv>1)
        EffectMath::setLed(myLamp.getPixelNumber(freqDiv*i+1,ypos), color);
    }
  }
  return true;
}
#endif

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

Евгений Л

★✩✩✩✩✩✩
21 Июл 2020
34
11
--------------------
Я понимаю, что немного некорректно влезать в разговор о варианте который я не только не прошивал, но даже и не глядел... Но просто из вашего разговора настолько очевидны грабли по которым прошлись при разработке, что трудно удержаться от комментирования. :)
Но если что - могу пойти лесом и не мешать :)
Как раз наоборот - не плохо бы советы услышать как побороть
 

novvel

★★★✩✩✩✩
29 Сен 2018
568
192
Разложение частот по FFT выделяет главную гармонику, если частота семплирования недостаточная, а присуствуют верхние частоты большой амплитуды, то будут выделяться другие гармоники и как следствие вы увидите то, что видите :). Вывод - нужно либо увеличивать верхнюю частоту семплирования, а она должна быть в ДВА раза больше чем целевая, т.е. для 20кГц нужно 40кГц, либо же смириться, либо делать фильтр программный.

Ну так баг АРУ программного походу.

--------------------
Я понимаю, что немного некорректно влезать в разговор о варианте который я не только не прошивал, но даже и не глядел... Но просто из вашего разговора настолько очевидны грабли по которым прошлись при разработке, что трудно удержаться от комментирования. :)
Но если что - могу пойти лесом и не мешать :)
АРУ там работает не пойми как, в анализаторе спектра там каждые 10мс вроде измеряется, скорректировав его до 50-100 стало намного лучше на музыке с большим динамическим диапазоном, в ЦМУ не ковырялся, в прошивке от сленка устраивает пока что все в этом направлении. А фильтр я вообще предполагаю надо сделать по входу "железный" кГц до 16-17, остальное мало информативно обычно в визуализации как по мне. Но если можно починить программно, то мне кажется лучше это сделать, чем ваять схему. Я тут вообще за минимализм в реализации по железу)) После 1-2 числа может разберу коробочку и попробую выпилить кондер и как то перевести в вариант из анализатора, если получится, что бы было только 1 резистор, ардуина и микрофон.
 

Diman

★★✩✩✩✩✩
20 Апр 2019
312
72
поставить по плате на каждый вход.
Чтобы VUmetr синхронно работал? Какой смысл делать стерео?

входу "железный" кГц до 16-17
Какой смысл если все необходимые частоты находятся в районе до 6 - 7кГц. Кто-нибудь реально слышит выше 15кГц?
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
Я часто слышу как свистят кондеи.. бесит дико. Но вот с какой частотой они свистят не знаю. Но согласен, что особо задирать не имеет смысла.
 

novvel

★★★✩✩✩✩
29 Сен 2018
568
192
Какой смысл если все необходимые частоты находятся в районе до 6 - 7кГц. Кто-нибудь реально слышит выше 15кГц?
Кто то может и слышит, я около 16,5кГц слышу, но в ЦМУ и прочем думаю около 10 надо точно, через микрофон до 7кГц сделал, потому что микрофон не очень хорошо ловит такие частоты на таком уровне (в музыке они тихие обычно, с генератора нормально до 18кГц шпарит примерно). Поэтому запас думаю нужен для тех кто по "проводу работает"

@Старик Похабыч, проверяй слух))


Короче не вытерпел и попробовал вариант как в анализаторе провернуть без кондеров, режим с анализом частот стал поживее работать, а вот остальные остались на том же уровне, вернул все взад) Да и после пайки и перешивки режим бегущих частот стал работать нормально.
 

Diman

★★✩✩✩✩✩
20 Апр 2019
312
72
Я часто слышу как свистят кондеи
Может они просят чтобы их плёночным или керамикой зашунтировали? Или это не электролиты?

Больше 16.2 не слышу. Но это еще и от наушников зависит сильно.
В хороших, результат может получиться ниже, так как искажений (слышимых) будет меньше.
 
  • Лойс +1
Реакции: novvel

viktor001

★✩✩✩✩✩✩
14 Окт 2019
113
36
Совершенно не важно кто какие частоты реально слышит. Вы "слушаете" ЦМУ глазами. И тут важно какой диапазон обрабатывает сама программа, на этот диапазон нужно и фильтр по входу ставить. Иначе получим эффект наложения частот.
 

viktor001

★✩✩✩✩✩✩
14 Окт 2019
113
36
Тут я полностью согласен. Но пока ещё нет идеального решения. Как всегда упирается в ресурсы как софта так и железа.
 

Старик Похабыч

★★★★★★★
14 Авг 2019
4,266
1,303
Москва
@viktor001, Ну вот мне стерео эффект глазами нафиг не нужен.. а кто то хочет что бы был. Сколько людей, столько и мнений. А мне надо еще лампу собрать и музыку тоже.. я просто знаю что хочу для себя.
 

viktor001

★✩✩✩✩✩✩
14 Окт 2019
113
36
Стерео - спорный вопрос. Без явно выраженного звукового сопровождения визуально будет та же лажа. Но если подойти к вопросу основательно, а не через пень колоду, лишь бы моргало, то вполне может быть сматрибельно.