2
$\begingroup$

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: STFT spectrogram with frequency up to 20KHZ

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?

$\endgroup$
2
  • $\begingroup$ 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) $$ $\endgroup$ Apr 23 at 18:38
  • $\begingroup$ Does this answer your question? Simulation of a Frequency ramp $\endgroup$ Apr 24 at 1:49

1 Answer 1

6
$\begingroup$

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.

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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.