Reduzieren des Rauschens

Um das Rauschen zu reduzieren finden Sie hier vier unterschiedliche Mittelwertsberechnungen. Welche Methode für Sie geeigent ist, hängt von Ihren Ausgangsdaten und dem gewünschte Ergebnis ab.

Arithmetischer Mittelwert
Gleitender Mittelwert
Quadratischer Mittelwert
Median

Arithmetischer Mittelwert zur Minderung des Rauschen

//Gibt die Tiefe des Durchschnitts an.
#define AVG_DEPTH      5

/*
  Dieser Code wird am Ende jedes Messzyklus ausgefuehrt.
*/
public Mdn_CtrlFinish()
{
  //Hält die letzten AVG_DEPTH Werte für die Mittelwertsberechnung.
  static Float:afStack[AVG_DEPTH];
  //Hält die Anzahl der im afStack gehaltenen gültigen Werte
  static       iCurrentStackCount;
  //Hält die Position des ältesten gültigen Messwert
  static       iCurrentOldestValuePos;

  new           Float:fTemperture;
  new Mdn_ValueStatus:iStatus;

  //Liest den aktuellen Messwert der Temperatur aus.
  Mdn_GetCh(MDN_CH_EXTTEMP, fTemperture, iStatus);

  //Zieht nur gültige Werte für die Mittelwertsberechnung heran
  if(iStatus == MDN_STATUS_OK)
  {
    //Fügt einen neuen Wert zur Liste der letzten gültigen Messwerte hinzu.
    //Wenn die Liste voll ist, wird der älteste Wert überschrieben.
    ArrayAddValuef(fTemperture, afStack, iCurrentStackCount, iCurrentOldestValuePos);

    //Berechnet den arithmetischen Mittelwert aus der Liste der gültigen Messwerte.
    getAVGf(afStack, iCurrentStackCount, fTemperture);

    //Speichert den Mittelwert der Temperatur im Messkanal ab.
    Mdn_SetCh(MDN_CH_EXTTEMP, fTemperture, iStatus);
  }
}

/**
  FIFO - optimierte Version
  Fügt einen neuen Wert zum Array hinzu und überschreibt den ältesten, wenn die Liste
  voll ist.
**/
stock ArrayAddValuef(Float:fNewValue, Float:afStack[], &iStackCount, &iOldestValuePos, iStackSize = sizeof(afStack))
{
  if(iStackCount == iStackSize)
  {
    afStack[iOldestValuePos] = fNewValue;
    iOldestValuePos = (iOldestValuePos + 1) % iStackSize;
  }
  else
  {
    afStack[iStackCount++] = fNewValue;
    iOldestValuePos = 0;
  }
}

/**
  Gibt den arithmetischen Mittelwert der Liste von Float-Werten zurück.
**/
stock getAVGf(const Float:afStack[], const iStackCount, &Float:fValue)
{
  for(new i=0; i<iStackCount; i++)
    fValue += afStack[i];

  fValue = fValue / iStackCount;
}

Gleitender Mittelwert zur Minderung des Rauschen

//Stellt den minimalen Standardwert für die Mittelwertsberechnung ein.
//Dieser Wert darf in normalen Messungen nicht unterschritten werden, da es
//ansonsten zu Fehlern in der Berechnung kommen kann.
#define INIT_VALUE_DEFAULT_MIN    -1000.0

//Gibt den Standardwert für die Tiefe des gleitenden Mittelwerts an.
//Dieser Wert kann beim Funktionsaufruf abgeändert werden.
#define INIT_VALUE_DEFAULT_DEPTH      5

/*
  Dieser Code wird am Ende jedes Messzyklus ausgefuehrt.
*/
public Mdn_CtrlFinish()
{
  //Speichert den Mittelwert zwischen 2 Messungen
  static        Float:fTemperatureAVG = INIT_VALUE_DEFAULT_MIN;

  new           Float:fTemperture;
  new Mdn_ValueStatus:iStatus;

  //Aktuellen Messwert des Kanals auslesen.
  Mdn_GetCh(MDN_CH_EXTTEMP, fTemperture, iStatus);

  //Zieht nur gültige Werte für die Mittelwertsberechnung heran
  if(iStatus == MDN_STATUS_OK)
  {
    //Berechnet den gleitenden Mittelwertswert für die ext. Temperatur und
    //speichert ihn wieder in den angegeben Kanal
    MovingAVG(fTemperture, fTemperatureAVG);

    //gleitenden Mittelwert als Messwert in den Kanal speichern
    Mdn_SetCh(MDN_CH_EXTTEMP, fTemperatureAVG, iStatus);
  }
}

//Berechnet den gleitenden Mittelwert.
//
// iChannel: Gibt den Kanal an, der für Berechnung herangezogen wird.
// fAverage: Gibt den Mittelwert vom letzten Messdurchlauf an.
// iDepth:   Gibt die Tiefe, für die Mittelwertsberechnung an.
//   Wenn dieser Wert nicht angegeben wird, dann wird INIT_VALUE_DEFAULT_DEPTH
//   verwendet.
MovingAVG(Float:fValue, &Float:fAverage, iDepth = INIT_VALUE_DEFAULT_DEPTH)
{
  new Float:fDepth = float(iDepth);

  if(fAverage <= INIT_VALUE_DEFAULT_MIN)
  {
    //Erster Durchlauf erkannt.
    //Setzt den Mittelwert auf den aktuellen Messwert.
    fAverage = fValue;
  }
  else
  {
    //Gleitenden Mittelwert berechnen
    fAverage = (fAverage * (fDepth - 1.0) + fValue) / fDepth
  }
}

Quadratischer Mittelwert

//Gibt die Tiefe des Durchschnitts an.
#define AVG_DEPTH      5

/*
  Dieser Code wird am Ende jedes Messzyklus ausgefuehrt.
*/
public Mdn_CtrlFinish()
{
  //Hält die letzten AVG_DEPTH Werte für die Mittelwertsberechnung.
  static Float:afStack[AVG_DEPTH];
  //Hält die Anzahl der im afStack gehaltenen gültigen Werte
  static       iCurrentStackCount;
  //Hält die Position des ältesten gültigen Messwert
  static       iCurrentOldestValuePos;

  new           Float:fTemperture;
  new Mdn_ValueStatus:iStatus;

  //Liest den aktuzellen Messwert der Temperatur aus.
  Mdn_GetCh(MDN_CH_EXTTEMP, fTemperture, iStatus);

  //Zieht nur gültige Werte für die Mittelwertsberechnung heran
  if(iStatus == MDN_STATUS_OK)
  {
    //Fügt einen neuen Wert zur Liste der letzten gültigen Messwerte hinzu.
    //Wenn die Liste voll ist, wird der älteste Wert überschrieben.
    ArrayAddValuef(fTemperture, afStack, iCurrentStackCount, iCurrentOldestValuePos);

    //Berechnet den arithmetischen Mittelwert aus der Liste der gültigen Messwerte.
    getRMSf(afStack, iCurrentStackCount, fTemperture);

    //Speichert den Mittelwert der Temperatur im Messkanal ab.
    Mdn_SetCh(MDN_CH_EXTTEMP, fTemperture, iStatus);
  }
}

/**
  FIFO - optimierte Version
  Fügt einen neuen Wert zum Array hinzu und überschreibt den ältesten, wenn die Liste
  voll ist.
**/
stock ArrayAddValuef(Float:fNewValue, Float:afStack[], &iStackCount, &iOldestValuePos, iStackSize = sizeof(afStack))
{
  if(iStackCount == iStackSize)
  {
    afStack[iOldestValuePos] = fNewValue;
    iOldestValuePos = (iOldestValuePos + 1) % iStackSize;
  }
  else
  {
    afStack[iStackCount++] = fNewValue;
    iOldestValuePos = 0;
  }
}

/**
  Gibt den quadratischen Mittelwert der Liste von Float-Werten zurück.
**/
stock getRMSf(const Float:afStack[], const iStackCount, &Float:fValue)
{
  for(new i=0; i<iStackCount; i++)
    fValue += afStack[i] * afStack[i];

  fValue = sqrt(fValue / iStackCount);
}

Median zur Minderung des Rauschen

//Gibt die Tiefe des Median an.
#define MEDIAN_DEPTH      5

/*
  Dieser Code wird am Ende jedes Messzyklus ausgefuehrt.
*/
public Mdn_CtrlFinish()
{
  //Hält die letzten MEDIAN_DEPTH Werte für die Median Berechnung.
  static Float:afStack[MEDIAN_DEPTH];
  //Hält die Anzahl der im afStack gehaltenen gültigen Werte
  static       iCurrentStackCount;
  //Hält die Position des ältesten gültigen Messwert
  static       iCurrentOldestValuePos;

  new           Float:fTemperture;
  new Mdn_ValueStatus:iStatus;

  //Liest den aktuellen Messwert der Temperatur aus.
  Mdn_GetCh(MDN_CH_EXTTEMP, fTemperture, iStatus);

  //Zieht nur gültige Werte für die Median-Berechnung heran
  if(iStatus == MDN_STATUS_OK)
  {
    //Fügt einen neuen Wert zur Liste der letzten gültigen Messwerte hinzu.
    //Wenn die Liste voll ist, wird der älteste Wert überschrieben.
    ArrayAddValuef(fTemperture, afStack, iCurrentStackCount, iCurrentOldestValuePos);

    //Berechnet den Median aus der Liste der gültigen Messwerte.
    getMedianf(afStack, iCurrentStackCount, fTemperture);

    //Speichert den Median der Temperatur im Messkanal ab.
    Mdn_SetCh(MDN_CH_EXTTEMP, fTemperture, iStatus);
  }
}

/**
  FIFO - optimierte Version
  Fügt einen neuen Wert zum Array hinzu und überschreibt den ältesten, wenn die Liste
  voll ist.
**/
stock ArrayAddValuef(Float:fNewValue, Float:afStack[], &iStackCount, &iOldestValuePos, iStackSize = sizeof(afStack))
{
  if(iStackCount == iStackSize)
  {
    afStack[iOldestValuePos] = fNewValue;
    iOldestValuePos = (iOldestValuePos + 1) % iStackSize;
  }
  else
  {
    afStack[iStackCount++] = fNewValue;
    iOldestValuePos = 0;
  }
}

/**
  Sortiert ein Array von Float-Werten mittels ShellSort-Algorithmus
**/
stock ShellSortf(Float:aValues[], iLength = sizeof(aValues))
{
    new iIndex;
    new iIndex1;
    new iSpalteValue;
    new iSpalteIndex;
    new Float:fTemp;

/*
    static const aSpalten[] = [2147483647, 1131376761, 410151271, 157840433,
    58548857, 21521774, 8810089, 3501671, 1355339, 543749, 213331,
    84801, 27901, 11969, 4711, 1968, 815, 271, 111, 41, 13, 4, 1];
*/
    static const aSpalten[] = [701, 301, 132, 57, 23, 10, 4, 1];

    for (iSpalteIndex = 0; iSpalteIndex < sizeof(aSpalten); iSpalteIndex++)
    {
        iSpalteValue = aSpalten[iSpalteIndex];
        // Sortiere die "Spalten" mit Insertionsort
        for (iIndex = iSpalteValue; iIndex < iLength; iIndex++)
        {
            fTemp = aValues[iIndex];
            iIndex1 = iIndex;
            while (iIndex1 >= iSpalteValue && aValues[iIndex1 - iSpalteValue] > fTemp)
            {
                aValues[iIndex1] = aValues[iIndex1 - iSpalteValue];
                iIndex1 = iIndex1 - iSpalteValue;
            }
            aValues[iIndex1] = fTemp;
        }
    }
}

/**
  Gibt den Median der Liste von Float-Werten zurück.
**/
stock getMedianf(const Float:afStack[], const iStackCount, &Float:fValue)
{
  new Float:afStackTemp[MEDIAN_DEPTH];
  new iIndex;

  //Werte in ein temporäres Array speichern
  for(iIndex = 0; iIndex < iStackCount; iIndex++)
    afStackTemp[iIndex] = afStack[iIndex];

  //temporäres Array sortieren
  ShellSortf(afStackTemp, iStackCount);

  //Median bilden
  if(iStackCount % 2 == 1)
    fValue = afStackTemp[iStackCount / 2];
  else
    fValue = (afStackTemp[iStackCount / 2] + afStackTemp[iStackCount / 2 - 1]) / 2.0;
}

Juergen

Jürgen kennen Sie vielleicht schon vom Telefon. Als Mitglied des Microtronics Support Teams hat er ein offenes Ohr für Kundenfragen aller Art. Jürgen ist ein Allrounder und hat bei Microtronics Erfahrung als Firmware- und Softwaretester sowie Entwickler gesammelt. Sein wertvolles Know-How in Sachen Pawn Scripts und PLC teilt er im Microtronics Blog mit Ihnen.

Letzte Artikel von Juergen (Alle anzeigen)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.