Generating sound of particular frequency matlab

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.

• 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. May 26 '17 at 12:42
• @MarcusMüller good answer! Why not paste below so the question is not left open? May 26 '17 at 12:52
• Read the documentation of audiowrite. It expects the signal to be within a certain range of amplitudes. You may also find fftshift interesting.
– MBaz
May 26 '17 at 13:43
• @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 . May 26 '17 at 15:17
• Could you please elaborate @MarcusMüller, I didn't quite understand what you meant by normalizing freq to sampling rate May 27 '17 at 6:07

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}$.

• 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. May 28 '17 at 8:03
• 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/… May 28 '17 at 8:17
• 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. May 28 '17 at 9:09
• 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. May 28 '17 at 12:49
• that's not the problem, the variable ":wave" in the example code is perfectly fine May 28 '17 at 14:03

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. 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: 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: i.stack.imgur.com/8MeTx.png (could not embed third image due to lack of reputation on this forum)

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