SMA Filter(Simple moving average) - Простое скользящее среднее или арифметическое скользящее среднее

Sdílet
Vložit
  • čas přidán 24. 07. 2024
  • Простое скользящее среднее, или арифметическое скользящее среднее (англ. simple moving average, англ. SMA) численно равно среднему арифметическому значений исходной функции за установленный период. В данном видео применим фильтр и посмотрим, как он поможет нам с обработкой внутреннего шума АЦП микроконтроллера.
    Заходи в нашу группу ВК solderingiron.stm32
    ЯндексДзен: zen.yandex.ru/id/622208eed2eb...
    Скачать библиотеку: github.com/Solderingironspb/S...
    00:00 Вступление
    01:32 Создание проекта
    05:45 Написание примера по замеру АЦП + фильтрация сигнала
    18:53 Вычисление напряжение на входе канала АЦП
  • Věda a technologie

Komentáře • 40

  • @edmelectronics4110
    @edmelectronics4110 Před 2 lety +1

    Отлично, поздравляю за етот ролик. Буду пользовать в будушем проекте етот замечательный филтер.

  • @dr.emmettbrown8466
    @dr.emmettbrown8466 Před 2 lety +2

    Взял на заметку. Спасибо!! Как раз сейчас буду использовать в проекте показания датчика давления жидкости. Сделал как раз схему по твоей наводке с ОУ и делителем.

    • @Solderingironspb
      @Solderingironspb  Před 2 lety

      Там это как никогда кстати подойдет) я к ОВЕН ПР200 недавно подключал датчик давления, так там после насоса давление очень сильно скакало и сложно было отстроить компаратор. (Т.е. не шум датчика, а именно сигнал) Пришлось тоже фильтровать, чтоб система более стабильной была.

    • @dr.emmettbrown8466
      @dr.emmettbrown8466 Před 2 lety

      @@Solderingironspb Извиняюсь, я могу если что обратиться к тебе за советом, если у меня будут трудности? )) Тем более живем в одном городе))

    • @Solderingironspb
      @Solderingironspb  Před 2 lety

      @@dr.emmettbrown8466 можно) я всегда на связи)

    • @dr.emmettbrown8466
      @dr.emmettbrown8466 Před 2 lety

      @@Solderingironspb Выражаю благодарность за схему с ОУ и делителем. Собрал, протестировал. Результат отличный. Показания очень точные. Плавают п пределах 2-4 соток без всяких усреднений.
      Правда я поставил дополнительно отдельную прецизионную LDO на опорное напряжение на ногу Vref и разделил цифровую и аналоговые земли.

  • @sozdatelEd
    @sozdatelEd Před 2 lety +1

    Первое что бросилось в глаза:
    SMA_Filter_Result = SMA_Filter_Result >> 5u;
    Человек качает библиотеку и меняет
    #define SMA_FILTER_ORDER 48
    Всё. Приехали.
    Во вторых - зачем долбать контроллер вызовами прерываний, если выдёргиваем данные только 1 из 300? Просто настраиваем время срабатывания прерывания по TIM4.
    В третьих - что-то намудрили Вы в функции фильтрации. Нафига что-то смещать?
    Просто пишем:
    uint16_t SMA_FILTER_Get_Value(uint16_t *SMA_Filter_buffer, uint16_t *RAW_Data) {
    static uint32_t SMA_Filter_Result;
    static uint16_t index_raw_buff;

    index_raw_buff++; if (index_raw_buff>SMA_FILTER_ORDER) { index_raw_buff=0; }
    SMA_Filter_buffer[index_raw_buff] = *RAW_Data;
    SMA_Filter_Result = 0;
    for (uint16_t i = 0; i < SMA_FILTER_ORDER; i++) {
    SMA_Filter_Result += SMA_Filter_buffer[i];
    }
    return SMA_Filter_Result/SMA_FILTER_ORDER;
    }

  • @PastuhMedvedey
    @PastuhMedvedey Před 2 lety +1

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

    • @Solderingironspb
      @Solderingironspb  Před 2 lety +1

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

  • @user-hm7gl7er6z
    @user-hm7gl7er6z Před 2 lety

    привет. увидел у тебя pycharm установлен. не будели уроков по пайтону в связке с МК?

    • @Solderingironspb
      @Solderingironspb  Před 2 lety +1

      Добрый день. Изучение python - это побочное явление у меня, когда нужно было сделать небольшой проект на работе. Уже давно там ничего не делаю, т.к. тянуть два разных языка очень сложно. Я и на C# тоже писал программы для работы с МК). В итоге понял, что лучше всего - это С на МК и С/С++ на PC. Так голова чище, т.к. не разрываешься уже между языками. Пишу консольные приложения и с интерфейсом на Qt 5.1x. Хотел делать уроки по нему, но пока стесняюсь, т.к. знаний в этой области куда меньше, поэтому часто на С++ делаю С вставки.

  • @OpenFrimeTVcom
    @OpenFrimeTVcom Před 2 lety

    мы делаем весы, и с АЦП наморочились очень сильно. Единственное что важно сделать это опорное очень хорошее, есть специальные микры под опорку. MCP1725 что то там. И второе это правильно подобрать кондеры по входу измерения, тут не работает чем больше емкость тем лучше. Нужно правильно подобрать, чтоб не плыло и тд)
    а так да, нужен только цифровой фильтр

    • @Solderingironspb
      @Solderingironspb  Před 2 lety

      все верно говоришь. Я сейчас тестирую TL431. Пробую вместо Vrefint его использовать. 2.5 вольта подаю на АЦП в 1 канал и 2 канал уже корректирую от результата с TL431. Потом видео может сниму. С источником тока дает очень хорошие результаты. Тут, как всегда, температура нам мешает. От нее зависит очень сильно точность. Но и то, TL431 дает очень хорошую стабильность. Но опять же их много разных. Я хз какие я использую, брал Б/У с плат питания.

    • @OpenFrimeTVcom
      @OpenFrimeTVcom Před 2 lety

      @@Solderingironspb понял, интересно будет посмотреть)

    • @olegp.3012
      @olegp.3012 Před 10 měsíci

      @@Solderingironspb так, если верить datasheet, изменение vrefint во всем рабочем температурном диапазоне 5 mV (STM32G0x0), а у TL431 4mV или 6mV (для разных корпусов, производитель TI), то есть они одного поля ягоды. Но у TL431 максимальное возможное значение гораздо выше - 25mV или 16mV против 7,5mV у контроллера.

    • @olegp.3012
      @olegp.3012 Před 10 měsíci

      Для f103 такого не нашел, но у g030 в datasheet указан адрес в памяти где лежит значение ацп vrefint, которое было измерено на заводе при напряжении питания 3V. По нему мы можем пересчитать напряжение питания, оно же опорное напряжение ацп у многих мк. И разделив его на 4095 получить напряжение одной единицы ацп.

  • @user-fd7fj4ii8g
    @user-fd7fj4ii8g Před 2 lety

    DMA у вас работает в циклическом режиме, как вы получаете 100 кГц. И зачем в прерывание стартуте DMA оно уже работает?

    • @Solderingironspb
      @Solderingironspb  Před 2 lety

      Преобразования АЦП я включаю в прерывании по таймеру программно(External Trigger Conversion Source: Regular Conversion launched by software).
      Если выполнить функцию HAL_ADC_Start_DMA(&hadc1, (uint32_t*)ADC_RAW_Data, 2) один раз, то произойдет только одно преобразование и все.

    • @user-fd7fj4ii8g
      @user-fd7fj4ii8g Před 2 lety

      @@Solderingironspb Почему только одно, если DMA работает циклически ?

    • @Solderingironspb
      @Solderingironspb  Před 2 lety

      Запустите проект и тестаните.

  • @sozdatelEd
    @sozdatelEd Před 2 lety

    хмм... странно... а куда комментарии пропадают с конструктивной критикой?
    ведь библиотека не идеальна. зачем народ вводите в заблуждение?

    • @Solderingironspb
      @Solderingironspb  Před 2 lety

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

    • @sozdatelEd
      @sozdatelEd Před 2 lety

      @@Solderingironspb нет. ссылку не прилагал, но там была подкорректированная функция Вашей библиотеки.
      Попробую ещё раз отправить разделив коммент на 2 части 🙄

    • @sozdatelEd
      @sozdatelEd Před 2 lety

      @@Solderingironspb первое что бросилось в глаза:
      SMA_Filter_Result = SMA_Filter_Result >> 5u;
      Человек качает библиотеку и меняет
      #define SMA_FILTER_ORDER 48
      Всё. Приехали.
      Во вторых - зачем долбать контроллер вызовами прерываний, если выдёргиваем данные только 1 раз из 300? Просто надо настроить нужное время срабатывания прерывания по TIM4.

    • @sozdatelEd
      @sozdatelEd Před 2 lety

      @@Solderingironspb в третьих - что-то намудрили Вы в функции фильтрации. Нафига что-то смещать?
      Просто пишем:
      uint16_t SMA_FILTER_Get_Value(uint16_t *SMA_Filter_buffer, uint16_t *RAW_Data) {
      static uint32_t SMA_Filter_Result;
      static uint16_t index_raw_buff;

      index_raw_buff++; if (index_raw_buff>SMA_FILTER_ORDER) { index_raw_buff=0; }
      SMA_Filter_buffer[index_raw_buff] = *RAW_Data;
      SMA_Filter_Result = 0;
      for (uint16_t i = 0; i < SMA_FILTER_ORDER; i++) {
      SMA_Filter_Result += SMA_Filter_buffer[i];
      }
      return SMA_Filter_Result/SMA_FILTER_ORDER;
      }

    • @Solderingironspb
      @Solderingironspb  Před 2 lety

      Чет я туплю...а как static uint16_t index_raw_buff; будет влиять на разные буферы?
      допустим мы вызовем функцию 2 раза, но в 1 раз первый канал АЦП со своим буфером, а во второй раз 2 канал АЦП со своим буфером.
      есть строка index_raw_buff++;
      после него SMA_Filter_buffer[index_raw_buff] = *RAW_Data;
      получится же так, что в первый вызов мы положим в 1 элемент 1 буфера 1 канал АЦП, а при втором вызове у нас static uint16_t index_raw_buff уже будет равна 1 и мы тогда положим во 2 элемент 2 буфера 2 канал АЦП данные, а в первом элементе уже будет пусто...
      Или я что-то неправильно прикинул?
      т.е. вызовов много, а счетчик индекса один.
      Прошу прощения, если что - утро, туплю)

  • @sozdatelEd
    @sozdatelEd Před 2 lety

    Первое что бросилось в глаза:
    SMA_Filter_Result = SMA_Filter_Result >> 5u;
    Человек качает библиотеку и меняет
    #define SMA_FILTER_ORDER 48
    Всё. Приехали.
    Во вторых - зачем долбать контроллер вызовами прерываний, если выдёргиваем данные только 1 из 300? Просто настраиваем время срабатывания прерывания по TIM4.
    В третьих - что-то намудрили Вы в функции фильтрации. Нафига что-то смещать?
    Просто пишем:
    uint16_t SMA_FILTER_Get_Value(uint16_t *SMA_Filter_buffer, uint16_t *RAW_Data) {
    static uint32_t SMA_Filter_Result;
    static uint16_t index_raw_buff;

    index_raw_buff++; if (index_raw_buff>SMA_FILTER_ORDER) { index_raw_buff=0; }
    SMA_Filter_buffer[index_raw_buff] = *RAW_Data;
    SMA_Filter_Result = 0;
    for (uint16_t i = 0; i < SMA_FILTER_ORDER; i++) {
    SMA_Filter_Result += SMA_Filter_buffer[i];
    }
    return SMA_Filter_Result/SMA_FILTER_ORDER;
    }

    • @PavelLaminar
      @PavelLaminar Před rokem

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

    • @sozdatelEd
      @sozdatelEd Před rokem

      @@PavelLaminar у автора библиотека в таком случае не работает с тем функционалом о котором он заявляет. Я указал на реальный косяк.

    • @PavelLaminar
      @PavelLaminar Před rokem

      @@sozdatelEd никакого косяка нет, несовершенство реализации - да. Самое простое определить через define сдвиг. Еще можно магию на макросах написать.

    • @sozdatelEd
      @sozdatelEd Před rokem

      @@PavelLaminar т.е. вы считаете не является косяком то, что автор вынес в define размер буффера для усреднения, а в реализации функции присутствует магический сдвиг? Или вы пользуетесь библиотеками где надо и в конфигурационном файле поменять значения и в файле с реализацией функций тоже найти магические комментарии где может быть будет понятно почему не взлетело после изменений значений в конфиге?
      К чёрту подробности. Пруфы в студию.
      А лучше разберите этот код на двух примерах:
      1. скачана библиотека и изменил буффер на 16
      2. скачана библиотека и изменил буффер на 48

    • @PavelLaminar
      @PavelLaminar Před rokem

      Вы точно прочитали и поняли мой предыдущих ответ? Я не спорю, что магические числа и прибитые гвоздями реализации это никуда не годится, но это говорит только о плохой реализации. Косяк это когда задаешь размер буфера 10, а получаешь 5 к примеру. Да и вообще я изначально ответил почему вариант с делением хуже сдвига