0
$\begingroup$

Question:

I want to develop an algorithm or something similiar (or function?), based on my question. The following question is, how do I send power values as PWM-signals (Puls-Width-Modulation) from Matlab through Arduino UNO? Because, i want to send those signals to a vibration motor, which is controlled by the Arduino UNO. Based on the values, these vibrations can be strong or weak, but in a certain rhtym.

Explanation:

I am not an expert how PWM works, but here is my explanation. As I understood, there is a digital signal source, on which you create an analog signal. Depending on the frequency, it can switch from LOW to HIGH very fast. If it works very fast, then it behaves as an analog signal with a constant voltage.

I will keep the explanation, how my codes works, very short. I advise you to try this code yourself, so perhaps you understand it better that way. I have an audio-file and read it in my code. Now i switch from the time domain to the frequency domain by using the function FFT. But the only difference is, that i am performing an STFT on my audio signal. I do it every 30ms, until to the length of my signal. I am aware, that there are many different function in matlab, which also can perform this easily, but there are not giving me the results i need. Now, i am plotting many different frequency spectrums every 30ms. But i split up my signal in three frequency bands. They are called LOW, MEDIUM and HIGH. Basically, this means I have 3 different spectrums plotting every 30ms. The next step I do, is summing all the magnitudes from ONE frequency spectrum together, this means I have ONE VALUE per frequency spectrum, which are being squared.

Now, i have the power from every spectrum ! And all of these values are being plotted in my code. I am only plotting the power values, otherwise my code performance time would be extremely slow.

Describing the problem:

I recommend you, to test out my code. Just take a small wav-file with a duration of 5 to 30 sec. Needs to be in the same directoy In my case, i took a audio file, which contains bass tones. Bass tones in my case, were manipulated, so they sound louder, but generally they have a higher amplitude, which means they have more power compared to the others tones. Anyway, if I have measured the highest values, which for example is 15000. All the others values are below 15000. Maybe 3000, 7850, 1240 and so on. Try to imagine a 2-D-Plot, where the y-axis is the PWM, which has the unit percent. This means, if 15000 is the highest measured value, this means it is 100 percent. The x-axis would be the power axis. This is simply for explaining. I need a function, which tells my motor, how strong the motor should vibrate. If measured 15 000, then it should vibrate „very strong“ and if 1240, then it should be very weak.

Does anyone have an idea, how i can do that? And if you can provide a solution, please explain it very clearly. Here is my code. If questions, please ask.

clear;
clc;
%% MATLAB
%% read file
%_________________________________________
[y,fs]=audioread('UnchainMyHeart.wav');
% audioread = read wav -file
% y = contains the audio signal
% fs = 44100
% 'UnchainMyHeart' = name of the wav-file
%_________________________________________
%% PARAMETER FOR STFT
%_________________________________________ 
t_seg=0.03; % length of segment in ms
fftlen = 4096; %FFT-Points

% Defining size of frequency bands
f_low= 1:200;    %lower frequencies
f_medium= 201:600;  %medium frequencies
f_high= 601:1000; %higher frequencies
%__________________________________________
%% CODE

segl =floor(t_seg*fs); 
windowshift=segl/2; 
% defining the size of the window shift
window=hann(segl); 
% apply hann function on segment length (30 ms)
window=window.'; 
% transpose vector
si=1; 
% defining start index
ei=segl; 
% defining end index

N=floor( length(y)/windowshift - 1);
% Calculates the number, how often the window has to shift
% until to length of the audio signal

f1=figure;
    % Generating new window

    f=0:1:fftlen-1;
    f=f/fftlen*fs;
    % defining frequency vector

    Ya=zeros(1,fftlen);

    ValuesOfYc = NaN(1,N);
    ValuesOfYd = NaN(1,N);
    ValuesOfYe = NaN(1,N);

    x =(1:N)*windowshift/fs;
    % defining x-axis

for m= 1:1:N 

    y_a = y(si:ei);
    % a segment is taken out from audio signal length(30ms) 
    y_a= y_a.*window;
    % multiplying segment with window (hanning) 
    Ya=fft(y_a, fftlen);
    % Applying fft on segment
    Yb=abs(Ya(1:end/2)).^2;  
    % Squaring the magnitudes from one-sided spectrum

        drawnow; % Updating the graphical values

    figure(f1);
    % Showing the power values

    %% frequency bands

    y_low = Yb(f_low);  % LOW frequency spectrum
    y_medium = Yb(f_medium); % MEDIUM frequency spectrum
    y_high = Yb(f_high); % HIGH frequency spectrum

    Yc=sum(y_low);
    Yd=sum(y_medium);
    Ye=sum(y_high);
    % Summing all the power values from one frequency spectrum together
    % so you get one power value from one spectrum 
    ValuesOfYc(m) = Yc;
    ValuesOfYd(m) = Yd;
    ValuesOfYe(m) = Ye;
    %Output values are being saved here, which are generated from the for
    %loop
    % m = start variable from for loop

    subplot(2,1,1)
    p=plot(x,ValuesOfYc,'r-');%,x, ValuesOfYd,'g-', x, ValuesOfYe,'b-' );  
    p(1).LineWidth =0.5;
    xlabel('time (Audio length)')
    ylabel('Power')
    grid on

    subplot(2,1,2)
    p=plot(x, ValuesOfYd,'g-', x, ValuesOfYe,'b-' );
    p(1).LineWidth =0.5;
    xlabel('time (Audio length)')
    ylabel('Power')
    grid on

    si=si+windowshift; 
    % Updating start index 
    ei=ei+windowshift; 
    % Updating end index


end
$\endgroup$
  • $\begingroup$ Since i cannot add a comment here, i will write an answer instead. First thank you very much, for going in depth. I apologize, if my question was confusing, but I appreciate it, for providing me a solution. I look into it and try it out myself. Thank you very much! $\endgroup$ – CidelFastro Feb 20 '17 at 7:32
1
$\begingroup$

I'm assuming the long-term goal is to make all of this work on the Arduino, not with matlab. If your question is about how to send a value from matlab to the Arduino, I'd argue that this is a general programming or arduino problem – and for the first, StackOverflow.com would be the right address, for the second arduino.stackexchange.com.

So I'm concentrating on the DSP aspects at hand:

If you want three bands only, there's absolutely no benefit in doing a 4096-FFT. Since your smallest band consists of 200 bins, you can simply use a $\frac{4096}{200}\approx 20$-point FFT without significant precision loss. In fact, since you don't care about $\frac 34$ of your spectrum, I'd argue that you'd begin with a halfband filter that throws out all frequencies above $\frac{f_\text{sample}}2$ and decimates by a factor of 2, then build an extremely relaxed filter for each of your passbands, and then simply square the samples passing through each of these, and low-pass filter these again (for averaging).

The resulting 1 halfband (halfing the rate) + 3x channel (each also halfing the rate) + 3x averaging filters (each probably reducing the rate to $\frac1{100}$) will be far easier to implement on a system like the arduino, and not hard in matlab, either.

The comparison of the energy values should be straightforward. As soon as you've found a measure for how much your system should vibrate, you'd just program that value as the duty cycle of your Arduino's PWM unit.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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