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

Saturday, December 7, 2013

Some Matlab Coding

Hey again readers, spent a couple of hours researching filter simulation in Matlab and got a few things figured out.

Right now my code uploads a wav, applies a 1st order butterworth low pass filter to it, and plays the filtered wav file back. That all is working fine. The challenge I am facing is somehow changing the cutoff frequency while the program is running so the sound "opens up and closes" during playback.

Here's how I'm approaching this right now:

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

This function samples (at the sample rate, fs) the wav file and stores those samples in the matrix x. x is a 2 by 37000ish matrix that contains a discrete representation of the wav file. I'm currently using a short ringtone for code testing as opposed to a full guitar track.

[x fs]=wavread('Bangarang_Phone.wav');

I then set my cutoff frequency whic for the filter U currently have is 900 hz.

Fc=900;

Then I use a butterworth function to implement a 1st order low pass filter.

w = Fc/(2*fs); % Normalized frequency
[b,a]=butter(1,w,'low'); %1st order butterworth LPF
y=filter(b,a,x); % pass the input signal through the filter

Then play the filtered sound

sound(y,fs)

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

That's what I have so far. I'm thinking I need to somehow implement a loop and change Fc as the filter is being applied. I just don't know how to do this though. That's for another hour!

More soon,

-Mark

Thursday, December 5, 2013

End of the Semester Matlab Simulation

Hey readers, finals are upon us and time is running out for this semester project. Obviously this thing is not ready to be placed in my amp so I will be writing some Matlab code and simulating what I've got so far.

First. I will simulate how I want the circuit to work. I'm going to record a short guitar track, import it into Matlab, and simulate a low pass filter. I'll vary the resistance to get the sweeping wah-wah effect I'v been looking for.

Next I'm going to simulate how the circuit is currently (not) working. Not entirely sure how to do this yet. We'll see what I can cook up over the week.

Expect one more post from me before the 16th of December!
-Mark