Flankenerkennung / Flankenfilterung

Moin,

ich erfasse mit einem IR Sender / Empfänger Impulse von einer Kodierscheibe auf einer rotierenden Welle um die Drehzahl zu messen.
Dies tue ich, in dem ich eine Minute lang den Wechsel von LOW nach HIGH an einem Digitaleingang mitzähle.
Das Ganze ist eine Drehzahlmessung von einem Lüfter.
Bis dahin funktioniert es wunderbar.
....nur manchmal messe ich zu hohe Drehzahlen.
Ich habe mir dann mit einem Oszilloskop das Signal angeschaut und stelle fest, dass manchmal noch mehr Flanken auftreten, die da nicht hingehören. An der Stelle kann ich aber aktuell nichts mehr ändern.
Nun habe ich mir überlegt, ob man das nicht softwaremäßig abfangen kann.
Entweder über ein Fenster oder über eine Plausibilitätsprüfung.
Fensterprüfung:
Die Flanken dürfen nicht schneller als erwartet kommen. (Die Flanke muss in einem gewissen Fenster kommen).

Plausibilitätsprüfung:
Da die Kodierscheibe 50% schwarz und 50% weiss ist, müssen die Flanken immer im gleichen Tastverhältnis kommen. Tun sie das nicht, gibt's da irgendwie ein Problem. Man müsste also die Zeit der HIGH Flanke und die Zeit der LOW Flanke messen, und die müssen zu 95% identisch lang sein. Ich glaube diese Art der Prüfung müsste besser funktionieren, da sie keine harten Grenzen kennt wie eine Fensterprüfung.

Funktioniert so eine Idee?
Hat sowas schon einer von Euch gemacht?

Das Frequenzsignal kommt in etwa von 0-70Hz.

Aktuell sieht mein (hierfür zusammengeschrumpfter) Code so aus:

void loop() {
  Sensor[1] = digitalRead(sensorPin[1]);
  if (Sensor[1] == HIGH && OldSensor[1] == LOW) {
    rpm[1]++;
  }
  OldSensor[1] = Sensor[1];
  if (millis() - Startzeit >= Messzeit) {
    Serial.print("rpm1: ");
    Serial.println(rpm[1]);
  }
  rpm[1] = 0;
  Startzeit = millis();
}

Wie könnte ich jetzt so eine Plausibilitätsprüfung einbauen?

Lieben Gruß,
Chris

Warum schreibst du so einen Sermon anstatt es einfach zu probieren?

Um zu erkennen dass eine Zeit aus einem Raster herausfällt müsste man die Zeiten vielleicht erst mal ermitteln.

Ich habe mir dann mit einem Oszilloskop das Signal angeschaut und stelle fest, dass manchmal noch mehr Flanken auftreten, die da nicht hingehören.

Es wäre clever ein Foto davon zu zeigen.

Wenn du ein Programm postest, bitte nimm eines dass auch kompiliert.

Moin,

meine Frage ist zunächst von akademischer Natur.
Die Frequenzen (und damit die Zeiten) habe ich bereits genannt.
Foto vom Oszi habe ich nicht, sonst hätte ich es gepostet. Das Phänomen passiert aktuell nur 2-3x pro Tag und dauert nur wenige Minuten. Um davon ein Foto zu schießen müsste man ständig da sein und ne Kamera im Anschlag haben. Das dauert also ne Weile bis ich ein Foto liefern kann. Aber wozu braucht man das? Ich habe doch beschrieben wie es aussieht?!

Gut, ich werde also noch versuchen ein Foto zu liefern, wir aber noch etwas dauern.

Trotzdem können wir ja theoretisch weitermachen.

Funktioniert so eine Idee?
Hat sowas schon einer von Euch gemacht?
Wie könnte ich jetzt so eine Plausibilitätsprüfung einbauen?

Lieben Gruß,
Chris

themanfrommoon:
Aktuell sieht mein (hierfür zusammengeschrumpfter) Code so aus:

Der Prozessor in meinem Gehirn meint, dieser Code funktioniert nicht, ist daher wertlos für die Beurteilung.

Soll Sensor[1] ein Hinweis auf mehrere Sensoren sein? Wenn ja, wie viele?

themanfrommoon:
Ich habe mir dann mit einem Oszilloskop das Signal angeschaut ...

themanfrommoon:
Um davon ein Foto zu schießen müsste man ständig da sein und ne Kamera im Anschlag haben.

Ein gewisser Spock hätte gesagt: "Das ist nicht logisch!" Was Du auf dem Oszilloskop siehst, kannst Du auch fotografieren.

themanfrommoon:
Trotzdem können wir ja theoretisch weitermachen.

Funktioniert so eine Idee?
Hat sowas schon einer von Euch gemacht?

Nein, nein, weil ich es nicht für sinnvoll erachte. Bei einer Frequenz von 40 Hz kann es sich um eine doppelte 20 Hz oder ein gültiges Signal handeln.

themanfrommoon:
Foto vom Oszi habe ich nicht, ... Aber wozu braucht man das?

Ein Foto ist nicht notwendig, aber ein weiteres Kriterium, das man mittels Foto möglicherweise erkennen kann. Das Foto als Ideenlieferant sozusagen. Außerdem bin ich hinsichtlich Deiner Fehleranalyse skeptisch, da ich mir keine Kodierscheibe vorstellen kann, die plötzlich ein Signal doppelter Frequenz liefert. Daher kann ich mir auch nicht vorstellen, wie das Signal aussieht und habe auch keine Idee für eine Gegenmaßnahme.

Auch wenn Du es nicht lesen magst, so mußt Du m. E. genauer für ein weiteres Kriterium analysieren, egal ob mit oder ohne Foto.

themanfrommoon:
meine Frage ist zunächst von akademischer Natur.

Ok.

themanfrommoon:
Die Frequenzen (und damit die Zeiten) habe ich bereits genannt.

0-70 Hz entspricht Zeiten von unendlich bis 14286 µs.

Akademische Antwort: unendlich ist nicht zu verifizieren.

themanfrommoon:
Ich habe doch beschrieben wie es aussieht?!

Ja, mit

Ich habe mir dann mit einem Oszilloskop das Signal angeschaut und stelle fest, dass manchmal noch mehr Flanken auftreten, die da nicht hingehören.

Das reicht (mir) nicht um einen Eindruck der Störung zu bekommen.

themanfrommoon:
Funktioniert so eine Idee?
Hat sowas schon einer von Euch gemacht?
Wie könnte ich jetzt so eine Plausibilitätsprüfung einbauen?

Ja, je nach Störung könnte das mehr oder weniger gut funktionieren.

Ja, ich habe schon Pulslängen verarbeitet.

Mit dem Editior via Tastatureingabe.

Mal ein anderer Ansatz:
Da du eine optische Erfassung benutzt könnte es sich doch um Spiegelungen oder Einstreungen von außen wie z.b. Neonröhren/ Energiesparlampen, Bewegungsmeldern, Überwachungskameras,...... Kannst du sowas ausschließen?

Ich tippe auch auf Einstreuung, wahrscheinlich optisch, ggf. auch EMP. Dagegen helfen lichdichte Verpackung und abgeschirmte/verdrillte Kabel.

Okay, ich seh schon, ihr braucht deutlich mehr Input. Den sollt ihr gerne haben. Ich versuche es immer so schlank wie möglich zu gestalten, damit ihr weniger Aufwand habt den ganzen Overhead zu durchforsten, der nicht zum Problem dazugehört. Ich weiss aber auch, dass man manchmal den Wald vor lauter Bäumen nicht sieht. Also jetzt denn die Maximalvariante :slight_smile:

Also, es geht um drei Lüfterdrehzahlen in einer Wärmepumpe.

  1. Zuluft (Belüftung von draussen nach drinnen)
  2. Abluft (Entlüftung von drinnen nach draussen)
  3. Fortluft (Luft für den aktiven Wärmetauscher zum Heizen)

Hier sieht man den passiven Kreuzwärmetauscher, der die Frischluft mit der Wärme der Abluft erwärmt:


Links sieht man die beiden runden Öffnungen, in denen sich die kleineren Lüftermotoren für Zuluft und Abluft befinden. Hier noch ohne Drehzahlsensoren.
Optische Einstreuung von aussen kann ich ausschließen. Es ist im Betrieb noch ein Deckel montiert, und dann ist es drinnen zappenduster.

Hier sieht man den größeren Abluftmotor bereits mit Drehzahlsensor:


Man kann gut die angerissene Kodierscheibe sehen, die dann mit schwarzem und weissem Edding ausgemalt wurde.

So sieht der IR Lichtkegel aus, der auf die Kodierscheibe fällt:

Hier nun der eingebaute Drehzahlsensor an einem kleinen Lüftermotor:

Und hier vom gleichen Sensor der IR Lichtkegel:

Hier die Hardware ich ich mir zusammengebaut habe:


Bestehend aus einem nodeMCU, einem Pedelwandler, drei IR Sensoren mit Komparator, drei LEDs, auf der Unterseite sind noch 4 Widerstände. Neben den LEDs sind noch ein paar Stiftleisten, damit ich schnell mal das Oszi draufstecken kann. Jeweils der High und Low Pegel vor und hinter dem Pegelwandler, und einmal Ground. Die Klemmbuchsen habe ich aus einer Telefonbuchse ausgebaut, die hier noch rum flog....
Die Potis auf den IR SEnsorplatinen habe ich mit dem Oszilloskop eingestellt: Nach links gedreht, bis der Output gerade sicher komplett High war, nach rechts gedreht, bis der Output komplett low war, und dann davon die Mitte. Leider ist diese Spanne sehr klein gewesen, was ein Teil des Problem sein könnte... Wie soll ich es beschreiben?! Ich kriege mit dem Einstellen der Potis das Problem verschoben, aber leider nicht sicher weg. Es tritt auch nur bei dem einen Drehzahlsignal auf, nicht bei den anderen.

Hier ein einwandfreies Signal:

Und hier nun endlich das gestörte Signal:

Meine Idee war nun folgende:
Bei dem einwandfreiem Signal gibt es einen High Pegel und einen Low Pegel von sagen wir mindestens 95% gleicher Länge.
Ist das erfüllt, so zählen wir einen Impuls hinzu.
Bei dem gestörten Signal gibt es einen High Pegel und einen Low Pegel, wieder von mindestens 95% gleicher Länge, aber zusätzlich noch einen kurzen High Impuls zwischendrin. Der muss nun irgendwie herausgefiltert werden.

Merkwürdig ist nun wann/wie dieses Phänomen auftritt.
Mein Sketch zählt alle drei Lüfter gleichzeitig eine Minute lang. Dabei summiert es die Impulse auf, teilt diese durch 2 und sendet sie dann an die Datenbank.

Das hier kommt dann dabei raus:
Die gelbe Linie die für etwa 10min so stark nach oben rausschießt ist dieser Fehler.

Hier ein Log über 1 Stunde:


Hier ein Log über 6 Stunden:

Hier ein Log über 24 Stunden:

Hat jemand eine Idee wie es zu so einer komischen Störung kommen kann?

Liebe Grüße,
Chris

//#define AUSGABE           // Serielle Ausgabe aktiv (kann man auskommentieren wenn die serielle Ausgabe der Daten nicht gewünscht ist)
//#define AUSGABEschleifen  // Serielle Ausgabe Anzahl Schleifen aktiv (kann man auskommentieren wenn die serielle Ausgabe der durchlaufenden Schleifen nicht gewünscht ist)
#define LEDsenden         // Die blaue ESP12 LED blinkt beim senden (kann man auskommentieren wenn die LED Anzeige nicht gewünscht ist)
#define DATENsenden         // Die Daten werden an den Server gesendet (kann man auskommentieren zum offline testen)
#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <ESP8266HTTPClient.h>
ESP8266WiFiMulti WiFiMulti;
#ifdef LEDsenden
byte LEDsend = 2;      // Arduino Pin vom der ESP12 onboard LED
#endif
const long BaudRate = 74880;              // Serielle Verbindungsgeschwindigkeit für die serielle Ausgabe
const int Messzeit = 60000;               // 60000 Millisekunden = 60 Sekunden = Umdrehungen pro Minute
unsigned long Startzeit;                  // Merker für die Zeit in Millisekunden seit letzten Aufruf der Funktion. Millis zählt immer weiter hoch seit dem Einschalten des Controllers
const int sensorPin[3] = {14, 12, 13};    // the number of the sensorPin[0...2]  (original: 14,12,13 bzw. D5, D6, D7)
const int LED[3] = {5, 4, 15};         // the number of the LED[0...2]  (original: 5,4,15 bzw. D1, D2, D8)
unsigned long Schleifen;                  // wie viele Schleifen wurden in der Messzeit durchlaufen? (Müssen mehr sein als die gemessene Frequenz)
int i;                                    // Zählvariable
int Sensor[3] = {1, 1, 1};                // Array Variable für den ausgelesenen Wert, muss am Anfang 1 sein
int OldSensor[3] = {1, 1, 1};             // Array Variable für den vorigen ausgelesenen Wert, muss am Anfang 1 sein
int rpm[3] = {0, 0, 0};                   // Array Variable für den ausgelesenen Wert, muss am Anfang 0 sein
const char WiFiSSID[] = "xxxxxxxxxx";          // Router SSID
const char WiFiPSK[]  = "xxxxxxxxxxxxxxxxx";    // Router Password
const String host = "xxxxxxxxxxxxxx";          // Server IP Adresse
const unsigned int port = xx;
const String url_start = "/middleware.php/data/";         // Unterordner für die Werteablage
const String url_stop = ".json?operation=add&value=";     // Dateierweiterung für die Werteablage und Parameter
byte maxwait = 120;
char *UUID[3] = {                          // Die UUID's der abzulegenden Kanäle werden in ein char array hinterlegt
  "xxxxxxxxxxxxxxxxxxxxxxxxxxxexxxxxxxx",    // UUID des 0. Kanals "Drehzahl Zuluft"
  "xxxxxxxxxxxxxxxxxxxxxxxxxxxexxxxxxxx",    // UUID des 1. Kanals "Drehzahl Abluft"
  "xxxxxxxxxxxxxxxxxxxxxxxxxxxexxxxxxxx"     // UUID des 2. Kanals "Drehzahl Fortluft"
};
//********************************************************************************************************************************
bool waitWifi() {
  while ((WiFiMulti.run() != WL_CONNECTED) && maxwait > 0) {
#ifdef AUSGABE
    Serial.println("Wait Wifi");
#endif
    delay(1000);
    maxwait--;
  }
  if (WiFiMulti.run() == WL_CONNECTED) return true;
  return false;
}
//********************************************************************************************************************************
void sendHttpData(String url) {
  HTTPClient http;
  if (waitWifi()) {
#ifdef AUSGABE
    Serial.print("GET: "); Serial.println(url);
#endif
    http.begin(host, port, url); //HTTP
    int httpCode = http.GET();
#ifdef AUSGABE
    if (httpCode) {
      if (httpCode == 200) {
        String payload = http.getString();
        Serial.println(payload);
      } else {
        Serial.print("HTTP "); Serial.println(httpCode);
      }
    } else {
      Serial.print("[HTTP] GET... failed, no connection or no HTTP server\n");
    }
#endif
  } else {
#ifdef AUSGABE
    Serial.print("No WiFi available\n");
#endif
  }
}
//********************************************************************************************************************************
void WertSenden(int i) {
  String url_temp = "";
  url_temp = url_start;
  url_temp += UUID[i];
  url_temp += url_stop;
  url_temp += rpm[i];
#ifdef AUSGABE
  Serial.println(url_temp);
#endif
#ifdef DATENsenden
  sendHttpData(url_temp);                       // ------------------Daten senden-----------------
#endif
}
//********************************************************************************************************************************
void setup() {
#ifdef AUSGABEschleifen           // wird nur kompiliert, wenn serielle Ausgabe aktiv ist
  Serial.begin(BaudRate);         // Starten der seriellen Ausgabe die mit einem seriellen Monitor angesehen werden kann
#endif
#ifdef AUSGABE                    // wird nur kompiliert, wenn serielle Ausgabe aktiv ist
  Serial.begin(BaudRate);         // Starten der seriellen Ausgabe die mit einem seriellen Monitor angesehen werden kann
  Serial.println("BOOT");
  Serial.print("Wifi...");
#endif
  WiFiMulti.addAP(WiFiSSID, WiFiPSK);
#ifdef AUSGABE
  Serial.println("OK");
#endif
  pinMode(sensorPin[0], INPUT);   // Initialisiert Pin sensorPin[0] als einen Input
  pinMode(sensorPin[1], INPUT);   // Initialisiert Pin sensorPin[1] als einen Input
  pinMode(sensorPin[2], INPUT);   // Initialisiert Pin sensorPin[2] als einen Input
  pinMode(LED[0], OUTPUT);        // Initialisiert Pin LED[0] als einen Output
  pinMode(LED[1], OUTPUT);        // Initialisiert Pin LED[1] als einen Output
  pinMode(LED[2], OUTPUT);        // Initialisiert Pin LED[2] als einen Output
  for (int i = 0; i < 3; i++) {   // Schleife 0-2
    digitalWrite(LED[i], LOW);    // LED[i] ausschalten
  }
#ifdef LEDsenden
  pinMode(LEDsend, OUTPUT);       // Initialisiert Pin LEDsend als einen Output
  digitalWrite(LEDsend, HIGH);    // LEDsend ausschalten
#endif
  Startzeit = millis();           // Startzeit merken
}
//********************************************************************************************************************************
void loop() {
  for (int i = 0; i < 3; i++) {      // Schleife 0-2
    yield();                         // Dem Prozessor Zeit für seine internen Prozesse geben und somit einen automatischen RESET verhindern
    Sensor[i] = digitalRead(sensorPin[i]);
    if (Sensor[i] == HIGH && OldSensor[i] == LOW) {
      rpm[i]++;
    }
    OldSensor[i] = Sensor[i];
    if (rpm[i] % 10 == 0) {
      digitalWrite(LED[i], LOW);
    }
    if (rpm[i] % 10 == 5) {
      digitalWrite(LED[i], HIGH);
    }
  }
#ifdef AUSGABEschleifen                 // wird nur kompiliert, wenn serielle Ausgabe aktiv ist
  Schleifen++;
#endif
  if (millis() - Startzeit >= Messzeit) { // Wenn der Messinterval abgelaufen ist Werte ausgeben und senden
    rpm[0] = rpm[0] / 2;                 // Die Sensoren machen zwei Impulse pro Umdrehung, daher geteilt durch 2
    rpm[1] = rpm[1] / 2;                 // Die Sensoren machen zwei Impulse pro Umdrehung, daher geteilt durch 2
    rpm[2] = rpm[2] / 2;                 // Die Sensoren machen zwei Impulse pro Umdrehung, daher geteilt durch 2
#ifdef AUSGABE                        // wird nur kompiliert, wenn serielle Ausgabe aktiv ist
    Serial.print("rpm1: ");
    Serial.print(rpm[0]);
    Serial.print("   rpm2: ");
    Serial.print(rpm[1]);
    Serial.print("   rpm3: ");
    Serial.println(rpm[2]);
#endif
#ifdef AUSGABEschleifen               // wird nur kompiliert, wenn serielle Ausgabe aktiv ist
    Serial.print("Schleifen durchlaufen: ");
    Serial.println(Schleifen);
#endif
    for (int i = 0; i < 3; i++) {      // Schleife 0-2 um die Werte zu senden
      WertSenden(i);                   // Wert(i) senden
      digitalWrite(LED[i], LOW);       // LED[i] ausschalten
#ifdef LEDsenden
      digitalWrite(LEDsend, LOW);    // LEDsend einschalten für einen gesendeten Wert
      delay(30);                     // 30 Millisekunden warten
      digitalWrite(LEDsend, HIGH);   // LEDsend ausschalten
      delay(30);                     // 30 Millisekunden warten
#endif
    }
    rpm[0] = 0;
    rpm[1] = 0;
    rpm[2] = 0;
    Schleifen = 0;
    Startzeit = millis();
  }
}

Vielleicht hast du auch das Problem, dass Edding für Infrarot nicht besonders schwarz ist?

Cola z.B. sieht unter IR wie Mineralwasser aus.

Hi

Wie fest bist Du an diese Sensoren gebunden?
Bei dem einen Lüfter sieht man schon, daß in der Luft auch einiges an Dreck enthalten ist - denke, daß Da ein optischer Sensor eher Nachteile bringen wird.
Wenn Du zwei (eigentlich egal, Hauptsache gleichmäßig/unwuchtfrei montiert) Magnete und einen Hall-Sensor nimmst?
Dem wäre Dreck recht egal.

Wenn Du einzelne Ausreißer hättest, würde ich vermuten, daß Du Da gerade einen Dreckfussel siehst - über 10 Minuten hinweg ist aber natürlich schon ein ganzer Sack Fusseln nötig :wink:

MfG

Wenn die Störungen irgendwie reproduzierbar sind, dann kannst Du ja auf dem zweiten Kanal den kompletten Signalweg und die Stromversorgung durchtesten.

Hmm, also an Dreck glaube ich nicht als Ursache. Dafür tritt der Fehler ja viel zu systematisch auf. Ausserdem funktioniert es ja auch zu 95% der Zeit einwandfrei. Die Lüfter laufen seit 2013 pausenlos. An den Naben waren sie auch nach der Laufzeit quasi sauber. Ich glaube auch nicht das Edding z.B. drehzahlabhängig IR durchlässig wird.

dann kannst Du ja auf dem zweiten Kanal den kompletten Signalweg und die Stromversorgung durchtesten

Wie meinst du das genau?

Hi

Andere blöde Idee:
Vll. kommst Du in irgend eine Resonanz?
Hast Du eine Grenz-Drehzahl, unter/über der Fehler nicht/dauernd auftritt?

Versuchsweise Mal einen Keramik-Kondensator an den Sensor angesteckt?

MfG

Hat Dein Scope keinen zweiten Kanal?

Ja, nu bin ich dahinter gekommen. Der IR Empfänger (weiss nicht so genau ob das eine Fotodiode oder ein Fototransistor ist) liefert auf dem fehlerhaften Kanal nur ein sehr sehr schwaches Signal. Wundert mich, dass der Komparator damit überhaupt noch was anfangen kann. Da muss ich mir wohl doch noch mal die Sendediode und den Empfänger anschauen. Vielleicht wird der zu stark abgeschattet oder die IR Diode ist Matsch?!

Hier ein funktionierender Kanal:

Hier der nicht sauber funktionierende Kanal mit gleicher Empfindlichkeit:

Hier der nicht sauber funktionierende Kanal mit 5x höherer Empfindlichkeit:

Dann brauche ich wohl nichts an der Software ändern, sondern muss die Heizung nochmal auseinanderbauen :wink:

Ja, ich habe schon Pulslängen verarbeitet.

Trotzdem hätte ich gerne mal gesehen wie man Pulslängen verarbeitet.

Lieben Gruß,
Chris

themanfrommoon:
Trotzdem hätte ich gerne mal gesehen wie man Pulslängen verarbeitet.

Kein Problem.

Ein Klasse um Impulse zu verarbeiten die über einen Hardware Interrupt signalisiert werden.
Habe ich benutzt um 433MHz Signale mitzuschneiden und zu analysieren.

Ist zu fett um es direkt zu posten, die .h Datei ist durch doxygen schwer lesbar und groß,
also alles zusammen als Library Pack im Anhang.

WhandallEBuffer.zip (270 KB)

Warum hast du eigentlich die Lüfter Narbe "geviertelt" und nicht "halbiert" aufgezeichnet?
Dann hättest du die halbe Frequenz und könntest einfacher per Kondensator oder per Software glätten. Du willst ja nur die Drehzahl erfassen und nicht positionieren.

Gruß

Moin.

Wegen möglicher Unwucht.
Ich bin Maschinenbauingenieur :wink:

Lieben Gruß,
Chris

Unwucht durch Edding Farbe auf der Narbe??? :o
So genau sind die Lüfter garnicht gewuchtet außerdem fallen deine Schmutzanhaftungen an den Flügeln mehr ins Gewicht :wink:

Gruß