I'm using the Signal Processing Toolbox in MATLAB to design a Butterworth low-pass filter. I'm told that my filter has been giving some unexpected results. In particular, when the values from this filter are differentiated (i.e. to calculate velocity from a position signal), the velocity values are coming out a little too high. However, with my limited experience in the field of Signal Processing, it's not clear exactly how the filter is failing, or indeed whether there is fact a problem at all. Perhaps the filter is somehow artificially raising the absolute value of the signal? Below is a MWE of the code I have written, based on the Signal Processing Toolbox, commented to try to explain each step. My question is: is this a simple case of a (correctly-implemented) low-pass filter or is there a better solution I might try? Note that my (true) input data tend to have
NaNs throughout; hence I include here some code to interpolate those before feeding into the filter.
function filteredData = testfilter(inputData) %% Generate an example signal inputData = filter([1,1],1,randn(1000,1)); %% Set filter parameters dataSamplingRate_hz = 1000; order = 4; cutoff = 90; %% Apply filter nyquistFrequency = dataSamplingRate_hz/2; % find the Nyquist frequency filterCutoff = cutoff/nyquistFrequency; [b,a] = butter(order,filterCutoff); % define the filter %[b,a] = besself(order,cutoff/nyquistFrequency); % maybe a Bessel filter would be better to use instead??? filteredData = nan(size(inputData)); % preallocate resources for i = 1:size(inputData,2) % for each column of inputData timestampsOfNans = isnan(inputData(:,i)); % find the timestamps of NaNs inputDataInterpolated = interpolatenans(inputData(:,i)); % replace NaNs with interpolated data (filters can't handle NaNs) filteredData(:,i) = filtfilt(b,a,double(inputDataInterpolated)); % filter the data (n.b. filtfilt() requires doubles) filteredData(timestampsOfNans,i) = NaN; % replace the NaNs back into the vector end %% Plot the 'before and after' signal figure hold on subplot(2,1,1) plot(inputData) subplot(2,1,2) plot(filteredData) function data = interpolatenans(data) % Interpolates NaNs in a vector by approximating with the data either side of the gap nans = isnan(data); % find nans t = 1:length(data); data(nans) = interp1(t(~nans),data(~nans),t(nans),'linear');
The above code produces the following plot, which looks - to my untrained eye - to be appropriate. Is this the case?
(I recognise that at this stage, I do not have a specific problem to address here, as I do not yet understand why my code is producing elevated values. If a specific problem is found with this code, I will adjust my question to reflect the underlying issue)