filtfilt changes signal amplitude badly - how to choose the right filter?

11 views (last 30 days)
Hi all,
I have been trying to filter a the displacement traces of a moving animal to calculate kinematics such as velocity and acceleration. The problem is that I do not know anything about how the signal should appear in the time or frequency domain - the animal moves continously varrying it's speed. I tried using various filters to remove the jitter and they seem to dampen the amplitude of the velocity a lot as you can see in the image (instantaneous velocity in blue is the unfiltered velocity trace and the filtered one is in magenta). Can anyone who knows more about signal processing help me to choose the right filter which can smothen this signal without loosing much information?
I am attaching a sample code and the starting variable xPos and yPos which will bring you on the same page as me in just few seconds.
Thanks already. :)
filteringArtifact.bmp
%%%%%%%%%%%%%%%%%%%%%%%
dx = [0; diff(xPos)]; % distance between two consecutive x-coordinates
dy = [0; diff(yPos)]; % distance between two consecutive y-coordinates
camscale_px_per_mm = 22;
datarate_Hz=700;
tmp_dist_unfilt = sqrt(dx.^2 + dy.^2);
tmp_dist_unfilt = tmp_dist_unfilt./camscale_px_per_mm; % convert to distance in mm
tmp_vel_unfilt = tmp_dist_unfilt.*datarate_Hz; % convert to velocity in mm/s
filterF = ones(1,4)./4; %for filtering out jitter
idx_nan = isnan(dx);
idx_nan = find(idx_nan==1);
dx(idx_nan) = 0; % for filtering nan values need to be removed
dy(idx_nan) = 0;
dxF = filtfilt(filterF, 1, dx);
dyF = filtfilt(filterF, 1, dy);
tmp_dist_fF = sqrt(dxF.^2 + dyF.^2); % distance moved between iterations, in pixels
tmp_dist_fF = tmp_dist_fF./camscale_px_per_mm; % convert to distance in mm
tmp_vel_fF = tmp_dist_fF.*datarate_Hz; % convert to velocity in mm/s
tmp_vel_fF(idx_nan) = nan; % re-insert the nan values
yyaxis left
plot(tmp_vel_unfilt);
yyaxis right
hold on;plot(tmp_vel_fF);
%%%%%%%%%%%%%%%%%%%%%%%%%
  2 Comments
Jan
Jan on 25 Jan 2019
Edited: Jan on 25 Jan 2019
What are the inputs? Did you measure the positions directly? What is the wanted output? The average or locally smoothed velocity?
Of course the moving average filter you have applied damps the amplitude. To suggest a "better" filter, you have to define, what you consider as wanted signal. Afterwards you can design a filter. Without defining, what the noise is, it is impossible to remove it without destroying the wanted information.
Please explain, what you want to achieve.
If you want to get a smoother velocity, you can use gradient instead of diff, because it uses a 2nd order quotient of differences instead of a 1st order. A larger time step helps also directly:
diff_X = X(2:end) - X(1:end-1); % same as diff(x)
diff_X8 = (X(9:end) - X(1:end-8)) / 8
This obtains the average velocity over 8 time steps without smoothing the original signal.
Marion Rosello
Marion Rosello on 25 Jan 2019
Thanks for your comments, Jan.
The positions: I use a high speed (700Hz) camera to capture the images and do some image processing on the fly to determine the centroid of thresholded images. I think the jitter comes from this small variations in determining the right pixels of the centroid.
Output: I'm looking for a locally smoothed velocity trace.

Sign in to comment.

Accepted Answer

Bjorn Gustavsson
Bjorn Gustavsson on 25 Jan 2019
Don't instantly start looking at your data after differentiation - differentiation is a noise-amplifying operation! First you have to take a look at the data and have a think about what your data and its intrinsic noise-characteristics:
t = (1:numel(xPos))/700;
subplot(2,2,1)
plot(t,xPos)
subplot(2,2,2)
plot(t,yPos)
subplot(2,2,3)
plot(xPos,yPos)
subplot(2,2,4)
comet(xPos,yPos)
Then you'll have to make some kind of decision on whether your animal actually moves in 1/700th of a second or if positional variations at that time-scale is just noise (Just look at the variation in kinetic energy or try to calculate the work done by your animal - integrate scalar product of velocity and acceleration divided by mass, is that even plausible considering the metabolism of you subject? Are the accelerations consistent with the maximum/steady force your animal can generate).
I'd guess you should filter much much longer than 0.005 s - perhaps 0.1 - 0.2 s:
for i1 = 2:2:201,
subplot(3,1,1)
plot(t,xPos)
hold on
plot(t,filtfilt(ones(1,i1)/i1,1,xPos),'r')
hold off
subplot(3,1,2)
plot(t,xPos-filtfilt(ones(1,i1)/i1,1,xPos))
subplot(3,2,5)
plot(t,gradient(xPos,t))
subplot(3,2,6)
plot(t,gradient(filtfilt(ones(1,i1)/i1,1,xPos),t),'r')
pause(0.1)
end
HTH
  5 Comments
Marion Rosello
Marion Rosello on 31 Jan 2019
Thanks! This helped me think and play more with the data. I'm getting there with the perfect data. :)
Bjorn Gustavsson
Bjorn Gustavsson on 31 Jan 2019
That's the right attitude! Throw your figurative kitchen sink at the problem, see what gets you forward...
...another thing to try might be to do something in line with what Loren Shure presented about loess smoothing/filtering in one of her post on the mathworks blogs a couple of years ago.
Please let us know how you succeed - because this was an intriguing filtering problem.
All the best

Sign in to comment.

More Answers (0)

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!