Frequenzauswertung/Prognose

McNugget

Level-2
Beiträge
220
Reaktionspunkte
10
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo allerseits.

Wie kann ich mit dem Signal einer Lichtschranke, die auf eine Lochscheibe auf einer Motorachse schaut, die Aktualgeschwindigkeit Pulse pro Minute berechnen?

Es ist mit ca. 800 bis 1000 Pulsen pro Minute zu rechnen.


Gruss

McNugget
 
Kommt ein wenig darauf an, wie genau es sein soll und wie schnell eine Änderung der Geschwindigkeit angezeigt werden soll.

Als einfachste Variante kannst du 1 Minute lang die Impulse zählen, dann hast du die Impulse/Minute.
Oder zu zählst die Impulse genau 1 Sekunde lang und multiplizierst sie mit 60, dann hast du auch wieder Impulse/Minute. Das ist dann zwar ungenauer, aber dafür wird jede Sekunde eine neue aktuelle Geschwindigkeit angezeigt.

Ist das alles zu ungenau, gibts auch noch andere Methoden, aber die sind dann abhängig vom Anwendungsfal und sicher auch aufwendiger.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Ralle.

Es muss nicht exorbitant genau sein, aber ich hätte gerne schnell die Werte.

Da die Lochscheibe ja immer die gleichen hell/dunkel-Abstände hat, habe ich mir gedacht, 2-5 hell und dunkel Zeiten zu nehmen, den Mittelwert und die Abweichung zu rechnen und dann auf eine Minute hochzurechnen.

Aber wie mache ich es, dass immer die aktuellsten Werte wieder in die Berechnung einfliessen? Man müsste ja die Werte sozusagen immer wieder in einer Tabelle durchschieben. (Bin leider alles andere als der König im Umgang mit Arrays.)

Wenn ich eine Minute lang betrachte und sich dann die Geschwindigkeit ändert, dauert es mindestens eine Minute in der neuen Geschwindigkeit um den neuen wert zu ermitteln. Das wäre irgendwie doch nicht elegant..

Gruss

McNugget
 
Ja genau, daher muß man sehen, was man braucht. Ich weiß nicht so genau, wie schnell deine Beckhoff die Impulse erfassen kann.

1. Du kannst entweder Impulse zählen über einen festen Zeitraum, wobei dieser Zeitraum dann deinen kürzeste "Aktualisierungszeit" darstellt.

2. Du nimmst die Zeit zwischen 2 Impulsen und rechnest das um. Ist die SPS nicht schnell genug, kannst du auch die Zeit zwischen 2, 3, 4 ... Impulsen messen. Dann variiert die Aktualisierungszeit, je langsamer das Rad, desto länger die Aktualisierungszeit. Je schneller das Rad, desto kürzer die Aktualisierungszeit, aber desto ungenauer wohl auch das Ergebnis.

Das mit dem Array und die Werte die Werte da durchschieben, so in einer Art gleitendem Mittelwert bedeutet ja im Endeffekt auch, daß eine Änderung der Geschwindigkeit am Impulsrad nur langsam in die Ausgabe der Geschwindigkeit eingeht.

Also ich würde mal mit Variante 2 anfangen. Einen Zähler, der z.Bsp. 4 Impulse zählt und einen Timer der die Zeit dazwischen mißt. das kann man dann in Impulse/Minute umrechnen. Wichtig ist, daß die LS und die Inputs auch schnell genug sind, aber bei 1000 Imp./Minute sollte das noch gehen. Je schneller die sind, und je kürzer die Zykluszeit der SPS, je genauer wird das ganze natürlich auch bei wenig ausgemessenen Impulsen.
 
Habe Wago.

Die Klemmen können bis 3ms runter, meine ich.

Wie würde ich Variante 2 (gefällt mir auch besser) in ST machen?

Gruss

McNugget
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das kann man natürlich auf viele Arten machen.

ich habs mal so probiert, zur Veranschaulichung und zum selbst üben ;):
Folgende Lib noch einbinden: TCSystem

einen FB anlegen --> FB_Zeitmessung_zwischen_Impulsen und
im Deklarationsteil:

Code:
FUNCTION_BLOCK FB_Zeitmessung_zwischen_Impulsen
VAR_INPUT
	bImpuls: BOOL;
	iImpulsanzahl: INT;
END_VAR
VAR_OUTPUT
	iImpulseproMinute: DINT;
END_VAR
VAR
	fbR_Trig: R_TRIG;
	iImpulszaehler: INT;
	fbGetSystemTime: GETSYSTEMTIME;
	iLowTimeNew, ILowTimeOld: UDINT;
	iImpulsTime: DINT;
END_VAR
und im Codeteil:

Code:
fbR_TRIG(CLK:=bImpuls , Q=>);

IF fbR_TRIG.Q THEN
	iImpulszaehler := iImpulszaehler + 1;
END_IF;

IF iImpulszaehler >= iImpulsanzahl THEN
	fbGETSYSTEMTIME(timeLoDW=>iLowTimeNew , timeHiDW=> );
	iImpulsTime := UDINT_TO_DINT(iLowTimeNew - iLowTimeOld) / (10000 * iImpulsanzahl); (* iImpTime in ms*)
	iImpulseproMinute := 60000 / ( iImpulsTime); (*Umrechnungin Impulse/Minute*)
	iLowTimeOld := ILowTimeNew;
	iImpulszaehler := 0;
END_IF;

Aufruf:

Code:
fbZeitmessungzwischenImpulsen(bImpuls:=bMyImpuls , iImpulsanzahl:=2 , iImpulseproMinute=>iMyImpulseproMinute );

wobei ich folgende globale Variablen definiert habe:

Code:
VAR_GLOBAL
	bMyImpuls: BOOL;
        iMyImpulseproMinute: DINT;
END_VAR

Der allererste Aufruf bringt hier natürlich immer ein falsches Ergebnis, da hier iLowTimeOld noch 0 ist oder einen alten Wert hat.
Dafür kann man sich im Notfall auch noch etwas einfallen lassen.
 
Zuletzt bearbeitet:
Hallo Ralle, danke für Deine Mühe.

Ich habe allerdings Wago und die TCSystem.lib scheint eine Beckhoff Lib zu sein.
Was gibt die aufgerufene Zeitfunktion genau aus?
Ich muss das ja irgendwie mit OSCAT oder Wago-Libs bewältigen.



Gruss

McNugget
 
GetSystemTime gibt in TwinCat den Systemzeitstempel als 64bit Wert mit einer 100ns Genauigkeit aus.
Bei Wago müsste es doch mindestens was gleichwertiges geben.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke für die Info.

Leider wüsste ich eben nicht, was bei Wago adäquat wäre.

Wie sieht das Datenformat den ganz genau aus?

Oder weiss jemand eine Wago Lib. die passen würde?

Gruss

McNugget
 
Danke Repök.

Ich habe es jetzt so angepasst:


bR_TRIG(CLK:=bImpuls , Q=>);

IF fbR_TRIG.Q THEN
iImpulszaehler := iImpulszaehler + 1;
END_IF;

IF iImpulszaehler >= iImpulsanzahl THEN
iLowTimeNew:=DINT_TO_UDINT (TIME());
iImpulsTime := UDINT_TO_DINT(iLowTimeNew - iLowTimeOld) / (10000 * iImpulsanzahl); (* iImpTime in ms*)
iImpulseproMinute := 60000 / ( iImpulsTime); (*Umrechnungin Impulse/Minute*)
iLowTimeOld := ILowTimeNew;
iImpulszaehler := 0;
END_IF;


Dabei bekomme ich die Fehlermeldung:

Kann Time nicht in DINT konvertieren.

Was mache ich noch falsch?



Gruss

McNugget
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Danke Repök.

Ich habe es jetzt so angepasst:


bR_TRIG(CLK:=bImpuls , Q=>);

IF fbR_TRIG.Q THEN
iImpulszaehler := iImpulszaehler + 1;
END_IF;

IF iImpulszaehler >= iImpulsanzahl THEN
iLowTimeNew:=TIME_TO_UDINT (TIME());
iImpulsTime := UDINT_TO_DINT(iLowTimeNew - iLowTimeOld) / (10000 * iImpulsanzahl); (* iImpTime in ms*)
iImpulseproMinute := 60000 / ( iImpulsTime); (*Umrechnungin Impulse/Minute*)
iLowTimeOld := ILowTimeNew;
iImpulszaehler := 0;
END_IF;


Dabei bekomme ich die Fehlermeldung:

Kann Time nicht in DINT konvertieren.

Was mache ich noch falsch?



Gruss

McNugget

Ich hatte eben geschrieben, dass die laufzeit als dint ausgegeben wird. Ist im prinzip richtig, aller dings im time-format. die konvertierung muss noch ngepasst werden. alle 49,7... tage bekommst du einen überlauf, da dann die 32bit voll sind.
 
Zuletzt bearbeitet:
Ist dein Motor langsamg genug / bzw die Zykluszeit der SPS kurz genug damit dein Programm mit dem Zählen der Impulse hinterher kommt?

Außerdem glaube ich, dass Time() nur 1ms Auflösung hat. Dann kannst du dir die 10000 bei der Impulszeit-berechnung sparen.
 
ich gebe ja zu, dass ich Einsteiger bin, daher würden mir etwas detailliertere Ausführungen sehr viel weiterhelfen.

Ich habe noch diverse Probleme mit den diversen Typen und deren Konvertierung.
Wann benutzt man welchen Datentyp wofür? Gibt es darüber ein Tut oder einen Leitfaden für Dummies?

Ich habe jetzt einen Lösungsnasatz mit einer Bibliothek, an die ich nicht rankomme und einen, in dem ich die Typen nicht verstehe/konvertieren kann.


Wo ist Time() beschrieben?


@Repök: Wie müsste ich denn die Konvertierung anpassen?

@MasterOhh: Ich weiss es aktuell noch nicht, icha habe einen Wago-Controller schon mit unter 18 ms Zykluszeit gehabt, es könnte also klappen. Da ich aber noch keinerlei brauchbaren Ansatz habe, weiss ich nicht, wie ich rausfinden kann, ob meine Annahmen stimmen.



Gruss

McNugget
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich kenne mich mit Wago gar nicht aus, aber geh mal in das Hilfesystem der Programmierumgebung und suche nach "Konvertierung" oder "Umwandlung" oder "Typkonvertierung" oder "Typumwandlung".

Wann benutzt man welchen Datentyp? Na ja, das hat sicher was mit Erfahrung zu tun, aber i.d.R. nutzt man den Datentyp, in den die Zahlen, mit denen man gerade operiert auch problemlos hineinpassen. Hat man nur positive Werte, nimmt man einen vorzeichenlosen, hat man kleine Zahlen, reicht ein INT, große Zahlen benötigen eher einen DINT. Ist man unsicher, am Anfang, nimmt man eher die größeren Datentypen, also DINT für ganze Zahlen mit oder ohne Vorzeichen, dafür verbraucht man etwas mehr Speicherplatz. Nun ist es so, daß man verschiedene Standarfunktionen nutzt, die das System mitbringt oder z.Bsp eine Library wie die Oscat-Library. Deren Funktionen verlangen nach bestimmten Eingabe- und Ausgabetypen, die wurden halt beim erstellen der Funktion vom Programmierer so festgelegt. Will also eine Funktion einen DINT als Input, du hast aber bisher mit INT gerechnet, dann mußt du diese INT nach DINT konvertieren, damit die Funktion diese Variable als Eingabewert akzeptiert.
 
So.

Ein kleiner Nachtrag.

@MasterOhh: Die GEschwindigkeit reicht vollends um die Pulse auszuwerten! ;-)

@Ralle: Vielen Dank, dass Du mir das noch mal etwas nöher gebracht hast. Gibt es die verscheidenen Typen irgendwo als Tabelle?

Ich habe den Code-Teil jetzt folgendermassen am Laufen:

fbR_TRIG(CLK:=bImpuls , Q=>);

IF fbR_TRIG.Q THEN
iImpulszaehler := iImpulszaehler + 1;
END_IF;

IF iImpulszaehler >= iImpulsanzahl THEN
iLowTimeNew:= TIME_TO_UDINT (TIME( )) ;
iImpulsTimeb := (iLowTimeNew - iLowTimeOld);
iImpulsTime := iImpulsTimeb / iImpulsanzahl; (* iImpTime in ms*)
iImpulseproMinute := 60000 / ( iImpulsTime); (*Umrechnungin Impulse/Minute*)
iLowTimeOld := ILowTimeNew;
iImpulszaehler := 0;
END_IF;

Vielen Dank an alle, die mich hier unterstützt/mit Infos gefüttert haben.

Ich habe gaaanz sicher bald wieder die ein oder andere dumme Frage.

Gruss

McNugget
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Ralle: Super Hinweis. Das hat mir schon wieder weitergeholfen.

@All:

Ich habe noch mal die OSCAT durchgesucht und etwas gefunden, was ich dann gleich für den Baustein verwenden konnte.

Vielleicht mag sich ja mal jemand den Code anschauen und mir sagen, ob das so elegant gelöst ist, oder ob es noch etwas performanenter laufen könnte.

Ich rufe diesen Baustein als eigenen Task im 5ms-Takt auf, damit er wirklich schnell sein kann.
Aktuell braucht er maximal (nur Start) 526us
und minimal 30us
Aktualwerte schwanken bis 50us.

Deklaration:
PROGRAM P_Pulse_Pro_Minute

VAR_INPUT
bImpuls: BOOL;
iImpulsanzahl: INT;
Abstand: REAL;
END_VAR

VAR_OUTPUT
iImpulseproMinute: INT;
m_pro_Min:REAL;
Stueck_pro_Min:REAL;
END_VAR

VAR
Nulltimer:TON;
fbR_Trig: R_TRIG;
iImpulszaehler: INT;
iLowTimeNew, ILowTimeOld, iImpulsTime,iImpulsTimea: DWORD;
steht: BOOL;
Nulltimer_ET: TIME;
END_VAR



Anweisungsteil:
fbR_TRIG(CLK:=bImpuls , Q=>);

steht := NOT bImpuls;

IF fbR_TRIG.Q THEN
iImpulszaehler := iImpulszaehler + 1;
ELSE
Nulltimer(IN:=steht , PT:=t#1s, Q=>, ET=>Nulltimer_ET);
END_IF;

IF Nulltimer.Q THEN
iImpulseproMinute:=0;
m_pro_Min :=0;
Stueck_pro_Min := 0;
RETURN;

ELSIF
iImpulszaehler >= iImpulsanzahl THEN
iLowTimeNew:=(T_PLC_US()) ; (*Zeit in us holen*)
iImpulsTimea := (iLowTimeNew - iLowTimeOld); (*high-Zeit errechnen*)
iImpulsTime := (iImpulsTimea / iImpulsanzahl); (* iImpTime in us*)
iImpulseproMinute := DWORD_TO_INT (60000000 / ( iImpulsTime)); (*Umrechnungin Impulse/Minute*)
iLowTimeOld := ILowTimeNew;
iImpulszaehler := 0;
END_IF;

m_pro_Min := iImpulseproMinute / Abstand;

Stueck_pro_Min := iImpulseproMinute / 10.0;


Bitte um Kritik und Verbesserungen. (Ich will ja was lernen.)

Gruss

McNugget
 
Sieht doch ganz gut aus. Nun hast du ja eine Funktion in der Wago gefunden, die die Zeit hinreichend genau bringt. Auch den Stillstand hast du eingebaut, damit die Anfangswerte nicht völlig falsch sind.
 
Die Funktion habe ich in der OSCAT.LIB gefunden.

Danke auch an dieser Stelle mal an alle Entwickler der OSCAT.Lib.

Den Stillstand habe ich eingebaut, da die Geschwindigkeitsanzeige (also bei Ausbleiben der Takte) auf dem letzten gemessenen Wert blieb.

Vielen Dank noch mal für die Hilfe.



Gruss

McNugget
 
Zurück
Oben