Creating Sound which changes frequency continuously

Hi,
i believe my problem is in fact quite simple to solve, but i am not an expert in sound proccesing/generating. i want to create a beep whose frequency is changing over a specific time, i.e. the * *frequency of the tone should change from 500 Hz to 1000 Hz within the specified time period (i really hope my explanations are understandable...).
as an example this is my code up to now:
a = 1; % amplitude
fs = 8192; % sampling frequency [Hz]
d = 3; % duration of beep [sec]
f_data = 100; % sampling rate of "input" frequency [Hz]
f_range = linspace(500,1000,f_data*d); % starting end ending freq. for the beep
% with 100 datapoints per second
% loop through frequency range
y = [];
for idx = 1:numel(f_range)
tmp_t = 0 : 1/fs : 1/f_data;
tmp_y = a * sin(2*pi * f_range(idx) * tmp_t);
y = [y tmp_y];
end
% play sound
sound(y,fs);
the actual results is somehow weird... there seems to be an overlap of two frequencies: one can hear the increasing frequency, but it is superposed with an much higer frequency resulting in something like a beat frequency.
any idea??
thanks a lot, adam

 Accepted Answer

Jan
Jan on 24 Jan 2017
Edited: Jan on 25 Jan 2017
One single sin() call should be enough, if you transform the time accordingly. For a linear time, the steps between the elements of the vector have the same size. If now the step size is increasing, you get a growing frequency:
duration = 3.0;
fs = 8192;
iniF = 500;
finF = 1000;
A = 1.0; % Amplitude
Now the wave with the inital frequency is:
t = iniF * linspace(0, 3, 3*fs);
y = A .* sin(2 * pi * t);
sound(y, fs);
Equivalently for the final frequency.
Now change the frequencies:
iniStepwidth = iniF / fs;
finStepwidth = finF / fs;
flowStepwidth = linspace(iniStepwidth, finStepwidth, duration * fs);
flowTime = cumsum(flowStepwidth);
y = A .* sin(2 * pi * flowTime);
sound(y, fs);
The frequency information is included in the time vector, which is not linear anymore. Instead of linspace other functions are possible here. I've used ".*" instead of "*" for the amplitude to allow using a vector also e.g. for a increasing volume.
You can see the reason for the artifacts created by your code in the diagram: Run your code, then:
plot(y);
xlim([2000, 2250])
You see, that the single parts do not end at the specified limits of the intervals.

3 Comments

Hello Jan!
Thanks a lot for this kind explaining and answer! As i see in your profile, your involved in motion analysis, so am i (and actually i'm from Gießen, but let's try this in english anyway, there might be other people interested in this topic...).
Actually this is an attempt to do some sonification of a movement, in more detail we want to measure the elbow angle while a person performs a flexion from 0° to 90° and back to 0°. This at two different velocities. Probably with an Steinbichler Motion Tracking System.
So the real problem is a little more complicated: non-linear movement, durations which depends on the executed action and the amount of datapoints are depending on the sampling rate with the movement will be captured.
Tried to implement this in your code by creating a cosinus-like function which is representing the angle. Lets assume this is measured with an sampling rate of 100 Hz ('angle_fs'). So the 2500 values in the 'angle' variable represent a movement which lasts 2.5 seconds. This angles will be scaled into the iniF and finF interval and then played as a sound.
fs = 8192;
iniF = 500;
finF = 1000;
A = 1.0; % Amplitude
% creating sample cosinus-like movement in elbow angle
angle_fs = 100; % sampling freq. of movement capturing [Hz]
angle = 45 * ( -cos(8 * pi * (0:0.001:.2499) ) + 1); % elbow angle [°]
% scale this angles into iniF-finF interval
angle_scaled = (angle - min(angle)) * (finF - iniF) / (max(angle) - min(angle)) + iniF;
plot(angle_scaled); % to confirm the previous steps
% create sound
flowSteps = angle_scaled / fs;
flowTime = cumsum(flowSteps);
y = A .* sin(2 * pi * flowTime);
sound(y, fs);
The problem right now is, that i am not sure how to implement the 'angle_fs'?! The sound only has the duration of
duration_is = numel(angle_scaled) / fs = 0.0305 s
but should be
duration_should = numel(angle_scaled) / angle_fs = 2.5 s
Thanks a lot!!
Adam
Jan
Jan on 25 Jan 2017
Edited: Jan on 25 Jan 2017
@Adam: Sound - to "visualize" an angle?!! Wow. I'm interested. I contact you by email.
ok :)
and despite the long day i just solved the problem. first calculate the duration
duration = numel(angle) / angle_fs;
than calculate how much time steps are needed
fs_dur = fs*duration;
and then use interp1 for linear interpolation (linear is not "perfect", but in that time dimensions it shouldn't matter)
angle_interp = interp1(1:numel(angle),angle,linspace(1,numel(angle),fs_dur));
continued like described above
angle_scaled = (angle_interp - min(angle_interp)) * (finF - iniF) / (max(angle_interp) - min(angle_interp)) + iniF;
% create sound
flowSteps = angle_scaled / fs;
flowTime = cumsum(flowSteps);
y = A .* sin(2 * pi * flowTime);
sound(y, fs);
done :) thanks again for your help!

Sign in to comment.

More Answers (0)

Tags

Asked:

on 24 Jan 2017

Commented:

on 25 Jan 2017

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!