Mittelwertbildung

pinolino

Level-1
Beiträge
261
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Zusammen,
ich habe im Forum nach einer Art Anleitung gesucht, um eine Mittelwertberechnung durchzuführen. Dabei bin ich auf Folgendes (von vierlagig!) gestoßen:

Code:
[LEFT]L 8                                //Startadresse des Arrays
SLD 3                              //Pointererzeugen
LAR1                               //und ins Adressregister laden
L 7                                //Anzahl der Schiebevorgänge laden
nex1: T #iLoopCounter
L DID [AR1,P#4.0]                  //Startadresse + 1 DW
T DID [AR1,P#0.0]                  //in Startadresse schreiben
+AR1 P#4.0                         //und das AR1 um 4.0 erhöhen = neue Startadresse
L #iLoopCounter                    //Schleifenzähler laden
LOOP nex1                          //um ihn zu dekrementieren und zurückzuspringen[/LEFT]
 
[LEFT]L #rInput                          //und den aktuellen Wert
T #aRealArray[7]                   //ins Real-ARRAY schubsen[/LEFT]


So, nun sind beim Durcharbeiten leider schon die ersten Fragen aufgetaucht – es wäre super, wenn ihr mir etwas helfen könntet, damit ich den Aufbau richtig verstehe…


1) Im AR1 steht ja zu Beginn: P#8.0

Es soll doch als erste Adresse die Anfangsadresse im Array „beschrieben“ werden – und diese erste Adresse ist doch 1 und nicht 8, oder?


2) L DID[AR1, P#4.0] ruft ja die Startadresse + 1 Doppelwort auf.

Warum ist es nötig, zusätzlich zur Startadresse noch ein Doppelwort zu laden?
Zu Beginn (also beim ersten Durchlauf der Schleife) muss doch der Zeiger auf die „Ursprungsadresse“ (in diesem Fall auf Adresse 8 im Array) zeigen…

3) „#rInput“ soll ja den aktuell anstehenden Wert, z.B. einen Messwert darstellen.

Was aber ist beim Aufruf des Bausteins für „#aRealArray[7]“ zu übergeben?


So, das wären zunächst einmal die ersten Fragen zu diesem Thema… wenn ich das verstanden habe, dann „forsche“ ich weiter… :)

Vielen Dank schon mal bis hierhin für eure Hilfe!

Grüße

pinolino
 
Das Programm ist keine Mittelwertbildung, sondern ein Schieberegister.
Der erste Wert wird gelöscht.
Die 2. bis 8. Werte werden an Stelle 1 - 7 verschoben
und der neue Wert (#rInput) wie an die 8. Stelle geschrieben.

Beim Schieben müssen die Real-Werte noch addiert und durch 8 dividiert werden!
 
Danke für die Antworten,

aber so ganz hab ich es noch nicht verstanden...


Das Schieberegister soll doch acht Speicherplätze besitzen. Es werden aber nur 7 Schleifendurchläufe programmiert.

Und warum wird als Startadresse nicht "L DID [AR1, P#0.0]" sondern "L DID [AR1, P#4.0]", also genau 1DW höher gewählt?

Danke, pinolino
 
Das Schieberegister soll doch acht Speicherplätze besitzen. Es werden aber nur 7 Schleifendurchläufe programmiert.

Und warum wird als Startadresse nicht "
Code:
L DID [AR1, P#0.0
]" sondern "L DID [AR1, P#4.0]", also genau 1DW höher gewählt?
Es werden 7 alte Werte verschoben, der 8.Wert ist ja der neue, der wird direkt rein geschrieben.

L DID [AR1, P#4.0] // Der zweite Wert
L DID [AR1, P#0.0] // wird auf den ersten geschrieben

Nach der 1.Schleife schaut es dann so aus.
Der Pointerversatz bleibt ja gleich aber das AR1 wird um 4 erhöht

L DID [AR1+4, P#4.0] // Der dritte Wert
L DID [AR1+4, P#0.0] // wird auf den zweiten geschrieben
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Es werden 7 alte Werte verschoben, der 8.Wert ist ja der neue, der wird direkt rein geschrieben.

L DID [AR1, P#4.0] // Der zweite Wert
L DID [AR1, P#0.0] // wird auf den ersten geschrieben

Nach der 1.Schleife schaut es dann so aus.
Der Pointerversatz bleibt ja gleich aber das AR1 wird um 4 erhöht

L DID [AR1+4, P#4.0] // Der dritte Wert
L DID [AR1+4, P#0.0] // wird auf den zweiten geschrieben

Danke für deine Erläuterung, Paule!

Ich nehme an in den jeweils beiden unteren Zeilen muss statt dem L ein T stehen - für Transferieren?


Mein Problem - irgendwie komme ich mit dem Ablauf noch nicht zurecht:

Soweit ich es verstanden habe, wird das Array von hinten nach vorne ( Platz 8 bis Platz 1) aufgefüllt.

1) Beim ersten Durchlauf des Programms steht doch für die Anweisung ( Zeile 6 bis Zeile 8 ) noch gar kein Wert zur Verfügung. Der erste Wert wird doch erst in der letzten Anweisungszeile geladen und in das Array geschrieben.

2) Sehe ich es richtig, dass der 8. Wert (also der jeweils neue) direkt in das 7. Feld des Arrays (T #aRealArray[7]) geschrieben wird?

3) Ist das Array dann wie folgt deklariert:

ARRAY [0..7] ?

Grüße
pinolino
 
Zuletzt bearbeitet:
Hier mal ein Baustein wie ich ihn verwende.

Code:
FUNCTION_BLOCK "FB_Mittelwertbildung"
TITLE =Mittelwertberechnung/ Integrationsbaustein
AUTHOR : 'F.J.'
VERSION : 1.0


VAR_INPUT
  Eingangswert : REAL ;    //Zu Glätender Istwert
  Speichertakt : BOOL ;    //Abfragetakt des Eingangswert
  SPS_Start : BOOL ;    //Start der Berechnung
  Zyklen : INT ;    //Ringspeichergröße (Zyklen x Speichertakt = Integrationszeit)
END_VAR
VAR_OUTPUT
  Zeigernummer : WORD  := W#16#10;    
  Endwert : REAL ;    //Geglaeteter Wert
END_VAR
VAR
  Messwert_500 : REAL ;    
  .
  .
  .
  .   
  Messwert_1 : REAL ;    
  Store_Mitteln : INT ;    
  Store_Mitteln_1 : REAL ;    
  Store_Nullen : INT ;    
  DB_wurde_Genullt : BOOL ;    
  Mittelwert : BOOL ;    
  FP_Takt : BOOL ;    
END_VAR
VAR_TEMP
  Impuls_Takt : BOOL ;    
  Zeiger_Speichern : DWORD ;    
  Zeiger_Mitteln : DWORD ;    
  Zeiger_Nullen : DWORD ;    
  Loops_Nullen : INT ;    
  Loops_Mitteln : INT ;    
END_VAR
BEGIN
NETWORK
TITLE =Reseten

      U     #SPS_Start; 
      SPB   strt; 

      L     0.000000e+000; 
      T     #Endwert; 

      L     16; 
      T     #Store_Mitteln; 
      T     #Store_Nullen; 
      T     #Zeigernummer; 
NETWORK
TITLE =DB Werte Nullen wenn keine abfrage

      U     #DB_wurde_Genullt; 
      BEB   ; 

      L     #Zyklen; 
NEXT: T     #Loops_Nullen; 
      L     #Store_Nullen; 
      L     4; 
      +I    ; 
      T     #Store_Nullen; 

      L     #Store_Nullen; 
      SLW   3; 
      T     #Zeiger_Nullen; 

      L     0.000000e+000; 
      T     DID [#Zeiger_Nullen]; 

      L     #Loops_Nullen; 
      LOOP  NEXT; 
      S     #DB_wurde_Genullt; 
      BE    ; 

strt: NOP   0; 
      R     #DB_wurde_Genullt; 
NETWORK
TITLE =Abtasttakt
//im zeitintervall von x sekunden (arbeitstakt) wird ein neuer wert aufgenommen.
      U     #Speichertakt; 
      UN    #FP_Takt; 
      =     #Impuls_Takt; 

      U     #Speichertakt; 
      =     #FP_Takt; 

      U     #Impuls_Takt; 
      R     #Mittelwert; 
      SPBN  arbt; 
NETWORK
TITLE =Speicherzeiger prüfen wenn Speicherende erreicht
//wenn speicherzeiger grösser als 2012 (500 Messwerte) dann auf 16 
//setzen (zeiger für messwertNr.1) 
      L     #Zeigernummer; 
      L     4; 
      +I    ; 
      T     #Zeigernummer; 

      L     #Zyklen; 
      L     4; 
      *I    ; 
      L     12; 
      +I    ; 
      L     #Zeigernummer; 
      TAK   ; 
      >I    ; 
      SPBN  NULL; 

      L     16; 
      T     #Zeigernummer; 

NULL: NOP   0; 

NETWORK
TITLE =Eingangswert abspeichern

      L     #Zeigernummer; 
      SLW   3; 
      T     #Zeiger_Speichern; 
      L     #Eingangswert; 
      T     DID [#Zeiger_Speichern]; 

NETWORK
TITLE =Mittelwert aus DB errechnen

arbt: NOP   0; 
      U     #Mittelwert; 
      SPB   aus; 

      L     0.000000e+000; 
      T     #Store_Mitteln_1; 

      L     16; 
      T     #Store_Mitteln; 


      L     #Zyklen; 
Next: T     #Loops_Mitteln; 

      L     #Store_Mitteln; 
      L     4; 
      +I    ; 
      T     #Store_Mitteln; 

      L     #Store_Mitteln; 
      SLW   3; 
      T     #Zeiger_Mitteln; 
      L     DID [#Zeiger_Mitteln]; 
      L     #Store_Mitteln_1; 
      +R    ; 
      T     #Store_Mitteln_1; 

      L     #Loops_Mitteln; 
      LOOP  Next; 

      L     #Zyklen; 
      ITD   ; 
      DTR   ; 
      L     #Store_Mitteln_1; 
      TAK   ; 
      /R    ; 
      T     #Endwert; 

      S     #Mittelwert; 
aus:  NOP   0; 
      BE    ; 
END_FUNCTION_BLOCK

Cheers Flo
 
Zuletzt bearbeitet:
Danke vecoplaner,

allerdings übersteigt dieser Baustein meine (derzeitigen) Kenntnisse!


Insofern wäre ich für eine Beantwortung meiner vorhergehenden Fragen sehr dankbar:

Mein Problem - irgendwie komme ich mit dem Ablauf noch nicht zurecht:

Soweit ich es verstanden habe, wird das Array von hinten nach vorne ( Platz 8 bis Platz 1) aufgefüllt.

1) Beim ersten Durchlauf des Programms steht doch für die Anweisung ( Zeile 6 bis Zeile 8 ) noch gar kein Wert zur Verfügung. Der erste Wert wird doch erst in der letzten Anweisungszeile geladen und in das Array geschrieben.

2) Sehe ich es richtig, dass der 8. Wert (also der jeweils neue) direkt in das 7. Feld des Arrays (T #aRealArray[7]) geschrieben wird?

3) Ist das Array wie folgt zu deklarieren:

ARRAY [0..7] ?

Grüße
pinolino
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Achso, du möchtest mit einem Array arbeiten (hab den fred wohl zu sehr
überflogen), der von mir gepostete Baustein bearbeitet einfach einen
Realwert, speichert ihn und berechnet danach den Mittelwert.
Also nicht das was du benötigst.


Gruß
 
Ja, genau - ich wollte mich gerne an das Beispiel aus meinem 1. Thread halten und es durcharbeiten...


Allerdings ist mir aber der Ablauf noch immer nicht ganz klar; könnte hier bitte nochmals jemand helfen?


Soweit ich es verstanden habe, wird das Array von hinten nach vorne ( Platz 8 bis Platz 1) aufgefüllt.

1) Beim ersten Durchlauf des Programms steht doch für die Anweisung ( Zeile 6 bis Zeile 8 ) noch gar kein Wert zur Verfügung. Der erste Wert wird doch erst in der letzten Anweisungszeile geladen und in das Array geschrieben. Was passiert denn dann an dieser Stelle?

2) Sehe ich es richtig, dass der 8. Wert (also der jeweils neue) direkt in das 7. Feld des Arrays (T #aRealArray[7]) geschrieben wird?

3) Ist das Array wie folgt zu deklarieren:

ARRAY [0..7] ?

Grüße
pinolino
 
Zuletzt bearbeitet:
Soweit ich es verstanden habe, wird das Array von hinten nach vorne ( Platz 8 bis Platz 1) aufgefüllt.
Korrekt!
Beim ersten Durchlauf des Programms steht doch für die Anweisung ( Zeile 6 bis Zeile 8 ) noch gar kein Wert zur Verfügung. Der erste Wert wird doch erst in der letzten Anweisungszeile geladen und in das Array geschrieben.
Ja, macht ja nix dann werden halt die Nullwerte rausgeschoben.
Sehe ich es richtig, dass der 8. Wert (also der jeweils neue) direkt in das 7. Feld des Arrays (T #aRealArray[7]) geschrieben wird?
3) Ist das Array dann wie folgt deklariert:
ARRAY [0..7] ?
Ganz genau, Du könntest natürlich die Array Felder mit 1..8 benennen dann wäre es leichter lesbar.

Die erste 8 ist klar?
Da sich das Ganze in einem Instanz DB abspielt wurde ja im Deklarationsteil das Array gesetzt. Und diese Startadresse ist in dem Beispiel die Adresse 8
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Die erste 8 ist klar?
Da sich das Ganze in einem Instanz DB abspielt wurde ja im Deklarationsteil das Array gesetzt. Und diese Startadresse ist in dem Beispiel die Adresse 8

habe es mittlerweile in besagtem beispiel angepasst, da lautet es jetzt

Code:
*
      LAR1  P##aRealArray               //Startadresse des Arrays ins Adressregister laden
was die funktion besser beschreibt und sachlich richtiger ist ... danke für den hinweis pinolino

ansonsten, ja, das ist ein array[0..7] ... ich programmiere! da fängt die welt mit 0 an! for i=0 to 7... U M100.0 usw.
 
Zuletzt bearbeitet:
Vielen Dank für deine Hilfe, Paule!

Die erste 8 ist klar?
Da sich das Ganze in einem Instanz DB abspielt wurde ja im Deklarationsteil das Array gesetzt. Und diese Startadresse ist in dem Beispiel die Adresse 8

Ja, denke diese erste 8 ist klar... somit könnte man für dieses Beispiel sagen, dass das Daten-Instanz-Doppelwort 8 des Instanz-DB´s die Startadresse angibt.

Nur, wo ist denn definiert, dass diese Startadresse ( also das DID8 ) dem Array-Feld 7 zugeordnet ist? Wo ist der Bezug zwischen Startadresse und Array-Feld?

Danke
pinolino
 
Zuletzt bearbeitet:
Nur, wo ist denn definiert, dass diese Startadresse ( also das DID8 ) dem Array-Feld 7 zugeordnet ist? Wo ist der Bezug zwischen Startadresse und Array-Feld?
Die Startadresse ist ja nicht dem Array-Feld 7 zu geordnet sondern dem Feld 1
Auf das Array-Feld 7 wird ja direkt zugegriffen.
Die direkte Zuweisung auf eine Adresse ( in diesem Fall 8 ) ist auch nicht sauber.
Aber 4L hat ja die bessere Lösung schon an seinem Beitrag geändert.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Das Programm ist keine Mittelwertbildung, sondern ein Schieberegister.
Der erste Wert wird gelöscht.
Die 2. bis 8. Werte werden an Stelle 1 - 7 verschoben
und der neue Wert (#rInput) wie an die 8. Stelle geschrieben.

Beim Schieben müssen die Real-Werte noch addiert und durch 8 dividiert werden!
He Pinolino,
jetzt wurden Dir hier schon verschiedene Lösungen angeboten.
Ist ja OK das Du Dich für die Lösung von 4L entschieden hast, aber da hat der Spezy mit seinem erst Beitrag absolut recht, die Daten hast Du jetzt erstmal verschoben.
Von einem Mittelwert bist Du noch eine Addition und einer Division entfernt. ;)
 
Benutze fertigen Baustein SAMP_AVE

In der CFC Library unter ELEM_300 gibt es einen fertigen Baustein zu Mittelwertbildung. FB4 "SAMP_AVE". Den benutze ich immer. Rufe ihn in einem Weckalarm-OB auf, um eine vernünftige Zeitbasis zu haben.

Beschreibung aus der Hilfe zum FB4:

SAMP_AVE

Funktion

Dieser Baustein gibt am Ausgang den Mittelwert der letzten N Eingangswerte aus.
OUT = (Ink + Ink -1 + ... + Ink -n + 1) / N
wobei Ink der aktuelle Eingangswert ist. Die Anzahl N der Eingangswerte muss die Bedingung
0 < N < 33
erfüllen.

Anlaufverhalten

Bei Anlauf und Erstlauf wird jedes Element des Buffers für IN- und OUT-Werte auf 0 gesetzt.

Gruß Buster
 
Danke nochmals für eure Erklärungen!

Das mit dem Schieben habe ich jetzt soweit verstanden... habe mir dazu die einzelnen Array-Felder mit ihren dazugehörigen Adressen notiert :

Array-Feld 0 → DID [AR1, P#0.0] → 1. Wert

Array-Feld 1 → DID [AR1, P#4.0] → 2. Wert

Array-Feld 2 → DID [AR1, P#8.0] → 3. Wert

Array-Feld 3 → DID [AR1, P#12.0] → 4. Wert

Array-Feld 4 → DID [AR1, P#16.0] → 5. Wert

Array-Feld 5 → DID [AR1, P#20.0] → 6. Wert

Array-Feld 6 → DID [AR1, P#24.0] → 7. Wert

Array-Feld 7 → DID [AR1, P#28.0] → 8. Wert


@Paule:
Ja stimmt schon, dass bereits mehrere Lösungen aufgezeigt wurden. Mir geht es aber auch darum, die Sache mit den Pointern und Arrays zu verstehen und nachvollziehen zu können, da dies Neuland für mich ist. Denke, wenn ich das Prinzip verstanden habe, dann verstehe ich auch die anderen Codes...


So, nun noch ein Problem:

Wollte das Ganze gerne mal mit PLCSIM testen - aber sobald ich im FB1 auf den Beobachtungsmodus klicke, geht die CPU in Stop! Wo könnte das Problem liegen?

Was ich gemacht habe:

1.
FB1 angelegt und den bekannten Code programmiert. In dem Deklarationsbereich des FBs habe ich "aRealArray" als statische Variable angelegt (siehe Bild!).

2.
Durch den Aufruf "Call FB1, DB1" im OB1 hat sich der Instanz-DB1 lt. Bild angelegt.

Wäre super nett, wenn ich noch einen Tipp bekommen könnte, was ich hier falsch gemacht habe...

Vielen Dank - auch für eure Geduld mit mir!
pinolino
 

Anhänge

  • Deklaration.jpg
    Deklaration.jpg
    16,6 KB · Aufrufe: 14
  • FB1.jpg
    FB1.jpg
    16,5 KB · Aufrufe: 21
  • Instanz-DB1.jpg
    Instanz-DB1.jpg
    44,4 KB · Aufrufe: 19
Danke vierlagig,

habe den FB1, den DB1 und den OB1 geladen.


Der Diagnosepuffer weist auf zwei Probleme hin:

1)
STOP durch Programmierfehler (OB nicht geladen oder nicht möglich, bzw. kein FRB vorhanden )
Unterbrechungstelle im Anwenderprogramm: Zyklisches Programm (OB 1)
Prioritätsklasse: 1
FB-Nummer: 1
Bausteinadresse: 16
Bisheriger Betriebszustand: RUN
Angeforderter Betriebszustand: STOP (intern)
interner Fehler, kommendes Ereignis


2)
Bereichslängenfehler beim Lesen
Instanz-DB, Doppelwortzugriff, Zugriffsadresse: 32
FB-Nummer: 1
Bausteinadresse: 16
Angeforderter OB: Programmierfehler-OB (OB 121)
OB nicht vorhanden oder gesperrt oder nicht startbar im aktuellen Betriebszustand
interner Fehler, kommendes Ereignis


Leider sagt mir das nicht so viel - kann man daraus ein Problem feststellen?

Danke, pinolino
 
Zurück
Oben