1
$\begingroup$

I want to generate a high frequency (single) tone. I am using matlab (any other platform/tool for the same will also work). I am using the following snippet which I wrote by referring to various sources achieving similar specification.

amp = 10;
Fs = 44100;
duration = 60;
freq = 20000;
t = (0:1/Fs:duration-1/Fs);
%t = linspace(0,duration,Fs*duration);

wave = amp*sin(2*pi*freq*t);
%sound(wave, Fs);

audiowrite('20KHz-pilot.wav',wave,Fs);

draw_spec = 0;
if(draw_spec == 1)
    NFFT = 2048;
    wave = wave(1:NFFT);
    y = fft(wave);
    y = abs(y/NFFT);
    y = y(1:NFFT/2+1);

    % as 0 and Fs don't have any alias while others do
    % we need to double the power of the other frequencies since we are
    % converting from 2 sided power spectrum to single sided spectrum.
    y(2:end-1) = 2*y(2:end-1);

    f = Fs*(0:(NFFT/2))/NFFT;
    plot(f,y);
end

The problem I am facing is that when I load the file in audacity it shows frequencies other than 20KHz in fact 20Khz is not there in spectrogram. Further when I play the sound I can hear it which should not be the case (most adults have audio hearing range upto 18Khz). Also plotting spectrum of the wave in matlab only shows 20KHz.

I have tried to use common conventional variable names so the code should be pretty self explanatory.

I am not able to find where I am making a mistake, is there a mistake in the code or is it that due to sampling rate etc. there are other frequencies also generated (aliasing or similar concepts). I tried playing the sound on different speaker systems to check if it could be a hardware issue but that was not the case.

NOTE: I have browsed through multiple resources with similar question title as mine, unfortunately none of them were able to help me. Thus, I resorted to posting this question.

$\endgroup$
5
  • 2
    $\begingroup$ you forgot to normalize your frequency to the sampling rate. Standard beginner's mistake – always ask yourself how many samples should your period be long (and not how many seconds); there's no "time" or "frequency" info attached to samples; they're just a sequence of numbers. The same sequence played back ("interpreted") at a sampling rate of 44.1 kHz will sound different than if played at let's say 16 kHz. $\endgroup$ Commented May 26, 2017 at 12:42
  • 1
    $\begingroup$ @MarcusMüller good answer! Why not paste below so the question is not left open? $\endgroup$ Commented May 26, 2017 at 12:52
  • $\begingroup$ Read the documentation of audiowrite. It expects the signal to be within a certain range of amplitudes. You may also find fftshift interesting. $\endgroup$
    – MBaz
    Commented May 26, 2017 at 13:43
  • $\begingroup$ @MarcusMüller seems a good answer , I think I have the same "Standard beginner's mistake" , I am also interested in full version your answer . $\endgroup$
    – MimSaad
    Commented May 26, 2017 at 15:17
  • $\begingroup$ Could you please elaborate @MarcusMüller, I didn't quite understand what you meant by normalizing freq to sampling rate $\endgroup$ Commented May 27, 2017 at 6:07

2 Answers 2

0
$\begingroup$

Try wave = amp*sin(2*pi*freq/Fs*t) instead. Since Fs maps to $2 \cdot \pi$, freq maps to $\frac{2\cdot\pi\cdot {\tt freq}}{\tt Fs}$.

Could be useful for reference on Wikipedia.

$\endgroup$
6
  • $\begingroup$ Although this solved my problem, I still did not understand why this was required, since I am taking time in the units of sec my frequency should be in 1/sec = Hz and not 1/samples. If I would have taken t = 0:duration*Fs then normalizing seems justified. $\endgroup$ Commented May 28, 2017 at 8:03
  • $\begingroup$ Further, all these resources seem to use my methodology and don't seem to face any problems: in.mathworks.com/matlabcentral/answers/… , dsp.stackexchange.com/questions/16845/… $\endgroup$ Commented May 28, 2017 at 8:17
  • $\begingroup$ My thought process: By physics a signal of frequency f should be of the form Yc(t) = Asin(wt) where w = 2*pif where t is in sec and f in Hz, w in radians. When discretizing it we just take samples at 1/Fs = T intervals so Yd(t) = Yc(nT) = Asin(2*pif*nT) which is what I think I am trying to do. $\endgroup$ Commented May 28, 2017 at 9:09
  • $\begingroup$ Yes, you are right. My bad, I guess this one is my own version of the "Standard beginner's mistake" :-). I would vote your answer but I am not allowed... Just for the record, if n = (0:Fs*duration); then wave = amp*sin(2*pi*freq/Fs*n) would work as expected. $\endgroup$
    – Fusho
    Commented May 28, 2017 at 12:49
  • $\begingroup$ that's not the problem, the variable ":wave" in the example code is perfectly fine $\endgroup$
    – Hilmar
    Commented May 28, 2017 at 14:03
0
$\begingroup$

I initially thought oxuf's and Marcus Müller's answers were right and I was not normalizing the frequency but that was not the case since my time vector takes values t = 0:1/Fs:duration, thus my time vector is in seconds (it does not take integer values for samples but represents the clock time at the ith sample), due to which my frequency should be in hertz and not normalized.

Waveform if oxuf's solution is implemented I played the audio after implementing oxuf's method which led to an audio with very low frequency which was inaudible to human ear so I thought problem solved and it must be of high frequency but that was not the case, the issue was something else.

@MBaz's comment led me to the answer, I had given a value of 10 to amplitude while its range should be from -1 to 1 from the MATLAB documentation of audio write and so MATALB was truncating the values which were higher than 1 in magnitude to 1 itself which was causing the issue, changing the value of amp to 1 solved the problem.

Below shows the waveforms in Audacity: Audacity waveforms for amp = 1 and amp = 10 respectively The lower waveform for amp = 10 is truncated and thus there are other frequencies in the signal.

For reference these are the spectrograms for the 2 audio: https://i.sstatic.net/8MeTx.png (could not embed third image due to lack of reputation on this forum)

$\endgroup$
3
  • $\begingroup$ @Moderator should I click to accept my own answer? That sounds like cheating :P $\endgroup$ Commented May 28, 2017 at 10:51
  • $\begingroup$ Yep, you found the issue. Matlab displays a big red warning "Warning: Data clipped when writing file." when running your code. Please read warnings. $\endgroup$
    – Hilmar
    Commented May 28, 2017 at 14:05
  • $\begingroup$ @Hilmar I did not notice any warnings, from next time I shall be careful to look for the same. Thanks $\endgroup$ Commented May 28, 2017 at 18:30

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.