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$ Commented Apr 23, 2024 at 18:38
  • $\begingroup$ Does this answer your question? Simulation of a Frequency ramp $\endgroup$ Commented Apr 24, 2024 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
  • 2
    $\begingroup$ In code: np.sin(2 * np.pi * (frequency_start * t + (frequency_end - frequency_start) * t**2 / (2 * duration))) $\endgroup$ Commented Apr 23, 2024 at 17:36

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.