Jump to content
  • Kaydol

Önerilen İletiler

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:
s1.png.611b61efd908928b4bb559697a6eb9fb.png

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:
s2.png.b418bf5e6610ee287fdb86d6e139dd7b.png

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.

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş

Aynı (ya da çok benzer) işi yapmanın çok kolay bir yolu var aslında. Bu yöntemle elde edilen çıkış şöyle:
s3.png.51465bd956558bcfc5566d07b93c6ba7.png

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...

 

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş

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));
}

 

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş

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.

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
ş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.

 

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
ş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;
}

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
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.  

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
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ı.

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
Guest Haluk Şimşek

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

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
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?

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
ş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;
}

 

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş

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.

İletiyi paylaş


İletiye bağlantı
Sitelerde Paylaş
Misafir
Bu konuyu yanıtla

×   Yapıştırdığınız içerik biçimlendirme içeriyor.   Biçimlendirmeyi Temizle

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Önceki içeriğiniz geri yüklendi.   Editör içeriğini temizle

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Yeni Oluştur...

Önemli Bilgilendirme

Facebook / Twitter / Google hesabınızla kolayca kaydolup cevap verebilir, soru sorabilir, istekte bulunabilirsiniz.
Devam etmeniz, forum kurallarını kabul ettiğiniz anlamına gelir.            Forum Kuralları