Kararlı ADC için dijital filtre

Başlatan Analogic, 13 Aralık 2011, 22:44:02

Analogic

Merhaba,
Pic ile kendi çapımda birşeyler yapabiliyorum. Fakat genellikle ADC okuması yaptığım devrelerde kararsız çalışma, yakınındaki diğer cihazlardan etkilenme, örneğin odanın lambasını yaktığım anda adc den okunan değerin peak yapması gibi sıkıntılar yaşıyorum.
Çok sık karşılaşmasam da, bu parazitlerden kurtulmak istiyorum,
Birçok elektronik devrede olduğu gibi, pic için de ekranlama, analog filtreler vs. yanında, yazılımsal olarak da etkili dijital filtre algoritmaları kullanıldığını öğrendim.
Bu dijital filtreler hakkında teorik bilgiler heryerde var fakat, Türkçe sitelerde dişe dokunur bir örnek-uygulama yada anlatım bulamadım.
Yapmak istediğim filtre tam olarak şöyle.
Peşpeşe 15 adet adc okuması yapacak, bunları değerlerinin büyüklüğüne göre sıralayıp, en küçük 5 taneyi ve en büyük 5 taneyi atacak.
(Böylece peak ve dip değerleri atmış olacağız.) Elimizde kalan ortadaki 5 değerin de ortalamasını alıp o değeri adc değeri olarak kabul edecek algoritmayı picbasic ile yapabilir miyiz? (Buna median filtre deniliyor galiba)

12f675 için yazdığım aşağıdaki kod parçacığında ete hocanın adc dersinde anlattığı ortalama alma metodunu kullandım, fakat daha stabil filtrelemeye ihtiyacım var. Ete hoca yada konu hakkında tecrübeli arkadaşlar bu konuda bildiklerini uygulama örnekleri vererek paylaşırlarsa, bu konudaki eksikliğin giderileceğini düşünüyorum.

Define   ADC_BITS      10   
Define   ADC_CLOCK      3   
Define   ADC_SAMPLEUS   50

TRISIO =  %00000001
ADCON0 = %10000010

deger var word
toplam var word
sonuc var word
sayac var byte

toplam=0

basla:

'-------------------
For sayac=1 To 5
ADCIN 0, deger
toplam=toplam+deger
next   
sonuc=toplam/5


Şu linkte birşeyler var ama pek birşey anlamadım malesef.
http://www.picbasic.co.uk/forum/showthread.php?t=8046&p=50415#post50415

F®T

TOP_R=0
         For R=0 To 24     
         RHAM=ADIn 0
         TOP_R=TOP_R+(RHAM+1)
         Next
         RHAM=TOP_R/25


Bu tip ortalama alabilirsin.25 ölçümün ortalamasıdır.


"Hakk" şerleri hayr eyler Zannetme ki gayr eyler Ârif anı seyreyler Mevlâ görelim neyler Neylerse güzel eyler.

Analogic

Alıntı yapılan: ferittt - 13 Aralık 2011, 22:52:26
TOP_R=0
         For R=0 To 24     
         RHAM=ADIn 0
         TOP_R=TOP_R+(RHAM+1)
         Next
         RHAM=TOP_R/25


Bu tip ortalama alabilirsin.25 ölçümün ortalamasıdır.

Merhaba, ilginiz için teşekkürler,
Yukarıdaki mesajımdaki kod parçacığında böyle bir ortalama alma mevcut zaten (5 değerin ortalaması) ama, ben filtreleme olayını anlamak-öğrenmek ve adc konusunda kendimi daha çok geliştirmek istiyorum.

ete

Median filtre algoritması genelde resim düzeltme sistemlerine uygulanır diye biliyorum.
Pic ADC okumalarında çok avantajlı olacağını sanmıyorum. ADC zaten bir iniş çıkış sistemidir. Giren sinyalin seviyesine göre okunan değer düşer yada artar. O halde düşenleri atacak yükselenleride atacaksın ortada ard arda durağan okumaların verdiği değerleri kullanacaksın demektir. Bu durumda yaptığın işin doğruluğu tartışılır bence. Bu konuya yeniden döneceğim ve nasıl yapılacağınıda açıklamaya çalışacağım.

Ben genelde çoklu okuma yapıp ortalama almayı yeğlerim. Zaman zamanda 20 eprom adresi kullanır ve ADC okumasından önce bütün kayıtları bir kaydırırım. Sonra okunan ADC yi en sona yazdırır ve bütün kayıtların ortalamasını alırım. Tabiiki okuma yaparkende bir ortalama alırım. Böylece önceki okunanlar ile yeni okunaların bir ortalaması sonucu verirki epeyce kararlı bir okuma yöntemidir. Fazla iniş çıkış vermez bu sistem. Tabiiki zaman alan bir iş.
Bu sistemi yaptığım digitalgüç kaynağında volt okuma ve akım okuma sisteminde kullanmıştım. Kullanmaz isen okunan değerler çok fazla eğişkenlik arz ediyor idi.

Genelde pic ADC okumalarında bu iki sistem kullanılır. Binlerce sistem gördüm ama Median kullanıldığını hiç görmedim.

Her neyse gelelim Median algoritmasına;
- 15 adetlik bir dizi değişkeni tanımlanacak.
- 15 adetlik bir döngü kurup okunan adc değerleri sırası ile dizi elemanlarına aktarılacak.
- Sonra okunan değerler büyükten küçüğe göre sıralanacak yada tersi fark etmez.
- Daha sonra ortadaki 5 adetin ortalaması alınıp kullanılacak. Sistem budur.
Neden dizi kullandık onuda açıklayayım. Bu tür işlemlerde dizi kullnılması gerekir. Çünki index yöntemi ile dizi elemanlarına yer değiştirme yapmanız gerekecektir. Dizi indexi kullanılarak bu iş kolayca yapılabilir.

Açıklamayı bu kadar veriyorum. Sanırım bu açıklamada belirtilenlerden yalnızca sıralama mantığını bilemiyoruz diyebilirsiniz. Onu şimdilik vermiyorum Eminim pek çoğunuz bunuda yapabilecek seviyededir. Bu gün içinde buna ait örneği vereceğim. Ama biraz düşünmenizi istiyorum.

Kolay Gelsin
Ete,




ete

Kimseden bir ses çıkmamış. Soru soranda yok. Her şey yolunda demek. Yada benden gelecek açıklamayı bekliyor millet.
Her neyse önemli değil. Açıklamamı işlemciye bağlı kalmadan standart açıklama şeklinde vereceğim. Öncelikle
bir dizi değişkeni tanımlayacağımızı belirtmiştik.

OKUNAN VAR WORD[15]  'parentez içinde kaç adet dizideğişkeni ihtiyacımız var ise o rakamı yazıyoruz . 15 adet okuma yapacağımız için değişken adedimiz 15 olacaktır. Ama sıralamada sıfır dahil olduğu için 0-14 arasını kullanacağız.

TEMP VAR WORD
TOPLAM VAR WORD
HAM VAR WORD
X     VAR BYTE
Y     VAR BYTE

Program başladıktan sonra önce 15 adet ADC okumasını yapıp okuma değerlerini dizi değişkenine aktaracağız.

FOR X=0 to 14
  ADCIN 0, HAM
  OKUNAN[X]=HAM+1
  PAUSEUS 100
NEXT

Buraya kadar 15 adet değişkenimizde okunan adc değerleri rastgele yerleşmiş oldu.
Şimdi bunları bir sıraya dizmemiz gerekiyor. Bubble Sort yöntemini kullanacağız.
FOR X=0 to 13
   FOR Y=(X+1) TO 14
      IF OKUNAN[X]>OKUNAN[Y] THEN
          TEMP=OKUNAN[X]
           OKUNAN[X]=OKUNAN[Y]
           OKUNAN[Y]=TEMP
      ENDIF
   NEXT
NEXT
Buraya kadar dizi değerlerini küçükten büyüğe doğru sıraya dizmiş olduk.
Şimdi ortadan 5 elemanı alıp ortalamasını alacağız.
TOPLAM=0
FOR X=5  TO 9
  TOPLAM=TOPLAM+OKUNAN[X]
NEXT
TEMP=TOPLAM/5
İşte sonunda ortada yer alan 5 elemanın ortalamasını alıp TEMP değişkenine yerleştirmiş olduk.
Yanlış yapılmaması için bu kod parçasında kullanılan diğer değişkenleride olması gerektiği gibi tanımladım.
Umarım anlaşılmıştır.


Ete

Analogic

Alıntı yapılan: ete - 14 Aralık 2011, 21:48:20
Kimseden bir ses çıkmamış. Soru soranda yok. Her şey yolunda demek. Yada benden gelecek açıklamayı bekliyor millet.
Her neyse önemli değil. Açıklamamı işlemciye bağlı kalmadan standart açıklama şeklinde vereceğim. Öncelikle
bir dizi değişkeni tanımlayacağımızı belirtmiştik.

Ete

Özür dilerim hocam, bugün yoğun bir gündü ancak müsait olabildim, siteye gündüz kısa bir süre girdim ama acil yetiştirmem gereken işler vardı, mesaj yazamadan çıkmak zorunda kaldım. İlgilendiğiniz için çok teşekkür ederim. Yanlış anlaşılmak istemem. Kesinlikle amacım hazır kodu al git filan değil, elektronik konusunda elimden geldiğince ben de bilgi ve tecrübelerim doğrultusunda bilgilerimi paylaşan bir insanım, pic başta olmak üzere mcu dünyası, picbasic gibi zayıf olduğum konularda da konuya hakim arkadaşların destekleriyle kendimi geliştirmeye çalışıyorum.
Verdiğiniz örneği inceleyip, konuyla ilgili farklı işlemcilerle birkaç deneme yaptıktan sonra tekrardan izlenimlerimi paylaşacağım.

Analogic

#6
[IMG]http://img846.imageshack.us/img846/4104/median.gif[/img]

Uygulamaya ait simulasyonun devresi ve 16F876da denediğim kodlar

DEFINE LCD_DREG PORTB 'LCD data bacakları hangi Porta bağlı?
DEFINE LCD_DBIT 4 'LCD data bacakları hangi bitten başlıyor?
DEFINE LCD_EREG PORTB 'LCD Enable Bacağı Hangi Porta bağlı?
DEFINE LCD_EBIT 3 'LCD Enable Bacağı Hangi bite bağlı ?
define LCD RWREG PORTB 'LCD R/W Bacağı Hangi Porta bağlı?
define LCD_RWBIT 2 'LCD R/W Bacağı Hangi bite bağlı ?
DEFINE LCD_RSREG PORTB 'LCD RS Bacağı Hangi Porta bağlı ?
DEFINE LCD_RSBIT 1 'LCD RS bacağı Hangi Bite bağlı ?
DEFINE LCD_BITS 4 'LCD 4 bit mi yoksa 8 bit olarak bağlı?
DEFINE LCD_LINES 2 'LCD Kaç sıra yazabiliyor


Define   ADC_BITS      10   
Define   ADC_CLOCK      3   
Define   ADC_SAMPLEUS   50
TRISA=1
TRISB=0
TRISC=0

ADCON1 = %10001110

OKUNAN VAR WORD[15]  'parentez içinde kaç adet dizideğişkeni ihtiyacımız var ise o rakamı yazıyoruz . 15 adet okuma yapacağımız için değişken adedimiz 15 olacaktır. Ama sıralamada sıfır dahil olduğu için 0-14 arasını kullanacağız.
TEMP VAR WORD
TOPLAM VAR WORD
HAM VAR WORD
X VAR BYTE
Y VAR BYTE

pause 100
LOW portb.2 'LCD RW PİNİ GNDYE ÇEKİLDİ

basla:

'Program başladıktan sonra önce 15 adet ADC okumasını yapıp okuma değerlerini dizi değişkenine aktaracağız.

FOR X=0 to 14
  ADCIN 0, HAM
  OKUNAN[X]=HAM+1
  PAUSEUS 100
NEXT

'Buraya kadar 15 adet değişkenimizde okunan adc değerleri rastgele yerleşmiş oldu.
'Şimdi bunları bir sıraya dizmemiz gerekiyor. Bubble Sort yöntemini kullanacağız.
FOR X=0 to 13
   FOR Y=(X+1) TO 14
      IF OKUNAN[X]>OKUNAN[Y] THEN
          TEMP=OKUNAN[X]
           OKUNAN[X]=OKUNAN[Y]
           OKUNAN[Y]=TEMP
      ENDIF
   NEXT
NEXT
'Buraya kadar dizi değerlerini küçükten büyüğe doğru sıraya dizmiş olduk.
'Şimdi ortadan 5 elemanı alıp ortalamasını alacağız.
TOPLAM=0
FOR X=5  TO 9
  TOPLAM=TOPLAM+OKUNAN[X]
NEXT
TEMP=TOPLAM/5
temp=temp-1       'filtrelenmiş sonuç ham değerden sürekli 1 fazla çıktığı için eklendi.

lcdout $fe,1
lcdout $FE,2,"Ham:",dec ham
LCDOUT $FE,$C0,"Filtreli:",dec temp
pause 50

goto basla


Filtreyi önce 12F675 ile denedim fakat derleme sırasında

unable to fit variable x
unable to fit variable y

hataları aldım. Bu hataları google da aradığımda, Picin hafızasının vs. yetmemiş olabileceği gibisinden mesajlar vardı, daha sonra algoritma ile ilgili kodlarda hiçbir değişiklik yapmadan sadece tanımlamaları 16f876ya uyarladım, Devreyi isite kurup denedim, sonuç beklediğimden daha iyi diyebilirim, adc ucuna pot bağlayınca adcdeki artma ve eksilmeleri sorunsuz algılıyor. Pota paralel bağladığım bir butonla da, adc girişine kısa süreli 5v peaklar uyguladım, filtrenin çalıştığını gördüm ama peakları yuttuğuna tam olarak ikna olamadım.
Daha abartılı bir peak testi yapmaya karar verdim.

Şimdi gelelim asıl olayımız olan peak testine, picin ADC ucuna 1khz frekanslı, min 2.5V - max 5V genliğe sahip, dc pulse uyguladım. Duty oranı %5-%10 iken, ham değerdeki peak lar ekrana yansırken, filtrelenmiş değer sabit 512de durdu. Duty oranı %20-25in üzerine çıkınca doğal olarak filtrelenmiş değer de, bir miktar yükseliyor.
Yani, bazı uygulamalarda lazım olan, örneğin, potla ayar yapılması gereken devreler için biçilmiş kaftan, bu haliyle adcden giren sinyalde %10 parazit olsa bile bu parazitleri görmezden gelebiliyor. (Tabi bu değerler simulasyon değerleri gerçekte değişebilir.)

Not: Konuya ilgi duyan arkadaşlara, vumetre vs. gibi adc deki değişikliğin çok hızlı ve keskin olarak algılanması gereken durumlarda bu tip filtreler kullanılamayacağını hatırlatmak isterim.

12F675te aldığım, "Unable to fit variable" hatasının sebebi nedir?
Bu filtreleri 12F675 gibi minik piclerde kullanmanın bir yolu olmalı...

ete

Verilen hata mesajı tamamen hafıza doldu bu iki değişken için yer kalmadı demek oluyor.
12F675 , program hafızası küçük olan bir pic dir. Dolayısıyla 15 adet word tipinde bir dizi hafızayı hemen dolduruyor.
BU yaklaşık 30 adet byte hafızası demektir. Anla ne kadar küçükbir program hafızası var bu işlemcinin.
İllaki 12F675 kullanmak istersen değişkenleri word değil byte olarak tanımlarsın ve ADC ölçüm hassasiyetini 10 bit den 8 bite düşürürsün.

Ete

Analogic

İllaki 12F675 olması elbette şart değil ama, sadece tek kanal adc üzerinde işlem yapmam gerektiğinde, kocaman bir işlemci kullanmak istemiyorum. Zaten daha komplike işlerde daha gelişmiş işlemciler kullanırım. Olayın mantığını anladım, biraz bubble sort yöntemini anlamakta sıkıntım var ama onu da araştıracağım. Düşük kapasiteli piclerin hafıza sorunu için de, galiba adcyi 8 bite çekmek en mantıklısı, çünkü aşırı hassas işlerden ziyade sık değer değiştirmeyen ve stabilitenin önemli olduğu uygulamalarda kullanılacağı için, 10 bit olmasının çok fazla bir esprisi de yok zaten. En kısa zamanda 8 bit olarak deneyeceğim.

ete

Bubble sort yönteminde dizinin ilk elamanı alınır ve dizinin geri kalan elemanları ile karşılaştırılır. Karşılaştırma sonucunda diğer eleman ilk elemandan daha küçük ise iki eleman yer değiştirir. Bu mantıkla dizininbütün elemanları bir birleri ile sırası ile karşılaştırlmış olur ve sonuçta dizi sıraya dizilmiş olur. Pratik ve iyi bir yöntem.

8 pin işlemci yerine gerekirse 18 pin işlemci yada 14 pin işlemci kullanabilirsin.
14 pin pek kullanamdım ama 18 pin olarak 16F88 sıklıkla kullandığım bir işlemcidir. Özellikleri nerede ise 16F628 ile aynıdır ancak hem ADC ilavesi vardır hemde hafızası daha fazladır.

Ete

Hattuşa

s.a.
buble shortla ilgili örnek yazılmış bir yazılım var elimde, yalnız bende ki yazılım 20 örnek alıp bu 20 örneğin en küçük 5 değeri ile en büyük 5 değerini hesaplamadan çıkarıp kalan 10 değerin ortalamasını alıyor. yazılım protonda yazılmış işinizi görürse ekleyebilirim.

ete

#11
Aslında işin prensibi o kadar basitki yazdığım kodalardan anlam çıkartırsınız diye düşünmüştüm.
Burada hem bubble sort tekniğini biraz detay vererek açıklayayım hemde diziden bir aralık alarak ortalamasını nasıl acağınızı tekrar açıklamış olayım.

Bubble sort da, önce dizi toplam sayısından bir eksiği kadar bir döngü kuruyoruz. İsterseniz örnekle yapalım daha kolay anlaşılır. Elimizde 20 birimlik bir dizi olsun (0-19 arası). Eleman sayımız 20 olmasına rağmen dizi 19 da bitiyor. Bu sayıya N diyelim şimdilik. Yani dizi eleman sayısının maksimum index değeridir bu sayı. (örneğimizde N=19)
Önce N-1 kadar bir döngü kuruyoruz.
FOR X=0 to (N-1)
Daha sonra okurulan döngü içinde çalışacak ikinci bir döngü daha kuruyoruz. Bu ikinci döngü ilk döngünün o andaki değerinden toplam index sayısına kadar kurulacaktır.
For Y=(X+1) to N
Şimdi İlk dizi değişkenini birinci döngü değişkenini index olarak kullanarak alalm ve ikinci döngü değişkeni indexi ile karşılaştıralım.
IF SAYI(X)>=SAYI(Y) Then   ' ilk dizi elemanı bir sonraki elemandan büyük veya eşit ise
  Temp=SAYI(X)    'ilk dizi elemanını geçici bir değişkene veriyoruz.
  SAYI(X)=SAYI(Y)  'değerler yer değiştirdi
  SAYI(Y)=TEMP    'değiştirme tamamlandı
ENDIF
Next Y
Next X
Olayı kafanızda canlandırırsanız şöyle oluşuyor; İlk dizi elemanı ikicisi ile karşılaştırılıyor.
Büyük ise yer değişiyor. BU sefer SAYI(X) ikinci elemanın değerini almış oluyor. Karşılaştırma devam ediyor. Bu sayı dizinin ikinci - üçüncü ve sonuncu elemanları ile karşılaştırılıyor ve büyükse onunla yer değiştiriyor. Dikkat ederseniz daima SAYI(X) değişkenine karşılaşılan en küçük değer yerleşmiş oluyor. Dizi sonuna kadar karşılaştırıldıktan sonra bu sefer dizinin ikinci elemanı alınıp üçüncüden başlayarak karşılaştırma yapılıyor ve bu işlemde dizi sonuna kadar yapılıyor. Burada da küçük olan daima SAYI(X) değişkenine geçiyor.
Bu şekilde işlem devam ederek dizi sıraya dizilmiş oluyor.
Şİmdi düşünün elinizde küçükten büyüğe doğru sıraya dizilmiş  bir dizi mevcut. Artık bunun istediğiniz bir aralıktaki elemanını alıp önce toplayıp sonra ortalamasını almak son derece kolay.
ELimizdeki örnek 20 birimlik bir dizi idi. (0-19) bunun sonda yer alan  10 elemanını alıp ortalamasını almak istersek;
TOPLAM=0  'bunu unutmayın
For X=10  to 19
TOPLAM=TOPLAM+SAYI(X)
Next
TEMP=TOPLAM/10
İşte bu kadar. İşin bu kısmı çok zor olmasa gerek. İsterseniz bir aralığı atın ister bir aralığı toplayın son derece kolay bir artık.

Ete

zoptrik

Ne zamandır böyle bir açıklama bekliyordum. Elleriniz dert görmesin hocam. Konuyu açandan da örnek verenden de sizden de Allah razı olsun.
iyi forumlar...
DEHA; İMKANSIZDA MÜMKÜNÜ GÖREBİLMEK DEMEKTİR.GEMİLERİN KARADA DA YÜZEBİLECEĞİNİ SEZMEK, MEHMETLERDEN BIRINI "FATİH" YAPAR...!

Analogic

#13
Başta ete olmak üzere, konuya ilgi gösteren herkese teşekkür ediyorum.
Paylaşmayı bilen herkesten Allah razı olsun.
Öğrenmeyi de, öğretmeyi de seviyorum.

Bu arada 12F675 üzerinde 8 bit olarak çalıştı.
İsis simulasyonunda pc biraz kasılıyor ama, derlenmesinde ve çalışmasında herhangi bir sorun yok.

a.zorba

proton versiyonuda benden olsun
Device 16F876A
Declare   LCD_DTPin   PORTB.4
Declare   LCD_RSPin   PORTB.2 'Pin35 -Portb.2
Declare   LCD_ENPin   PORTB.3 'Pin36 -Portb.3
Declare   LCD_Interface   4
Declare   LCD_Lines   2

Declare Adin_Res   10
Declare Adin_Tad   FRC
Declare Adin_Stime   50
TRISA=1
TRISB=0
TRISC=0

ADCON1 = %10001110

Dim OKUNAN [15] As Word  'parentez içinde kaç adet dizideğişkeni ihtiyacımız var ise o rakamı yazıyoruz . 15 adet okuma yapacağımız için değişken adedimiz 15 olacaktır. Ama sıralamada sıfır dahil olduğu için 0-14 arasını kullanacağız.
Dim TEMP As Word
Dim TOPLAM As Word
Dim HAM As Word
Dim X As Byte
Dim Y As Byte

DelayMS 100
Low PORTB.2 'LCD RW PİNİ GNDYE ÇEKİLDİ

basla:

'Program başladıktan sonra önce 15 adet ADC okumasını yapıp okuma değerlerini dizi değişkenine aktaracağız.

For X=0 To 14
  ADCIN 0, HAM
  OKUNAN[X]=HAM+1
DelayUS 100
Next

'Buraya kadar 15 adet değişkenimizde okunan adc değerleri rastgele yerleşmiş oldu.
'Şimdi bunları bir sıraya dizmemiz gerekiyor. Bubble Sort yöntemini kullanacağız.
For X=0 To 13
   For Y=(X+1) To 14
      If OKUNAN[X]>OKUNAN[Y] Then
          TEMP=OKUNAN[X]
           OKUNAN[X]=OKUNAN[Y]
           OKUNAN[Y]=TEMP
      EndIf
   Next
Next
'Buraya kadar dizi değerlerini küçükten büyüğe doğru sıraya dizmiş olduk.
'Şimdi ortadan 5 elemanı alıp ortalamasını alacağız.
TOPLAM=0
For X=5  To 9
  TOPLAM=TOPLAM+OKUNAN[X]
Next
TEMP=TOPLAM/5
TEMP=temp-1       'filtrelenmiş sonuç ham değerden sürekli 1 fazla çıktığı için eklendi.

Print  $fe,1
Print At 1,1,"Ham:",Dec HAM
Print At 2,1,"Filtreli:",Dec TEMP
DelayMS 50

GoTo basla

Powered by EzPortal