Matlab függvény: Logger Lite olvasó kényszerrezgéshez

A Fizipedia wikiből

Segítség egy egyszerű függvény elkészítéséhez

Ebben a részben szövegesen nyújtunk segítséget a függvény elkészítéséhez. Gyakorlásként célszerű saját ötlet, vagy a lenti segítség alapján elkészíteni a megfelelő függvényt. Ha ez nem kivitelezhető (túlmutat a gyakorlat idején, nincs megfelelő Matlab tapasztalat), akkor a következő fejezetben egy konkrét példát talál a függvényre, melyet használni is tud a mérés során. FIGYELEM A lenti példa függvény bonyolultabb, mint a gyakorlat elvégzéséhez szükséges funkcionalitású függvény. A saját készítésű függvény ettől lehet sokkal egyszerűbb.

Első lépésként vizsgálja meg az adatfájl struktúráját és határozza meg milyen formátumban szerepelnek benne az adatok (oszlopok száma, oszlopok azonosítása, elválasztó karakter, fejlécsorok száma)! A beolvasáshoz a textscan() függvényt célszerű használni (a függvényről bővebb információkat a Matlab help-ben talál, mely megnyílik, ha beírja a doc textscan parancsot a Command Window-ba)

  • A függvény első paramétere a fájl azonosítója, melyet a fájl megnyitására szolgáló fopen() függvény ad vissza.
  • Második paraméterként az adatok formátumát kell megadni egy stringként pl. három double értéket tartalmazó oszlop esetén az alábbi formátumban: "%f %f %f"
  • A Delimiter tulajdonság beállításával határozhatjuk meg az elválasztó karaktert. Példa tabulátor elválaszto karakter esetére: textscan(fid,"%f %f %f",'Delimiter','\t').
  • A HeaderLines tulajdonság beállításával határizhatjuk meg a fejlécsorok számát. Példa 5 soros fejléc esetére: textscan(fid,"%f %f %f",'Delimiter','\t','HeaderLines',5,).

A fentiekkel az alapvető beolvasást el tudjuk végezni, azonban ha alaposabban megvizsgáljuk az adatokat, látható, hogy amennyiben a GoLink szenzort is csatlakoztatjuk és az optikai jeladó jelét is mérjük pl. 100Hz-el, akkor a GoMotion jelét túlmintavételezzük (max 25Hz-es mintavételezésre képes). A Logger Lite azokat a sorokat, amelyeknél nem tudott adatot rögzíteni a GoMotion szenzor, egy szóközzel tölti fel. Ezt a beolvasáskor kezelnünk kell.

  • A TreatAsEmpty paraméterrel álíthatjuk be, hogy a szóközt üres értékként kezelje, majd az EmptyValue paraméterrel azt is be tudjuk állítani, hogy az üres értékek helyére milyen értéket írjon a textscan() függvény. Ennek az értéknek célszerű valami jól felismerhető értéket választani, mert később erre szereténk szűrni (pl. végtelen, negatív végtelen, stb). Folytatva a fenti függvényt, példa az üres sorok kezelésére és feltöltésére negatív végtelennel: textscan(fid,"%f %f %f",'Delimiter','\t','HeaderLines',5,'TreatAsEmpty',{' '},'EmptyValue',-Inf).

A textscan függvény kimenetként egy cell típusú változót ad vissza, melynek egyes elemei a beolvasott oszlopok. A továbbiakban az időjelre és a GoMotion pozíciójának értékeire lesz szükség, ezeket célszerű kimásolni 1-1 vektorba. Ha túlmintavételeztük a GoMotion szenzort, akkor az üres értékeket még kezelnünk kell. Ehhez célszerű a find() függvényt használni!

A megfelelő függvény egy lehetséges megvalósítása kis extrával

Az alábbi függvénnyel megvalósítható a GoMotion jelének beolvasása, sőt extraként a meghajtójel frekvenciáját is kiszámolja, ha csatlakoztatva van a GoLink szenzor. A függvény bemeneteként meg kell adni a Logger Lite által kimentett fájl elérési útját és opcionális paraméterként megadható egy kezdeti és egy végső időpontot (másodpercben). A függvény a két időpont közötti adatokat fogja betölteni. Fontos, hogy a GoMotion legyen az 1-es számú szenzor, így a pozíciójel a kimentett fájl második oszlopába kerül. Ha az optikai szenzor jelét mérő GoLink nincs csatlakoztatva, akkor azt a függvény jelzi, így a meghajtásra vonatkozó értékeket nem számolja ki, de a GoMotion pozíciójelét így is ki tudja számolni. A függvény a következő kimeneteket adja vissza:

  • t - a GoMotion szenzor mintavételezéséhez tartozó időpillanatok [s]
  • pos - A GoMotion szenzor által mért pozíció (nullára centrálva) [m]
  • pos0 - A GoMotion által mért pozíció átlaga, azaz a rúd nyugalmi helyzete (a tényleges pozíció a pos és pos0 összege) [m]
  • t_drive - A GoLink szenzor mintavételezési időpontjai [s]
  • signal_drive - A GoLink szenzor jele [V].
  • sin_drive - A függvény által számolt elméleti szinuszos meghajtójel normált amplitúdóval.
  • drive_fq - A meghajtójel függvény által számolt értéke [Hz]

A függvény Matlab kódja

  function [t pos pos0 t_drive signal_drive sin_drive drive_fq]=read_sin_dr(file,start,stop)
       arguments
            file (1,1) string
            start (1,1) {mustBeNumeric, mustBeFinite} =0
            stop (1,1) {mustBeNumeric} = Inf
       end
               %Fontos, hogy a GoLink és a GoMotion is csatlakoztatva legyen és a megfelelő legyen a sorrendjük! GoMotion poziítiója legyen a 2. oszlop!
   t=[];
   pos=[];
   pos0=[];
   t_drive=[];
   signal_drive=[];
   sin_drive=[];
   drive_fq=[];
   try
               %Fájl megnyitása
       fid=fopen(file);
       if(fid==-1)
           disp("Hiba a fájl megnyitásakor!")
           return
       end
               %Beolvasás a fájlból:
               %A Logger Lite által kimentett txt 7 fejlécsort tartalmaz, ezt kezeljük a -- 'HeaderLines',7 -- beállítással, utána 5 oszlopban tabulátorral elválasztva jönnek az adatok, a formátum "%f %f %f %f %f" (double értékeket olvasunk be) és az elválasztó karaktert a -- 'Delimiter','\t' -- állítja be.
               %A túlmintavételezés miatt a GoMotion szenzor jelében csak minden negyedik sorban szerepel érték, a beolvasásnál ezt kezelni kell. A kimaradó értékek helyett szóköz szerepel, a beolvasófüggvényben ezt üres értékként kezeljük, amit a -- 'TreatAsEmpty',{' '} -- állít be. Utána az üres értékeket negatív végtelenre állítjuk, mert erre könnyű szűrni, ezt a -- 'EmptyValue',-Inf -- beállítás oldja meg.
   temp=textscan(fid,"%f %f %f %f %f",'Delimiter','\t','HeaderLines',7,'TreatAsEmpty',{' '},'EmptyValue',-Inf);
               %A beolvasás egy cell változót ad vissza, ebből kivesszük az értékekek. Az első oszlop az idő, a második oszlop a GoMotion jele, az 5. oszlop a GoLink jele.
       t_drive=temp{1};
       signal_drive=temp{5};
       t=temp{1};
       pos=temp{2};
               %Ha adtunk meg start és stop értéket, akkor kivágja a kettő közötti tartományt.
       if(stop>start)
           temp2=temp{2}(find(t_drive>=start&t_drive<=stop)); %Ezt a változót majd az elméleti meghajtójel levágásánál használjuk
           signal_drive=signal_drive(find(t_drive>=start&t_drive<=stop));
           t_drive=t_drive(find(t_drive>=start&t_drive<=stop));
           pos=pos(find(t>=start&t<=stop));
           t=t(find(t>=start&t<=stop)); 
       end
               %A GoMotion jeléből csak azokat a sorokat szeretnénk a végső jelben látni, ahol ténylegesen van érték. Ezek a nem -Inf-el egyenlő sorok, ezeket keressük meg a find() függvénnyel és csak ezeket adjuk át a pos változónak.
               %Utána az időjelnél hasonlóan járunk el, csak azokat az időpontokat adjuk át, amelyeknél a pozíciónak értelmes értéke van.
       t=t(find(pos~=-Inf));     
       pos=pos(find(pos~=-Inf));
               %A pozíció nullontját kiszámolja egyszerű átlagolással és levonja, így egyszerűbb a későbbi illesztés
       pos0=mean(pos);
       pos=pos-pos0;
               %Meghajtás frekvenciájának meghatározása:
               %Először kisimítjuk a jelet, az 5V-hoz közeli értékeket 5V-ra állítjuk, így az esetleges zaj nem fog zavarni a numerikus deriváltban.
       signal_drive(find(signal_drive>=4.95))=5;
               %Vesszük a deriváltat és meghatározzuk az előjelét minden pontra. Azokat az pozíciókat keressük majd, ahol a derivált előjelet vált.
       sgn_diff=sign(diff(signal_drive));
               %Először megkeressük a negatív helyeket, majd egy for ciklussal megnézzük minden negatív pont utáni pontban az előjelet és ahol pozitív, ott volt egy csúcs
       posn=find(sgn_diff==-1);
       posp=[];
       for i=1:length(posn)
           if(sgn_diff(posn(i)+1)==1)
               posp(end+1)=posn(i)+1;
           end
       end
               %Megszámoljuk hány csúcs volt összesen és az utolsó, valamint az első pozíciójának különbségéből tudjuk az időt, ezt el kell osztani a periódusok (csúcs-1) számával és megvan a preiódusidő, ebből pedig a frekvencia.
       Nump=length(posp);
       DT=t_drive(posp(end))-t_drive(posp(1));
       dt=DT/(Nump-1);
       drive_fq=1/dt;
               %Elkészíti az elméleti meghajtójelet
       sin_drive=cos(2*pi*drive_fq*(t_drive-t_drive(posp(1)))+pi);
       sin_drive=sin_drive(find(temp2~=-Inf));
   catch
       if(isempty(drive_fq))
           disp("Hiba az optikai jeladó jelének feldolgozásában!")
           return
       end
           disp("Hiba a futtatásban!")
       return
   end