Arduino – Hareketli Ortalamalar Filtresi Uygulaması (Moving Average)

Hareketli Ortalamalar Filtresi Nedir?

Hareketli Ortalamalar Filtresi sinyal işleme oldukça sık kullanılan bir filtredir. Karşınıza daha çok “Moving Average Filter” ismiyle çıkacaktır. Filtre adından da anlaşıldığı gibi sürekli ortalamalar alan bir filtredir. Her yeni değer okunduğunda en eski değeri bırakır, yeni gelen değerle ile ortalamayı tekrar alır ve bunu çıkış olarak verir. Yani her okunan değerde ortalama değeri güncellenir. Aşağıdaki şekilde daha net anlaşılmaktadır:

Peki Bu Filtre Ne Zaman Kullanılır?

Şöyle düşünün: Bir sensörden sürekli veri okuyorsunuz. Okuduğunuz verilerden hepsi sizin istediğiniz değerler değil. Yani arada bazı istenmeyen değerleriniz var. Anlık bir yükselme veya düşme olduğu durumda bunun gerçekten doğru mu olduğunu anlamanın bir yolu var. O da yükselme veya düşmenin (değişimin) devam edip etmemesi. Örneğin bir uzaklık sensörünü ele alalım. Okunan uzaklık değeri bir anda yükseldi. Eğer hedef gerçekten uzaklaştıysa devamında okunan değerler de yüksek gelecektir. Yok eğer sensörün hatalı bir çıkışı ise filtremiz o anlık yüksek gelen değeri ortalamanın içinde yumuşatacaktır. Böylece istenmeyen pürüzlerden kurtulmuş oluruz. Eşzamanlı çalışan bu filtre ile sensör okumalarınızda çok daha gerçekçi sonuçlar elde edebilirsiniz.

Tabi avantajları olduğu gibi dezavantajları da mevcut. Her ne kadar eşzamanlı çalışsa da bir gecikmeye sebep olduğu söylenebilir. Burada ortalaması alınan veri sayısı önemlidir. Yukarıdaki şekilde 5 adet verinin ortalaması alınmıştır. Burada eğer sayıyı arttırırsak eski değerlerin yeni değerlere olan etkisi arttırmış oluruz. Yeni gelen değerlerin doğru olması durumunda sonuç biraz geç yansıyacaktır. Mesafe sensöründe olduğu gibi anlık bir uzaklaşma durumunda bunun filtre çıkışına yansıyışı biraz zaman alacaktır. Tecrübelerimize göre bunu ortalaması alınan değer sayısının yarısı kadar olduğunu söyleyebilirim. Yani 10 ölçümün ortalamasının alındığı bir filtrede gerçek sonucun filtre çıkışında görülmesi için en az 5 okuma yapılması gerekir. Her okuma arasındaki süreye göre ne kadar gecikme yaşanacağını hesaplayabilirsiniz.

Kalman vs Moving Average

Kalman Filtresi Uygulaması’na göre biraz daha ilkel bir yöntem olduğunu söyleyebiliriz. Hatta bu filtre Kalman kazancının 0.5 alınması durumudur (Arduino ile Kalman Filtresi Uyglaması yazımıza buradan ulaşabilirsiniz.). Kalman Filtresi gelecek değerleri hesaplayan bir filtre olduğu için minimum gecikme ile çalışmaktadır ve hareketli ortalamalar filtresine göre daha doğru sonuçlar verecektir. Bununla birlikte sisteme uygulaması ve model oluşturulması biraz zordur. İki filteyi bir arada kullanma durumu da oldukça yaygındır. Hareketli ortalamalar filtresinin sonuçlarına Kalman filtresi uygulanarak sinyal çok daha düzgün bir forma getirilebilir.

Dikkat Edilmesi Gerekenler

Filtrenin tasarımında dikkat edilmesi gereken bazı noktalar vardır. En başta belirttiğimiz gibi gecikme ile doğruluk arasındaki dengeyi kurmanız gerekmektedir. Burada bir optimum olduğunu ve bunun uygulamaya göre değiştiğini söyleyebiliriz. Bu optimum noktada:

  • Sinyalin doğruluğu girişe göre karşılaştırılıp gözlemlenmeli. Eğer ki girişten çok farklı bir sinyal almıyorsanız daha fazla örneğin ortalamasını alabilirsiniz. Eğer çıkışınız girişe tepki vermiyorsa: yani aşırı doğrultulmuşsa bunun sebebi çok fazla örneğin ortalamasını almanızdır. Sonuç eski değerlere çok bağlıdır.  Bu yüzden örnek sayısını azaltmanız gerekir.
  • Sinyal gecikmesi girişe göre karşılaştırılmalı ve gözlemlenmeli. Eğer çok fazla gecikme varsa bunun sebebi bir önceki maddede olduğu gibi çok fazla örnek alınmasıdır. Yani çıkış artık girişe tepki vermede gecikiyordur.
  • Saniyede okuduğunuz veri sayısı da bu değeri etkilemektedir. Çok sık veri okduğunuz bir sensörde yukarıdaki maddelere bağlı kalmak koşulu ile biraz daha fazla örnekleme yapabilirsiniz.

Arduino ile Moving Average

Hareketli ortalamalar filtresini Arduino ile rahatlıkla kullanabilirsiniz. Kalman filtresi yazımızda olduğu gibi burada da ivme sensöründen değerler okuduk. Filtreyi fonksiyon haline getirdik. Sizler de uygulamalarınızda filtreyi rahatlıkla kullanabilirsiniz. Arduino kodları işe şu şekilde:

TEST SONUÇLARI

Kullanılan ivmeölçer -16000 ila 16000 arası değer vermektedir. Yapılan testlerde saniyede 100 örnek alınmış ve sensör hızlı bir şekilde X ekseni üzerinde döndürülmüştür. Elde edilen sonuçlar X ekseninin sonuçlarıdır. Ölçüm değerlerinden bazıları (-16000) – (160000) aralığında olmamakla birlikte çoğu zaman gürültülüdür. Filtre sonuçları aşağıda verilmiştir:

Sonuç-1: Test 1.83 Saniye Sürmüştür – 183 Değer

Sonuç-2: Test 1.55 Saniye Sürmüştür – 155 Değer

Sonuç-3 : Test 2.8 Saniye Sürmüştür – 280 Değer

Test sonuçlarında da görüldüğü gibi hareketli ortalamalar filtresi oldukça başarılı bir iş çıkarmıştır. Sizler de proje ve uygulamalarınızda rahatlıkla kullanabilirsiniz. Sorunuz olursa lütfen yorumlarda belirtin. İyi eğlenceler!

“Arduino – Hareketli Ortalamalar Filtresi Uygulaması (Moving Average)” Hakkında 3 Yorum

  1. sa hocam çok usta bir yazılımcı degilim bana yardım edermisiniz burda yazdıgım koda yani adc1 ve adc0 yazdıgınız
    filtreyi nasıl uygulayabilirim bana duzenlermisiniz gercekten cok lazım odev olarak biyere kadar getirdim biyerden sonra
    tıkandım alcak geciren filtre olarak 10uf 10k direnc koydum ama yine yanlıs olcumler alıyorum allah rızası icin yarıdm edin

    #include
    #include
    Adafruit_ADS1115 ads;
    #include // lcd kütüphanesi.
    LiquidCrystal lcd(12,11,5,4,3,2); // lcd baglı bacaklar.
    int maviled = 10;
    int y_led = 9;
    int sariled = 7;
    float sonuc = 0; // float
    int ref = 0;
    int ref2 = 0;
    float aa = 0;
    float bb = 0;
    float cc = 0;
    void setup() {
    Serial.begin(9600);
    // ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV (default) // şimdilik bunu kullan.
    ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit = 2mV 0.125mV // kullandıgım
    // ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1 bit = 1mV 0.0625mV
    // ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V 1 bit = 0.5mV 0.03125mV
    // ads.setGain(GAIN_EIGHT); // 8x gain +/- 0.512V 1 bit = 0.25mV 0.015625mV
    //ads.setGain(GAIN_SIXTEEN); // 16x gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV
    ads.begin();
    lcd.begin(16,2); // lcd 2×16 karekter olduunu belirttik…
    pinMode(maviled, OUTPUT); // Kullanılıyor.
    pinMode(y_led, OUTPUT) ; // Kullanılıyor.
    pinMode(sariled, OUTPUT) ; //

    }
    // veya || işareti ve &&
    //———————————————- ASIL SENSOR 18675 REF SENSOR 17277 = aradaki fark 2000 üstü veyada 2000 altı FARK
    void loop() {
    // dogru olan sensor bakımından.
    int16_t adc0, adc1, adc2, adc3;
    adc0 = ads.readADC_SingleEnded(0); // referans sensörü bu .
    adc1 = ads.readADC_SingleEnded(1); // asıl algılayan sensor.
    aa = adc1 * (4.35 / 32767.0 );
    bb = adc0 * (4.35 / 32767.0 ); //4.37
    // cc = sonuc * (4.35 /32767.0);
    ref = adc0*1/100; // 0.2 10 / 10 / 5 (1)
    ref2 = adc0*4/100; //10 //9.8 //50 denemeler( 4 ,)
    sonuc = ( aa – bb );

    if ( adc1 > adc0+ref )

    {
    digitalWrite(maviled,HIGH);
    digitalWrite(y_led ,LOW);

    }

    else

    {

    digitalWrite(maviled,LOW);

    }

    if ( adc1 == adc0 )

    {

    digitalWrite(maviled,LOW);
    digitalWrite(y_led ,LOW);
    }

    if ( adc1 < adc0 – ref2 )

    {
    digitalWrite(y_led ,HIGH);
    digitalWrite(maviled,LOW);

    }

    else {

    digitalWrite(y_led ,LOW);

    }

  2. hocam sadece adc1 ve adc0 için istiyorum kodlar biraz karısık voltaj muhabetini silicam adc1 ve adc0 filtre olsun yeter

  3. Merhabalar,

    Yazıda vermiş olduğumuz hareketli ortalamalar filtresi için bir fonksiyondur. Kodun içerisinde kullanabilirsiniz. Eğer fonksiyon kullanımını bilmiyorsanız kısaca bahsedeyim. Kodun main fonksiyonu dışında bir yere, vermiş olduğum fonksiyonu direk kopyalayın. Kodun en alt kısmına yapabilirsiniz. (Loop fonksiyonunun dışına.) Devamında fonksiyon içerisindeki değişkenleri kodun başında tanımlayın (avg, val1…, counter, m, d). Devamında Loop fonksiyonunun içine counter ekleyin (c++ gibi. Sıfırdan başlaması lazım.). Daha sonra Loop fonksiyonunun içinde adc’den okuduğunuz değeri

    => filtrelenmis_deger = mov_avg(counter, okunan_deger);

    kodu ile filtreleyebilirsiniz. Ayrıca Kalman filtresi kullanmak istersen ” https://www.mcufreak.com/arduino-kalman-filtresi-uygulamasi/ ” yazımıza da bakabilirsin. Umarım açıklayıcı olmuştur. İyi çalışmalar.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.