Skip to content

Instantly share code, notes, and snippets.

@jurihock
Created November 6, 2023 21:45
Show Gist options
  • Save jurihock/b47fc2619e00b61bdc1ae95108cfecc6 to your computer and use it in GitHub Desktop.
Save jurihock/b47fc2619e00b61bdc1ae95108cfecc6 to your computer and use it in GitHub Desktop.
Very simple RMS based frequency estimator
# References:
#
# 1) Simple and Accurate Frequency to Voltage Converter
# https://web.mit.edu/Magic/Public/papers/05491499.pdf
#
# 2) Recursive RMS (STM32 Implementation)
# https://www.youtube.com/watch?v=miUXBXUDJDI
#
# 3) How do I take the discrete derivative of Cosine, and show that it still equals -Sine?
# https://math.stackexchange.com/a/2276816
import matplotlib.pyplot as plot
import numpy as np
def rms(x, l):
lx = np.resize(np.pad(x, (l, 0)), x.shape)
dx = (x**2 - lx**2) / l
y = np.cumsum(dx)
y = np.sqrt(y)
return y
sr = 44100
n = sr//2
l = 1000
t = np.arange(n) / sr
f = np.array([100, 200, 400])
a = np.array([1, 1/2, 1/4])
roi = np.min(f) - 100, np.max(f) + 100
x = np.mean(a[:, None] * np.sin(2 * np.pi * f[:, None] * t), axis=0)
y = np.diff(x, prepend=0)
x = rms(x, l)
y = rms(y, l)
with np.errstate(all='ignore'):
w = y / x
f = w * sr / (2 * np.pi)
print(np.median(f[~np.isnan(f)]))
plot.plot(t * 1e3, f)
plot.xlabel('ms')
plot.ylabel('hz')
plot.ylim(roi)
plot.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment