Sunday, December 15, 2013

Final Post: Matlab Simulation Results

Hey guys, here is the final post for this semester project.

As I mentioned in my last post, I needed to do some Matlab simulations to wrap this thing up. It took a long time and a lot of help from my professor and a kind graduate student at school but I got some pretty cool results!

I had already decided to utilize the Matlab function "butter" and "filter" to accomplish the task at hand, that being to vary the cutoff frequency of the filter as the signal is passed through the circuit.

Here's how these two functions filter a signal. "butter" receives a cutoff frequency and generates two filter coefficients, named a and b. "filter" takes these coefficients and applies them to a signal. The problem is that "butter" only generates two coefficients for one specific cutoff frequency. No good if I want a changing cutoff frequency. Well I was thinking I would need to implement a loop of some kind to generate a whole heap of coefficients. This is exactly what my professor advise! Yay for having some intuition for this stuff...

So once I implement a loop to generate (and store in a vector, by the way) a whole heap of coefficients, I need to apply all of these to "filter." I needed to know how filter worked. Well Matlab's handy dandy "help" function proved useful as it explained that the function, "filter," is nothing more than a difference equation. That equation being (for a 1st order butterworth filter):

     a(1)*y(n) = b(1)*x(n) + b(2)*x(n-1) - a(2)*y(n-1)

I have no practical understanding of how or why this equation filters a signal but it's what Matlab said and I was going to roll with it. Haha!

So all that was left to do is create another loop that would apply all of those coefficients from "butter" and playback the resulting sound.

So I am not very familiar with Matlab. I've had a few projects at school but I haven't spent extensive time in it. I knew I needed loops but I wasn't sure how to write them! Thankfully a kind friend at school offered to help. Together, we were able to write code that receives an input wave file, applies a filter with a linearly increasing cutoff frequency, and play back the sound. I flipped out when it worked. Who knew you could do this kind of stuff with Matlab? I didn't till now.

Once the ball was rolling I wanted to do some cool stuff like vary the cutoff frequency sinusoidally. Turns out it was not that hard to do! At first, all I did was stick a sine function in front of the cutoff frequency variable inside the loop. However, sine would eventually generate negative frequencies which "butter" did not like. After a minute of thinking I figured it would be easiest to simply get the absolute value of the sine so those negatives would go away. Bam! That worked just fine.

So, my final code varied the cutoff frequency three different ways. My code also generated plots of those variations and created wave files to playback. Below are those results and the code.

Here is the original guitar clip I recorded direct into my Digital Audio Workstation (Reason 6.0!) and exported as a wave file: https://soundcloud.com/visorakmark/ampharos-original-unfiltered

First, I simply "opened up" the filter as time passed.
Here is the resulting sound: https://soundcloud.com/visorakmark/ampharos-linear-increase




Then I applied a sinusoid to the cutoff frequency.
Here is the resulting sound: https://soundcloud.com/visorakmark/ampharos-sinusoidal-variation



Finally, I applied an increasing sinusoid to the cutoff frequency.
Here is the resulting sound: https://soundcloud.com/visorakmark/ampharos-increasing-sinusoid



And here's the code. Note if you try to run this it will take several minutes to execute.

------------------------------------------------------------


% Ampharos_LPF
% This program applies an "opening" low pass filter to a wave file,
% meaning the cutoff frequency of the filter is changed as the filter
% is applied to the signal. This results in a "fading in" of the sound.
% Note that this is not the same as overall signal gain control, but a
% filtering of higher frequencies. As the wave file is played, more higher
% frequencies are allow to pass through and the sound "opens up." The
% cutoff Frequency is also vaired sinusoidaly and varied with an increasing
% sinusoid.
%
% These processes are accomplished through a "brute force" implementation of
% the Matlab function called "filter." "filter" applies two variables to a
% signal. These variables are generated using the Matlab function
% "butterworth." "butterworth" recieves a cutoff frequency and generates two
% variables that can be applied to a signal to filter specific
% frequencies.

% This program requires the cutoff frequency of the filter to
% change with time. "butter" and "filter" cannot accomplish this task
% alone. Considering 'butter" generates two filter variables for a
% specific frequency, a loop is used to generate and store multiple filter
% frequencies. A loop is then used to apply the generated cutoff
% frequencies to the signal. Finally, the signal is played back.

%This process is executed three seperate times, each time applying a
%different type of cutoff frequency variation.


% The wav file is read into Matlab
[x fs]=wavread('MarkGuitar.wav');

%play original signal
sound(x,fs)

%The butterworth loop variables are set up
count=0;
minFc=1;
inc=1;
maxFc=(1+minFc+length(x).*inc);

    %This section of code applies a linearly increasing filter to the signal
    for Fc=minFc:inc:maxFc

        count=count+1

        w = Fc/(2*fs); % Normalized frequency
        [b,a]=butter(1,w,'low'); %1st order butterworth LPF
        PlotFreq(count)=Fc;

        % This loop has been generalized to take any order butterworth filter,
        % hence the length(a) and length(b). coefA and coefB also store the
        % recieve Fc and w for reference.
        coefA(count,1:length(a))=a;
        coefA(count,length(a)+1)=Fc;
        coefA(count,length(a)+2)=w;

        coefB(count,1:length(b))=b;
        coefB(count,length(b)+1)=Fc;
        coefB(count,length(b)+2)=w;

    end
 
% Access filter variables
Avalues=coefA(:,1:2);
Bvalues=coefB(:,1:2);

% Apply filter variables to signal x.
Y=getOut(Avalues,Bvalues,x,fs);

% Plot Fc vs count to vizualize how the cutoff frequency was varied during
% variable generation
figure(1)
plot(PlotFreq)
title('Linearly Increasing Cutoff Frequency Variation');
xlabel('time');
ylabel('cutoff frequency');

%Play filtered signal
sound(Y,fs)






%Reset variables for second filtering implementation
count=0;
minFc=1;
inc=1;
maxFc=(1+minFc+length(x).*inc);

    %For constant sinusoidal filtering%
    for i=minFc:inc:maxFc

        count=count+1

        Fc = 20000;
        Fc = abs(sin(0.0005*i))*Fc;
        PlotFreq(i)=Fc;
        w = Fc/(2*fs); % Normalized frequency  w = (sin(count)*w
        [b,a]=butter(1,w,'low'); %1st order butterworth LPF

        % This loop has been generalized to take any order butterworth filter,
        % hence the length(a) and length(b). coefA and coefB also store the
        % recieve Fc and w for reference.
        coefA(count,1:length(a))=a;
        coefA(count,length(a)+1)=Fc;
        coefA(count,length(a)+2)=w;

        coefB(count,1:length(b))=b;
        coefB(count,length(b)+1)=Fc;
        coefB(count,length(b)+2)=w;

    end

% Access filter variables
Avalues=coefA(:,1:2);
Bvalues=coefB(:,1:2);

% Apply filter variables to signal x.
Y=getOut(Avalues,Bvalues,x,fs);

% Plot Fc vs time to vizualize how the cutoff frequency was varied during
% variable generation
figure(2)
plot(PlotFreq)
title('Sinusoidal Cutoff Frequency Variation');
xlabel('time');
ylabel('cutoff frequency');

%Play filtered signal
sound(Y,fs)






%Reset variables for second filtering implementation
count=0;
minFc=1;
inc=1;
maxFc=(1+minFc+length(x).*inc);

    %This section of code applies an increasing sinusoidal filtering to the
    %signal
    for Fc=minFc:inc:maxFc

        count=count+1
        Fc = abs(sin(0.0005*count))*Fc;
        PlotFreq(count)=Fc;
        w = Fc/(2*fs); % Normalized frequency  w = (sin(count)*w
        [b,a]=butter(1,w,'low'); %1st order butterworth LPF

        % This loop has been generalized to take any order butterworth filter,
        % hence the length(a) and length(b). coefA and coefB also store the
        % recieve Fc and w for reference.
        coefA(count,1:length(a))=a;
        coefA(count,length(a)+1)=Fc;
        coefA(count,length(a)+2)=w;

        coefB(count,1:length(b))=b;
        coefB(count,length(b)+1)=Fc;
        coefB(count,length(b)+2)=w;

    end

% Access filter variables
Avalues=coefA(:,1:2);
Bvalues=coefB(:,1:2);

% Apply filter variables to signal x.
Y=getOut(Avalues,Bvalues,x,fs);

% Plot Fc vs time to vizualize how the cutoff frequency was varied during
% variable generation
figure(3)
plot(PlotFreq)
title('Increasing Sinusoidal Cutoff Frequency Variation');
xlabel('time');
ylabel('cutoff frequency');

%Play filtered signal
sound(Y,fs)

------------------------------------------------------------

And here are those functions I called above:

------------------------------------------------------------
function y=FilterApply(a,b,x,y,sigInd,filtInd)

term1(sigInd)=(b(filtInd,1).*x(sigInd))./a(filtInd,1);
term2(sigInd)=(b(filtInd,2).*x(sigInd-1))./a(filtInd,1);
term3(sigInd)=a(filtInd,2).*y(sigInd-1)./a(filtInd,1);

y(sigInd)= term1(sigInd)+term2(sigInd)-term3(sigInd);

------------------------------------------------------------
function Y=getOut(a,b,X,fs)

% This is essentially the Matlab function "filter" but now able to
% recieved multiple filter variables and apply them. Note this function
% utilizes the mathematical definition for the filter function to apply
% the variables to the singal.

% Given
%     signal X (length n)
%     coef matrix a & b
%     fs = 44100
%     signal y previous
%     signal y at n==1

Y=zeros(1,length(X));
filtInd=2;
for sigInd=2:1:length(X)
    out=FilterApply(a,b,X,Y,sigInd,filtInd);
    Y(sigInd)=out(sigInd);
    filtInd=filtInd+1;
end

------------------------------------------------------------

And that's a wrap! Been a great semester of learning. Hope you all enjoyed following along. Perhaps I will continue this project down the road. Who knows. For now I'm going on break and will see you later.

-Mark

No comments:

Post a Comment