When working with any kind of measurement data there is (at least) for me always a phase where I have to play around with different filters (such as MedianFilter
, MeanFilter
, LowpassFilter
...) to figure out how to improve my data in some aspect (filtering noise, detecting outliers, detecting edges...). Two things have always bugged me when using the build-in filter functions:
filters expect simple list like
{y1,y2,y3,y4}
when (more often than not) measurement data is of the form{{x1,y1}, {x2, y2}, {x3, y3}, {x4, y4}}
where $x_i$ is some index (e.g. time or frequency) and $y_i$ is the respective measurement (e.g. voltage or force)filters have a syntax of the form
someFilter[data, parameters]
and not an operator formsomeFilter[parameters][data]
This leads often to a Kuddelmuddel of [[]]
mixed with a bunch of Transpose
and/or intermediate (global) variables
What is a stylistically good way to deal with this?
Answer
The answer I came up with is
Clear@applyFilter;
applyFilter[filter_] := Function[data,
Module[{freq, value},
{freq, value} = Transpose@data;
Transpose[{freq, filter@value}]
]
];
applyFilter[filters__] := RightComposition @@ (applyFilter /@ {filters})
applyFilter[{filter_, n_}] := Nest[applyFilter[filter], # , n] &
The features are:
Applying filters in operator form
applyFilter[MedianFilter[#, 5] &] @ someData
Chaining filters together
myfilter = applyFilter[
MedianFilter[#, 5] &,
MeanFilter[#,2 ] &
]
(*used with myfilter @ someData *)Multiple filter passes
applyFilter[{MeanFilter[#, 2] &, numberOfPasses}]
and can be used on some example data
example = Transpose[{Range@100, Accumulate@(RandomVariate[NormalDistribution[0, 1], 100])}]
with for instance a MedianFilter
to flatten the peaks/remove outliers
applyFilter[MedianFilter[#, 3] &] @ example
or a MedianFilter
followed up by a MeanFilter
(this can be advantageous compared to using only a MeanFilter
if there are huge outliers in the data)
applyFilter[MedianFilter[#, 3] &, MeanFilter[#, 2] &] @ example
or multiple passes of some filter (1 pass through MedianFilter
and 10 passes through MeanFilter
)
applyFilter[MedianFilter[#, 3] &, {MeanFilter[#, 2] &, 10}] @ example
For me at least, something like applyFilter
makes using the build-in filters a lot more user-friendy when experimenting with data.
Manipulate[
ListLinePlot[{
example,
applyFilter[MedianFilter[#, r] &, {MeanFilter[#, r1] &, n}]@example}],
{{r, 0, "Medianfilter radius"}, 0, 10, 1}, Delimiter,
{{n, 0, "Meanfilter passes"}, 0, 10, 1},
{{r1, 0, "Meanfilter radius"}, 0, 10, 1}]
Comments
Post a Comment