şenol eker 50 Oluşturuldu: 18 Nisan, 2020 Share Oluşturuldu: 18 Nisan, 2020 Bir sensordan aldığımız verileri kullanırken, eğer sensor örneğin bir ivmeölçer ya da analog bir sensor gibi "gürültülü" veri üretiyorsa, bu verilerin ortalamasını alarak kullanmak iyi bir fikirdir. Örneğin son 10 değerin ortalamasını alabiliriz. Peki, bunu nasıl yapacağız? Son on tane değeri belleğe alıp sonra bunların ortalamasını mı almalıyız? Ya da çok hızlı veri akışı varsa, son yüz tane, son bin tane verinin ortalamasını almak için, son bin tane veriyi bellekte tutmamız mı gerekir? Ortalama alırken bu son bin tane veriyi toplayıp sonra bir kaydırıp yeni veriyi en sona koyabiliriz. Epey karmaşık değil mi? Ya da kaydırma yerine bir işaretçi ile son veriyi işaret edip, kaydırma yapmadan bu işi yapabilecek bir yöntem de geliştirebiliriz. Hatta bir de her seferinde toplamak yerine her seferinde iptal edilen (1001. eski) veriyi çıkartıp son gelen veriyi toplama ekleyebiliriz. İşlem süresi daha kısalır ama kodumuz daha karmaşıklaşır. Ayrıca ilk 1000 veri gelene dek çıkış vermememiz gerekir. Çünkü henüz gereğince veri toplanmamıştır. Bunun önüne geçmek için ilk 1000 veri sırasında "gelen kadarıyla" ortalama alınabilir. Bunu da ilave ettiğimizde gerçekten karmaşık ve uzun bir kodumuz olur. Ayrıca son 1000 tane veriyi kaydecedek bellek alanı bilgisayarlarda sorun olmasa da, bir mikrodenetleyicide bu ciddi bir sorundur. Aslında aynı işi yapmanın çok kolay bir yolu da vardır. Size bu algoritmayı tanıtmak isterim. Bunun için bir örnek veri seti hazırladım: Görüldüğü gibi, sinüse benzer ama oldukça gürültülü bir veri. Eğer bu verilerin klasik usulde "10 eleman ortalaması" alınırsa, veriler oldukça düzelir: Bunu yapabilmek için kabaca şöyle bir kod yazmak gerek: int veri[10]; //Okunan son veriyi saklayacağımız alan int i; for (i=0;i<10;i++) //ilk 10 veri okunuyor { veri[i]=ReadVeri(); } while (1) //Ana döngü { int top=0; //toplam for (i=0;i<10;i++) //Son 10 verinin toplamını alıyoruz { top+=veri[i]; } float sonuc=top/10.0; //Ortalama printf ("%i\r\n",(int)sonuc); //sonucu yazıyoruz for (i=0;i<9;i++)//Verileri bir kaydırıyoruz { veri[i]=veri[i+1]; } //son olarak da yeni açılan boş yere, yeni veriyi okuyalım: veri[9]=ReadVeri(); } Sonraki gönderide "sihirli formül" geliyor. 1 Alıntı İletiye bağlantı Sitelerde Paylaş
şenol eker 50 18 Nisan, 2020 gönderildi Yazar Share 18 Nisan, 2020 gönderildi Aynı (ya da çok benzer) işi yapmanın çok kolay bir yolu var aslında. Bu yöntemle elde edilen çıkış şöyle: Diğeriyle neredeyse aynı sonucu veriyor gördüğünüz gibi. Ama yazmamız gereken kod diğeri ile mukayese bile edilemez: float oranh=0.9; float oranl=1-oranh; float sonuc=ReadVeri(); while (1) { printf("%i\r\n";(int)sonuc); sonuc=sonuc*oranh+ReadVeri()*oranl; } Burada verdiğimiz oranh, son kaç verinin ortalamasını almak istediğimiz. 0.9 verdiğimizde son 10; 0.99 verdiğimizde son 100; 0.999 verdiğimizde son 1000 verinin ortalamasını almaya benzer bir sonuç elde ederiz. Bu yöntemi ben bir yerden öğrenmedim; daha önce çok defa başıma geldiği gibi kendim buldum ama sonradan benden yıllar önce başka birinin bunu zaten icat etmiş olduğunu öğrendim. Kaynak olmaksızın, eğitim almaksızın kendine kendine öğrenmenin zararları işte... Bunun da daha önce icat edildiğinden eminim. Ama kim icat etmiştir, adı nedir bilmiyorum. Bilen varsa ve yazarsa ben de öğrenirim... 2 Alıntı İletiye bağlantı Sitelerde Paylaş
freedom33 3 18 Nisan, 2020 gönderildi Share 18 Nisan, 2020 gönderildi Merhaba Şenol Hocam; aslında kendi hendine öğrenmenin zararı değil bence yararı olmuş, emeğinize sağlık. Diğer konuya yazan da bendim o an google hesabından kolay üyelik ile giriş sağlamıştım şimdi üye oldum, orada da dediğim gibi sadece yazılımla analog filitre olayını 2 ay araştırmıştım en sonunda birinin yaptığı kütüphane en sağlıklısı ve kullanım kolaylığı için tercih ettim. https://michaelthessel.com/analog-smoothing-library-for-arduino/ Ama sizin kodunuzuda deneyeceğim, şu var ki aslında bu hereketli filitre ortalamaları çok hızlı okumalar için sağlıklı olmadığını düşünüyorum, 500ms. de bir okumalar için çok ideal, ama hala diğer konuda paylaştığım median filitresini çok merak ediyorum, çünkü videoda ortalama ile aldığı veriler az da olsa oynarken median tekniğinde sabit kalıyor. int medyanFiltre(uint16_t dzi[],uint8_t n) { int z; long toplam=0; for(z=(n/4);z<n-(n/4);z++) toplam+=dzi[z]; return (toplam/(n>>1)); } 2 Alıntı İletiye bağlantı Sitelerde Paylaş
şenol eker 50 21 Nisan, 2020 gönderildi Yazar Share 21 Nisan, 2020 gönderildi Neden hızlı verilerde uygun olmadığını düşündünüz? Eğer birinci gönderideki kodu kullanırsanız tabii ki uygun olmaz Ama ikinci gönderideki kod oldukça uygun kanımca, yüksek frekanslarda da. Aslında veriye göre, hangi yöntemin daha iyi olacağı değişir. Örneğin ben özel bir işte bir filtre kullanmıştım. Burada gelen veriler; periyodu tamı tamına bilinen, ama fazı bilinmeyen çok gürültülü bir sinüse ait idi. Gerekli bilgi ise, bu sinüsün fazı idi. Ne medyan ile ne ortalama ile çözüelmez. Birinde ortalama daha iyi iken diğerinde medyan iyi olabilir. Yukarıdaki kod ise, eşdeğer bir yürüyen ortalamaya nazaran çok çok az bir kod, çok az bellek gereksinimi çok az clock ile yaklaşık aynı sonucu verir. Burada yayınlama sebebim o idi. Alıntı İletiye bağlantı Sitelerde Paylaş
freedom33 3 26 Nisan, 2020 gönderildi Share 26 Nisan, 2020 gönderildi şenol eker, 4/21/2020 - 6:41 PM yazdı: Neden hızlı verilerde uygun olmadığını düşündünüz? Eğer birinci gönderideki kodu kullanırsanız tabii ki uygun olmaz Ama ikinci gönderideki kod oldukça uygun kanımca, yüksek frekanslarda da. Aslında veriye göre, hangi yöntemin daha iyi olacağı değişir. Örneğin ben özel bir işte bir filtre kullanmıştım. Burada gelen veriler; periyodu tamı tamına bilinen, ama fazı bilinmeyen çok gürültülü bir sinüse ait idi. Gerekli bilgi ise, bu sinüsün fazı idi. Ne medyan ile ne ortalama ile çözüelmez. Birinde ortalama daha iyi iken diğerinde medyan iyi olabilir. Yukarıdaki kod ise, eşdeğer bir yürüyen ortalamaya nazaran çok çok az bir kod, çok az bellek gereksinimi çok az clock ile yaklaşık aynı sonucu verir. Burada yayınlama sebebim o idi. Aynen Şenol Hocam 1.kod için söylemiştim. 1 Alıntı İletiye bağlantı Sitelerde Paylaş
freedom33 3 21 Mayıs, 2020 gönderildi Share 21 Mayıs, 2020 gönderildi şenol eker, 4/21/2020 - 6:41 PM yazdı: Neden hızlı verilerde uygun olmadığını düşündünüz? Eğer birinci gönderideki kodu kullanırsanız tabii ki uygun olmaz Ama ikinci gönderideki kod oldukça uygun kanımca, yüksek frekanslarda da. Aslında veriye göre, hangi yöntemin daha iyi olacağı değişir. Örneğin ben özel bir işte bir filtre kullanmıştım. Burada gelen veriler; periyodu tamı tamına bilinen, ama fazı bilinmeyen çok gürültülü bir sinüse ait idi. Gerekli bilgi ise, bu sinüsün fazı idi. Ne medyan ile ne ortalama ile çözüelmez. Birinde ortalama daha iyi iken diğerinde medyan iyi olabilir. Yukarıdaki kod ise, eşdeğer bir yürüyen ortalamaya nazaran çok çok az bir kod, çok az bellek gereksinimi çok az clock ile yaklaşık aynı sonucu verir. Burada yayınlama sebebim o idi. Yapamadım Şenol Hocam; readveri benim analog girişten aldığm değer mi olucak, açıkçası örnek olarak tüm kodu gönderebilir misiniz? float oranh=0.9; float oranl=1-oranh; float sonuc=ReadVeri(); while (1) { printf("%i\r\n";(int)sonuc); sonuc=sonuc*oranh+ReadVeri()*oranl; } Alıntı İletiye bağlantı Sitelerde Paylaş
azmi 24 22 Mayıs, 2020 gönderildi Share 22 Mayıs, 2020 gönderildi freedom33, 15 saat önce yazdı: Yapamadım Şenol Hocam; readveri benim analog girişten aldığm değer mi olucak, açıkçası örnek olarak tüm kodu gönderebilir misiniz? Evet readveri değişken sizin adc kanalınızdan okuduğunuz bilgiyi tutacak oradan veri[ ] adlı bir dizi oluşturup buraya kaydedeceksiniz. Alıntı İletiye bağlantı Sitelerde Paylaş
freedom33 3 22 Mayıs, 2020 gönderildi Share 22 Mayıs, 2020 gönderildi azmi, 7 saat önce yazdı: Evet readveri değişken sizin adc kanalınızdan okuduğunuz bilgiyi tutacak oradan veri[ ] adlı bir dizi oluşturup buraya kaydedeceksiniz. Örnek yazarsanız memnun olurum , yine olmadı. Alıntı İletiye bağlantı Sitelerde Paylaş
azmi 24 25 Mayıs, 2020 gönderildi Share 25 Mayıs, 2020 gönderildi Hangi İşlemci ve Hangi derleyici ?kullanıyorsunuz Alıntı İletiye bağlantı Sitelerde Paylaş
Guest Haluk Şimşek 31 Mayıs, 2020 gönderildi Share 31 Mayıs, 2020 gönderildi Ben burada uyguladım ve gayet başarılı buldum. Hareketli veya sabit ortalama almaktan çok daha iyi sonuç verdi. Her seferinde ölçülen değerin etkisini 10 da 1 veya 100 de bir gibi oranla etkilediğinden ortalama ile aynı işi yapılmış oluyor. Şenol beye teşekkür ederim. https://hobidenfazlasi.blogspot.com/2020/05/avr-adc-okuma-ve-rs485-ile-aktarma.html?m=1 Alıntı İletiye bağlantı Sitelerde Paylaş
şenol eker 50 2 Haziran, 2020 gönderildi Yazar Share 2 Haziran, 2020 gönderildi freedom33, 5/22/2020 - 9:32 PM yazdı: Örnek yazarsanız memnun olurum , yine olmadı. Ne yapmak istediğinizi anladığıma emin olamadım. Burada bir "normal ortalama alma yöntemi" kodu var, bu kod çok uzun, çok yavaş ve çok bellek tüketiyor. Makalede asıl anlatılan ise "akan veride ortalama alma yöntemi". Bu kod çok kısa, RAM gereksinimi de çok az. Siz hangisini uygulamak istiyorsunuz? Alıntı İletiye bağlantı Sitelerde Paylaş
freedom33 3 3 Haziran, 2020 gönderildi Share 3 Haziran, 2020 gönderildi şenol eker, 21 saat önce yazdı: Ne yapmak istediğinizi anladığıma emin olamadım. Burada bir "normal ortalama alma yöntemi" kodu var, bu kod çok uzun, çok yavaş ve çok bellek tüketiyor. Makalede asıl anlatılan ise "akan veride ortalama alma yöntemi". Bu kod çok kısa, RAM gereksinimi de çok az. Siz hangisini uygulamak istiyorsunuz? Ben sizin 2. verdiğiniz kodu uygulamak istemiştim, arduino mega ya bağlı analog bir sensör kontrol etmek için, ve aynı zamanda float döndürmem gerek veriyi ondalıklı sonuç alabilmem için. float oranh=0.9; float oranl=1-oranh; float sonuc=ReadVeri(); while (1) { printf("%i\r\n";(int)sonuc); sonuc=sonuc*oranh+ReadVeri()*oranl; } Alıntı İletiye bağlantı Sitelerde Paylaş
şenol eker 50 19 Haziran, 2020 gönderildi Yazar Share 19 Haziran, 2020 gönderildi Yazdığın kod son derece doğru. Ama float olan yerleri float olarak belirtmek daha garanti olacak: float oranh=0.9; float oranl=1.0-oranh; //.0 ekledim float sonuc=(float)ReadVeri(); //float ekledim while (1) { printf("%i\r\n";(int)sonuc); sonuc=sonuc*oranh+(float)ReadVeri()*oranl; //(float ekledim) } Bunda yaşadığınız sıkıntı nedir? Eğer yeterli yumuşatma yapmıyorsa, oranh'ı yükseltin. Örneğin: float oranh=0.95; ya da float oranh=0.98; gibi. Kimi uygulamalarda 0.998'e kadar çıkmak icap eder eğer veri çok gürültülü ise ve oluşacak lag sorun çıkartmayacaksa. 1 Alıntı İletiye bağlantı Sitelerde Paylaş
ergin demirtas 1 6 Aralık, 2020 gönderildi Share 6 Aralık, 2020 gönderildi şenol eker, 4/18/2020 - 11:57 AM yazdı: Aynı (ya da çok benzer) işi yapmanın çok kolay bir yolu var aslında. Bu yöntemle elde edilen çıkış şöyle: Diğeriyle neredeyse aynı sonucu veriyor gördüğünüz gibi. Ama yazmamız gereken kod diğeri ile mukayese bile edilemez: float oranh=0.9; float oranl=1-oranh; float sonuc=ReadVeri(); while (1) { printf("%i\r\n";(int)sonuc); sonuc=sonuc*oranh+ReadVeri()*oranl; } Burada verdiğimiz oranh, son kaç verinin ortalamasını almak istediğimiz. 0.9 verdiğimizde son 10; 0.99 verdiğimizde son 100; 0.999 verdiğimizde son 1000 verinin ortalamasını almaya benzer bir sonuç elde ederiz. Bu yöntemi ben bir yerden öğrenmedim; daha önce çok defa başıma geldiği gibi kendim buldum ama sonradan benden yıllar önce başka birinin bunu zaten icat etmiş olduğunu öğrendim. Kaynak olmaksızın, eğitim almaksızın kendine kendine öğrenmenin zararları işte... Bunun da daha önce icat edildiğinden eminim. Ama kim icat etmiştir, adı nedir bilmiyorum. Bilen varsa ve yazarsa ben de öğrenirim... Burada ki ''oran'' değişkenlerinden bağımsız bir şekilde son 100 veri için benzer ortalama bir filtre yapmak istiyorsak; filtreliveri=hamveri*0.99+hamveri*0.01 diyebilir miyiz hocam? 1 Alıntı İletiye bağlantı Sitelerde Paylaş
şenol eker 50 6 Aralık, 2020 gönderildi Yazar Share 6 Aralık, 2020 gönderildi "Kabaca" evet. Ama aslında bu yöntem, tam olarak "son yüz tanenin ortalaması" sayılmaz. Sondakilerin ağırlığı daha fazla, eskilerin ağırlığı daha azdır. Ancak çok zaman bu, son yüz tanenin ortalamasından daha işe yarar sonuç verir. Sonuca bakıp bu değerleri değiştirebiliriz. Şuna çok dikkat: iki katsayının toplamı 1 olmalı. Burada hataya düşmemek için ben genellikle: p1=0.99 p2=1-p1 gibi yazarım ve sadece p1'i değiştiririm. Son 10 tanesi için 0,9 bve 0,1 son 100 tanesi için 0,99 ve 0,01 son 1000 tanesi için 0,999 ve 0,001 gibi düşünebiliriz. Ancak tekrar ediyorum, 0,99/0,01 ile bu algoritmayı uygulamak ile son 100 tanesinin ortalamasını almak "benzer" sonuçlar verse de, tam olarak bu değil. 2 Alıntı İletiye bağlantı Sitelerde Paylaş
Önerilen İletiler