Liste der Anhänge anzeigen (Anzahl: 3)
Guten Morgen Searcher,
dein Oszilloskopbild habe ich mal vergrößert und ausgedruckt und mit dem Lineal gemessen.
Anhang 34204
Hier ist eindeutig zu erkennen, dass die Messwerte erheblich schwanken.
Da Du anscheinend wenig RAM zur Verfügung hast, wäre ein Softwarefilter (Tiefpass) angebracht.
Ich hab mal in mühsamer Kleinarbeit einen Tiefpass geschrieben, der ohne Floats auskommt
und auch keinen Puffer benötigt, da er in Echtzeit (Samplegenau) funktioniert.
Der Code ist absolut trivial, aber entspricht exakt einem RC-Tiefpass und lässt sich sehr einfach anpassen.
Zunächst mal einige Erläuterungen dazu:
Das Entscheidende ist die Abtastrate (Samplerate) also wieviele Messwerte kommen pro Sekunde
und die Centerfrequenz (Fc) des Filters.
Beispiel bei mir:
Mein ADU liefert 1000 Messwerte pro Sekunde, das ist also die Abtastrate
Die Centerfrequenz (Fc) ist die Frequenz an dem die Amplitude um 3 Dezibel fällt wenn man eine
Sinusschwingung durch den Filter schickt.
Um sich unnötige (komplizierte) Berechnungen zu ersparen, kann mein Controller eh nicht
habe ich "vorab" einen Faktor benannt mit "D" berechnet.
Dieser Wert wird nur einmal (extern, Taschenrechner) berechnet und abgelegt.
Da ich keine floats habe, wird der Wert vorher noch mit 65536 multipliziert
So kann ich auch Nachkommastellen berücksichtigen
Ich habe den Code inzwischen in Pascal und C implementiert, aber ich denke das sollte kein Problem sein
ihn nach (sieht aus wie Basic ?) zu konvertieren.
Die Funktion ist für 32 Bit Integer ausgelegt
In Basic musst Du vermutlich den Typ long nehmen für 32 Bit
Dreh und Angelpunkt ist die Vorabberechnung bzw. der Wert von "D"
D:=1-exp(-(2*pi*Fc) / Samplerate);
Hier kannst Du aber auch ganz experimentell Werte probieren und schauen wie es sich verhält.
Die "C" Variante
Code:
/*---------------------------------------------------------------------------*/
/* Siro's Spezialfunktion für einen Softwarefilter Tiefpass */
/* simuliert exakt ein ganz normales R/C Glied */
/* D:=1-exp(-(2*pi*Fc) / Samplerate); */
/* Fc ist die Centerfrequenz, der -3dB Punkt */
/* dann den Wert noch mit 65536 multiplizieren, wegen Integer Berechnungen < 0 */
/* Bezogen auf eine Abtastrate von 1000 Hz (1KHz) ergeben sich folgende Werte */
/* D = 21 ==> Fc = 0.05 Hz */
/* D = 41 ==> Fc = 0.1 Hz */
/* D = 206 ==> Fc = 0.5 Hz */
/* D = 410 ==> Fc = 1 Hz */
/* D = 818 ==> Fc = 2 Hz */
/* D = 2026 ==> Fc = 5 Hz */
/* D = 3991 ==> Fc = 10 Hz */
/* D = 7739 ==> Fc = 20 Hz */
/* D = 17668 ==> Fc = 50 Hz */
/* D = 30573 ==> Fc = 100 Hz */
/* D = 46884 ==> Fc = 200 Hz */
/* D = 62704 ==> Fc = 500 Hz */
S32 flowFilter(S32 value)
{ const S32 d = 206; // LowPassFilter Fc=0.5 Hz at 1000 Hz Samplerate
static S32 n = 0;
static S32 rest = 0;
S32 xx;
value = value - n;
xx = value * d;
rest = (xx+rest) % 65536; // % ist MOD Modulo (Divisionsrest) in "C"
xx = (xx+rest) / 65536;
n = n + xx;
return n;
}
/*---------------------------------------------------------------------------*/
Die "Pascal" Variante:
Code:
{------------------------------------------------------------------------------}
// !!!!! die mit const deklarierten Variablen
// müssen "statisch lokal" sein oder "global"
// sie müssen also erhalten bleiben nach dem Verlassen der Funktion
// in Pascal kann man das mit Const erzwingen.
Function FilterTP(value:Integer):Integer; // Tiefpass
const d : Integer = 206; // LowPassFilter Fc=0.5 Hz at 1000 Hz Samplerate
const n : Integer = 0;
const rest : Integer = 0;
var xx : Integer = 0;
begin
value:= value - n;
xx := value * d; // d ist ja schon mit 65536 multipliziert
rest := (xx + rest) MOD 65536; // wir muessen jetzt durch 65536 teilen
xx := (xx + rest) DIV 65536; // und den jeweiligen rest uns merken
n := n + xx;
result:=n;
end;
{------------------------------------------------------------------------------}
Der Aufruf erfolgt mit
Messwert:=FilterTP(Messwert); // durch den Filter jagen
Ausgabe(Messwert); // hier dann anzeigen
Du kannst einfach mit dem Wert für "D" herum experimentieren,
je kleiner der Wert wird, umso ruhiger wird auch deine Anzeige, aber auch träger.
PS.: Die Variablen innerhalb der Funktion solltest Du vermutlich "GLOBAL" definieren, ich hab nicht gefunden dass Basic statische lokale Variablen kann...
Einfach mal den D Wert irgendwie setzen und vor deiner Anzeige des Messwertes diesen durch den Filter schicken.
Siro
Hier mal ein Beispiel was er aus meinem verrauschten Signal macht: die grüne Kurve ist die gefilterte mit obigen Code.
Anhang 34205
Hier habe ich den D-Wert vergößert: es wird etwas unruhiger, aber dafür schnellere Reaktionszeit
Anhang 34206
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:
Zitat von
Searcher
Filter hab ich noch nicht gemacht.
Doch, sicher. Einen Buffer mit Messwerten füllen und daraus den Mittelwert bilden, ist ein Filter. Ich hatte in meinem vorigen Beitrag schon ein einfaches Tiefpassfilter angedeutet. Ich will das hier noch mal etwas ausführlicher beschreiben.
Damit das folgende besser verständlich ist, erläutere ich hier mal die von mir verwendeten Begriffe. Erstens der Messwert. Dieses ist das ungefilterte Ergebnis einer Messung: ein ADC-Wert (Spannung), der Temperaturwert aus einem digitalen Sensor, die Messwerte aus einem Accelerometer oder Gyrosensor oder, wie hier, die Zeit aus einem Input Capture. Und zweitens der Anzeigewert. Dies ist der Wert nach dem Filter und hat die selbe Einheit und Skalierung wie der Messwert. Der Messwert wird regelmäßig ermittelt, hier im Capture-Interrupthandler. Es könnte genausogut ein ADC im Timerinterrupt sein.
Die allgemeine Formel für einen Tiefpass ist: (neuer) Anzeigewert = k * (alter) Anzeigewert + (1 - k) * Messwert
k ist ein Koeffizient zwischen 0 und 1. Da einmal mit k und einmal mit 1-k multipliziert wird, bleibt die Skalierung von Messwert und Anzeigewert gleich. Der neue Anzeigewert ist also ein gewichtetes Mittel aus dem alten Anzeigewert und dem aktuellen Messwert.
Zur Abschätzung, was diese Formel bewirkt, kann man mal Extremwerte für k wählen: für k = 0 erhält man immer den aktuellen Messwert, das Filter hat keine Wirkung. Für k = 1 erhält man den Anzeigewert und der bleibt konstant. Zusammen mit der Frequenz, mit der die Messungen erfolgen, gibt k die Grenzfrequenz des Filters. Siro hat das dargestellt und ausgerechnet, ich kneife mir typisch die Rechnung und probiere einfach.
Wie kann man die Rechnung eines solchen Filters für einen µC leicht gestalten? Nun man verwendet Intergermathematik. Damit kann man k im Bereich 0 - 1 aber nicht darstellen. Wenn ich die Formel aber so schreibe : (k * Anzeigewert + (k - 1) * Messwert) / 1, kann man diesen Bruch so erweitern, daß sich sowohl das erweiterte k als auch (erweitert) 1 - k als Integer darstellen lassen. Wenn ich dann auch noch mit einer Potenz von 2 erweitere, wird aus dem Teilen ein Rightshift. Ein besonders einfacher Fall egibt sich für k = 0,5: (Anzeigewert + Messwert)/2. Ähnlich einfach ist auch k = 0,75: (3 * Anzeigewert + Messwert) / 4. Wobei man für µC, die keine HW-Multiplikation haben auch (Anzeigewert + Anzeigewert + Anzeigewert + Messwert) / 4 schreiben kann. Wie man hier auch erkennen kann, tragen bei k = 0,75 die alten Messwerte stärker zum Ergebnis bei als der neue Wert. Die Grenzfrequenz liegt also tiefer.
Da bei diesem Filter alle alten Messwerte (hier Anzeigewert genannt) zum neuen Wert beitragen, nennt man diese Filter IIR (Infinite Impulse Response). Infinite daher, weil jeder Messwert "für immer" mit im Anzeigewert steckt, jedoch entsprechend gering gewichtet. Wenn man im Gegensatz dazu auf einem Buffer rechnet, nennt man das ein FIR (Finite Impulse Response) Filter. Dabei kann der Buffer gleitend oder hintereinander gefüllt werden. Die Filtertypen haben unterschiedliche Eigenschaften. Ich zeig mal ein Bild, das ich aus dem Mikrocontroller.net Forum habe. Da hat Yalu X, der von digitaler Signalverarbeitung viel mehr Ahnung als ich hat, den Frequenzgang der beiden Filter mal geplottet.
Anhang 34208
In der roten Kurve erkennt man den klassischen Tiefpass, das IIR Filter. Den gleitenden Mittelwert (grüne Kurve) benutzt man gerne, um feste Störfrequenzen wie 50Hz auszublenden. Man dimensioniert es dann mit Bufferlänge und Samplingrate so, daß z.B. das erste Minimum auf diese 50Hz fällt und diese Störsignal nur sehr gering zum Ergebnis beiträgt. Da ein solcher Fall hier nicht vorliegt, sind die aufwändigere Rechnung und der größere Speicher für ein FIR nicht nötig.
Mit der Anzeige der Messwerte hat das nichts zu tun. Wenn die serielle Ausgabe kürzer ist, als die Zeit zwischen zwei Capture-Interrupts, wie du berechnet hast, kann die Ausgabe aus dem Capture-Interrupt selbst erfolgen. Das vermeidet jeglichen Konflikt. Da der Mensch nicht mehr als ca. 5 Werte pro Sekunde wirklich erfassen kann, muß man die Anzeige nicht bei jedem Interrupt updaten.
MfG Klebwax
P.S. irgendwie ist das Bild nicht angekommen, versuche es nochmal