How to detect oscillations/characteristic frequencies in data?

,

I have a (many) signal I have gotten from experiments. The extent can be argued, but I’d definitely say there is something pulsing/oscillatory going on:

using Plots
plot(signal)

image

How do I actually show this though? I have tried to use the welch periodogram. However, it mainly seems to show a peak at 0 (which is what you’d expect from white noise, right?):

using DSP
wpd = welch_pgram(signal, 300)
plot(wpd.freq, wpd.power)

image

Removing the mean have little effect:

signal2 = signal ./ mean(signal)
wpd2 = welch_pgram(signal2, 300)
plot(wpd2.freq, wpd2.power)

image

Ideally, I was hoping one peak only, at a non-zero frequency, corresponding to the frequency of the pulsing. Am I right that the periodogram seems to suggest my signal is mostly noise?

Is there a go-to function/approach in Julia to determine whether there is an oscillatory behaviour going on? I was thinking maybe something like Signal-to-noise ratio - MATLAB snr

This looks to me like a chaotic spiky oscillator. I wouldn’t put to much attention on signal 2 noise ration, because it seems that there is almost no noise. I am not sure what welch does, but it seems incorrect… What does the standard FFT power spectrum show (after removing mean)? EDIT: I didn’t see that the mean was divided, I assumed it was subtracted without looking at the code. Welsch works fine.

If neither work, you can try some of the methods in this function to get the dominant period: Fixed points & Periodicity · ChaosTools.jl

1 Like

You should subtract, not divide!

PS:
Check out the EasyFFTs package.

2 Likes

As said above, you want to subtract the mean. You typically also want to plot the spectrum with a logarithmic y-axis, often also logarithmic x-axis.

2 Likes

Power at 0 Hz is caused by a non-zero mean. Since your data is all non-negative, this is basically guaranteed. Dividing the source signal by its mean really just normalizes the mean of the new signal; subtracting the mean will zero it.

signal2 = signal ./ mean(signal)
# mean(signal2) ≈ 1.0
signal2 = signal .- mean(signal)
# mean(signal2) ≈ 0.0
1 Like

Thanks everyone!

Substracting the mean did indeed give a more meaningful result:

ChaosTools sounds like it might be worth trying, I will give it a look.