Instantaneous frequency can be defined as a derivative of an instantaneous phase of an analytic signal which can be nicely seen in practice in this example from Scipy's documentation. But it seems like it does not always work like this. I played with the code from the example and obtained varied results like for this sine wave with frequency gradually changing from 2 to 12Hz:
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import hilbert, chirp
duration = 1.0
fs = 400.0
samples = int(fs*duration)
t = np.arange(samples) / fs
w = 2*np.pi*(2 + 10*t)
signal = np.sin(w*t)
analytic_signal = hilbert(signal)
amplitude_envelope = np.abs(analytic_signal)
instantaneous_phase = np.unwrap(np.angle(analytic_signal))
instantaneous_frequency = (np.diff(instantaneous_phase) /
(2.0*np.pi) * fs)
This is the resulting figure with the original frequency plotted in grey on the bottom subplot:
fig = plt.figure()
ax0 = fig.add_subplot(211)
ax0.plot(t, signal, label='signal')
ax0.plot(t, amplitude_envelope, label='envelope')
ax0.set_xlabel("time in seconds")
ax0.legend()
ax1 = fig.add_subplot(212)
ax1.plot(t, 0.5*w/np.pi, lw=2, color='gray')
ax1.plot(t[1:], instantaneous_frequency)
ax1.set_xlabel("time in seconds")
fig.show()
In the bottom plot the blue line and the grey line go in the same direction, but there is a huge discrepancy between the two and I do not mean the ever-present edge effect. The calculated instantaneous frequency is rising at the rate that is almost a double of the actual reaching values above 20Hz at the end.
I tried it for other sine waves with constant amplitudes and varied frequencies getting similar results. Only when I used a signal with a constant frequency the blue line was matching the grey line on the bottom plot. My question here is: are there any conditions a signal must meet for the definition of the instantaneous frequency to hold true, so it can be derived from the instantaneous phase of the analytic signal?