Commit 089d0548 authored by Bruno Randolf's avatar Bruno Randolf

use linux ewma functions

parent 2a8cd7dd
......@@ -23,7 +23,7 @@ OBJS=main.o capture.o protocol_parser.o network.o wext.o \
util.o ieee80211_util.o listsort.o \
display.o display-main.o display-filter.o display-help.o \
display-statistics.o display-essid.o display-history.o \
display-spectrum.o display-channel.o
display-spectrum.o display-channel.o average.o
LIBS=-lncurses -lm
CFLAGS+=-Wall -DDO_DEBUG=$(DEBUG) -g
......
/*
* lib/average.c
*
* This source code is licensed under the GNU General Public License,
* Version 2. See the file COPYING for more details.
*/
#include "average.h"
#include "util.h"
#include <error.h>
/**
* DOC: Exponentially Weighted Moving Average (EWMA)
*
* These are generic functions for calculating Exponentially Weighted Moving
* Averages (EWMA). We keep a structure with the EWMA parameters and a scaled
* up internal representation of the average value to prevent rounding errors.
* The factor for scaling up and the exponential weight (or decay rate) have to
* be specified thru the init fuction. The structure should not be accessed
* directly but only thru the helper functions.
*/
/**
* ewma_init() - Initialize EWMA parameters
* @avg: Average structure
* @factor: Factor to use for the scaled up internal value. The maximum value
* of averages can be ULONG_MAX/(factor*weight). For performance reasons
* factor has to be a power of 2.
* @weight: Exponential weight, or decay rate. This defines how fast the
* influence of older values decreases. For performance reasons weight has
* to be a power of 2.
*
* Initialize the EWMA parameters for a given struct ewma @avg.
*/
void ewma_init(struct ewma *avg, unsigned long factor, unsigned long weight)
{
if(!is_power_of_2(weight) || !is_power_of_2(factor))
error(1, 0, "weight and factor have to be a power of two!");
avg->weight = ilog2(weight);
avg->factor = ilog2(factor);
avg->internal = 0;
}
/**
* ewma_add() - Exponentially weighted moving average (EWMA)
* @avg: Average structure
* @val: Current value
*
* Add a sample to the average.
*/
struct ewma *ewma_add(struct ewma *avg, unsigned long val)
{
avg->internal = avg->internal ?
(((avg->internal << avg->weight) - avg->internal) +
(val << avg->factor)) >> avg->weight :
(val << avg->factor);
return avg;
}
#ifndef _LINUX_AVERAGE_H
#define _LINUX_AVERAGE_H
/* Exponentially weighted moving average (EWMA) */
/* For more documentation see average.c */
struct ewma {
unsigned long internal;
unsigned long factor;
unsigned long weight;
};
extern void ewma_init(struct ewma *avg, unsigned long factor,
unsigned long weight);
extern struct ewma *ewma_add(struct ewma *avg, unsigned long val);
/**
* ewma_read() - Get average value
* @avg: Average structure
*
* Returns the average value held in @avg.
*/
static inline unsigned long ewma_read(const struct ewma *avg)
{
return avg->internal >> avg->factor;
}
#endif /* _LINUX_AVERAGE_H */
......@@ -178,7 +178,7 @@ update_status_win(struct packet_info* p)
chan = &spectrum[p->pkt_chan_idx];
if (chan != NULL && chan->packets >= 8)
siga = normalize_db(-iir_average_get(chan->signal_avg),
siga = normalize_db(ewma_read(&chan->signal_avg),
max_stat_bar);
else
siga = sig;
......@@ -249,7 +249,7 @@ print_list_line(int line, struct node_info* n)
mvwprintw(list_win, line, 1, "%c", spin[n->pkt_count % 4]);
mvwprintw(list_win, line, COL_SNR, "%2d/%2d/%2d",
p->phy_snr, n->phy_snr_max, iir_average_get(n->phy_snr_avg));
p->phy_snr, n->phy_snr_max, ewma_read(&n->phy_snr_avg));
if (n->wlan_mode == WLAN_MODE_AP )
mvwprintw(list_win, line, COL_STA,"A");
......
......@@ -75,7 +75,7 @@ update_spectrum_win(WINDOW *win)
sig = normalize_db(-spectrum[i].signal, SPEC_HEIGHT);
if (spectrum[i].packets > 8)
siga = normalize_db(
-iir_average_get(spectrum[i].signal_avg),
ewma_read(&spectrum[i].signal_avg),
SPEC_HEIGHT);
else
siga = sig;
......@@ -102,7 +102,7 @@ update_spectrum_win(WINDOW *win)
wattron(win, BLUE);
list_for_each_entry(cn, &spectrum[i].nodes, chan_list) {
if (cn->packets >= 8)
sig = normalize_db(-iir_average_get(cn->sig_avg),
sig = normalize_db(ewma_read(&cn->sig_avg),
SPEC_HEIGHT);
else
sig = normalize_db(-cn->sig, SPEC_HEIGHT);
......@@ -131,7 +131,7 @@ update_spectrum_win(WINDOW *win)
usen = normalize(use, 100, SPEC_HEIGHT);
use = (iir_average_get(spectrum[i].durations_avg) * 100.0)
use = (ewma_read(&spectrum[i].durations_avg) * 100.0)
/ conf.channel_time;
usean = normalize(use, 100, SPEC_HEIGHT);
......
......@@ -40,6 +40,7 @@
#include "ieee80211.h"
#include "ieee80211_util.h"
#include "wext.h"
#include "average.h"
struct list_head nodes;
struct essid_meta_info essids;
......@@ -107,8 +108,7 @@ copy_nodeinfo(struct node_info* n, struct packet_info* p)
n->wlan_tsf = p->wlan_tsf;
n->wlan_bintval = p->wlan_bintval;
}
iir_average(n->phy_snr_avg, p->phy_snr);
iir_average(n->phy_sig_avg, p->phy_signal);
ewma_add(&n->phy_snr_avg, p->phy_snr);
if (p->phy_snr > n->phy_snr_max)
n->phy_snr_max = p->phy_snr;
if (p->phy_signal > n->phy_sig_max || n->phy_sig_max == 0)
......@@ -159,6 +159,7 @@ node_update(struct packet_info* p)
n = malloc(sizeof(struct node_info));
memset(n, 0, sizeof(struct node_info));
n->essid = NULL;
ewma_init(&n->phy_snr_avg, 1024, 8);
INIT_LIST_HEAD(&n->on_channels);
list_add_tail(&n->list, &nodes);
}
......@@ -382,7 +383,7 @@ update_spectrum(struct packet_info* p, struct node_info* n)
chan->packets++;
chan->bytes += p->pkt_len;
chan->durations += p->pkt_duration;
chan->signal_avg = iir_average(chan->signal_avg, chan->signal);
ewma_add(&chan->signal_avg, -chan->signal);
if (!n)
return;
......@@ -399,6 +400,7 @@ update_spectrum(struct packet_info* p, struct node_info* n)
cn = malloc(sizeof(struct chan_node));
cn->node = n;
cn->chan = chan;
ewma_init(&cn->sig_avg, 1024, 8);
list_add_tail(&cn->chan_list, &chan->nodes);
list_add_tail(&cn->node_list, &n->on_channels);
chan->num_nodes++;
......@@ -406,7 +408,7 @@ update_spectrum(struct packet_info* p, struct node_info* n)
}
/* keep signal of this node as seen on this channel */
cn->sig = p->phy_signal;
cn->sig_avg = iir_average(cn->sig_avg, cn->sig);
ewma_add(&cn->sig_avg, -cn->sig);
cn->packets++;
}
......@@ -807,8 +809,8 @@ auto_change_channel(void)
spectrum[conf.current_channel].durations_last =
spectrum[conf.current_channel].durations;
spectrum[conf.current_channel].durations = 0;
iir_average(spectrum[conf.current_channel].durations_avg,
spectrum[conf.current_channel].durations_last);
ewma_add(&spectrum[conf.current_channel].durations_avg,
spectrum[conf.current_channel].durations_last);
}
last_channelchange = the_time;
......@@ -824,8 +826,11 @@ init_channels(void)
/* get all available channels */
conf.num_channels = wext_get_channels(mon, conf.ifname, channels);
for (i = 0; i < conf.num_channels && i < MAX_CHANNELS; i++)
for (i = 0; i < conf.num_channels && i < MAX_CHANNELS; i++) {
INIT_LIST_HEAD(&spectrum[i].nodes);
ewma_init(&spectrum[i].signal_avg, 1024, 8);
ewma_init(&spectrum[i].durations_avg, 1024, 8);
}
/* get current channel & map to our channel array */
freq = wext_get_freq(mon, conf.ifname);
......
......@@ -21,6 +21,7 @@
#define _MAIN_H_
#include "list.h"
#include "average.h"
#define VERSION "2.0-rc2"
......@@ -160,9 +161,8 @@ struct node_info {
/* wlan phy (from radiotap) */
int phy_snr_min;
int phy_snr_max;
int phy_snr_avg;
struct ewma phy_snr_avg;
int phy_sig_max;
int phy_sig_avg;
/* wlan mac */
unsigned char wlan_bssid[MAC_LEN];
......@@ -245,13 +245,13 @@ extern struct chan_freq channels[MAX_CHANNELS];
struct channel_info {
int signal;
int signal_avg;
struct ewma signal_avg;
int noise;
unsigned long packets;
unsigned long bytes;
unsigned long durations;
unsigned long durations_last;
unsigned long durations_avg;
struct ewma durations_avg;
struct list_head nodes;
unsigned int num_nodes;
};
......@@ -266,7 +266,7 @@ struct chan_node {
struct list_head chan_list; /* list for nodes per channel */
struct list_head node_list; /* list for channels per node */
int sig;
int sig_avg;
struct ewma sig_avg;
unsigned long packets;
};
......
......@@ -239,3 +239,13 @@ kilo_mega_ize(unsigned int val) {
snprintf(buf, sizeof(buf), "%d", val);
return buf;
}
/* simple ilog2 implementation */
int
ilog2(int x) {
int n;
for (n = 0; !(x & 1); n++)
x = x >> 1;
return n;
}
......@@ -87,19 +87,13 @@ kilo_mega_ize(unsigned int val);
#define max(_x, _y) ((_x) > (_y) ? (_x) : (_y))
#define min(_x, _y) ((_x) < (_y) ? (_x) : (_y))
/* Fixed Point IIR Averaging Filter:
*
* y(n) = 0.875*y(n-1) + 0.125*x(n)
* y(n) = y(n-1) - 0.125*y(n-1) + 0.125*x(n)
* 8*y(n) = 8*y(n-1) - 0.125*8*y(n-1) + x(n)
* 8*y(n) = 8*y(n-1) - 8*y(n-1) >> 3 + x(n)
*
* We store y(n) in Q13.3 format to get higher precision, less round off error.
*/
#define iir_average(_avg, _val) \
(_avg = _avg - (_avg >> 3) + _val)
static inline __attribute__((const))
int is_power_of_2(unsigned long n)
{
return (n != 0 && ((n & (n - 1)) == 0));
}
#define iir_average_get(_avg) \
(_avg >> 3)
int
ilog2(int x);
#endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment