# Why does frequency sweeping double the frequency?

You can generate a signal with frequency f with sin(2*pi*f*t) where t is time. Yet, when I sweep the frequency from 0 to 10KHz, my signal reaches 20kHz.

Here is the instantaneous FFT:

And the code you can use to reproduce:

import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

duration = 10        # Duration of the audio in seconds
sample_rate = 44100  # Sample rate in Hz
t = np.linspace(0, duration, int(sample_rate * duration))

# Generate sine wave with increasing frequency
frequency_start = 10  # Start frequency in Hz
frequency_end   = 10000  # End frequency in Hz
sine_wave = np.sin(2 * np.pi * np.linspace(frequency_start, frequency_end, len(t)) * t)

# Compute STFT
window_size = 1024
hop_length = 256
frequencies, times, Z = signal.stft(
sine_wave,
fs=sample_rate,
nperseg=window_size,
noverlap=window_size-hop_length
)

# Plot spectrogram
plt.figure(figsize=(10, 6))
plt.pcolormesh(times, frequencies, 20 * np.log10(np.abs(Z)), shading='gouraud')
plt.colorbar(label='Amplitude (dB)')
plt.ylabel('Frequency (Hz)')
plt.xlabel('Time (s)')
plt.title('STFT Spectrogram')
plt.show()


I generated a wav file from the signal generated and played it over speakers. It's indeed going till 20 kHz.

Why does this happen? What's the correct way to generate a frequency sweep? How does scipy.signal.chirp produce the correct result?

• The derivative of instantaneous phase $\frac{\mathrm{d}}{\mathrm{d}t}\theta(t)$ is instantaneous frequency $\omega(t)$ (in radians per unit time, not Hz). It is not (necessarily) what is multiplying $t$ in the argument of the $\sin(\cdot)$ or $\cos(\cdot)$. It's $$x(t) = A \cos\left(\int_{0}^{t} \omega(u) \, \mathrm{d}u + \theta(0)\right)$$ not $$A \cos\big(\omega(t)t+\theta(0) \big)$$ Apr 23 at 18:38
• Does this answer your question? Simulation of a Frequency ramp Apr 24 at 1:49

You're calculating the parameters into the sinusoid incorrectly. By simply plugging in a linear frequency ramp into the sinusoid, you do not get the appropriate quadratic phase that is needed to produce a linear ramp. Recall that the frequency is the derivative of the phase. You can calculate the phase needed from the desired frequency ramp.

In your case, the linear frequency function (rads/s) using simple algebra is:

$$f(t) = 2\pi(999t + 10)$$

Integrate this to get the phase function $$\phi(t)$$:

$$\phi(t)=\int{}f(t)dt=2\pi\left(\frac{999t^2}{2} + 10t\right)$$

Using this as $$\sin(\phi(t))$$ will then give you the desired frequency ramp.

• In code: np.sin(2 * np.pi * (frequency_start * t + (frequency_end - frequency_start) * t**2 / (2 * duration)))
– Jdip
Apr 23 at 17:36