gleitende Mittelwertbildung Filter funktioniert nicht

Gast #4159030
Lesenswert?

Hallo Gemeinde,

ich habe ein Problem mit meinem Filter Aufruf.

Der Code sieht folgendermaßen aus:
1
float Filter_UohneL(float Delta_Alpha)
2
{
3
  
4
  static unsigned long avgsum=0;   
5
  static short n = 0;
6

7
  if (n<15) {
8
    n++;
9
    avgsum += Delta_Alpha;
10
    return avgsum/n;
11
  }
12
  else {
13
    avgsum -= avgsum/15;
14
    avgsum += Delta_Alpha;
15
    return avgsum/15;
16
  }
17
}

Der Aufruf erfolgt folgermaßen in der Main:
1
Delta_Alpha_gefiltert = Filter_UohneL (Delta_Alpha);

Aber wieso wird immer Null zurückgegeben?
Vielen Dank an die Helfenden
#4159036
Lesenswert?

Ich kann falsch liegen, aber innerhalb einer Funktion funktioniert

static short n = 0;

nicht oder ist nicht Kompilerübergreifend.

Ersetze es mal (testweise) gegen die klassisce Variante, die Variable zu 
setzen bevor sie das erste mal verwendet wird.

An deiner Steller wäre ausserdem eine for(n=0;n>=15;N++){..} besser.
Gast #4159049
Lesenswert?

Mark schrieb:
>
> Aber wieso wird immer Null zurückgegeben?

Weil dein Delta_Alphaimmer < 15 ist?
Deklariere avgsum auch als float.


Davon abgesehen ist das kein gleitender Mittelwert (aka Mittelwert der 
letzten n Werte) sondern ein IIR Tiefpassfilter. (IIR = Infinit Impulse 
Response)
Gast #4159069
Lesenswert?

> Sag mal, was genau unterrichtest du eigentlich?
> Programmierung kanns ja wohl nicht sein

Doch doch, das kann sehr wohl sein. Wenn ich mir anschaue, was meine 
Kinder im Informatikunterricht in der Schule so alles (nicht) gelehrt 
bekommen.

Gruß, Stefan
#4159074
Lesenswert?

Timo schrieb:
> achne..const war eine Konstante :->)

Vorsicht:
In C ist eine als 'const' markierte Variable nach wie vor eine Variable. 
Allerdings eine von der du die Zusicherung machst, dass du sie in deinem 
Programm nicht verändern wirst. Das 'const' bedeutet in C 'not 
modifiable'.
Es ist KEINE Konstante!

Der Unterschied ist subtil und tritt dann zu Tage, wenn du versuchst 
eine derartige vermeintliche 'Konstante' an Stellen zu verwenden, an 
denen von der Syntax her tatsächlich eine Konstante gefordert wird. Wie 
zb. bei einem 'case' in einem switch-case.
Gast #4159125
Lesenswert?

So wie die Funktion oben beschrieben ist macht sie
kein Mittelwert. Deshalb bin ich davon ausgegangen,
das sie irgendwo von ausserhalb in einer Schleife immer
wieder aufgerufen wird, um einen neuen Mittelwert zu
berechenen. (Warums sonst soll man in der Funktion
Variablen statisch halten?).

N wird bei jedem Aufruf um eins erhoeht, ergo irgendwann
laeuft N mal ueber.

Oberlehrer
#4159144
Lesenswert?

Karl Heinz schrieb:
> In C ist eine als 'const' markierte Variable nach wie vor eine Variable.
> Allerdings eine von der du die Zusicherung machst, dass du sie in deinem
> Programm nicht verändern wirst. Das 'const' bedeutet in C 'not
> modifiable'.
> Es ist KEINE Konstante!

"C" kommt mir vor, wie die Durchquerung eines Urwaldes voller Schlangen 
und Skorpione in einer mondlosen Nacht ohne Taschenlampe.

MfG Paul
#4159148
Lesenswert?

Oberlehrer schrieb:
> So wie die Funktion oben beschrieben ist macht sie
> kein Mittelwert. Deshalb bin ich davon ausgegangen,
> das sie irgendwo von ausserhalb in einer Schleife immer
> wieder aufgerufen wird, um einen neuen Mittelwert zu
> berechenen.

So weit so gut,
Zum Beispiel von der Hauptschleife, die den ADC ausliest und die 
sukzessive ermittelten Werte filtern lässt.

> (Warums sonst soll man in der Funktion
> Variablen statisch halten?).

Damit sie von ausserhalb der Funktion nicht zugreifbar sind. Die 
Variablen gehören konzeptionell zu der Funktion und sind nur innerhalb 
der Funktion relevant.
Das ist eigentlich der Standardfall, warum man Variablen static macht.

>
> N wird bei jedem Aufruf um eins erhoeht, ergo irgendwann
> laeuft N mal ueber.

Und das hier
1
  if (n<15) {

zählt gar nichts?

n wird bis 15 hochgezählt (bei jedem erneuten Funktionsaufruf um 1 mehr) 
und bleibt dann bei 15 stehen.

Und der Zweck besteht darin, dass er über die letzten 15 Werte Tiefpass 
filtern möchte, allerdings das Problem hat, dass der ganze Klaperatismus 
ja auch erst mal anlaufen muss. D.h. für die ersten 14 Messwerte kommt 
eine andere Berechnung zum Zug, weil sich ja die Summe der ersten 15 
Werte erst nach und nach mit jedem Funktionsaufruf aufbauen muss. Daher 
wird nicht 1/15 der Summe abgezogen und daher wird da auch noch nicht 
durch 15 dividiert.
Sobald die Funktion das 15.te mal (und folgende) aufgerufen wird ist die 
ganze Sache mit dem n vom Tisch: Ab dann wird von der bisherigen Summe 
1/15 abgezogen, der neue Messwert in die Summe eingerechnet und der 
Durschnitt geliefert.

Eigentlich eine ganz einfache Funktion.
Moderator (Firma: Titel) Persönliche Seite #4159151
Lesenswert?

Oberlehrer schrieb:
> Und ausserdem dividerst du durch 0!
Zwar nicht, aber diese Division ist fast genauso /umständlich/:
Mark schrieb:
> return avgsum/15;

Man sollte sein Zielsystem kennen und wissen, dass so ein Rechenknecht 
im Zweiersystem arbeitet. Dann kommt man pfeilschnell auf die Idee, dass 
eine Filterweite von 16 und damit eine Division durch 16 wesentlich 
geschickter wäre...

Mark schrieb:
> float Filter_UohneL(float Delta_Alpha)
Worauf soll das Ganze nochmal laufen? Kann das Zielsystem mit float 
umgehen?
Falls ja:
> static unsigned long avgsum=0;
Ich würde wenigstens diese lokale Summe dann auch zu einem float 
machen...

Mark schrieb:
> Der Code sieht folgendermaßen aus:
Der kommt mir bekannt vor... ;-)
http://www.lothar-miller.de/s9y/archives/25-Filter-in-C.html
Gast #4159169
Lesenswert?

> D.h. für die ersten 14 Messwerte kommt
>eine andere Berechnung zum Zug, weil sich ja die Summe der ersten 15
>Werte erst nach und nach mit jedem Funktionsaufruf aufbauen muss.

hier kann man sich fragen, ob das wichtig ist. Immerhin sinds nur die 
ersten x(15) Werte, wo sich das aufbaut. Evtl. kann man das auch 
ignorieren. So spart man sich einen Vergleich, der bis auf die ersten 
paar Mal nie erfüllt ist...
1
float Filter_UohneL(float NewValue)
2
{
3
  #define  FILTERLEN   15
4

5
  static float ArrayData[FILTERLEN];
6
  static float ArraySum = 0;
7
  static short ArrayIdx = 0;
8

9
  //-- letzten Wert entfernen -----------
10
  ArraySum -= ArrayData[ArrayIdx];
11

12
  //-- neuen Wert eintragen -------------
13
  ArrayIdx++;
14
  if ( ArrayIdx >= FILTERLEN ) ArrayIdx = 0;
15
  ArrayData[ArrayIdx] = NewValue;
16

17
  //-- neue Summe bilden ----------------
18
  ArraySum += ArrayData[ArrayIdx];
19

20
  //-- Wert zurückgeben -----------------
21
  return ( ArraySum / FILTERLEN );
22
}
Gast #4159190
Lesenswert?

static, siehe:
http://de.wikipedia.org/wiki/Static_%28Schl%C3%BCsselwort%29

Das kleine Problem dabei:
Die Variablen avgsum und n gibt es nur einmal. Solange die Funktion 
Filter_UohneL() nur an einer einzigen Stelle verwendet wird, gibt es 
kein Problem. Sobald Du aber Dein Programm erweiterst, hast Du ein 
Problem:
1
Delta_Alpha_gefiltert = Filter_UohneL (Delta_Alpha);
2
Delta_Beta_gefiltert  = Filter_UohneL (Delta_Beta);

In avgsum wird jetzt Delta_Alpha_gefiltert UND Delta_Beta_gefiltert 
aufaddiert - was zu falschen Ergebnissen führt.

Gruß, Stefan
#4159308
Lesenswert?

Matthias Lipinsky schrieb:
>> …
>
>
1
> float Filter_UohneL(float NewValue)
2
> {
3
>   #define  FILTERLEN   15
4
> 
5
>   static float ArrayData[FILTERLEN];
6
>   static float ArraySum = 0;
7
>   static short ArrayIdx = 0;
8
> 
9
>   //-- letzten Wert entfernen -----------
10
>   ArraySum -= ArrayData[ArrayIdx];
11
> 
12
. . .
13
>

Läuft der Dir nicht wegen Rundungsproblemen (float) aus dem Ruder?

Gruß Martin
Gast #4159456
Lesenswert?

Karl Heinz schrieb:
> Es ist KEINE Konstante!

Aber, aber, Karlheinz.
Das kommt nämlich ganz auf die Umstände drauf an. Bei Zeugs, was auf 
deinem PC komplett im RAM läuft, hast du ja Recht, aber initialisierte 
Konstanten landen bei den µC, die ich vor der Nase habe, gnadenlos im 
Flash und bleiben dort auch. Da ist Neese mit Zuweisungen aller Art. 
Allenfalls kriegt man ne Data-Exception auf die Rübe.

Aber die Code-Kostproben, die hier kamen, sind schon grandios...

Eigentlich macht man's etwa so:

typ buf[zweierpotenz];
int zeiger;
typ summe;

void init_me(void)
{ summe = zeiger = 0; }

typ filtere (typ was)
{ typ tmp;

  tmp = summe - buf[zeiger] + was;
  buf[zeiger] = was;
  zeiger = (zeiger+1) & (zweierpotenz-1);
  return tmp>>zweierpotenz;
}

So. Hoffentlich nix vergessen...
Wer will, kann natürlich auch krumme Pufferlängen nehmen, dann ist eben 
ein if(zeiger>=buflenge) zeiger=0 und eine Division am Ende nötig.

W.S.
Gast #4159460
Lesenswert?

Das Problem mit dem "ersten Einschwingen" kann man so elegant lösen:
man initialisiert die Summe auf den n-fachen Wert.
Entweder automatisch:
#define FS 64  //Filterstärke
firstTime=1;

im Filter:
if(firstTime){adcSum = FS * adc; firstTime = 0;}
else {adcSum += adc - adcSum / FS;}

Oder beim Initialisieren (z.B. wenn der Wert in etwa bekannt ist).
Oder man nimmt zuerst einen schwachen Filter:
#define FS1 8       //Filterstärke 1
#define FS2 8 * FS1 //Filterstärke 2
firstTimes=16;

if(firstTimes){
  if(firstTimes-- == 16) {adcSum = FS2 * adc;} //Filter setzen
  else {adcSum += FS2 / FS1 * adc - adcSum / FS2;} //schwach filtern
  }
else {adcSum += adc - adcSum / FS2;} //stark filtern

Code wie immer ungetestet, kam mir gerade so in den Sinn  ;-)

Oft ist es besser (genauer), am Ende des Filters adcSum nicht zu 
dividieren, um in den Werte-Bereich von adc zu kommen, sondern direkt 
mit der Summe weiterzurechnen.

> Vorsicht:
> In C ist eine als 'const' markierte Variable nach wie vor eine
> Variable. Allerdings eine von der du die Zusicherung machst,
> dass du sie in deinem Programm nicht verändern wirst. Das
> 'const' bedeutet in C 'not modifiable'. Es ist KEINE Konstante!
Daher ist es besser, Konstanten als Macros zu definieren.
Gast #4159520
Lesenswert?

eProfi schrieb:
> if(firstTimes){

Naja.. meine Meinung dazu ist, den Filterkernel so klein wie möglich zu 
halten. Da ist es eigentlich egal, ob bei den ersten 16 oder 32 Werten 
Murks rauskommt und später läuft das Ganze ja sowieso, da ist dann ne 
Fallabfrage nicht mehr nützlich.

W.S.
#4159527
Lesenswert?

W.S. schrieb:
> Karl Heinz schrieb:
>> Es ist KEINE Konstante!
>
> Aber, aber, Karlheinz.
> Das kommt nämlich ganz auf die Umstände drauf an.


Du solltest dir endlich mal angewöhnen zu akzeptieren, dass nicht deine 
Compiler Implementierungen definieren, wie C zu funktionieren hat, 
sondern einzig und allein der Standard.

> Bei Zeugs, was auf
> deinem PC komplett im RAM läuft, hast du ja Recht, aber initialisierte
> Konstanten landen bei den µC, die ich vor der Nase habe, gnadenlos im
> Flash und bleiben dort auch.

Und? Ist komplett irrelevant

> Da ist Neese mit Zuweisungen aller Art.
> Allenfalls kriegt man ne Data-Exception auf die Rübe.

Und auch das ist korrekt.
Beim Versuch der Veränderung einer const Variablen landet man in 
'undefined behaviour land'. Hat nur leider nichts damit zu tun, das 
const markierte Variablen in C keine Konstanten sind (im Gegensatz zu 
C++)
#4159552
Lesenswert?

Karl Heinz schrieb:

> Hat nur leider nichts damit zu tun, das
> const markierte Variablen in C keine Konstanten sind (im Gegensatz zu
> C++)

Vielleicht wird dir der Unterschied (und das wovon ich eigentlich 
spreche) bewusst, wenn du dieses 'Programm' einmal durch den C Compiler 
und einmal durch den C++ Compiler jagst und dir die Fehlermeldungen mal 
ansiehst
1
const int size = 5;
2

3
int data[size];
4

5
int main(int argc, char* argv[])
6
{
7
}

C: illegal. size ist keine Konstante
C++: legal. size ist eine Konstante
Gast #4160252
Lesenswert?

Ja, Delta_Alpha ist immer kleiner 1.

Der Filter scheint im Betrieb zu funktionieren, nur beim allerersten 
Anschalten werden erst n Werte gesammelt...
Siehe Foto (sorry wegen der Quali).
Das war aber nicht Sinn der Sache..
Jemand Rat?
Angehängte Dateien:
Gast #4160384
Lesenswert?

Numerisch verfolgen ist schlecht.
Aber verdoppele ich "n" so verdoppelt sich auch die "Totzeit" zu Beginn 
des vorherigen Fotos.
Anscheinend ist Delta_alpha zu Beginn, solange n nicht seinen Max Wert 
erreicht hat, wirklich null. Wüsste aber nicht wieso..
komisch..
#4160397
Lesenswert?

Mark schrieb:
> Numerisch verfolgen ist schlecht.

Das wiederrum ist ganz schlecht.
Einer der schlimmsten Fehler, den man meiner Meinung nach machen kann, 
ist es sich von Anfang an keine Debugmöglichkeit zu verschaffen, an der 
man auch mal Zahlenwerte rauskriegt. Die Methode 'Stochern im Nebel' war 
zum Debuggen noch nie sehr effektiv.

Kannst du dir die ersten sagen wir mal 20 Werte nicht zb in ein EEPROM 
schreiben lassen und dann später vom EEPROM auslesen? (Benutzt du 
überhaupt einen AVR?)

> Anscheinend ist Delta_alpha zu Beginn, solange n nicht seinen Max Wert
> erreicht hat, wirklich null. Wüsste aber nicht wieso..

Wo kommen die her und was passiert mit dem gefilterten Wert weiter?
Gast #4160502
Lesenswert?

Erst mal Danke für den ersten "Nebelstocherer". Leider ohne Erfolg.

Also was ich in etwa mache ist folgendes:

Der Aufruf sieht in der main so aus:
1
Delta_Alpha = PI_ohneL(Id_neu, Id_alt, Imax);
2
Delta_Alpha_gefiltert = Filter_UohneL (Delta_Alpha, Stromregelung);
3
ALPHA_radiant = ALPHA_radiant - Delta_Alpha_gefiltert;
4
ALPHA_ohneL = ALPHA_radiant * 6366.197717;

Ich mache eine Phasenanschnittssteuerung, aber sobald ich n , wie 
gesagt, höher setze, wird zu Beginn mit dem größten Alpha angeschnitten.

PI_ohneL sieht so aus:
1
float PI_ohneL(float Id_neu, float Id_alt, float Imax)    //Für ohne Linearisierung
2
{
3
  
4
  xd = (Imax - Id_neu);
5
  xd_1 = (Imax - Id_alt);
6
  /*
7
  if (PIdurchlauf == 1)   //Um beim ersten Durchlauf P-Anteil nicht zu vernachlässigen
8
  {
9
    xd_1 = 0;
10
    PIdurchlauf = 0;
11
  }  
12
  else  xd_1 = (Imax - Id_alt);
13
*/
14
  TermA = (xd - xd_1);
15
  TermB = k_Ri * TermA;
16
  TermC = T_AB/T_Ri;
17
  TermD = k_Ri * TermC;
18
  TermE = TermC * xd_1;
19
  TermF = TermB + TermE;   
20
  new_u_ist = TermF;
21
        //new_u_ist = (new_u_ist + k_Ri_lin * (xd - xd_1) + k_Ri_lin * T_AB_lin / T_Ri_lin * xd_1) ;
22

23
  u_ohneL = new_u_ist;
24
  
25
  return u_ohneL;    //Übergabe Stellgröße
26
}

Im Grunde funktioniert ja alles, nur eben dass der Start in Abhängigkeit 
von "n" verzögert wird
Gast #4160544
Lesenswert?

Zu früh gefreut.
Nach dem Bespielen (sprich Reset) des uC und starten des Programms läuft 
alles wie es soll.
Nur nach dem erneuten Starten des Programms durch einen Taster steigt 
und fällt die anfängliche Totzeit mit n!?

Was muss ich denn wo nullsetzen?
Mir würde es ja einleuchten, wenn die vorherigen Werte noch gespeichert 
wären, aber wieso die ersten n Werte nach dem fortsetzen des Programms 
mit Null initialisiert werden das verstehe ich nicht.
Gast #4160567
Lesenswert?

Und entschuldigung falls ich nerve, aber eine Frage noch:

Funktioniert die Funktion PI_ohneL so wie sie soll?
Weil ich new_u_ist einfach ganz normal als float innerhalb der header 
Datei in der die Funktion geschrieben ist, definiert habe, nicht als 
static..
Gast #4160588
Lesenswert?

Karl Heinz schrieb:
> Einer der schlimmsten Fehler, den man meiner Meinung nach machen kann,
> ist es sich von Anfang an keine Debugmöglichkeit zu verschaffen, an der
> man auch mal Zahlenwerte rauskriegt. Die Methode 'Stochern im Nebel' war
> zum Debuggen noch nie sehr effektiv.


Der einzig vernünftige Weg, so etwas komplexes (1) zum Laufen zu 
bekommen, ist, es erst in C auf dem PC zu implementieren, die Funktion 
mit reichlich Testszenarien zu füttern und Diagramme der Ausgabe zu 
malen a la meintest.exe > zahlen.csv und Excel.

Wenn das vernünftige Werte liefert, schiebt man tiefpass.c und 
tiefpass.h einfach in uc-Projekt.


(1) relativ zum Kenntnisstand
Gast #4160603
Lesenswert?

Mark schrieb:
> Zu früh gefreut.
> Nach dem Bespielen (sprich Reset) des uC und starten des Programms läuft
> alles wie es soll.
> Nur nach dem erneuten Starten des Programms durch einen Taster steigt
> und fällt die anfängliche Totzeit mit n!?
>
> Was muss ich denn wo nullsetzen?
> Mir würde es ja einleuchten, wenn die vorherigen Werte noch gespeichert
> wären, aber wieso die ersten n Werte nach dem fortsetzen des Programms
> mit Null initialisiert werden das verstehe ich nicht.

Sind sie auch. n und avgsum werden nur beim laden des Programms auf 0 
gesetzt. Das ist die schonmal oben angesprochene Falle von static 
Variabblen.
#4160608
Lesenswert?

Mark schrieb:
> Wie kann man denn eine static zurücksetzen wenn man möchte?

Gar nicht.
Genau das ist der Sinn der Sache mit 'static', dass du ausserhalb der 
Funktion an diese Variable nicht ran kommst.

Also entweder verpasst du der Funktion ein Argument, mit dem du ihr 
mitteilst: "jetzt gehts von vorne los" oder du machst dir dieses 'n' 
(nenn die Variable aber dann anders) global um in der 
Programmstartsequenz es auf 0 setzen zu können.

> Lag wohl doch daran, dass n int war.

In dem Fall hätte es nur eine einzige Lösung gegeben:
Wenn dein Compiler so verkorkst ist, dass er so etwas einfaches wie eine 
Datentypanpassung (die genau geregelt ist) nicht hinkriegt, dann will 
ich gar nicht wissen, was dieser Compiler noch alles nicht hinkriegt. 
Dann gibt es nur eine Lösung: Diesen Haufen Schrott entsorgen und einen 
wenigstens halbwegs vernünftigen Compiler nehmen.
#4160616
Lesenswert?

Mark schrieb:

> Funktioniert die Funktion PI_ohneL so wie sie soll?

Was wird das jetzt eigentlich schon wieder mal?
Schon wieder eine Nachhilfestunde in elementaren C Kentnissen? Denkst du 
nicht, dass du derartige Dinge schon längst beherrschen solltest, ehe du 
dich an dein erstes reales Projekt wagst?

Ich kann immer nur immer wieder den Kopf schütteln. Was waren wir doch 
für Trottel damals, als wir unsere Programmiersprache von der Pieke auf 
gelernt haben. Offenbar braucht mann das ja gar nicht. Seltsam ist immer 
nur, dass es genau wir sind, die dann immer aushelfen müssen. Hmm. Ob da 
wohl ein Zusammenhang besteht?
Gast #4160648
Lesenswert?

Karl Heinz schrieb:
> Du solltest dir endlich mal angewöhnen zu akzeptieren, dass nicht deine
> Compiler Implementierungen definieren, wie C zu funktionieren hat,
> sondern einzig und allein der Standard.

Ach Karlheinz, mir scheint, daß dir mal wieder nach etwas Zoff oder 
zumindest nach etwas Reibung zumute ist. Halte ich für völlig 
überflüssig, aber was soll man machen, wenn ein Mod sich daneben 
benimmt...

Also, das Einzige, was ICH akzeptiere, ist die blutige Praxis. 
Theoretisierendes Geschwafel und Scholastik mag ich nicht. Eher schon 
echte und vorzugsweise mathematische Logik. Deshalb sind die real in 
dieser Welt existierenden Compiler-Implementierungen wichtiger als das 
Wälzen irgend eines Standards - der zumindest für mich in einigen Teilen 
höchst zweifelhaft ist. Und letztendlich sieht es eben genau so aus, 
wie ich das geschrieben habe.

So. Wo const draufsteht, ist auch const drin - und du darfst dich nun 
freuen (oder eher nicht), wenn dir dein Compiler beim Beschreiben einer 
const Entity nicht auf die Finger haut. Du darfst also dir das Nötige 
dafür angewöhnen.

Uff!

Aber mal zum grundsätzlichen Prinzip beim gleitenden Mittelwert als dem 
zweitsimpelsten aller Filter:
1. es ist das am schnellsten berechenbare Filter
2. es ist das einzige, was wirklich formgetreu arbeitet, also keinerlei 
Ripple und keinen Phasengang besitzt
3. es hat wie alle Filter eine konstante Signalverzögerung von 
Taps/FSample. Da kommt man grundsätzlich nicht drum herum.
4. es ist der Sauberkeit zuliebe sicherlich eine gute Idee, den 
Samplepuffer vor Erstverwendung zu nullen, aber wirklich notwendig ist 
es nicht

Ähem.. das simpelste wäre ein IIR Filter:
Meßwert = (AlterMeßwert + AktuellerMeßwert)/2;


W.S.
#4160662
Lesenswert?

W.S. schrieb:

> So. Wo const draufsteht, ist auch const drin - und du darfst dich nun
> freuen (oder eher nicht), wenn dir dein Compiler beim Beschreiben einer
> const Entity nicht auf die Finger haut.

Ich stelle fest: Du hast kein Wort verstanden.
Wieder mal Halbwissen. Allerdings diesmal gepaart mit 
Selbstüberschätzung.

Du treibst gerade eine tote Sau durchs Dorf. Denn das ...
> wenn dir dein Compiler beim Beschreiben einer const Entity nicht
> auf die Finger haut.
... ist nicht der Unterschied den C zwischen einer 'non modifable 
variable' und einer 'compile-time constant' macht. Auch Flash, ROM, 
EEPROM, PROM, etc. haben damit aus Sicht der Sprache genau gar nichts zu 
tun. Wenn dein Compiler const markierte Variablen ins Flash legt - schön 
für ihn. Genau darum gehts aber nicht.
Es geht darum, dass der Begriff 'Konstante' eine definierte Bedeutung 
hat. Und eine als const markierte Variable, qualifiziert sich nicht für 
diese Bedeutung. Das wiederrum hat Konsequenzen, weil an einigen Stellen 
in der C-Syntax explizit eine Konstante gefordert wird.
#4160664
Lesenswert?

Nur mal eine kurze Anmerkung, weil ich stutzig geworden bin: Wenn man so 
ein Filter nicht mittels Programm sondern mit Bauelementen realisiert, 
dann muß doch nach dem ersten Einschalten auch erst mal einen Moment 
gewartet werden, bis "hinten raus" brauchbare Sachen kommen.
Warum wollt ihr in dem Programm offenbar mit Gewalt diesen Moment, bis 
15 oder 16 "Stützstellen" eingelaufen sind, nicht abwarten?

(Bitte die Frage in Klartext beantworten, ich kann kein "C" und will 
(und muß) es auch nicht mehr lernen.)

MfG Paul
#4160745
Lesenswert?

Paul Baumann schrieb:

> gewartet werden, bis "hinten raus" brauchbare Sachen kommen.

'brauchbar' ist aber nicht 'es kommt zuerst mal nur 0 raus'.

> Warum wollt ihr in dem Programm offenbar mit Gewalt diesen Moment, bis
> 15 oder 16 "Stützstellen" eingelaufen sind, nicht abwarten?

jedes Filter muss sich erst mal einschwingen.
Seines tut das offenbar nicht. Und das sollte eigentlich nicht so sein. 
D.h. da gibt es irgendetwas im Programm, was entweder
* fehlerhaft
* oder nicht komplett verstanden
ist. Und das ist kein gutes Zeichen. Dem muss man nachgehen.

> (Bitte die Frage in Klartext beantworten, ich kann kein "C" und will
> (und muß) es auch nicht mehr lernen.)

Das wär in BASCOM auch nicht anders.
Wenn du eine Berechnung hast, von der du weisst, dass sie nicht 0 
ergeben kann und es kommt trotzdem 0 raus, dann ist irgendwo etwas faul.
Das können natürlich auch Eingangsdaten sein, die nicht die Werte haben, 
die man annimmt das sie haben. Im Laufe der Jahre hab ich gelernt, genau 
da als erstes Nachzuhaken: Sind die Werte, die ich in ein System 
reingebe auch wirklich die, die ich die ganze Zeit einfach annehme ohne 
sie gesehen zu haben? Öfter als mir lieb ist, stellt sich nämlich raus: 
Ooops, sie sind es nicht.
Würde hier bedeuten: Der Filter ist vollkommen in Ordnung, aber die 
ersten Datenwerte sind tatsächlich 0.
Gast #4160766
Lesenswert?

W.S. schrieb:
> Das kommt nämlich ganz auf die Umstände drauf an. Bei Zeugs, was auf
> deinem PC komplett im RAM läuft, hast du ja Recht, aber initialisierte
> Konstanten landen bei den µC, die ich vor der Nase habe, gnadenlos im
> Flash und bleiben dort auch. Da ist Neese mit Zuweisungen aller Art.
> Allenfalls kriegt man ne Data-Exception auf die Rübe.

$OS kann Const in Readonly Pages tun.
Gast #4160788
Lesenswert?

Also an alle sich Beteiligenden schon ein Mal ein recht herzliches 
Dankeschön.
Mir ist bewusst, dass man einfache Sachen von der Programmierumgebung 
simulieren kann (AVR Studio 6). Aber eben nur einfache Sachen, das 
setzen von Bits für INTs oder ADCs geht auch, macht mir aber schon 
wieder keinen Spaß mehr.
Und Formeln habe ich natürlich vorher auch in Exel eingegeben und was 
als Ergebnis rauskommt überprüft.
Eine RS232 Schnittstelle und Ausgabe auf HTerm etc. habe ich in meinem 
Leben auch schon gemacht und halte ich für ziemlich wichtig, aber wenn 
es die Platine nicht zulässt, ist es doof..

C Programmierung habe ich schon das ein oder andere Mal gemacht, aber 
anscheinend zuvor nie mit static Variablen. Zugegeben habe ich den 
Filter aus dem Netz, von dem sich hier auch bereits gemeldeten Person ;)
Trotzdem geht ja anscheinend auch alles mit globalen Variablen, die 
behalten ja ihren Wert auch.. also mein Programm läuft, static war da 
einfach der für mich unnötige Zusatz..
Gebe ich jedem Recht, dass man sich selber mit dem Thema und den 
Grundlagen auseinander setzen muss. Und diese simplen Fragen zu 
Grundlagen tuen mir Leid.
Ich bin beim Durchspielen im Kopf allerdings immer noch nicht ganz 
darauf gekommen, wieso man avgsum und n auf null setzen muss.. Aber es 
geht jetzt so, indem ich sie in der Tasterfunktion nulle.

Aber dazu eine Frage: wieso sollte ich nicht "n" als Variable benutzen?
Das tu ich nämlich. Man benutzt doch auch "i" zB..

Und eine weitere Frage: ist es jetzt ein IIR oder doch ein gleitender 
Mittelwert Filter?
#4160796
Lesenswert?

Mark schrieb:

> Aber dazu eine Frage: wieso sollte ich nicht "n" als Variable benutzen?
> Das tu ich nämlich. Man benutzt doch auch "i" zB..

Das kommt drauf an.
In einer Funktion mit optisch überschaubarem Geltungsbereich sind 
einbuchstabige Variablennamen, besonders wenn es sich um Zähler handelt, 
absolut kein Problem.

Wenn aber eine Variable global wird, dann läuft man schnell Gefahr, dass 
in einem anderen Modul es auch eine Variable namens n gibt. Und dann 
kollidiert das ganze. Je größer der Sichtbarkeitsbereich einer Variablen 
ist, desto aussagekräftiger sollte ihr Name sein. Das heisst jetzt 
nicht, dass da Wortmonster entstehen müssen. Aber mit einem 
"nrFilterSamples" kann man auch in einem halben Jahr noch eruieren, was 
der Zweck der Variablen war, und das das mit einem 'n' in der LCD 
Ansteuerung nichts zu tun hat.

EInbuchstabige Variablen benutzt man gerne an Stellen, an denen man eine 
Variable braucht, weil man etwas braucht was sich verändern kann aber 
der genaue Name nicht so wichtig ist. Typischerweise sind das zb die 
Laufvariablen in for-Schleifen; zb bei der Abarbeitung eines Arrays
1
   for( i = 0; i < irgendwas; i++ )
2
     data[i] = ....
hier kommt es nicht wirklich auf den Namen an. Der 'Einsatzbereich' 
dieser Variablen ist überschaubar eng. Ein längerer Name würde keinen 
Lesevorteil bieten. Die Variable i hat keine spezielle spezifische 
Bedeutung.
#4160798
Lesenswert?

Mark schrieb:

> Eine RS232 Schnittstelle und Ausgabe auf HTerm etc. habe ich in meinem
> Leben auch schon gemacht und halte ich für ziemlich wichtig, aber wenn
> es die Platine nicht zulässt, ist es doof..

Auch nicht, indem du die beiden Pins für die UART kurzerhand und mit 
einem Messer von ihrer jetzigen Aussenbeschaltun befreist und einen 
UARTzugang mit ein paar Drahtstücken und einem auf einem STück 
Lochraster gelötetem MAX232 herstellst?

Ich würde das ins Auge fassen, ehe ich da jetzt Stunden in Rätselraten 
investiere.
Da oben hast du sowieso noch sowas wie einen  PID Regler, wenn ich das 
richtig sehe. Auch bei dem wird sich so eine Ausgabemöglichkeit noch als 
nützlich erweisen um mal zu sehen, wie sich eigentlich die PID Werte 
zeitlich  entwickeln.
Gast #4160805
Lesenswert?

Ok, danke für die ausführliche Antwort.

Evtl. werde ich das morgen in Angriff nehmen.
Aber da es ein wirklich winziger SMD uC ist, wird kein Kabel lange daran 
halten..
Na mal sehen.

Und den Filter würde ich einfach VZ1 Filter nennen?
Mit gleitender Mittelwertbildung?
#4160808
Lesenswert?

Mark schrieb:
> Ok, danke für die ausführliche Antwort.
>
> Evtl. werde ich das morgen in Angriff nehmen.
> Aber da es ein wirklich winziger SMD uC ist, wird kein Kabel lange daran
> halten..

Es muss nur lang genug halten :-)

> Und den Filter würde ich einfach VZ1 Filter nennen?
> Mit gleitender Mittelwertbildung?

es ist ein IIR Filter. Aber häng dich da jetzt nicht am Namen auf.
Gast #4164140
Lesenswert?

Karl Heinz schrieb:
> Ich stelle fest: Du hast kein Wort verstanden.
> Wieder mal Halbwissen. Allerdings diesmal gepaart mit
> Selbstüberschätzung.

Du agierst nach dem Motto "Haltet den Dieb!.."
Tja, das Halbwissen und die Selbstüberschätzung gebe ich dir postwendend 
zurück. Werde entweder konkret oder laß das Diskutieren mit mir sein.

Manchmal sehe ich bei dir einen Hang zur böswilligen Unterstellung, 
insbesondere bei:
Karl Heinz schrieb:
> ... ist nicht der Unterschied den C zwischen einer 'non modifable
> variable' und einer 'compile-time constant' macht. Auch Flash, ROM..

Ganz konkret, du meinst wohl:
#define Karl  123
im Gegensatz zu
const int Heinz = 456;

Bei letzterem haben sehr wohl Flash, Rom und Konsorten was zu sagen, 
denn dort landet Heinz, vorausgesetzt, es handelt sich um ne Firmware, 
die dort gespeichert wird.

Jaja - beim alten Borland Pascal war das anders, da stand ganz fett in 
der Doku, daß initialisierte Variablen eben nur initialisiert sind und 
man dennoch schreibend drauf zugreifen kann. Also:
const
  Karl = 123;
  Heinz : integer = 456;

Aber das galt für einen Betrieb des Programmes im RAM ohne Schutz für 
das Code- und Konstanten-Segment. Vielleicht ist das bei deinem Free-BSD 
anders, daß man da lustig im Code oder den Konstanten herumschreiben 
kann, ohne vom OS dabei erwischt zu werden.

W.S.
Moderator #4164184
Lesenswert?

W.S. schrieb:
> Ganz konkret, du meinst wohl:
> #define Karl  123
> im Gegensatz zu
> const int Heinz = 456;

Karl Heinz hat das doch oben anhand eines Beispiel erläutert:
1
const int size = 5;
2

3
int data[size];

Das geht in C nicht (in C++ schon). C erwartet als Größenangabe eines
Arrays einen konstanten Ausdruck.

Eine Variable (in diesem Fall size), auch wenn sie als const deklariert
wurde, ist aber kein konstanter Ausdruck im Sinne von C.

Sie ist es auch nicht, wenn sie vom Compiler/Linker ins Flash gelegt
wurde.

Sie ist es auch nicht, wenn statt des Flash maskenprogrammiertes ROM
verwendet wird.

Sie ist es auch nicht, wenn sie in Granit gemeißelt wurde.

Nicht einmal Diamant wäre hart genug, um aus der Variable einen
konstanten Ausdruck gemäß C-Standard zu machen.

Du kannst es drehen und wenden wie du willst: Obiges Code-Schnipsel ist
einfach kein korrektes C und wird von jedem C-Compiler zurecht angemahnt
werden.

Deswegen sollte man den Unterschied zwischen einer const-deklarierten
Variablen und einem konstanten Ausdruck kennen, egal, auf welcher
Architektur man programmiert.

Man kann jetzt beliebig lange darüber diskutieren, warum das Ganze
unlogisch ist. Ja, es ist unlogisch und wurde deswegen in C++ geändert.
Und es steht jedem, den das stört, frei, von C auf C++ umzusteigen. Der
Umstellungsaufwand ist nicht sehr groß.
Gast #4166355
Lesenswert?

Yalu X. schrieb:
> Das geht in C nicht (in C++ schon). C erwartet als Größenangabe eines
> Arrays einen konstanten Ausdruck.

Ach Yalu, erstmal Dank an dich für Sachlichkeit.

MIR ist das alles durchaus klar. ICH weiß durchaus zu unterscheiden 
zwischen Ausdrücken (inc. konstanten Ausdrücken) einerseits und 
Variablen, die gelegentlich als const Variablen deklariert sind und 
deshalb eben ne Konstante sind bzw. gefälligst sein sollen, wodurch das 
Wort "Variable" eigentlich sachlich falsch ist und besser "Konstante" 
genannt werden sollte.

Karl Heinz schrieb:
> Vorsicht:
> In C ist eine als 'const' markierte Variable nach wie vor eine Variable.
> Allerdings eine von der du die Zusicherung machst, dass du sie in deinem
> Programm nicht verändern wirst. Das 'const' bedeutet in C 'not
> modifiable'.
> Es ist KEINE Konstante!

Da habe wir's: Karl Heinz verwechselt "Konstante" mit "konstanter 
Ausdruck".

Genau DAS DAS DAS ist der elende Aufhänger:

Eine const Variable IST eine Konstante und ihr wurde in ihrer 
Deklaration der Wert eines "konstanten Ausdruckes" zugewiesen. Das hat 
nix mit gemachten Zusicherungen zu tun.

Uff. Ich hoffe, wir haben's jetzt endlich.

Es gibt bei vielen heutigen C-Compilern in dieser Hinsicht ein ganz 
anderes Problem, nämlich, daß man const Variablen ohne typecast (sofern 
technisch möglich) nicht als Argumente für Funktionen verwenden kann, 
ohne vom Compiler angemosert zu werden, "warning: argument xyz looses 
'const' property" oder so ähnlich. Das hat ja bei Harvard-Architekturen 
durchaus seinen Sinn, weil dort ja ein Pointer, der in den Datenbereich 
zeigt, etwas ganz anderes ist als einer, der in den Programm- und 
Konstantenbereich zeigt. AVR's oder PIC's sind da typische Vertreter. 
Aber bei nem ARM nervt sowas.

W.S.
Moderator #4166700
Lesenswert?

W.S. schrieb:
> Es gibt bei vielen heutigen C-Compilern in dieser Hinsicht ein ganz
> anderes Problem, nämlich, daß man const Variablen ohne typecast (sofern
> technisch möglich) nicht als Argumente für Funktionen verwenden kann,
> ohne vom Compiler angemosert zu werden, "warning: argument xyz looses
> 'const' property" oder so ähnlich.

Das liegt üblicherweise nicht am Compiler, sondern am Programmierer.

In folgendem Beispiel ist my_array als const deklariert, der Formalpara-
meter array von func aber nicht:
1
void func(int array[]);
2

3
int main(void) {
4
  const int my_array[3] = { 0, 1, 2 };
5

6
  func(my_array);
7

8
  return 0;
9
}

Beim Aufruf von func mit my_array könnte nun func die Elemente von
my_array überschreiben, was aber wegen der const-Deklaration von
my_array nicht sein darf. Das meckert der Compiler zurecht an.

Das Problem lässt sich dadurch beheben, dass der Formalparameter von
func ebenfalls als const deklariert wird:
1
void func(const int array[]);

Damit verschwindet die Fehlermeldung, es sei denn, func versucht
trotzdem, die Array-Elemente zu ändern. In diesem Fall wird eine
Fehlermeldung beim Kompilieren von func ausgegeben.

Man ist in C aber nicht gezwungen, const-Deklarationen zu verwenden. Nur
wenn man es tut, muss man es konsequent überall im gesamten Code tun.

> Das hat ja bei Harvard-Architekturen durchaus seinen Sinn

Auch hier: Das hat nicht primär etwas mit der Hardwarearchitektur zu
tun. Indem ich eine Variable als const deklariere, teile ich dem
Compiler mit, dass er davon ausgehen kann, dass sie bei jedem Zugriff
denselben Inhalt hat. Der Compiler kann dadurch ggf. Variablenzugriffe
wegoptimieren.

Mit der const-Deklaration bitte ich den Compiler aber auch nachzusehen,
ob in meinem Code die Variable nicht versehentlich doch irgendwo
beschrieben wird. Das wäre dann ein Programmierfehler, und es freut
mich, wenn er bereits zur Compile-Zeit aufgedeckt wird.

Ein const in der Variablendeklaration bedeutet übrigens nicht unbedingt,
dass der Variableninhalt bereits zur Compile-Zeit bekannt ist und die
Variable deswegen im nichtflüchtigen Speicher angelegt werden kann. Es
bedeutet lediglich, dass die Variable, nach dem sie einmal initialisiert
worden ist, für den Rest ihrer Lebensdauer nicht mehr geändert wird. Der
Initialisierungswert muss auch nicht unbedingt ein konstanter Ausdruck
sein.

Beispiel:
1
void func(int n) {
2
  const int n2 = n * n;
3
    .
4
    .
5
}

Hier kann n2 bei jedem Aufruf von func einen anderen Wert annehmen
(abhängig vom Argument n). Bis zum Ende von func kann n2 aber kein neuer
Wert zugewiesen werden.
Gast #4167544
Lesenswert?

Yalu X. schrieb:
> Das Problem lässt sich dadurch beheben, dass der Formalparameter von
> func ebenfalls als const deklariert wird:
> void func(const int array[]);

Na klasse.

So, und nun schreib mal, wie du dir einen Treiber vorstellst, der 
beides ohne Warnung verträgt, z.B. sowas:

bool String_Out(char* P, int UART) {....}

also einen Peripherietreiber, der sowohl den Inhalt von Pufferarrays als 
auch konstante Strings ausgeben kann.

Nee, ich meine hier NICHT NUR sowas:
String_Out("YALU", COM1); //(das geht immer)
sondern eben auch
const char yalu[] = { 'Y','A','L','U',0 };
char buf[120];
...
String_Out(buf, COM2);
und
String_Out(yalu, COM3);

Egal wie du es drehst und wendest, entweder plazierst du bei wenigstens 
einem Aufruf nen Cast oder du mußt mit der Warnung leben. Das war der 
Punkt den ich angesprochen hatte.

W.S.
Moderator #4167581
Lesenswert?

W.S. schrieb:
> Egal wie du es drehst und wendest, entweder plazierst du bei wenigstens
> einem Aufruf nen Cast oder du mußt mit der Warnung leben. Das war der
> Punkt den ich angesprochen hatte.

Wieso hast du das const vor dem char *P nicht einfach mal ausprobiert?
Dann wäre dir vielleicht ein Licht aufgegangen.

Natürlich kannst du jederzeit eine Nicht-Const-Variable in einem
Const-Kontext verwenden, nur umgekehrt nicht.

Oder anders ausgedrückt:

Es ist zwar verboten, eine Const-Variable zu verändern, es ist aber
nicht verboten, eine Nicht-Const-Variable unverändert zu lassen.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren