РЕШЕНО Полное сглаживание данных фоторезистора.

Тема в разделе "Arduino & Shields", создана пользователем Gritsan, 13 дек 2019.

  1. Gritsan

    Gritsan Нерд

    Приветствую Вас.
    плата Digispark(attiny85)
    фоторезистор "5528"
    светодиод.
    Цель проекта- плавное управление яркостью светодиода, (чем ярче освещение тем ярче светодиод)

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

    При низкой освещенности заметно хаотичное мерцание.

    Может есть какое то решение. Или стоит рассматривать другие датчики?


    Код (C++):
        #define PIN_LED 10
        #define PIN_PHOTO_SENSOR A0
        void setup() {
          Serial.begin(9600);
          pinMode(PIN_LED, OUTPUT);
        }
        void loop() {
          int val = analogRead(PIN_PHOTO_SENSOR);
          Serial.println(val);
          int ledPower = map(val, 0, 1023, 0, 255); // Преобразуем полученное значение в уровень PWM-сигнала. Чем меньше значение освещенности, тем меньше мощности мы должны подавать на светодиод через ШИМ.
          analogWrite(PIN_LED, ledPower); // Меняем яркость
        }
    Благодарю.
     
  2. Airbus

    Airbus Радиохулиган Модератор

    А если 1023 тупо делить на 4?
     
    Gritsan нравится это.
  3. Gritsan

    Gritsan Нерд

    Если я правильно понял, то нужно делить перед "map"?
    Стабильнее но не идеально.
    Код (C++):
    7
    8
    8
    7
    7
    7
    7
    7
    7
    7
    8
    8
    7
    7
    7
    7
    7
    7
    7
    7
    8
    8
    8
     
  4. asam

    asam Гик

    Ну, отбрасываем младшие 2 разряда путем деления на 4, как тут уже сказалию. Все равно 2 младшие разряда скачут. map при этом не нужен будет, потому что уже преведется делением на 4 к 255. А вот перед тем как менять яркость - вычислить простое скользящее среднее точкам по 100.
     
    Gritsan нравится это.
  5. Gritsan

    Gritsan Нерд

    А не могли бы Вы подсказать где код посмотреть?
    Код (C++):
    #define analogInPin A0        
    const byte averageFactor = 5;   // коэффициент сглаживания показаний (0 = не сглаживать)
                                      // чем выше, тем больше "инерционность"
                                       // считанное значение
    int sensorValue = 0;        

    void setup()
      {
      Serial.begin(9600);
      }
    void loop()
      {
      sensorValue = analogRead(analogInPin);
      if (averageFactor > 0)        // усреднение показаний для устранения "скачков"
      {  
      int oldsensorValue = sensorValue;
      sensorValue = (oldsensorValue * (averageFactor - 1) + sensorValue) / averageFactor;
       // <новое среднее> = (<старое среднее>*19 + <текущее значение>) / 20
      }
      Serial.print("sensor = " );
      Serial.println(sensorValue);

      delay(50);                  
      }
    }
     
  6. Asper Daffy

    Asper Daffy Иксперд

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

    Если нужна фильтрация, будь любезен читать входной сигнал строго через равные промежутки времени. Рассчитай для этой входной частоты частоту среза фильтра и ставь хоть что (того же Чебышева) и всё будет нормально.
     
    DetSimen нравится это.
  7. Asper Daffy

    Asper Daffy Иксперд

    Это что? Сначала oldsensorValue и sensorValue делаем одинаковыми, а потом типа что-то вычисляем? Зачем?
     
    DetSimen нравится это.
  8. Sergku

    Sergku Нерд

    Это поможет:
    Код (C++):

    #define potPin A0

    byte
      currCnt = 0; // max 255
    unsigned long
      tmr = 0,
      currVal = 0;

    void setup() {
      Serial.begin(9600);
      pinMode(potPin, INPUT);
    }

    void loop() {

      if (millis() - tmr >= 10){
        tmr = millis();
          if(currCnt++ < 50) // max 254
            currVal += analogRead(potPin);
          else{
            printAvg((currVal /= --currCnt));
            currVal = currCnt = 0;
          }
      }
    }

    void printAvg(const unsigned long &iVal){
      Serial.println(iVal);  // Вывод среднего значения
      Serial.println(map(iVal, 0, 1023, 0, 255)); // для PWM
    }
     
     
    Последнее редактирование: 14 дек 2019
    Gritsan нравится это.
  9. Airbus

    Airbus Радиохулиган Модератор

    А погрешность показания в 1/255 критична?Если да то нужен более точный датчик
     
  10. Gritsan

    Gritsan Нерд

    К сожалению, без примера я не смогу это реализовать.
    Фильтры применял вот так:
    Код (C++):
    #define FILTER_STEP 5
    #define FILTER_COEF 0.1
    int val;
    float val_f;
    unsigned long filter_timer;
    #define LED 1           // задаем имя для Pin P2, Светодиод
    int FTR = 1;    //фоторезистор


    void setup() {
    }
    void loop() {
     
      if (millis() - filter_timer > FILTER_STEP) {
        filter_timer = millis();    // просто таймер
        // читаем значение (не обязательно с аналога, это может быть ЛЮБОЙ датчик)
        val = analogRead(FTR);
        // основной алгоритм фильтрации. Внимательно прокрутите его в голове, чтобы понять, как он работает
        val_f = val * FILTER_COEF + val_f * (1 - FILTER_COEF);
        analogWrite(LED, val_f);
       
      }
    }
     
  11. Gritsan

    Gritsan Нерд

    Точность не важна, но диапазон желательно побольше. И 2, 50 пробовал.
     
  12. Gritsan

    Gritsan Нерд

    Спасибо
    Работает! Если у меня получится добавить плавности при смене яркости, то это решение!
     
  13. Sergku

    Sergku Нерд

    С плавностью там более чем все в порядке:)
     
    Gritsan нравится это.
  14. Gritsan

    Gritsan Нерд

    1. Световое сопротивление при 10 люкс: 8-20 кОм
    Темновое сопротивление при 0 люкс: 1,0 МОм
    2. Диапазон яркости(шинрина, шаг) как правильно выразится?
    3. Это значения в "map".
     
  15. Gritsan

    Gritsan Нерд

    У меня через пол секунды меняется яркость.
    может не правильно все делаю
    Код (C++):
    #define LED 1           // задаем имя для Pin P2, Светодиод
    int potPin = 1;    //фоторезистор

    byte
    currCnt = 0;
    unsigned long
    tmr = 0,
    currVal = 0;

    void setup() {
    //Serial.begin(9600);
    pinMode(potPin, INPUT);
    }

    void loop() {

    if (millis() - tmr >= 10){
    tmr = millis();
    if(currCnt++ < 100)
    currVal += analogRead(potPin);
    else{
    printAvg((currVal /= 100));
    currVal = currCnt = 0;
    }
    }
    }

    void printAvg(const unsigned long &iVal){
    //Serial.println(iVal); // Вывод среднего значения
    analogWrite(LED, iVal);
    }
     
  16. Sergku

    Sergku Нерд

    Тут полный цикл заполнения происходит за 100 *10 за 1 секунду
    И analogWrite(LED, map(iVal, 0,1023,0,255)) можно уменьшить количество выборок до 50 тогда как раз 0.5 секунды будет
     
    Последнее редактирование: 13 дек 2019
    Gritsan нравится это.
  17. parovoZZ

    parovoZZ Гуру

    Так подсказали же - скользящее алгебраическое среднее вычислять. Ну и по возможности не работать на малых значениях АЦП - там велико влияние начального смещения УВХ.
     
    Gritsan нравится это.
  18. Ariadna-on-Line

    Ariadna-on-Line Гуру

    Вам, я так понимаю, важно математические методы оттачивать. Если нет - поставьте между фоторезистором и входом Ардуины конденсатор в роли интегратора (один конец на вход, другой на GND). За постоянную времени возьмите 100мСек.
     
    Последнее редактирование: 13 дек 2019
    Gritsan нравится это.
  19. Asper Daffy

    Asper Daffy Иксперд

    И каков срез этого фильтра? Вы, похоже, не умеете это считать.

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

    Есть решение проще, возьмите готовую программу генерации фильтров, скажите ей частоту среза и она Вам выдаст готовый фильтр (прямо кусок кода на С), останется только его в программу вставить (например, поставьте Чебышева второго или третьего порядка). Ссылка на программу и подсказка по небольшой доработке есть вот здесь.
     
    Gritsan, DetSimen и ИгорьК нравится это.
  20. Sergku

    Sergku Нерд

    тут, конечно, беда.. да и pinMode(LED , OUTPUT); не хватает
     
    Gritsan нравится это.