Schwingungs-/Frequenz-Anlayse

Zuviel Werbung?
-> Hier kostenlos registrieren
... erzähl ...
was nimmst du dafür ?

Ich wollte jetzt nicht Werbung machen deswegen erst jetzt:

VIPA
CPU mit normalen I/Os und mehr Rechenleistung als 317
314-6CF02 CPU 314ST/DPM - SPEED7-Technologie

Schnelle Eingänge mit Speicherfunktion
331-7BF70 SM 331S - Analoge Eingabe FAST - SPEED-Bus

Speedbus Backplane zur linken Seite (an der rechten Seite gehen die normalen Module)
391-1AF10 BP 391 SPEED-Bus, DIN rail, 530mm, 2xEs


Bei Bedarf ist es mit dem System auch möglich von der CPU aus mit dem OB28
alle 250µs Werte aus dem Analogmodul zu holen. (OB28 ist wie OB35 nur fest
auf 250µs, OB29 ist fest auf 500µs)
 
Ich würde den Aliasfilter nicht vergessen, sonst erhält man Messungen, die nicht korrekt sind. Daher der Aliasfilter sollte Frequenzen oberhalb der halben Abtastfrequenz unterdrücken und zwar so viel, dass das LSB des AD-Konverters auf diese Frquenzen nicht mehr anspricht. Da kein Filter derart exakt ist, wird man nicht das volle Spektrum bis Fabtast/2 nutzen können. Der Aliasfilter sollte idealerweise im AD-Konverter liegen.

Der Hintergrund ist der, dass bei der Abtasttung bei Fabtast/2 die Frequenzen gespiegelt werden, so dass es zu Überlagerungen kommt. Der Filter ist häufig ein Problem, wenn der steil sein muss, weswegen man gerne Fabtast erhöht, um die Filterkurve flacher machen zu können, was auch wesentlich billiger ist.


Etwas was zu berücksichtigen sein könnte, ist die Samplezeit. Während die Eingangsspannung eingelesen wird, ändert sich der Eingang. Dieses Samplefenster wirkt sich derart aus, dass je breiter dieses Fenster ist, desto ungenauer die Frequenzbestimmung.Beckhoff 12-Bit-Ethercat-Klemmen haben eine Wandlungszeit von 500us. Über die Samplezeit wird natürlich nichts geschrieben und ich muss davon ausgehen, dass der AD-Wandler ohne Sample-und-Hold-Glied am Eingang liegt.

Ein billiges Oszilloskop von Agilent, macht das übrigens auch und mit allem was man benötigt. Man kann das dann sogar per RS232 machen. Der Eingangswiderstand ist dann 1Megaohm und weitere Funktionen, um die Hauptfrequenzen herauszubekommen sind kein Problem. Ich würde das der SPS vorziehen.
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
@Longbow:
Ich werde das mal im Hinterkopf behalten. Im Augenblick ist der Umstieg kein Thema ...

@drfunfrock:
Samplingrate im Moment : jede ms.
OB35-Aufruf alle 3 ms - sicher ist auch alle 2 ms machbar, bringt aber keinen entscheidenen Zugewinn. Mit Filtern habe ich bei / mit einem Konkurenzprodukt (Delphin) gearbeitet. Hier spielte es keine Rolle, ob der relativ komplizierte Filter von denen aktiv war oder nicht. Somit arbeitet mein Auswerte-Programm derzeit (natürlich) auch ohne. Zur Zeit keine Nachteile erkennbar. Der festgestellten Frequenz-Ereignisse bewegen sich sehr exakt im Bereich der erwarteten Symptom-Frequenzen. Bei meinen Lagern mit der aktuellen Drehzahl zur Zeit 64 Hz und 40 Hz.

Gruß
LL
 
@Longbow:
Ich werde das mal im Hinterkopf behalten. Im Augenblick ist der Umstieg kein Thema ...

Samplingrate im Moment : jede ms.

Gruß
LL
Du hast eine Abtastfrq. von 1000Hz. Der Filter müsste also bei 500Hz liegen. Damit sollte ein Filter 2. oder 4. Ordnung ausreichen, was sich mit OPs machen lässt. Es kann aber sein, dass in deinen Konvertern schon einer drin ist. Ich würde mir die Arbeit nicht machen und lieber einen Oscar spendieren. Das Problem ist, dass du nicht weisst, wann die Aliasfrequenzen dich stören und du musst sie filtern.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Longbow:
Ich werde das mal im Hinterkopf behalten. Im Augenblick ist der Umstieg kein Thema ...

@drfunfrock:
Samplingrate im Moment : jede ms.
OB35-Aufruf alle 3 ms - sicher ist auch alle 2 ms machbar, bringt aber keinen entscheidenen Zugewinn. Mit Filtern habe ich bei / mit einem Konkurenzprodukt (Delphin) gearbeitet. Hier spielte es keine Rolle, ob der relativ komplizierte Filter von denen aktiv war oder nicht. Somit arbeitet mein Auswerte-Programm derzeit (natürlich) auch ohne. Zur Zeit keine Nachteile erkennbar. Der festgestellten Frequenz-Ereignisse bewegen sich sehr exakt im Bereich der erwarteten Symptom-Frequenzen. Bei meinen Lagern mit der aktuellen Drehzahl zur Zeit 64 Hz und 40 Hz.

Gruß
LL

Und was für eine Analogkarte setzt du ein, wie schnell ist die? Ich hatte das auch mal getestet, da kannst du so schnell abfragen wie du möchtest, die Werte ändern sich dann ebend nur jedes 3. oder 4. Mal. Ist also auf jeden Fall mal interessant, die Datenreihe genauer anzusehen, um festzustellen, was der AD-Wandler wirklich bringt.
 
@Ralle:
Da ich jetzt nicht mehr auf der Arbeit bin und nicht genau nachschauen kann schiesse ich mal aus der Hüfte. Ich behaupte mal die Karte heißt : 335-7HG01
In den Parametern läßt sie sich auf eine Abtastrate von 1ms einstellen. Ich erhalte beim Einlesen über den OB35 auch keine 2 gleichen Werte beim Einlesen. Ich muss aber gestehen, dass diese Abtast-Frequenz das absolute Max. meiner bisherigen Mess- und Auswerte-Versuche darstellt.

@drfunfrock:
Die Idee mit dem externen Gerät (in diesem Fall wie schon ein paar mal erwähnt von Fa. Delphin) war der Start dieser Geschichte von Seiten meiner Firma. Dieses Gerät macht angeblich 20.000 Messungen in 3,2 Sek. und hat alles an Filtern, was man sich vorstellen kann. Dummerweise (und da kommt dann mein Neben-Projekt ins Spiel) liefert es KEINE reproduzierbaren Ergebnisse ein und desselben Lagers. Die Amplitudenwerte an den Symptom-Frequenzen streuen zischen 5 und 15 - oder anders gesagt zwischen IO und NIO. Wie soll man so eine Auswertung fahren ?
Meine Eigene kleine Bastelei, eigentlich als Add-On zu einer bestehenden Anordnung gedacht, obwohl von den Fähigkeiten wesentlich primitiver, macht diese Streuung nicht. Ein Lager schwankt an der Symptom-Frequenz und aber auch im Rest-Spektrum nur um +/- 5% zwischen 2 Messungen (maximal) - und ich habe wirklich viel getestet heute.
Was würdest daraus nun für Schlüsse ziehen ?

Gruß
LL

Nachtrag:
Ich möchte hier niemanden meine Arbeit verkaufen. Ich habe nur ein paar Leuten im Forum, die mich bei dieser Sache auf die richtige Spur gebracht haben, versprochen, über den Fortgang dieser Geschichte zu berichten, was ich nun hiermit getan habe. Vielleicht hilft es ja irgendwann irgendwem weiter ...
 
Zuletzt bearbeitet:
Das die Frequenz schwankt ist nicht ungewöhnlich. Das du andere Ergebisse mit der externen Box erhälst, kann schon daran liegen, dass das Sample- und Hold-Glied am Eingang des AD-Wandlers eine andere Zeitspanne zum Sampeln benötigt. Je kleiner diese Zeitspanne, desto genauer kannst du verschiedene Frequenzen von einander unterscheiden. Daher auch dein Problem mit den schwankenden Frequenzen. Das externe Gerät arbeitet einfach genauer, während dein SPS-Eigenbau 2 nebeneinanderliegende Linien zu einer macht, weil ich vermute, dass die Samplefrequenz gleich der Wandlungszeit ist.

Der Punkt ist der, dass die Gleichungen für die FFT in der Regel für die Abtastung mit einem unendlich schmalen Dirac-Impuls angegeben werden. Das ist natürlich nicht die Realität. Die Abtastung sieht so aus, dass man z.B. über eine Zeit deltaT die Spannung am Eingang einliesst. Somit gleicht die Abtastfunktion mehr einem Rechteck. Dh. wird das Eingangssignal noch mit dieser Rechtecksfunktion verknüpft. Das Resultat ist das, je grösser deltaT wird, desto schlechter die Unterscheidung zwischen nebeneinanderliegenden Frequenzlinien. Dh. in deinem Fall wirst du eine Art Mittel erhalten, was anscheinend genügend ist.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@drfunfrock:
Fast keinen Einwand zu deinem Beitrag ...
Frequenz-Schankungen wären OK und liegen sicher auch in der Natur der Sache. Amplituden-Schwankungen in dem geschilderten Maße m.E. nicht. Zur Verdeutlichung :
Ein Amplituden-Ausschlag von 5 wäre gerade noch IO. Darüber eigentlich NIO. Schwankungen in der Abtastung von 5 - 15 in einem Frequenzband bei Mittelung der Werte bei dem gleichen Teil für das Prüfverfahren nicht tolerierbar.
Mir ist klar, dass meine Auswertung möglicherweise von seiner "Ungenauigkeit" profitiert. So etwas ähnliches hatte ich an anderer Stelle auch schon mal. Entscheidend ist aber in der Hauptsache, dass die Auswerte-Ergebnisse reproduzierbar sind und das kann "mein" FFT-FB interessanterweise leisten.
Ich habe aber (angeregt durch deine Beiträge) noch ein paar Manipulationen im Hinterkopf, die ich auf jeden Fall noch testen werde / möchte. Mal sehen, was dabei herauskommt. Ich werde davon berichten ...

Gruß
LL
 
Hallo Larry, kannst du mir den Code für die FFT-Analyse zu kommen lassen?
Gruß
Alex
 
Zuletzt bearbeitet:
Hallo Alex,

ich beantworte das mal hier (auf die PN bekommst du also nicht noch zusätzlich ein Feedback ;))

Selbstverständlich kann ich dir den Code zukommen lassen (ihn hier veröffentlichen). Das werde ich nächste Woche dann machen.
Du mußt allerdings schon die schon angesprochenen Einschränkungen in Kauf nehmen :
- die Zykluszeit der Auswertung wächst exponentiell zur Anzahl der auszuwertenden Messwerte.
- aufgrund der Abtastrate bis bu hinsichtlich der Frequenzen, die sinnvoll abgebildet werden, eingeschränkt.

Verrätst du mir im Gegenzug, was du damit vor hast ?

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Larry,
die Schwingungsanalyse ist für einen Getriebeprüfstand gedacht. Ein Schwingungssensor (ein PCH1272 4..20mA) wird am Analogeingang eines SM_1231 AI4_13Bit eingelesen und mit der SPS S7_1212C ausgewertet.
Das zu erwartende Frequenzspektrum liegt im Bereich 10...400Hz, wobei ich mit der Hardware nur die Schwingungen bis ca. 200Hz einlesen und analysieren kann (die Schwingungen an der Welle 1 des Getriebes n = 1460 1/min werden leider nicht zu analysieren sein).
Ich habe das Ganze schon mit DFT umgesetzt (N = 500, OB30 = 2ms, FK=250 => Ausgabe-Frequenzspektrum = bis 250Hz), aber die Auswertungszeiten liegen "jenseits von Gut und Böse".....
Ich muss ehrlich gestehen, dass ich den FFT Algorithmus nicht ganz nachvollziehen kann (DFT ist dagegen um einiges verständlicher), aber ist es nicht so, dass die Zykluszeit mit DFT um N² und mit FFT um N*log(N) ansteigt?

Gruß
Alex
 
Zuletzt bearbeitet:
Hallo Larry,

du hast bestimmt mit: "- die Zykluszeit der Auswertung wächst exponentiell zur Anzahl der auszuwertenden Messwerte " das gedacht, dass N*log(N) = N*10^(exp.),
da log(N)= exp.?
Der FFT-Algorithmus ist um einiges schneller als der DFT-Algorithmus.


Gruß
Alex
 
Zuletzt bearbeitet:
Du hast Recht, dass der FFT sehr viel schneller ist als der DFT - trotzdem vergeht einiges an Zeit bei der Auswertung.
Ob du da mit deiner 1212 glücklich wirst möchste ich ein wenig bezweifeln.
Ich bin mir wegen der genauen Zeiten nicht mehr so ganz sicher - habe es aber so in Erinnerung : CPU 317 , Aufzeichnungs-Intervall 1ms für eine Sekunde = 1000 Werte := Auswertezeit deutlich über 1 Sekunde. Ich meine, dass es so war (das geht auch glaube ich aus der Formel mit der darin stattfindenden Iteration hervor), dass die Verdoppelung der Werte eine Vervierfachung der Auswertezeit bedingt hat.

Bei uns hatte der Algorhythmus letztlich nicht den erwarteteten Ausschlag gebracht sondern ein sehr viel einfacheres Verfahren : ich habe keine Schwingung mehr aufgezeichnet sondern das Reibmoment (wobei darin ja letztlich auch eine Schwingung abgebildet wird) mit einer schneller Messrate. Diese Kurve habe ich dann leicht geglättet und die geglättete Version von der Rohversion subtrahiert und die Ergebnis-Werte absolut dargestellt. Es ging uns letztlich auch gar nicht um eine spezielle Frequenz sondern nur um Geräusche allgemein. Die so erzeugte "neue" Kurve stellte nun den Geräusch-Anteil des Lagers recht gut dar.

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Auf dem Prüfstand werden die Getrieben auf der Lebensdauer getestet und die evt. Schwachstellen, mittels der Zuordnung mit der Zeit steigenden Amplituden der Schwingungen zu den Lagern und Zahnräder, ermittelt.
Die Belastungsroutine für das Getriebe läuft auf einer separaten SPS (auch eine 1212C), die Schwingungsanalyse übernimmt eine SPS die nur die FFT macht.

Mit der DFT-Auswertung von N=500 (die Aufnahmezeit = 1 sec) ist die SPS über 7 sec beschäftigt - das ist sehr, sehr lang. Deswegen möchte ich den FFT-Algorithmus einsetzen und hoffe damit auf die Auswertungszeit von ca. 200-300ms zu kommen.

PS. - Larry, was für die Hardware hast du für die Reibmomentaufnahme gehabt?

Gruß
Alex
 
Hallo,

so ... nun komme ich dazu, mich wieder mit dieser Angelegenheit zu befassen.

Bei der Reibmomentmessung habe ich mit einem passenden DM-Sensor und einer schnellen Analogkarte gearbeitet. Hier sind auch (zumindestens bei einer S7-300 500 bis 1000 Messung in der Sekunde machbar)

Nun zu deinem Code-Wunsch :
Code:
FUNCTION_BLOCK FB168                                    // UP Mess-Daten aufzeichnen und FFT-Analyse
TITLE   = 'UP Mess-Daten aufzeichnen und FFT-Analyse'   // UP Mess-Daten aufzeichnen und FFT-Analyse
AUTHOR  : 'Larry'
VERSION : '1.6'   //   20.04.2009
FAMILY  : 'LL_Std'
KNOW_HOW_PROTECT
CONST  
    Array_max   := 2048 ;           // max. Anzahl von Einträgen im Array
    
    Pi          := 3.1415926 ;
    Tag_in_ms   := 86400000 ;
END_CONST
VAR_INPUT
   akt_Messwert           : INT ;   // akt. Messwert (INT)
   Anzahl_Werte           : INT ;   // Anzahl der zu erfassenden Werte [max. = 1024]
   Drehzahl_Messung       : REAL ;  // Drehzahl während der Messung  (1/Min.)
   
   Werte_doppeln          : BOOL ;  // ? Daten verdoppeln / Zwischen-Daten bilden
   Auswertung_x2          : BOOL ;  // ? Auswertung quadrieren
   Auswertung_glaetten_1  : BOOL ;  // ? vor der Auswertung glätten
   Auswertung_glaetten_2  : BOOL ;  // ? nach der Auswertung glätten
   
   akt_Uhrzeit            : TOD ;   // aktuelle Uhrzeit
   akt_Datum              : DATE ;  // aktuelles Datum
   Faktor_Amplitude : REAL := 1.0 ; // Anpassung der Ampituden-Darstellung
   
   _Steuerung             : INT ;   // Steuer-Eingänge :
   CMD_Reset_Puffer       : BOOL ;  // -Reset der Daten-Aufzeichnung
   CMD_Einlesen           : BOOL ;  // -Daten einlesen
   CMD_Auswertung         : BOOL ;  // -Daten auswerten
END_VAR
VAR_IN_OUT
   _Meldungen             : INT ;   // Melde-Ausgänge :
   OK_Reset_Puffer        : BOOL ;  // -Reset der Daten-Aufzeichnung erfolgt
   Messung_aktiv          : BOOL ;  // -Messung ist gestartet
   Liste_voll             : BOOL ;  // -alle/vorgegebene Daten sind erfasst
   OK_Auswertung          : BOOL ;  // -Daten sind ausgewertet
   Auswertung_IO          : BOOL ;  // -Auswertung ist IO
   Auswertung_NIO         : BOOL ;  // -Auswertung ist NIO
END_VAR
VAR_OUTPUT
END_VAR
 

VAR
   Last_Messwert          : INT ;        // Wert des zuletzt eingelesenen Messwertes
   Index                  : INT ;        // Zeiger auf Daten-Index für "Daten Einlesen"
   
   FB_noch_aktiv          : BOOL := false ;   // Baustein wird noch bearbeitet
   Daten_Init_OK          : BOOL := false ;   // Datenbereich ist initialisiert
   Daten_Liste_voll       : BOOL := false ;   // Ende des Datenbereichs beim Schreiben erreicht
   Messung_gestartet      : BOOL := false ;   // HM "Messung ist gestartet"
   Messung_beendet        : BOOL := false ;   // HM "Ende der Messung"
   FM_Messung_beendet     : BOOL := false ;   // Flankenmerker "Ende der Messung"
   VorgabeWerte           : ARRAY [1..5] OF STRUCT 
      Aktiv               : BOOL ;   // Messbereich auswerten ?
      F_min               : REAL ;     // unterste Auswerte-Frequenz
      F_max               : REAL ;     // oberste  Auswerte-Frequenz
      MittelWert          : REAL ;     // max. Mittelwert der Messerte im vorgegebenen Bereich 
      MaxWert             : REAL ;     // max. Spitzenwert der Messerte im vorgegebenen Bereich 
   END_STRUCT ;  

   Auswertung : STRUCT 
      Anzahl_Werte           : INT ;    // Anzahl der Quell-Werte
      Frequenz_Faktor        : REAL ;   // Teilungs-Faktor Frequenz in der Auswertung  [Hz/Index]
      Anzahl_MessWerte       : INT ;    // Anzahl der Mess-Werte
      
      Datum                  : DATE ;   // Datum beim Start der Messung
      Uhrzeit_Start          : TOD ;    // Uhrzeit beim Start der Messung
      Uhrzeit_Ende           : TOD ;    // Uhrzeit beim Ende der Messung
      Dauer_der_Messung      : REAL ;   // Dauer der letzten Messung [s]
      Anz_Umdrehungen        : REAL ;   // Anzahl der Umdrehungen während der Messung 
      
      max_Amplitude          : REAL ;   // größter Amplituden-Wert
      Mittelwert             : REAL ;   // Mittelwert aller Messwerte
      Freq_Schwerpunkt       : INT ;    // Werte-Schwerpunkt bei Frequenz
      
      MessBereich            : ARRAY[1..5] OF STRUCT
         MittelWert          : REAL ;   // Mittelwert der Messerte im vorgegebenen Bereich 
         MaxWert             : REAL ;   // Maximalwert der Messerte im vorgegebenen Bereich 
         Mittelwert_NIO      : BOOL ;   // Mittelwert > Vorgabewert
         Maxwert_NIO         : BOOL ;   // Maximalwert > Vorgabewert
      END_STRUCT ;  
      
      Amplitude              : ARRAY [0..Array_max/2] OF INT ; // Frequenz-Spektrum  //  Index * "Frequenz_Faktor" ergibt die Frequenz des Datenpunktes
   
      Werte_real             : ARRAY [0..Array_max] OF REAL ;  // Quell-Werte Real-Teil
      Werte_imag             : ARRAY [0..Array_max] OF REAL ;  // Quell-Werte Imaginär-Teil
   END_STRUCT ;  
END_VAR

VAR_TEMP
   i , j , k , L  : INT ;    // Schleifen-Variable
   X , Y          : INT ;
 
   Anz_Bits       : INT ;       
   Bit_Maske      : INT ;       
   Winkel         : REAL ;
   Frequenz       : REAL ;
   temp , temp2   : REAL ;
   Bereich_Summe  : ARRAY [0..7] OF REAL ;
   Bereich_Werte  : ARRAY [1..5] OF INT ;
   wCos , wSin    : REAL ;
   tReal , tImag  : REAL ;
   
   h_Uhrzeit      : DINT ;  // HM Zeit-Messung 
   
   Glaettung, k1, k2 : INT ;
   Glaettung_Teiler  : INT ;
   Glaettung_Summe   : REAL ;
END_VAR
// -----------------------------------------------------------------------------------------------------------------------
BEGIN
// -----------------------------------------------------------------------------------------------------------------------
IF NOT FB_noch_aktiv THEN
   FB_noch_aktiv := true ;
 
Zuletzt bearbeitet:
Teil 2 :
Code:
// -----------------------------------------------------------------------------------------------------------------------
// --- Daten-Baustein initialisieren -------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
IF CMD_Reset_Puffer AND NOT OK_Reset_Puffer THEN
   FOR i := 0 TO Array_max/2 BY 1 DO
      Auswertung.Amplitude [i]  := 0 ;
   END_FOR ;
   FOR i := 0 TO Array_max BY 1 DO
      Auswertung.Werte_real [i] := 0.0 ;
      Auswertung.Werte_imag [i] := 0.0 ;
   END_FOR ;
   Auswertung.Anzahl_Werte     := 0 ;
   Auswertung.Anzahl_MessWerte := 0 ;
   Auswertung.Frequenz_Faktor  := 0.5 ;
   
   Auswertung.max_Amplitude    := 0.0 ;
   Auswertung.Mittelwert       := 0.0 ;
   Auswertung.Freq_Schwerpunkt := 0 ;
   Auswertung.Datum   := D#1990-01-01 ;
   Auswertung.Uhrzeit_Start := TOD#0:0:0.0 ;
   Auswertung.Uhrzeit_Ende  := TOD#0:0:0.0 ;
   
   FOR j := 1 TO 5 BY 1 DO 
      Auswertung.MessBereich[j].MittelWert     := 0.0 ;    // Mittelwert der Messwerte im vorgegebenen Bereich 
      Auswertung.MessBereich[j].MaxWert        := 0.0 ;    // Maximalwert der Messwerte im vorgegebenen Bereich 
      Auswertung.MessBereich[j].Mittelwert_NIO := false ;  // Mittelwert > Vorgabewert
      Auswertung.MessBereich[j].Maxwert_NIO    := false ;  // Maximalwert > Vorgabewert
   END_FOR ;
   
   Daten_Liste_voll := false ; 
   Index := 0 ;
   Last_Messwert := 0 ;
   
   CMD_Einlesen    := False ;
   CMD_Auswertung  := False ;
    OK_Auswertung  := False ;
   Auswertung_IO   := False ;
   Auswertung_NIO  := False ;
    
   Messung_gestartet := false ;
   FM_Messung_beendet := false ;
    
   Daten_Init_OK := true ; 
END_IF ;
OK_Reset_Puffer := CMD_Reset_Puffer ;
// -----------------------------------------------------------------------------------------------------------------------
// --- Daten der Messung einlesen ----------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
IF CMD_Einlesen
   AND Daten_Init_OK
   AND NOT CMD_Reset_Puffer
   AND NOT CMD_Auswertung
   AND NOT Daten_Liste_voll
   THEN
    
   IF NOT Werte_doppeln THEN  // Werte im Takt des OB-Aufruf's einlesen
      Auswertung.Werte_real [Index] := INT_TO_REAL (akt_Messwert) ;
      Index := Index + 1 ;
   ELSE                       // Zwischenwerte bilden zwischen akt. Wert und letztem Wert
      Auswertung.Werte_real [Index] := INT_TO_REAL (akt_Messwert + Last_Messwert) / 2.0 ;
      Index := Index + 1 ;
      IF Index <= Array_max then
         Auswertung.Werte_real [Index] := INT_TO_REAL (akt_Messwert) ;
         Index := Index + 1 ;
      END_IF ;   
      Last_Messwert := akt_Messwert ;
   END_IF ;
  
   IF NOT Messung_gestartet THEN
      Auswertung.Datum   := akt_Datum ;
      Auswertung.Uhrzeit_Start := akt_Uhrzeit ;
      Auswertung.Uhrzeit_Ende  := TOD#0:0:0.0 ;
      Auswertung.Anzahl_Werte  := Anzahl_Werte ;
      Messung_gestartet := true ;
   END_IF ; 
END_IF ;
Messung_aktiv := Messung_gestartet ;
// -----------------------------------------------------------------------------------------------------------------------
Daten_Liste_voll := (Index > Anzahl_Werte) OR (Index > Array_max) ;
Liste_voll := Daten_Liste_voll ;
Messung_beendet := Daten_Liste_voll ; // or (Messung_gestartet AND NOT CMD_Einlesen) ;
IF Messung_beendet AND NOT FM_Messung_beendet THEN
   Auswertung.Uhrzeit_Ende := akt_Uhrzeit ; ;
   h_Uhrzeit := TOD_TO_DINT(Auswertung.Uhrzeit_Ende) - TOD_TO_DINT(Auswertung.Uhrzeit_Start) ; 
      IF h_Uhrzeit < 0 THEN h_Uhrzeit := h_Uhrzeit + Tag_in_ms ; END_IF ;
   Auswertung.Dauer_der_Messung := DINT_TO_REAL (h_Uhrzeit) / 1000.0 ;
   Auswertung.Anzahl_Messwerte := Index -1 ;
   FM_Messung_beendet := true ;
END_IF ;    


// -----------------------------------------------------------------------------------------------------------------------
// --- Daten der Messung auswerten ---------------------------------------------------------------------------------------
// -----------------------------------------------------------------------------------------------------------------------
IF CMD_Auswertung AND NOT OK_Auswertung 
AND NOT CMD_Einlesen 
   THEN
    
// vor der Analyse die Werte-Tabelle glätten
   IF Auswertung_glaetten_1 THEN 
      FOR i := 1 TO Auswertung.Anzahl_Messwerte -1 BY 1 DO
         temp := Auswertung.Werte_real [i] + Auswertung.Werte_real [i+1] ;
         Auswertung.Werte_real [i] := temp / 2.0 ;
      END_FOR ;
      temp := Auswertung.Werte_real [Auswertung.Anzahl_Messwerte] + Auswertung.Werte_real [1] ;
      Auswertung.Werte_real [Auswertung.Anzahl_Messwerte] := temp / 2.0 ;
   END_IF ;
   
   
// FFT-Analyse
   FOR i := 1 TO Auswertung.Anzahl_Messwerte BY 1 DO          // beim Start sind Real- und Imaginär-Anteil zunächst gleich ...
      Auswertung.Werte_imag [i] := Auswertung.Werte_real [i] ;
   END_FOR ;
   
   Anz_Bits := REAL_TO_INT (LOG(Auswertung.Anzahl_Werte) / LOG(2.0)) ;  
   
   FOR j := 1 TO Anz_Bits BY 1 DO 
      Bit_Maske := WORD_TO_INT (SHL (IN:=w#16#1 , N:=j)) ;    // entspricht: 2^j
      L := Auswertung.Anzahl_Werte / Bit_Maske ;              // L := Auswertung.Anzahl_Werte / (2 ^ j) ;
      Winkel := Pi / L ;
      FOR k := 0 TO Auswertung.Anzahl_Werte - 1 BY 2 * L DO 
         FOR i := 0 TO L - 1 BY 1 DO 
            wCos := COS(i * Winkel) ; 
            wSin := SIN(i * Winkel) ;
            X := (k + i) ;
            Y := (k + i + L) ;
            IF (X <= Array_max) AND (Y <= Array_max) THEN
               Auswertung.Werte_real [X] := Auswertung.Werte_real [X] + Auswertung.Werte_real [Y] ;
               Auswertung.Werte_imag [X] := Auswertung.Werte_imag [X] + Auswertung.Werte_imag [Y] ;
               tReal := Auswertung.Werte_real [X] - 2 * Auswertung.Werte_real [Y]  ;
               tImag := Auswertung.Werte_imag [X] - 2 * Auswertung.Werte_imag [Y]  ;
               Auswertung.Werte_real [Y] := tImag * wSin + tReal * wCos ;
               Auswertung.Werte_imag [Y] := tImag * wCos - tReal * wSin ;
            END_IF ;   
         END_FOR ;
      END_FOR ;
   END_FOR ;

   // Bits invertieren - Werte umgruppieren
   j := 0 ;
   FOR i := 0 TO Auswertung.Anzahl_Werte - 2 BY 1 DO 
      IF i < j THEN  // austauschen (i) gegen (j)
         temp := Auswertung.Werte_real [j] ;
         Auswertung.Werte_real [j] := Auswertung.Werte_real [i] ;
         Auswertung.Werte_real [i] := temp ;
      
         temp := Auswertung.Werte_imag [j] ;
         Auswertung.Werte_imag [j] := Auswertung.Werte_imag [i] ;
         Auswertung.Werte_imag [i] := temp ;
      END_IF ;
      k := Auswertung.Anzahl_Werte / 2 ;
      
      WHILE k < (j + 1) DO
         j := j - k ;
         k := k / 2 ;
      END_WHILE ;
      j := j + k ;
   END_FOR ;
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Teil 3 :

Code:
   // errechnete Werte nach-berechnen
   Auswertung.Anzahl_MessWerte := Auswertung.Anzahl_Werte / 2 ;
//   Auswertung.Frequenz_Faktor := 1.0 / Auswertung.Dauer_der_Messung ;
   Auswertung.Frequenz_Faktor := 500.0 / Auswertung.Anzahl_Werte ;
   Auswertung.Anz_Umdrehungen := Drehzahl_Messung * Auswertung.Dauer_der_Messung / 60.0 ;
   FOR i := 0 TO Auswertung.Anzahl_MessWerte -1 BY 1 DO 
      tReal := Auswertung.Werte_real [i] ;   IF tReal < 0 THEN tReal := -tReal ; END_IF ;  // negative Werte invertieren ...
      tImag := Auswertung.Werte_imag [i] ;   IF tImag < 0 THEN tImag := -tImag ; END_IF ;
      temp := (tReal + tImag) / INT_TO_REAL (Auswertung.Anzahl_Werte) ;   // Amplitude des Ausgabe-Wertes
      temp2 := temp * Faktor_Amplitude / Auswertung.Anz_Umdrehungen ;
      
      IF Auswertung_x2 THEN   // Ausgabe quadrieren ?
         temp2 := temp2 * temp2 / 50.0 ;
      END_IF ;   
      
      Auswertung.Werte_real [i] := temp2 ;
   END_FOR ;
   Auswertung.Werte_real [Auswertung.Anzahl_MessWerte] := 0.0 ;
   
   
// nach dem Überprüfen die Werte-Tabelle glätten
   IF Auswertung_glaetten_2 THEN 
      Glaettung := 8 ;
      FOR i := 0 TO Auswertung.Anzahl_Messwerte -1 BY 1 DO
         Glaettung_Summe := 0.0 ; Glaettung_Teiler := 0 ;
         k1 := i - (Glaettung / 2) ;  
         k2 := k1 + Glaettung ; 
            IF k1 < 1 THEN k1 := 1 ; END_IF ;
            IF k2 > Auswertung.Anzahl_Messwerte THEN k2 := Auswertung.Anzahl_Messwerte ; END_IF ;
         FOR j := k1 TO k2 BY 1 DO
            Glaettung_Summe := Glaettung_Summe + Auswertung.Werte_real [j] ;
            Glaettung_Teiler := Glaettung_Teiler + 1 ;
         END_FOR ;   
         Auswertung.Werte_real [i] := Glaettung_Summe / INT_TO_REAL (Glaettung_Teiler) ;
      END_FOR ;
   END_IF ;
   
   
   // errechnete Werte ausgeben und überprüfen
   Bereich_Summe [0] := 0.0 ;    // Auswertung.Mittelwert
   FOR j := 1 TO 5 BY 1 DO 
      Bereich_Werte [j] := 0 ;      // Anzahl Werte im Bereich
      Bereich_Summe [j] := 0.0 ;    //  Summe Werte im Bereich
   END_FOR ;    
     
   FOR i := 0 TO Auswertung.Anzahl_MessWerte -1 BY 1 DO 
      temp := Auswertung.Werte_real [i] ; IF temp < 0.01 THEN temp := 0.01 ; END_IF ;
      
      Bereich_Summe [0] := Bereich_Summe [0] + temp ;
      Frequenz := INT_TO_REAL (i+1) * Auswertung.Frequenz_Faktor ;
      
      FOR j := 1 TO 5 BY 1 DO 
         IF VorgabeWerte[j].Aktiv AND 
            (Frequenz >= VorgabeWerte[j].F_min) AND (Frequenz <= VorgabeWerte[j].F_max) THEN 
                Bereich_Summe [j] := Bereich_Summe [j] + temp ; 
                Bereich_Werte [j] := Bereich_Werte [j] + 1 ; 
                IF temp > Auswertung.MessBereich[j].MaxWert THEN Auswertung.MessBereich[j].MaxWert := temp ; END_IF ;
         END_IF ;
      END_FOR ;  
      
      IF (temp > Auswertung.max_Amplitude) THEN Auswertung.max_Amplitude := temp ; END_IF ;
      Auswertung.Amplitude [i] := REAL_TO_INT (temp * 10.0) ; 
   END_FOR ;
   Auswertung.Mittelwert := Bereich_Summe [0] / INT_TO_REAL (Auswertung.Anzahl_MessWerte) ;  // Mittelwert der Kurven-Werte
   // Schwerpunkt des Wertebereichs berechnen
   Bereich_Summe[6] := Bereich_Summe[0] / 2.0 ;
   Bereich_Summe[7] := 0.0 ;   
   FOR i := 0 TO Auswertung.Anzahl_MessWerte -1 BY 1 DO 
      temp := Auswertung.Werte_real [i] ; IF temp < 0.01 THEN temp := 0.01 ; END_IF ;
      Bereich_Summe[7] := Bereich_Summe[7] + temp ;
      IF Bereich_Summe[7] >= Bereich_Summe[6] THEN 
         Auswertung.Freq_Schwerpunkt := REAL_TO_INT(INT_TO_REAL (i+1) * Auswertung.Frequenz_Faktor) ;
         EXIT ;
      END_IF ;   
   END_FOR ;

  
   // Auswertung IO / NIO   
   Auswertung_NIO := false ;
   FOR j := 1 TO 5 BY 1 DO 
      IF VorgabeWerte[j].Aktiv THEN 
         Auswertung.MessBereich[j].MittelWert := Bereich_Summe [j] / INT_TO_REAL (Bereich_Werte [j]) ;       // Mittelwert
         Auswertung.MessBereich[j].Mittelwert_NIO := (Auswertung.MessBereich[j].MittelWert > VorgabeWerte[j].MittelWert) ;
         Auswertung.MessBereich[j].Maxwert_NIO    := (Auswertung.MessBereich[j].MaxWert > VorgabeWerte[j].MaxWert) ;
      END_IF ; 
      Auswertung_NIO := Auswertung_NIO OR Auswertung.MessBereich[j].Mittelwert_NIO OR Auswertung.MessBereich[j].Maxwert_NIO ;
   END_FOR ;
   Auswertung_IO := NOT Auswertung_NIO ;
      
   OK_Auswertung := true ;
END_IF ;
// ----------------------------------------------------------------------------------------------------------------------
   FB_noch_aktiv := false ;
END_IF ;  // FB_noch_aktiv
IF FB_noch_aktiv THEN
IF NOT CMD_Reset_Puffer AND NOT CMD_Einlesen AND NOT CMD_Auswertung THEN 
   FB_noch_aktiv := false ;
END_IF ; END_IF ;  
// -----------------------------------------------------------------------------------------------------------------------
END_FUNCTION_BLOCK
// -----------------------------------------------------------------------------------------------------------------------
 
Hallo Larry,
danke für den Code.
Habe heute ein Teil davon (FFT-Analyse) übernommen, aber leider keine saubere Darstellung im FFT-Diagramm bekommen. Die Amplitude erscheint nicht an den richtigen Frequenzen und die Größe passt nicht.
Ich glaube mein Fehler befindet sich im Segment "// errechnete Werte nach-berechnen", da habe ich das:
" temp := (tReal + tImag) / INT_TO_REAL (Auswertung.Anzahl_Werte) ; // Amplitude des Ausgabe-Wertes
temp2 := temp * Faktor_Amplitude / Auswertung.Anz_Umdrehungen ;

IF Auswertung_x2 THEN // Ausgabe quadrieren ?
temp2 := temp2 * temp2 / 50.0 ;"
nicht ganz nachvollziehen können.
Könntest du mir erklären, was an dieser Stelle passiert?

Danke im Voraus
Alex
 
Hallo Larry,
es wäre hilfreich , wenn du nur den FFT-Algorithmus posten würdest. Ich habe leider den Code oben nur zum Teil nachvollziehen können.
Das, mit der Zeitaufnahme und der Drehzahl ist für deine Anwendung angeppast und die Anpassung der Amplitude zur Frequenz in der FFT
etngeht mir vollkommen.

Gruß
Alex
 
Zurück
Oben