3-Phasen-Strommessung mittels ESP32: Fragen zum ADC-Verhalten und Timing

Guten Morgen zusammen,
in einer Applikation möchte ich den Strom an drei Phasen messen. Nutzen möchte ich dazu einen ESP32, da dieser mehrere Analog-Input-Kanäle hat und direkt die Konnektivität herstellen kann. Es gibt dazu wunderbares Beispiel, wie etwa unter dem Link Open_Energy_Monitor_mit_dem_ESP32. Nach näherer Analyse dieser Lösung und der Sketches unter openenergymonitor habe ich habe mal wieder grundlegende Fragen, die ich gerne mit Euch diskutieren würde, da ich das gerne nachvollziehen möchte. Es geht um zwei Dinge: Zum einen den ADC des ESP32 und zweitens -wieder einmal eine Frage zu dessen Timing-.

  • ADC des ESP32
    Ich habe in Foren gesehen, dass der ADC Schwächen hat und zwar erstens, eine Nichtlinearität und zweitens dass nicht der gesamte Bereich ausgeschöpft wird. Das führt mich zur Einstiegs-Frage:
    Für Applikationen, die einen Analog-Input benötigen, nutzt man den ESP32 besser nicht?
    Meine nächsten Fragen adressieren die Angaben zum Eingangsbereich des ESP32. Oftmals steht einfach, dass die maximale Spannung 3,3 Volt beträgt. Jetzt steht aber unter https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html unter dem Stichwort “Attenuation”, dass die Eingangsspannung bis zu 4,9 Volt betragen kann (wenn 11dB attenuation (ADC_ATTEN_DB_11) gewählt werden.
    Hier ist Frage: Ist das richtig?
    Dieser Spannungsbereich wird irgendwie dann noch einmal verringert, da -ebenfalls unter obigem Link- folgendes steht:

0dB attenuaton (ADC_ATTEN_DB_0) between 100 and 950mV
2.5dB attenuation (ADC_ATTEN_DB_2_5) between 100 and 1250mV
6dB attenuation (ADC_ATTEN_DB_6) between 150 to 1750mV
11dB attenuation (ADC_ATTEN_DB_11) between 150 to 2450mV

Meine Aufgabe, bzw. Idee ist/war es, den ESP32 für die Strommessung an drei Phasen heranzuziehen. Nutzen will ich diesen Sensor. Dieser liefert jeweils eine Ausgangsspannung von 0-1 Volt. Ich denke, ich muss denn letztendlich um den Sensor und die Auflösung folgende Einstellungen vornehmen:

//…
adc1_config_width(ADC_WIDTH_BIT_12); // 12 Bit für maximale Auflösung
adc1_config_channel_atten(ADC1_CHANNEL_0,ADC_ATTEN_DB_0); // Messbereich 100 and 950mV → Sensor hat 0-1 V
//…

Ist das für meinen Sensor korrekt oder übersehe ich da etwas? Ich muss natürlich “hoffen” bzw. überprüfen, ob meine Sensorwerte nicht über 950mV hinausgehen, bzw. nicht unter 100 mV fallen…?

  • Timing der Stromerfassung
    Hier geht mir es um den korrekten und saubersten Ansatz zur Erfassung der Messwerte. Wenn ich die ganzen Beispiele korrekt nachvollzogen habe, werden bei der Erfassung von Wechselgrößen die Anzahl der Nulldurchgänge (der Sinusschwingungen) gezählt und dann die Effektivwerte berechnet. Jetzt stellt sich mir die Frage, wie ich eine korrekte Zeitbasis erhalte, bzw. ob das für meine Anforderung überhaupt nötig ist. Dazu habe ich einmal mögliche Ansätze zusammengefasst:
    Ansatz 1: "Einfaches Sampling"
    Im Beispiel unter Open_Energy_Monitor_mit_dem_ESP32 wurde die Datenerfassung gelöst, indem in der loop jeweils für jede der Phasen einfach analogRead benutzt wurde:

//Phase1
for (int n=0; n<numberOfSamples; n++)
{
//Used for offset removal
lastSampleI=sampleI;

//Read in voltage and current samples.
sampleI = analogRead(inPinI1);

//Used for offset removal
lastFilteredI = filteredI;

//Digital high pass filters to remove 1.6V DC offset.
filteredI = 0.9989 * (lastFilteredI+sampleI-lastSampleI);

//Root-mean-square method current
//1) square current values
sqI = filteredI * filteredI;
//2) sum
sumI += sqI;
delay(0.00002);
}
//**************************************************************************
//Phase2+3 siehe oben

Hier stellen sich mir mehrere Fragen: Was hat es hier mit dem delay(0.0002) auf sich? Sind das nicht immer ganzzahlig Millisekunden-Werte? Passt das allgemein so? Ich denke das geht, wenn die Anforderungen an die Genauigkeit nicht ganz so anspruchsvoll sind, denn die Stromwerte von Phase 1, 2 und 3 sind ja zeitlich um die delay versetzt…?
Ansatz 2: "Einfaches Sampling mit maximaler Samplingrate und Zählen der Nulldurchgänge"

Ein weiterer Ansatz wäre es sicherlich, die Nulldurchgänge wirklich zu zählen und dann die 3 Kanäle auf einmal zu lesen:

// code from https://community.openenergymonitor.org

unsigned long start = millis(); //millis()-start makes sure it doesnt get stuck in the loop if there is an error.

while(st==false) //the while loop…
{
startV = analogRead(inPinV); //using the voltage waveform
if ((startV < (ADC_COUNTS0.55)) && (startV > (ADC_COUNTS0.45))) st=true; //check its within range
if ((millis()-start)>timeout) st = true;
}

//-------------------------------------------------------------------------------------------------------------------------
// 2) Main measurement loop
//-------------------------------------------------------------------------------------------------------------------------
start = millis();

while ((crossCount < crossings) && ((millis()-start)<timeout))
{
numberOfSamples++; //Count number of times looped.
lastFilteredV = filteredV; //Used for delay/phase compensation

//-----------------------------------------------------------------------------
// A) Read in raw voltage and current samples - PHASE 1, 2 & 3
//-----------------------------------------------------------------------------
sampleI1 = analogRead(inPinI); //Read in raw current signal - PHASE 1
sampleI2 = analogRead(inPinI); //Read in raw current signal - PHASE 2
sampleI3 = analogRead(inPinI); //Read in raw current signal - PHASE 3

lastVCross = checkVCross;
if (sampleV > startV) checkVCross = true;
else checkVCross = false;
if (numberOfSamples==1) lastVCross = checkVCross;

if (lastVCross != checkVCross) crossCount++;
}
}

Ich denke, die “Zeitbasis” passt hier schon besser…?

Ansatz 3: "Sampling mit festgelegter Samplingrate über Timer-Interrupt und Zählen der Nulldurchgänge oder ADC Conversion Complete Interrupt Service Routine (ISR)"

Ein weiterer -und wahrscheinlich der sauberste- Ansatz bezüglich der Zeitbasis wäre vielleicht der Einsatz eines Timer-Interrupts, der sicherstellt, dass der ADC mit einer festen Abtastrate abgefragt wird und zudem sicherstellt, dass die drei Stromsamples auch wirklich zu einem Zeitwert gehören. Hier habe ich mal einen ersten “Pseudocode” erstellt:

void IRAM_ATTR onTimer() {
  led=!led; // Toggle LED-Status
  sampleI1 = analogRead(inPinI);                 //Read in raw current signal - PHASE 1
  sampleI2 = analogRead(inPinI);                 //Read in raw current signal - PHASE 2
  sampleI3 = analogRead(inPinI);                 //Read in raw current signal - PHASE 3
  counterISR ++;                                        // Hochzählen des Counters für jeden Interrupt

}

void setup() {
 Serial.begin(9600);
 pinMode(LEDPIN, OUTPUT); // LED-Pin als Ausgang
 Serial.println("Timer-Start");
 timer = timerBegin(0, 80, true);
 timerAttachInterrupt(timer, &onTimer, true);
 timerAlarmWrite(timer, 1000000, true);
 timerAlarmEnable(timer); // Enable Timer
}

void loop() { /*Hier werden jetzt nur die Nulldurchgänge (counterISR) gezählt und die Variablen in ein Array geschrieben */ }

Meine Annahme wäre, dass ich hier nun bei jedem Interrupt gleichzeit drei Werte habe, die ich zu diesem Zeitpunkt den drei Stromwerten zuordnen kann, oder benötige ich hier noch weiteren Code, der auf die Umwandlung der einzelnen ADC-Kanäle wartet, z.B. über

bool IRAM_ATTR __adcStart(uint8_t pin){
bool IRAM_ATTR __adcBusy(uint8_t pin){
uint16_t IRAM_ATTR __adcEnd(uint8_t pin)

[/li]

Es wäre sehr nett von Euch wenn sich der Eine oder Andere mal Zeit nehmen und mit mir in die Diskussion einsteigen könnte. Mir geht es vor allem darum, etwas zu lernen.

Ich freue mich auf Eure Rückmeldungen!

Viele Grüße

Bire

Hallo
Die Zusammenhänge bei Drehstrom sind Dir bekannt. Ebenso die Unterschiede zwischen Scheitelwert, Mittelwert und Effektivwert. Wirkstrom Blindstrom.

Wenn ja dann überlege wie du die Messwerte der drei Ströme zur Brechnung einer beliebigen Kurvenform benutzen kannst. Wenn es sich um reinen Sinus handelt gibt es feste konstante.

Hallo "Rentner",

vielen Dank für Deine Antwort. Zu Deiner Rückfrage: Ja, die Theorie ist mir bekannt. Grundsätzlich ist die Sache ja gelöst und man kann den Code in den von mir im ersten Post beschriebenen Links nachvollziehen. Das ist nicht die Herausforderung. Mir geht es darum, zu verstehen, wie ich die Werte möglichst genau, das heißt mit korrekter Zeitbasis als Grundlage für die Erfassung des Sinus vom ADC des ESP32 lesen. Die Beispiele sind meist für den Arduino und zum ESP32 findet man wenig bis keine Dokumentation.

Erster Schritt ist es erst einmal Klarheit in die Parameter des ADC zu bekommen, dann bekomme ich die Werte, die Du beschrieben hast auch berechnet.

Dir erst einmal Danke und Grüße

Bire

Hi

In wie fern interessiert Dich dabei der Sinus?
Nebenbei: Die Form der Wechselspannung wird so ziemlich Alles sein, nur kein Sinus (mehr).

Dein Problem wird, unter Anderem, daß Du ZEITGLEICH die Spannung UND den Strom erfassen musst.
Beides kann sowohl positiv, wie negativ sein - und erschwerend hinzu kommt, auch bunt gemischt - also positive Spannung und negativer Strom und umgekehrt.
Das Alles musst Du ‘möglichst oft’ erfassen, am Besten mit einer dennoch festen Zeitbasis, da Du dann aus der errechneten Leistung (Die auch negativ sein kann), die Wh/kWh aufaddieren kannst.

Wofür? (Aber: Ja, habe auch AC-Strom-Wandler mit integrierter Spannungsbegrenzung)

MfG

Guten Abend postmaster-ino!

Danke für Deine Antwort! Das heißt also, ich habe mir wieder einmal eine harte Nuss rausgesucht...

Hallo

Ich gehe jetzt Mal davon aus das du den Energieverbauch messen willst. Den von dir erwähnten Link hab ich mir Mal kurz angesehen . Gehe ich jetzt aber nicht drauf ein.
Ich fange jetzt mal am Anfang an .
Was willst du also wie messen. Wenn es um den Hausgebrauch geht kannst du ja eigendlich von ohmischer Last ausgehen. Und wenn du eigendlich keine Phasenanschnitt gesteuerten Verbraucher hast wird es ja schon wesentlich einfacher. (Waschmaschine. Gedimmte Lampen)

Also Mal die obigen Einschränkungen vorausgesetzt reicht es ja wenn du die aritmetischen Mittelwerte der Ströme in festen Zeitintervallen misst und damit das zeitliche Integral bildest.

Spannung ist konstant also kannst du mir den Strömen die Leistung berechnen .

Ich denke mal eine Stromkurve messen innerhalb einer Periode , und zusätzlich die Spannung um an den cos phi zu kommen und dann die Stromkurve zu integrieren bekommt man nicht genau genug hin um das Ergebniss wesentlich zu verbessern . Selbst bei 20-40 Messwerte je Periode ist das ja noch eine ziemliche Treppenfunktion wie soll das der Effektivwert berechenbar sein.

Heinz

Hallo Heinz,

danke für Deine ausführlichen Hinweise!

Ich gehe jetzt Mal davon aus das du den Energieverbauch messen willst.

Nein. Ich benötige "nur" die Stromsignale der einzelnen Phasen eines Drehstrommotors. Dazu würde ich gerne mittels des ADC die drei Eingangskanäle möglichst zeitäquidistant und gleichzeitig abtasten. Das mit der Mittel-/Effektivwerbildung bekomme ich hin, denke ich - wenn ich meine Werte schnell genug eingelesen bekomme und das zu den korrekten Zeitpunkten.

Die zentrale Frage ist: Wie bekomme ich drei Analogeingänge mit dem ESP32 schnellst möglich abgetastet und demselben Zeitwert zugeordnet?

Der sketch aus dem Beispiel funktioniert ja offensichtlich. Hier war mir nur unklar, was die sequentielle Abarbeitung Phase 1 --> Phase 2 --> Phase 3 für Einflüsse auf das Ergebnis hat und was es sich mit dem delay(0.00002) auf sich hat.

Wenn hier jemand einen Optimierungsvorschlag, bzw. Hinweise hat, z.B. mittels der Interrupts, die ich schon erwähnt hatte, wäre ich sehr dankbar!

Viele Grüße und allen eine erholsame Mittagspause!

Grüße

Bire

delay(0.00002) ist Unsinn. Erstens will delay einen ganzzahligen Wert und zweitens ist delay kontraproduktiv, wenn Du schnell sein willst.

Gruß Tommy

Hallo Tommy,

danke für die schnelle und konkrete Aussage. Dann habe ich das schon einmal geklärt! Dann ist vermutlich die squentielle Abarbeitung der 3 analogRead() für die drei Phasen auch nicht optimal, oder?

Danke Dir und Grüße

Bire

Etwas anderes als serielle Abarbeitung wirst Du nicht bekommen, selbst wenn Du den 2. Kern mit einspannen könntest, was ich nicht vermute.

Gruß Tommy

Hallo

Du solltest das Projekt vergessen

Wenn der Motor am Netz läuft kannst du zwar den Strom messen. Das ist dann der Blindstrom , was willst du damit anfangen. Den cos phi hast du nicht, OK auf dem Motor steht einer drauf der gilt aber nur für die Nenndaten , also bei Nennlast , Nennfrequenz Nennspannung usw. hat man eigendlich nie den Fall.

Wenn der Motor an einem Frequenzumrichter hängt wirds richtig kompliziert , hatte ich ja schon angedeutet. Spannung , Frequenz ändern sich ja. Zudem werden die mit 4- 8 kHz getaktet was zusatzlich den Blindstrom beeinflusst.
Alle modernen Frequenumrichter bieten die Möglichkeit die Wirkleistung zu messen und meist geben sie auch den Energieverbrauch an. Meist kann man die verbussen und die Daten dann auslesen.

Noch was zu dem von dir angegebenen Skatch , wenn das so ein Blödsinn wie Delay( 000.2) drinsteht würde ich die richtige Funktion mit Vorsicht betrachten

Tommy56:
delay(0.00002) ist Unsinn. Erstens will delay einen ganzzahligen Wert und zweitens ist delay kontraproduktiv, wenn Du schnell sein willst.

Gruß Tommy

Und außerdem sind 20ns Wartezeit auf einem System mit 62,5ns Taktperiode unmöglich.

Hallo Tommy,

danke!

Dann wäre vermutlich folgender Ansatz besser, oder?

void loop() {

// Phase1, 2 and 3 
  for (int n=0; n<numberOfSamples; n++)
{
 
   //Used for offset removal
   lastSampleI1=sampleI1;
   lastSampleI2=sampleI2;
   lastSampleI3=sampleI3;
 
   //Read in voltage and current samples.   
   sampleI1 = analogRead(inPinI1);
   sampleI2 = analogRead(inPinI2);
   sampleI3 = analogRead(inPinI3);
 
   // Hoch-Tiefpassfilterung aller Kanäle

   // Aufsummierung   
}
}

ohne delay - und alles in einer Schleife.

Oder meinst Du, der Ansatz mit dem Timer-Interrupt lohnt sich weiterzuverfolgen?

Vielen Dank Dir

Grüße

Bire

Hallo uwefed und Renter,

danke Euch beiden

@uwefed: Das ist natürlich das Argument, vielen Dank für Deinen Hinweis. Hatte ich sonst auch noch nie so gesehene, weshalb mich das stutzig gemacht hat.

@Rentner: Auch Dir Danke, auch wenn Du mich etwas “demotivierst”…Meine Ansicht war folgende: Die Sketches und auch die Applikationen unter openenergymonitor sehen für mich sehr “industrienah” aus. Hier findet man Applikationen, die gesamte Häuser und Industrieanlagen - auch 3-Phasig - monitoren. Die Sache mit dem Frequenzumrichter ist richtig. Die Signale am Ausgang sind andere. Dieses könnte ich ja tatsächlich über einen Ausgang am FU erfassen - wäre mit Sicherheit simpler. Ich erfasse den Strom jedoch vor dem Umrichter (Leitung Steckdose <–> Umrichter) , bzw. soll das System auch für Motoren ohn FU nutzbar sein. Siehst Du unter diesen Vorsaussetzungen doch noch Potenzial?

Vielen Dank Euch und Grüße

Bire

Hallo

Nein nicht wirklich , du kommt nicht wirklich ohne den tatsächlichen cos phi aus.

Wenn es immer um Motoren gehen würde kannst du auch nur eine Phase messen die Ströme sind doch immer gleich. Die Umrichter messen auch nur einen Strom , letztlich kostet das Geld drei Wandler einzusetzen und es bringt nix.

Umrichter auf der Eingangsseite zu messen und daraus auf Motor zu schließen kenn ich nicht, macht aber wegen des verwendeten Zwischenkreises keinen Sinn. Ich denke der in den Umrichter fliessende Strom spiegelt den Blindstrom der gesamten Anordnung aus Umrichter und Motor wieder. Da fließt ja letztlich bei jeder Halbwelle nur für sehr kurze Zeit ein Strom . Das ist vergleichbar mit einem Bruckengkeuchrichter. Umrichter haben im Eingang ja eine Drehstrombrücke und der Wechselrichter bezieht seinen Strom aus dem DC Zwischenkreises.

Hallo Rentner,

danke für Deinen Hinweis. Du hast natürlich recht:

Wenn es immer um Motoren gehen würde kannst du auch nur eine Phase messen die Ströme sind doch immer gleich. Die Umrichter messen auch nur einen Strom , letztlich kostet das Geld drei Wandler einzusetzen und es bringt nix.

Die Strangströme sind bei einer symmetrischen Belastung gleich und somit brauche ich auch nur eine Phase messen…

Deine Hinweise zum Zwischenkreis und der Blindleistung schaue ich mich gleich noch einmal genauer an…

Danke Dir und Grüße

Bire