Median Filter

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Filtern von Messwerten - Medianfilter

Motivation

Beim Messen von analogen Signalen kommen Störungen recht häufig vor. Diese Störungen sind Ausreißer, die die gesamte Signalverarbeitung stören.

Man brauch also einen Filter, der hochfrequente Störungen aus den Messwerten entfernt. Für diesen Zweck kann der Medianfilter verwendet werden.

Funktionsbeschreibung

Der Medianfilter speichert N Messwerte in einem sortierten Array und verwendet nur den Wert an der mittleren Position des Arrays. Enthält das Array eine gerade Anzahl von Elementen, dann wird der Mittelwert der beiden mittleren Elemente zurückgegeben.

Wird ein neuer Messwert an den Medianfilter übergeben, dann wird der älteste Messwert durch den neuen ersetzt und die Liste neu sortiert.

Implementierung

Der Medianfilter ist in C99 implementiert und unterstützt mehrere Instanzen, da man häufig verschiedene analoge Messwerte filtern will.

Für eine Instanz des Medianfilters muss folgende Initalisierung vorgenommen werden:

#include "median.h"

void test_median(void)
{
    struct s_median myMedian;
    int sizemedian = 9;
    uint16_t data[sizemedian];
    uint8_t ages[sizemedian];

    median_constructor (&myMedian, data, ages, sizemedian);

    while (1)
    {
        uint16_t advalue = readADWandler();
        uint16_t filteredValue = median_insert (&myMedian, advalue);
        processValue (filteredValue);
    }
}

median.h

/*
 * median.h
 *
 *  Created on: 05.11.2013
 *      Author: Jens Riebold, Kößweg 13, 91056 Erlangen
 *
 *  Jens Riebold AT web PUNKT de
 */
 
#ifndef MEDIAN_H_
#define MEDIAN_H_

#include <stdint.h>
 
struct s_median
{
    uint16_t *data;
    uint8_t *age;
    uint8_t size;
    uint8_t count;
};
 
/** Initialize the Median Object */
void median_constructor (struct s_median*, uint16_t*, uint8_t*, uint8_t);
 
/** Insert an Element to the Median Filter */
uint16_t median_insert (struct s_median*, uint16_t);

#endif /* MEDIAN_H_ */

median.c

/*
 * median.c
 *
 *  Created on: 05.11.2013
 *      Author: Jens Riebold, Kößweg 13, 91056 Erlangen
 *
 *  Jens Riebold AT web PUNKT de
 */
 
#include "median.h"
 
/**
 * Initialize the Median Object
 */
void median_constructor (struct s_median *p, uint16_t *data, uint8_t *age, uint8_t size)
{
    p->age = age;
    p->data = data;
    p->count = 0;
    p->size = size;

    // Initialize the values and ages
    for (uint8_t i=0; i < size; i++)
    {
        data[i] = 0;
        age[i] = 0;
    }
}
 
/**
 * Insert an Element to the Median Filter
 */
uint16_t median_insert (struct s_median *p, uint16_t value)
{
    uint8_t inspos = p->size;
    uint8_t pos;

    // Replace the Oldest entry and store the insertion position in inspos
    for (pos=0; pos < p->size; pos++)
    {
        if (p->age[pos] > 0)
            p->age[pos] -= 1;
        else if (inspos == p->size)
        {
            inspos = pos;
            p->data[pos] = value;
            p->age[pos] = p->size - 1;
        }
    }

    // Count the current number of data until the size is reached
    if (p->count < p->size)
        p->count += 1;

    uint16_t tmpdata;
    uint8_t tmpage;
    uint8_t swapcount = 0;

    // shift the elements up to the right sorted position
    for (pos = inspos+1; pos < p->count; pos++)
    {
        if (p->data[pos-1] < p->data[pos])
            break;

        tmpdata        = p->data[pos];
        tmpage         = p->age[pos];
        p->data[pos]   = p->data[pos-1];
        p->age[pos]    = p->age[pos-1];
        p->data[pos-1] = tmpdata;
        p->age[pos-1]  = tmpage;
        swapcount++;
    }

    // If we already shifted up, then we need no shift down
    if (swapcount == 0)
    {
        // shift the elements down to the right sorted position
        for (pos=inspos; pos > 0; pos--)
        {
            if (p->data[pos] < p->data[pos-1])
            {
                tmpdata        = p->data[pos];
                tmpage         = p->age[pos];
                p->data[pos]   = p->data[pos-1];
                p->age[pos]    = p->age[pos-1];
                p->data[pos-1] = tmpdata;
                p->age[pos-1]  = tmpage;
            }
        }
    }

    pos = p->count;
    if (pos & 0x01)
    {
    	// Return the median if the count is an odd number
        return p->data[pos >> 1];
    }
    else
    {
        // Return the average value of the two median values
        pos = pos >> 1;
        return (uint16_t) (((uint32_t) p->data[pos-1] + p->data[pos]) >> 1);
    }
}