Bitte um Hilfe bei einem Problem (zyklische Abfrage)

Bosga

Level-1
Beiträge
21
Reaktionspunkte
2
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo erstmal!
Bin ganz neu in der Branche und kenne mich leider fast garnicht aus..
Hoffe das ändert sich mit der Hilfe von euch!
Kann einwenig C und Java.
Nun steh ich vor dem ersten Problem in SCL.
Von der Simotion bekomme ich in einen DB einen Wert(Nm - DMax) eines Drehzahlmotors geschrieben.
Dieser Wert würde ich gerne alle 100ms (das 10* = 1sek) abfragen, und dies in einen ersten Puffer schreiben und in der 2 sek nochmal 10 mal abfragen (je 100ms) in einen 2ten Puffer schreiben.
Nun den Mittelwert vom ersten Puffer berechnen und den Mittelwert vom 2 Puffer berechnen.
Diese 2 Mittelwerte nun vergleichen.
Wenn der Mittelwert des 2ten Puffers gestiegen ist,soll eine Meldung rausgehauen werde oder es soll in eine Variable ein Bool wert geschrieben werden.
Diese komplette Prozedur wiederholt sich dann nach jeder 2 Sekunde.
Dieser züglicher Aufruf alle 100ms und der Vergleich der 2 Puffer bereitet mir sehr Probleme.
Wäre über eure Hilfe wirklich sehr sehr dankbar!
LG
Bosga
 
vermisse die frage! vermisse die darstellung des problems!
ICH VERMISSE EIGENINITIATIVE
...und ich vermisse angaben zur verwendeten hardware und software und den daten ... sinds nun INT, DINT, REAL und soweiter und sofort ...

ein tipp von mir: es gibt einen CPU-Taktmerker mit 100ms -> Mx.0
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Ist ein REAL wert.
Hardware CPU 317
Bekommt die Werte von einer Simotion. Aber denke ist für mich hier nicht so wichtig.
Gruß
 
Zuletzt bearbeitet:
was hast du denn schon?
hapert es an den SCL-Grundlagen oder am Datenhandling?
am Summieren und durch die Anzahl der Summanden dividieren dürfte es nicht scheitern, oder?

also kurz gesagt: was willst du wissen :confused:
 
es geschehen noch wunder:

bosga schrieb:
Mir fehlt einfach das handling. Wie gesagt mein hauptroblem ist das ich keine ahnung habe wie ich eine variable alle 100ms abrufe, dessen wert in ein array schreibe ....

was läßt sich da finden? *klick* suche ... hmm ... SCL *tipp* array *enter*

Pointer in SCL ?

[edit] besonders der beitrag von kai :rolleyes: [/edit]
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Vierlagig: Ich glaube, da bist du jetzt ein wenig hart mit Bosga. Er hat seine Problemstellung doch schön beschrieben ...

@Bosga: Ich würde da wie folgt vorgehen ...
Einen FB bauen, der im OB35 im gewünschten Zeitraster aufgerufen wird.
Bei jedem Aufruf des FB's zählst du einen internen Zähler hoch. Ist der Zähler im Bereich 1 .. 20 schreibst du die eingelesenen Werte in dein ARRAY (vom Instanz-DB). Ist der Zähler = 21, dann wertest du das aus. Ist der Zähler 22 .. 41 dann schreibst du die Werte in das 2. ARRAY und ist der Zähler 42 dann wertest du dieses aus und setzt den Zähler zurück.
Versuch doch mal, das umzusetzen ...

Gruß
LL
 
Würde es nicht auch genügen, die jeweils 10 Werte aufzusummieren und dann die Summen zu vergleichen?

Grüße von HaDi
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich würde auch so vorgehen wie Larry Laffer das beschreibt.
Der Vergleich der beiden Mittelwerte bereitet dir auch Probleme? Warum nimmst du nicht einfach eine If-Abfrage???

IF rMittelwert1 = rMittelwert2 THEN
//----- Werte sind gleich -----
;
ElSIF rMittelwert1 > rMittelwert2 THEN
//----- Grösser -----
;
ElSIF rMittelwert1 < rMittelwert2 THEN
//----- Kleiner -----
;
ENDIF;
 
... ob man die beschriebene Aufgabe so oder so erledigt ist (glaube ich) nicht das Thema. Ich würde da ggf. auch anders vorgehen (kommt immer darauf an, was man noch so vorhat). Bei mir stehen bei solchen Sachen ganz häufig Kennlinie-Darstellungen mit auf dem Programm und deshalb halte ich diesen Lösungsweg auch nicht für abwegig.

Deswegen - wenn es "nur" um die Mittelwerte geht, dann stimme ich HaDi zu 100% zu. Falls mehr angesagt ist, dann ist der Ansatz von Bosga auf jeden Fall absolut OK ...

Gruß
LL
 
Hi Leute,

erstmal vielen vielen Dank für eure Antworten und somit Hilfe!!!

Ich werde die vorgeschlagenen Methoden heut oder morgen im Büro gleich mal ausprobieren.
Hoffe kann mit weiteren Antworten von euch rechnen ;)

Gruß

Bosga
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Larry:
Du hast natürlich vollkommen recht. Mein Vorschlag taugt nur, wenn
1. ein gewöhnlicher, arithmetischer Mittelwert berechnet werden soll und
2. weder der Mittelwert noch die Einzelwerte anderweitig gebraucht werden.
Ansonsten wäre mein Ansatz mit deinem aus Beitrag #6 vergleichbar.

Grüße von HaDi
 
Hi ihr,

also ich hab mal eine Lösung für mein Problem geschrieben.
Wollte fragen ob ihr mal drüberfliegen könnt.
Die Array-Variante wäre wahrscheinlicher "schöner" gewesen.
Aber mir geht es mom. nur um die Funktionalität.
(Werde es dann noch ändern)
Bin ja noch blutjunger Anfänger bezügl. dem Umgang mit SPS... :p

LG
Bosga
 

Anhänge

  • Lösung.txt
    4,4 KB · Aufrufe: 16
Hm könnte gehen, ich habs mal korrigiert, damit der Compiler das übersetzen kann:

Code:
FUNCTION_BLOCK FB100
//Baustein für die Gradientenregelung des Drehmoments 



VAR_INPUT
DB_NR                       :WORD   ;                               //    DB Nummer 
BYTEADDR_DB                 :INT    ;                               //    Anfangsadresse   
SAMPLE_T                    {S7_sampletime:= 'true'}  :REAL:=0.1;   //  = 100ms  * 10(Durchläufe) --> 1s (OB35 - Zyklus 100ms)  
//DM_max                       {S7_m_c:='true'} :    REAL;            //    Variable DM_Max 
END_VAR

  
VAR_IN_OUT
DM_max                       {S7_m_c:='true'} :    REAL     ;       //    Gradient Drehmoment(je Antrieb)    
END_VAR


VAR_OUTPUT    
Ergebniss : BOOL;                                                   // "True" wenn Puffer2 < Puffer1
END_VAR


VAR
Cnt_DM_max  : REAL;                                                 //Innerer Counter
CNT         : INT;                                                  //Äußerer Counter

Puffer1     : REAL;
Puffer2     : REAL;

Wert1       : REAL;
Wert2       : REAL;
Wert3       : REAL;
Wert4       : REAL;
Wert5       : REAL;
Wert6       : REAL;
Wert7       : REAL;
Wert8       : REAL;
Wert9       : REAL;
Wert10      : REAL;
Wert11      : REAL;
Wert12      : REAL;
Wert13      : REAL;
Wert14      : REAL;
Wert15      : REAL;
Wert16      : REAL;
Wert17      : REAL;
Wert18      : REAL;
Wert19      : REAL;
Wert20      : REAL;

//Ergebniss : BOOL;

END_VAR     
 


BEGIN
//-------------------------------------------------Werte aus DB(DB_NR) lesen----------------------------------------------------------------------------

DM_max              :=WORD_TO_INT( WORD_TO_BLOCK_DB(DB_NR).DW[BYTEADDR_DB+50]);       //    Gradient Drehmoment(je Antrieb)    
       
//----------------------------------------------------------Counter-------------------------------------------------------------------------------------

IF Cnt <= 20 THEN
Cnt := Cnt + 1;                                                                      //Äußere Counter  1-20(0,1s - 2.0s)    
Cnt_DM_max :=  Cnt_DM_max  +  SAMPLE_T;                 //Der Counter beginnt bei 0,1s (100ms) und zählt jeden weiteren Bausteinaufruf(OB35) 0,1s weiter
 
       IF Cnt_DM_max = 0.1 THEN Wert1   := DM_max; END_IF;
       IF Cnt_DM_max = 0.2 THEN wert2   := DM_max; END_IF;
       IF Cnt_DM_max = 0.3 THEN wert3   := DM_max; END_IF;
       IF Cnt_DM_max = 0.4 THEN wert4   := DM_max; END_IF;
       IF Cnt_DM_max = 0.5 THEN wert5   := DM_max; END_IF;
       IF Cnt_DM_max = 0.6 THEN wert6   := DM_max; END_IF;
       IF Cnt_DM_max = 0.7 THEN wert7   := DM_max; END_IF;
       IF Cnt_DM_max = 0.8 THEN wert8   := DM_max; END_IF;
       IF Cnt_DM_max = 0.9 THEN wert9   := DM_max; END_IF;
       IF Cnt_DM_max = 1.0 THEN wert10  := DM_max; END_IF;
   IF Cnt_DM_max = 1.1 THEN wert11  := DM_max; END_IF;
   IF Cnt_DM_max = 1.2 THEN wert12  := DM_max; END_IF;
   IF Cnt_DM_max = 1.3 THEN wert13  := DM_max; END_IF;
   IF Cnt_DM_max = 1.4 THEN wert14  := DM_max; END_IF;
   IF Cnt_DM_max = 1.5 THEN wert15  := DM_max; END_IF;
   IF Cnt_DM_max = 1.6 THEN wert16  := DM_max; END_IF;
   IF Cnt_DM_max = 1.7 THEN wert17  := DM_max; END_IF;
   IF Cnt_DM_max = 1.8 THEN wert18  := DM_max; END_IF;
   IF Cnt_DM_max = 1.9 THEN wert19  := DM_max; END_IF;
   IF Cnt_DM_max = 2.0 THEN wert20  := DM_max; END_IF;

ELSE
Cnt :=0; 
Cnt_DM_max :=0;                      //Nach 2Sekunden wird der Counter wieder auf 0 gesetzt und die Zählung beginnt von vorne
END_IF;
    
//--------------------------------------------------------Mittelwertbildung----------------------------------------------------------------------------

Puffer1 := (Wert1  + Wert2  + Wert3  + Wert4  + Wert5  + Wert6  + Wert7  + Wert8  + Wert9  + Wert10) / 10 ;
Puffer2 := (Wert11 + Wert12 + Wert13 + Wert14 + Wert15 + Wert16 + Wert17 + Wert18 + Wert19 + Wert20) / 10 ;

//-----------------------------------------------------------Vergleich---------------------------------------------------------------------------------


IF Puffer2 > Puffer1 THEN
    Ergebniss := true;
ELSE
    Ergebniss := false;
END_IF;
  
     
//-------------------------------------------------------Schreiben in den DB--------------------------------------------------------------------------
                 
//WORD_TO_BLOCK_DB(DB_NR).DW[BYTEADDR_DB+50] := INT_TO_WORD(DM_max);             //  Gradient Drehmoment(je Antrieb)    
        
END_FUNCTION_BLOCK
Und hier mal mit Array:

Code:
FUNCTION_BLOCK FB100
//Baustein für die Gradientenregelung des Drehmoments 



VAR_INPUT
  DB_NR                       :WORD   ;                               //    DB Nummer 
  BYTEADDR_DB                 :INT    ;                               //    Anfangsadresse   
  SAMPLE_T                    {S7_sampletime:= 'true'}  :REAL:=0.1;   //  = 100ms  * 10(Durchläufe) --> 1s (OB35 - Zyklus 100ms)  
END_VAR

  
VAR_IN_OUT
  DM_max                       {S7_m_c:='true'} :    REAL     ;       //    Gradient Drehmoment(je Antrieb)    
END_VAR


VAR_OUTPUT    
  Ergebniss : BOOL;                                                   // "True" wenn Puffer2 < Puffer1
END_VAR


VAR
  CNT         : INT;                                                  //Äußerer Counter
  I           : INT; 
  Puffer1     : REAL;
  Puffer2     : REAL;

  Wert        : ARRAY[1..20] OF REAL;

END_VAR     
 


BEGIN
//-------------------------------------------------Werte aus DB(DB_NR) lesen----------------------------------------------------------------------------

DM_max              :=WORD_TO_INT( WORD_TO_BLOCK_DB(DB_NR).DW[BYTEADDR_DB+50]);       //    Gradient Drehmoment(je Antrieb)    
       
//----------------------------------------------------------Counter-------------------------------------------------------------------------------------

IF Cnt <= 20 THEN
  Cnt := Cnt + 1;                                                                      //Äußere Counter  1-20(0,1s - 2.0s)    
  Wert[Cnt] := DM_max;
ELSE
  Cnt :=0; 
END_IF;
    
//--------------------------------------------------------Mittelwertbildung----------------------------------------------------------------------------

Puffer1 := 0.0;
Puffer2 := 0.0;

FOR I := 1 TO 10 do 
  Puffer1 := Puffer1 + Wert[i];
  Puffer2 := Puffer2 + Wert[I+10];
END_FOR;
  Puffer1 := Puffer1 / 10;
  Puffer2 := Puffer2 / 10;

//-----------------------------------------------------------Vergleich---------------------------------------------------------------------------------


IF Puffer2 > Puffer1 THEN
    Ergebniss := true;
ELSE
    Ergebniss := false;
END_IF;
  
     
//-------------------------------------------------------Schreiben in den DB--------------------------------------------------------------------------
                 
//WORD_TO_BLOCK_DB(DB_NR).DW[BYTEADDR_DB+50] := INT_TO_WORD(DM_max);             //  Gradient Drehmoment(je Antrieb)    
        
END_FUNCTION_BLOCK
Allerdings mußt du das Ergebnis mal prüfen, hab wenig Zeit, übersetzen läßt es sich. Auf jeden Fall ist da noch einiges an Optimierungsmöglichkeiten vorhanden, die Mittelwertbildung ist mir hier zu Rechenintensiv, das geht noch einfacher, denke ich, evtl. in jedem Schritt innerhalb der IF-Abfrage als gleitender Mittelwert. Suche mal im Forum, da hatten wir schon eine Diskussion zur optimalen Mittelwertberechnung.

PS: Hab noch eimal einen Fehler korrigiert, die Puffer müssen gelöscht werden, vor der Berechnung.
 
Zuletzt bearbeitet:
Übrigens, das hier:

Code:
Puffer1 := Puffer1 / 10;
Puffer2 := Puffer2 / 10;

kann man getrost weglassen, weil weiter unten ja beide auf größer verglichen werden. Am Ergebns des Vergleichs ändert sich durch die Division ja nichts, also ist die "für die Katz". Aber für diese Tier arbeitet der Mensch ja die meiste Zeit im Leben ;) .
 
Zurück
Oben