Zero detection in online signal
Show older comments
Hi.. I am acquiring a signal from an EEG from a matlab script. I know approximatly the frequency of the signal (0.5Hz to 4 Hz).
I need to play a sound when the signal does a negative zero crossing. So I need to detect the correct instant to fire the audio in real ltime.
500 samples make 1 second of the signal.
I would have to band pass the signal to remove high frequencies (otherwhise, it could incur spurious zero crossing). For example, I could band pass 10 samples (which would take me 20 ms ) .
%s - > acquired signal (10 samples)
x = filter (s) % x is the bandpassed signal
for ii = 1:10
if (x(ii-1) > 0 && x(ii) < 0 ) % lets say that this happend for the fifth element of x (ii = 5)
sound('pinknoise.wav')
end
end
I tought about using the following as a filter because it has linear delay.
%%%%%
h = fdesign.bandpass('fst1,fp1,fp2,fst2,ast1,ap,ast2', Fstop1, Fpass1, Fpass2, Fstop2, Astop1, Apass, Astop2, Fs);
Hd = design(h, 'equiripple', 'MinOrder', 'any');
y = filter(Hd,x);
%%%%%
However, I am not sure about the delay that the filter would introduce. It Introduces a phase shift (delay) of 2 samples. Therefore is it correct to say that the negative zero crossing happened at the (5 - 2) third element of s?
How to get this delay? Is this zero cossing algorithm reasonable? Are there otherS best than this one?
Best
Answers (1)
Your filtering idea, could probably be made to work. As an alternative, you might consider the use of a Schmidt trigger, to "debounce" the signal. It is extremely simple. You would adjust the lower threshold to be large enough to avoid false triggers.
Even with this approach there will be a tradeoff between false alarms, and the delay to detect them. With a large threshold and a slowly descending signal there will be a some samples of delay between the true zero crossing and when the lower threshold is crossed, and the trigger event occurs.
If you aren't familiar with Schmidt triggers you can Google them, and find lots of references.
Here's a rough example:
% Parameters
aNoise = 0.1; % noise amplitude
f = 1; % example signal frequency [Hz]
a = 3; % example signal amplitude
numCycles = 10; % number of signal cycles
fsmpl = 100; % sampling frequency [Hz]
xLower = 0.3; % Lower Schmidt Threshold
xUpper = 0; % Upper Schmidt Threshold
% Generate noisy signal
T = 1/f; % signal period
Tsmpl = 1/fsmpl;
t = 0:Tsmpl:numCycles*T;
x = a*sin(2*pi/T*t) + aNoise*randn(size(t));
% Loop through signal values one sample at a time to simulate real time
% application
val = zeros(size(t));
soundOn = zeros(size(t));
prevVal = 0;
for k = 1:numel(x)
% Pass signal through Schmidt Trigger
val(k) = schmidt(x(k),xLower,xUpper);
% Check if this was a zero crossing (schmidt changed state)
if (val(k) - prevVal) > 0
soundOn(k) = 1;
end
prevVal = val(k);
end
% Plot results
plot(t,x,t,val,t,soundOn,'o')
grid
legend('signal','schmidtState','soundOn')
function val = schmidt(x,xLower,xUpper)
persistent isNeg % trigger state
% initialize
if isempty(isNeg)
isNeg = false;
end
if x <= xLower && ~isNeg
isNeg = true;
end
if x > xUpper && isNeg
isNeg = false;
end
% Compute output signal, as zero or 1 numerical value
val = double(isNeg);
end
16 Comments
L
on 8 Nov 2023
I would first suggest that you evaluate the Schmidt trigger idea as an alternative to filtering. It is a very simple and widely used approach. If it works well enough for you, then you don't have to worry about your problems with the filter.
Regarding your problems with implementing a filter. First, why are you bandpass filtering the signal? Do you have some reason to believe the noise is only in a narrow range? I would think you would just want to low pass filter the data to get rid of the relatively high frequency noise.
If you still need detailed help with the filter implementation, please attach an example data file with your signal, and the code that you have written so far.
L
on 8 Nov 2023
L
on 8 Nov 2023
Jon
on 8 Nov 2023
Oh I see, you want to bandpass to just keep the frequencies of interest. Sorry I was somehow thinking you were using a notch filter to get rid of noise at a specific frequency.
Regardless, it would be good to be clear about why you "need" a filter. I would turn the question around and specify what you really need to find out from the signal, and then figure out what you need to do to accomplish that.
To get rid of the dc component, a very simple high pass filter can be used. for example. Essentially you are implementing the equivalent of "ac coupling" on a scope. For this you could for example just subtract the current value from the previous n-point moving average. Another similar idea is to subtract the current value from the output of a first order lag.
If you could further specify what it is you want to extract from the signal and attach an exemplar signal, and your files so far I could take a look.
For your application, do you have the entire signal available, and you are postprocessing it, or do you only get one value every 1/500 sec and you have to decide based on the current and previous values whether it has crossed zero or not.
In order to use MATLAB's bandpass function you would need to have the whole signal available. It can not be applied one value at a time, for a real time application. Because it post processes the values it is able to shift the signal back in time to compensate for the filter delay.
Here is a little example to illustrate. Note how the whole filtered signal is shifted back in time, and is clearly non-causal, as it anticipates the change in the signal value. I also plot the result of applying the filter, without the backward time shift using MATLAB's filter function. In the example I used a fir filter as you said you were interested in a linear phase response. Note however that the filter length, and corresponding delay are quite long.
% Make a signal with a dc component and a single zero crossing
Ts = 1/500; % sampling period [s]
t = 0:Ts:200;
N = numel(t);
x = zeros(N,1);
x(round(N/2):end) = -3;
x = x + 2;
% Band pass filter the signal, with passband from 0.25 to 4 Hz
[xf,d] = bandpass(x,[0.25,4],1/Ts,'ImpulseResponse','fir');
% Plot output of "bandpass function"
plot(t,x,t,xf)
xlabel('time [s]')
legend('original signal','filtered signal')
title('Output of MATLAB bandpass function')
% Generate output of signal that would be generated in real time
xfrt = filter(d,x);
plot(t,x,t,xfrt)
xlabel('time [s]')
legend('original signal','filtered signal')
title('Output of MATLAB filter function')
L
on 9 Nov 2023
The signal shown in your attached file is steadily increasing with time. How then do you define a zero crossing. Are you perhaps thinking that you want to subtract off the trend line (assuming it is linearly increasing) and see where it crosses the trend line?
Note, you say that the signal has a dc component. A "dc" component would be a constant added to your signal.
You have a growing value added to your signal. Here is a plot of what you sent.
Or - are you trying to find the zero crossings of the first derivative of this signal?
load data2
N = numel(data2);
Ts = 1/500;
idx = 1:N;
t = (idx-1)*Ts;
plot(t,data2)
xlabel('time [seconds]')
L
on 9 Nov 2023
Jon
on 9 Nov 2023
OK, I will have to think about this a little. I'll let you know if I have a good approach.
L
on 10 Nov 2023
Jon
on 10 Nov 2023
I did quickly try this but wasn't able to get any meaningful results.
I'm sorry I'm stuck at this point. Maybe someone else can help.
I'm having problems even conceptually with thinking about how to deal with this ramping function, and exactly how you are defining a zero crossing. Obviously the raw signal itself never crosses zero. So somehow we must remove the ramp and produce a signal that crosses zero.
While I can roughly understand your idea of bandpassing to detrend (remove the linear growth) I'm not sure how to think about frequency response of the filter in the context of this ramping signal.
Jon
on 10 Nov 2023
I'm sorry, but I can't really put much more time into this right now, but here are some references I found that might be of interest
https://www.sciencedirect.com/science/article/pii/S1053811919301545
L
on 14 Nov 2023
Jon
on 14 Nov 2023
Before getting to the details of that, what is the signal that you are applying the Schmidt trigger to?
In my example of applying a Schmidt trigger, I have assumed that the input signal is varying about zero, and you are looking for where it crosses zero. You could also have a signal that varied about some other constant and subtract off that constant to transform it to a zero crossing problem. In any case it was not intended for a ramp signal such as the one you attached. Have you found a way to first "detrend" the data, so you now have a signal that varies above and below some constant value, rather than a ramp signal as you now have?
Categories
Find more on Descriptive Statistics in Help Center and File Exchange
Products
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!


