1. Write a program (in C/C++) to design a FIR low pass filter. The program should ask for the number of taps, sampling frequency, the cut-off frequency and whether windowing is to be used. Choose a suitable window.
The C++ programming language was chosen to complete the objectives outlined for this assignment. The FIR low pass filter was created through research of similar implementations in books, notes and web based examples. The program was compiled using Visual Studio.
F.I.R. filters (Finite Impulse Response) are implemented using a finite number “n” delay taps on a delay line and “n” computation coefficients to compute the algorithm (filter) function. They can offer shape, factor accuracy and stability equivalent to very high-order linear active filters that cannot be achieved in the analogue domain.
FIR filters can create transfer functions that have no equivalent in linear circuit technology. FIR filters are formed with only the equivalent of zeros in the linear domain. This means that the taps depress or push down the amplitude of the transfer function. The amount of depression for each tap depends upon the value of the multiplier coefficient. Hence, the total number of taps determines the “steepness” of the slope. More taps increase the steepness of the filter roll-off while increasing calculation time (delay) and for high order filters, limiting bandwidth. There is tradeoff between phase delay and filter precision when designing FIR filters.
Filter Design:
For my filter, I have utilized the Windowing and the Hanning Technique.
Windowed Filter:
The simplest technique is known as “Windowed” filters. This technique is based on designing a filter using well-known frequency domain transition functions called “windows”. The use of windows often involves a choice of the lesser of two evils. Some windows, such as the Rectangular, yield fast roll-off in the frequency domain, but have limited attenuation in the stop-band along with poor group delay characteristics. Other windows like the Blackman, have better stop-band attenuation and group delay, but have a wide transition-band (the band-width between the corner frequency and the frequency attenuation floor). Windowed filters are easy to use, are scalable (give the same results no matter what the corner frequency is) and can be computed on-the-fly by the DSP.
Rectangular windowing is a simple multiplication by 0 or 1, the impulse response is cut to zero at the point the window stops. In this example the window is the size of the entire filter effectively making no difference to the output.
w(n) = 1
Hanning Window:
The “Raised Cosine” window uses a similar technique although the coefficient is calculated differently.
To determine the coefficients and fill the coefficients array, requires the “Nyquist Frequency” of the filter.
H(Θ) is the frequency response as a function of the Nyquist frequency. Using a discrete inverse Fourier transform the coefficients for a low pass filter can be described as:
The code for my filter is contained in Appendix A.
filter.cpp is the main application source file.
filter.h is the header file.
main.cpp has the entry point for the program. In that object of filter, a class is created
and filtering is called to start the filtering.
2. Use your program to design a filter (i)with and (ii)without windowing, whose number of taps is equal to the last two digits of your id number. The sampling frequency is to be 8000Hz and cut off frequency is 200Hz.
For this part, I used 101 as my number of taps, my id ends in 00 so I added 101.The graphs are plotted using Microsoft Excel. The function CalCoeff(), calculates the coefficients and these are displayed using the display() function. The code for my filter is contained in Appendix A.
(i) With Hanning Window
Phase Response:
Figure 1 – Phase Response with windowing
Appendix B gives the values used to calculate this graph.
Amplitude Response:
Purple indicates the use of Hanning windowing.
Blue indicates without the use of windowing.
Figure 2 – Amplitude Response with and without windowing
Appendix B gives the values used to calculate this graph.
(ii) Without Windowing:
Phase Response:
Figure 3 – Phase Response without Windowing
Appendix B gives the values used to calculate this graph.
Amplitude Response:
Please see Figure 2.
Appendix B gives the values used to calculate this graph.
3. Write a program (in C/C++) to calculate the frequency response (Amplitude & Phase) of a digital filter and use it to plot the frequency response of the filters you designed in 2. Compare the responses (Amplitude & Phase).
For this part, I added FreqResponse() function to the program which calculates the Amplitude & Phase response. The calculated phase response and amplitude response values are stored in phase.txt and amp.txt respectively. The code for my filter is contained in Appendix A.
Figure 4 – Phase Response of Filter designed in Part 2
Figure 5 – Amplitude Response of Filter designed in Part 2
4. Make a file of about 400 samples [at 8kHz] of your own speech waveform.[try to get the transition between a fricative (like "sh") and a vowel (like "a")]. Plot the original waveform, process it through your filter and plot the resultant output. Compare the input and output signals. What is the time shift between the input and output? Why?
I created a file at 8kHz using the word “shark” to create the waveform beneath. The results used to calculate Figure 6 and 7 are contained in Appendix C. There is a time shift between input & output signal, as the speech signal passes through the filter. The filtered output is longer than the input signal by no of taps chosen – in our case 100 (101 – 1). So, time shift = 100.
I changed the CalCoeff() function of my previous program to write coefficients to a file.
void Filter::CalCoeff()
{
//Allocate memory for coefficients
p_mcoeff = new double[m_tap];
ofstream coeffFile;
coeffFile.open (“C:\coeff.txt”);
int i=1,count;
//To keep our filter causal, shift the centre of it to the middle of taps.
if(m_tap%2 == 0)
{
count = (m_tap – 1)>>1;
}
else
{
count = m_tap >> 1;
}
//Calculate centre value of coefficient.
p_mcoeff[count] = m_nqFreq/PI;
//Calculate remaining values of coefficient.
while(i<=count)
{
p_mcoeff[count-i]=sin(i*m_nqFreq)/PI/i;
p_mcoeff[count+i]=p_mcoeff[count-i];
i++;
}
coeffFile<<m_tap<<” “;
for(i=0;i<m_tap;i++)
{
Then I processed the coefficients of my filter and my waveform through the new filter. This is contained in Appendix B. The same coefficients are used in Part 5. It utilizes the same header file. I edited the main file to prompt the user to input files. This is contained in Appendix B. This filter performs 4 main tasks:
1. Reads the coefficients of filter from the specified .txt file.
2. Reads the samples of the speech signal from the specified .wav file.
3. Convolution of coefficients & samples.
4. Writes the output of the filtered signal in a file.
Figure 6 – Speech Waveform
Figure 7 – Output Waveform
5. Using Matlab, plot the spectrum of the input and output [of the vowel part of the] speech signals. Comment.
From the graphs, it can be seen that both signals have different levels of power. The filtered output can be seen in Figure 8.
The Matlab code used to complete this:
sound_data = wavread(‘C:\temp\part_4_voice.wav’);
filter_coeff = [0.00636938;0.00641538;0.00630221;0.00602589;0.00558612;0.00498633;0.00423384;0.00333978;0.00231904;0.00119006;-2.53607e-005;-0.00130248;-0.00261392;-0.00393023;-0.00522029;-0.006452;-0.00759278;-0.00861027;-0.00947294;-0.0101507;-0.0106157;-0.0108426;-0.0108094;-0.0104981;-0.00989464;-0.00898978;-0.00777917;-0.00626361;-0.00444919;-0.00234732;2.53607e-005;0.00264715;0.00549151;0.00852747;0.0117201;0.0150308;0.0184184;0.0218392;0.0252482;0.0285994;0.0318471;0.0349461;0.0378527;0.0405256;0.0429265;0.0450207;0.0467777;0.0481717;0.0491824;0.0497948;0.05;0.0497948;0.0491824;0.0481717;0.0467777;0.0450207;0.0429265;0.0405256;0.0378527;0.0349461;0.0318471;0.0285994;0.0252482;0.0218392;0.0184184;0.0150308;0.0117201;0.00852747;0.00549151;0.00264715;2.53607e-005;-0.00234732;-0.00444919;-0.00626361;-0.00777917;-0.00898978;-0.00989464;-0.0104981;-0.0108094;-0.0108426;-0.0106157;-0.0101507;-0.00947294;-0.00861027;-0.00759278;-0.006452;-0.00522029;-0.00393023;-0.00261392;-0.00130248;-2.53607e-005;0.00119006;0.00231904;0.00333978;0.00423384;0.00498633;0.00558612;0.00602589;0.00630221;0.00641538;0.00636938;];
filtered_output = conv(filter_coeff,sound_data);
fft_output = abs(fft(filtered_output));
fft_input = abs(fft(sound_data));
subplot(2,1,1), plot(fft_input,’red’);
xlabel(‘frequency’);
ylabel(‘Amplitude’);
title(‘Specturm of input speech signal’);
subplot(2,1,2),plot(fft_output,’blue’);
xlabel(‘frequency’);
ylabel(‘Amplitude’);
title(‘Specturm of output speech signal’);
Figure 8 – Input and Output Waveform
6. Construct a real – time implementation of your filter on the C31 DSK. Record a few seconds o your speech.
To complete this part, I had to write a C31 Assembler version of my filter. I used RFIR.ASM as a guide.
There were 3 main changes I made to this:
- TA .set 48.828
This had to be changed to 48.828 as the original sampling frequency was set too high.
- The Data buffer was changed to 128 bits(2^8) as I used 101 taps for my filter.
- The coefficients were changed to the values of my filter.
;———————————————————
; FIR.ASM
; Keith Larson
; TMS320 DSP Applications
; (C) Copyright 1995,1996
; Texas Instruments Incorporated
;
; This is unsupported freeware with no implied warranties or
; liabilities. See the disclaimer document for details
;
; The FIR filter code used in this example is taken
; from the TMS320C3x Users Guide. The AIC setup and
; control is designed to work with the TMS320C31 DSK
;
; This example can either be loaded and run from the debugger
; or by directly loading and running from DSK3LOAD
;———————————————————
;
; How to change the sampling frequency.
;
; [Ronan Scaife, DCU, October 17th 2001]
;
; By changing either TA/TB and RA/RB in the AIC,
; OR by changing the figures for the C31 timer
; see the section of code labelled “ST-STUB”
; below, you can change the sampling frequency.
; The default settings in Keith Larsen’s
; original version give fS ~ 48,828 s/s.
; For more interesting effects, I have modified
; TA and RA to 16 to reduce fS to 24,414 s/s.
;
; Edited By Sameer Kumar
;———————————————————
;
; Define constants used by program ;
;TA .set 8 ; AIC timing register values
TA .set 48.828 ; AIC timing register values/this value must be changed as the original sampling frequency is too high
TB .set 16 ;
;RA .set 8 ;
RA .set 16 ;
RB .set 16 ;
GIE .set 0×2000 ; This bit in ST turns on interrupts
.include “C3XMMRS.ASM” ;
;
; change start addr for WinDSK [RS 8-x-01]
;
; .start “AICTEST”,0×809820 ; Start assembling here
.start “AICTEST”,0×809900 ; Start assembling here
.sect “AICTEST” ;
;- – - – - – - – - – - – - – - – - – - – - – - – - – - – - – -
; 128 bit float data buffer of incoming data from the AIC
; The location in memory must be on a 2^N boundary and the
; size of the coefficeint table must be the same as the data
; Taps for my filter = 101, therefore 128 bit data buffer must be utilised
;- – - – - – - – - – - – - – - – - – - – - – - – - – - – - – -
ADC_recv .float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
.float 0.0 ;
;- – - – - – - – - – - – - – - – - – - – - – - – -
; FIR filter coefficients
;- – - – - – - – - – - – - – - – - – - – - – - – -
FIR_coef .float 0.00636938
.float 0.00641538
.float 0.00630221
.float 0.00602589
.float 0.00558612
.float 0.00498633
.float 0.00423384
.float 0.00333978
.float 0.00231904
.float 0.00119006
.float -2.53607e-005
.float -0.00130248
.float -0.00261392
.float -0.00393023
.float -0.00522029
.float -0.006452
.float -0.00759278
.float -0.00861027
.float -0.00947294
.float -0.0101507
.float -0.0106157
.float -0.0108426
.float -0.0108094
.float -0.0104981
.float -0.00989464
.float -0.00898978
.float -0.00777917
.float -0.00626361
.float -0.00444919
.float -0.00234732
.float 2.53607e-005
.float 0.00264715
.float 0.00549151
.float 0.00852747
.float 0.0117201
.float 0.0150308
.float 0.0184184
.float 0.0218392
.float 0.0252482
.float 0.0285994
.float 0.0318471
.float 0.0349461
.float 0.0378527
.float 0.0405256
.float 0.0429265
.float 0.0450207
.float 0.0467777
.float 0.0481717
.float 0.0491824
.float 0.0497948
.float 0.05
.float 0.0497948
.float 0.0491824
.float 0.0481717
.float 0.0467777
.float 0.0450207
.float 0.0429265
.float 0.0405256
.float 0.0378527
.float 0.0349461
.float 0.0318471
.float 0.0285994
.float 0.0252482
.float 0.0218392
.float 0.0184184
.float 0.0150308
.float 0.0117201
.float 0.00852747
.float 0.00549151
.float 0.00264715
.float 2.53607e-005
.float -0.00234732
.float -0.00444919
.float -0.00626361
.float -0.00777917
.float -0.00898978
.float -0.00989464
.float -0.0104981
.float -0.0108094
.float -0.0108426
.float -0.0106157
.float -0.0101507
.float -0.00947294
.float -0.00861027
.float -0.00759278
.float -0.006452
.float -0.00522029
.float -0.00393023
.float -0.00261392
.float -0.00130248
.float -2.53607e-005
.float 0.00119006
.float 0.00231904
.float 0.00333978
.float 0.00423384
.float 0.00498633
.float 0.00558612
.float 0.00602589
.float 0.00630221
.float 0.00641538
.float 0.00636938 ; FIR filter coefficients
END_coef
;- – - – - – - – - – - – - – - – - – -
BufSz .set END_coef – FIR_coef
;- – - – - – - – - – - – - – - – - – -
SIZE .word BufSz ; Size of filter
ADC_first .word ADC_recv
ADC_end .word FIR_coef
ADC_last .word ADC_recv
FIR_coefx .word FIR_coef
;————————————
; Define some constant storage data
;————————————
A_REG .word (TA<<9)+(RA<<2)+0 ; A registers
B_REG .word (TB<<9)+(RB<<2)+2 ; B registers
C_REG .word 00000011b ; control
S0_gctrl_val .word 0x0E970300 ; Serial port control register values
S0_xctrl_val .word 0×00000111 ;
S0_rctrl_val .word 0×00000111 ;
;****************************************************
; Begin main code loop here
;****************************************************
main or GIE,ST ; Turn on INTS
ldi 0xF4,IE ; Enable XINT/RINT/INT2
b main ; Do it again!
;——————————-
DAC2 push ST ; DAC Interrupt service routine
push R0 ;
pushf R0 ;
push R2 ;
pushf R2 ;
push AR0 ;
push AR1 ;
ldi @ADC_last,AR1 ;
ldi @FIR_coefx,AR0 ;
ldi @SIZE,BK
FIR mpyf3 *AR0++,*AR1++(1)%,R0
ldf 0.0,R2
ldi @SIZE,RC
subi 2,RC
rptb FIR2
mpyf3 *AR0++,*AR1++(1)%,R0
FIR2 || addf3 R0,R2,R2
addf R2,R0
fix R0,R0
andn 3,R0 ;
sti R0,@S0_xdata ; Output the new DAC value
pop AR1 ;
pop AR0 ;
popf R2 ;
pop R2 ;
popf R0 ;
pop R0 ;
pop ST ;
reti ;
;——————————-
ADC2 push ST ;
push R3 ;
pushf R3 ;
push AR0 ;
ldi @S0_rdata,R3 ;
lsh 16,R3
ash -16,R3
ldi @ADC_last,AR0
float R3,R3
stf R3,*AR0++
cmpi @ADC_end,AR0
ldige @ADC_first,AR0
sti AR0,@ADC_last
pop AR0
popf R3 ;
pop R3 ;
pop ST ;
reti ;
;*****************************************************;
; The startup stub is used during initialization only ;
; and can be safely overwritten by the stack or data ;
;*****************************************************;
.entry ST_STUB ; Debugger starts here
ST_STUB ldp T0_ctrl ; Use kernel data page and stack
ldi @stack,SP
ldi 0,R0 ; Halt TIM0 & TIM1
sti R0,@T0_ctrl ;
sti R0,@T0_count ; Set counts to 0
ldi 1,R0 ; Set periods to 1
sti R0,@T0_prd ;
ldi 0x2C1,R0 ; Restart both timers
sti R0,@T0_ctrl ;
;———————
ldi @S0_xctrl_val,R0;
sti R0,@S0_xctrl ; transmit control
ldi @S0_rctrl_val,R0;
sti R0,@S0_rctrl ; receive control
ldi 0,R0 ;
sti R0,@S0_xdata ; DXR data value
ldi @S0_gctrl_val,R0; Setup serial port
sti R0,@S0_gctrl ; global control
;======================================================;
; This section of code initializes the AIC ;
;======================================================;
AIC_INIT LDI 0×10,IE ; Enable only XINT interrupt
andn 0×34,IF ;
ldi 0,R0 ;
sti R0,@S0_xdata ;
RPTS 0×040 ;
LDI 2,IOF ; XF0=0 resets AIC
rpts 0×40 ;
LDI 6,IOF ; XF0=1 runs AIC
;———————
ldi @C_REG,R0 ; Setup control register
call prog_AIC ;
ldi 0xfffc ,R0 ; Program the AIC to be real slow
call prog_AIC ;
ldi 0xfffc|2,R0 ;
call prog_AIC ;
ldi @B_REG,R0 ; Bump up the Fs to final rate
call prog_AIC ; (smallest divisor should be last)
ldi @A_REG,R0 ;
call prog_AIC ;
b main ; the DRR before going to the main loop
;——————————-
prog_AIC ldi @S0_xdata,R1 ; Use original DXR data during 2 ndy
sti R1,@S0_xdata ;
idle
ldi @S0_xdata,R1 ; Use original DXR data during 2 ndy
or 3,R1 ; Request 2 ndy XMIT
sti R1,@S0_xdata ;
idle ;
sti R0,@S0_xdata ; Send register value
idle ;
andn 3,R1 ;
sti R1,@S0_xdata ; Leave with original safe value in DXR
;———————
ldi @S0_rdata,R0 ; Fix the receiver underrun by reading
rets ;
stack .word $ ; Put stack here
;****************************************************;
; Install the XINT/RINT ISR handler directly into ;
; the vector RAM location it will be used for ;
;****************************************************;
.start “SP0VECTS”,0x809FC5
.sect “SP0VECTS”
B DAC2 ; XINT0
B ADC2 ; RINT0
7. Play back the original speech and the signal filtered by your filter. Listen carefully to both and comment on what you hear.
The signal filtered by my filter is muffled in comparison to the original speech. The ‘s’ part of ‘shark’ is barely audible.
Appendix A.
The code used for part 1, 2 and 3.
filter.h
//Author: Sameer Kumar
//Date: 22/11/2006
#include <iostream>
#include <math.h>
#include <fstream>
using namespace std;
class Filter
{
//number of taps
int m_tap;
//Cut-of frequency
int m_fc;
//Sampling frequency
int m_fs;
//Nyquist Frequency
double m_nqFreq;
//Array of coefficients
double *p_mcoeff;
//Take input parameters from prompt
void TakeArguments();
//Calculate coefficients
void CalCoeff();
//Apply windowing function to coefficients
void Windowing();
//Display coefficients
void Display();
//Calculate frequecncy response of FIR filter
void FreqResponse();
public:
//main function to do filtering
void Filtering();
//Destructor to delete memory allocated for coefficeints.
~Filter()
{
delete [] p_mcoeff;
};
};
main.cpp
//Author: Sameer Kumar
//Date: 22/11/2006
// main.cpp : Defines the entry point for the console application.
//
#include “filter.h”
int main(int argc, char* argv[])
{
Filter f;
f.Filtering();
return 0;
}
filter.cpp
//Author: Sameer Kumar
//Date: 22/11/2006
#include “filter.h”
const double PI = 3.14;
//Take input parameters from prompt
void Filter::TakeArguments()
{
//Take taps as a input parameter.
cout<<”Please enter number of taps”<<endl;
cin>>m_tap;
//Take cut-off frequecy as a input parameter
cout<<”Please enter the cut-off frequency”<<endl;
cin>>m_fc;
//Take sampling frequency as a input parameter.
cout<<”Please enter the sampling frequency”<<endl;
cin>>m_fs;
//Calculate nyquist frequency
m_nqFreq = 2 * PI * m_fc/m_fs;
}
//Calculate FIR coefficeints.
void Filter::CalCoeff()
{
//Allocate memory for coefficients
p_mcoeff = new double[m_tap];
int i=1,count;
//To keep our filter causal, shift the centre of it to the middle of taps.
if(m_tap%2 == 0)
{
count = (m_tap – 1)>>1;
}
else
{
count = m_tap >> 1;
}
//Calculate centre value of coefficient.
p_mcoeff[count] = m_nqFreq/PI;
//Calculate remaining values of coefficient.
while(i<=count)
{
p_mcoeff[count-i]=sin(i*m_nqFreq)/PI/i;
p_mcoeff[count+i]=p_mcoeff[count-i];
i++;
}
}
//Apply hanning window function to coefficients.
void Filter::Windowing()
{
for(int i = 0 ; i < m_tap ; i++)
{
double win_val = 0.5 – 0.5 * cos( 2*PI*(i+ 1)/(m_tap+1));
p_mcoeff[i] *= win_val;
}
}
//Display the coefficients of FIR filter.
void Filter::Display()
{
for(int i = 0 ; i < m_tap ; i++)
{
cout<<p_mcoeff[i]<<endl;
}
}
//Calculate frequecy response (Amplitude & Phase)
void Filter::FreqResponse()
{
int degree = 180;
ofstream ampFile,phaseFile;
//Open files to write amplitude and phase values.
ampFile.open (“amp.txt”);
phaseFile.open (“phase.txt”);
double temp;
for(int i=0;i<=degree;i++ )
{
double real=0,imag = 0;
double nqfreq = ((double) 2*i/degree -1)*PI;
//Calculate real and imaginary frequecies.
for(int j=0;j<m_tap;j++ )
{
int time = j – (m_tap – 1)/2;
real += p_mcoeff[j]*cos(time*nqfreq);
imag -= p_mcoeff[j]*sin(time*nqfreq );
}
if(nqfreq > 0)
{
//Calculate amplitude
temp = sqrt(pow(real,2) + pow(imag,2));
ampFile<<temp<<endl;
//Calculate phase.
temp = atan(imag/real);
phaseFile<<temp<<endl;
}
}
//Close txt files.
ampFile.close();
phaseFile.close();
}
//Do filtering
void Filter::Filtering()
{
bool window;
//Take input parameter
TakeArguments();
//Calculate coefficients
CalCoeff();
//Take input parameter for window selection
cout<< “Please Enter the windowing option”<<endl;
cout<<”0: No Window”<<endl;
cout<<”1: With Hanning Window”<<endl;
cout<<”2: With rectangular Window”<<endl;
cin>>window;
//Depending upon window option, select windowing function.
//For rectangular and no window option, w(n) = 1
if(window == 1)
{
Windowing();
}
Display();
FreqResponse();
}
Appendix B.
The code used for Part 4.
main.cpp
//Author: Sameer Kumar
//Date: 22/11/2006
#include “filter.h”
int main(int argc, char* argv[])
{
Filter fp;
char inFile[20],coeffFile[20];
//Take the coefficient file as argument.
cout<<”Please enter the coefficient file”<<endl;
cin>>coeffFile;
//Take the input wave file as argument.
cout<<”Please enter the input wave file”<<endl;
cin>>inFile;
try
{
//Do filtering
fp.Filtering(coeffFile,inFile);
}
catch(Exception e)
{
cout<<e.GetMessage()<<endl;
}
return 0;
}
filter.cpp
//Author: Sameer Kumar
//Date: 22/11/2006
#include “filter.h”
//Check wave header
void WavHeader::ConfirmHeader()
{
//Compares rID with “RIFF”
if(!((rID[0]==’R')||(rID[1]==’I')||(rID[2]==’F')||(rID[3]==’F')))
{
throw Exception(“Wrong RIFF Format”);
}
//Compares wID with “WAVE”
if(!((wID[0]==’W')||(wID[1]==’A')||(wID[2]==’V')||(wID[3]==’E')))
{
throw(“Wrong WAVE Format”);
}
//Compares fID with “fmt”
if(!((fId[0]==’f')||(fId[1]==’m')||(fId[2]==’t')))
{
throw(“Wrong fmt format”);
}
//Checks formatTag
if(wFormatTag!=1)
{
throw(“Wrong Wave Format tag”);
}
//Checks bits per sample with 16 & 8
if( (nBitsPerSample != 16) && (nBitsPerSample != 8) )
{
throw(“Wrong Bits per sample”);
}
}
//Checks whether chunk is data chunk or not
int ChunkHeader::IsDataChunk()
{
//Checks dID with “data”
if((dId[0]==’d') && (dId[1]==’a') && (dId[2]==’t')&& (dId[3]==’a'))
{
return 1;
}
return 0;
}
//Reads coefficients from file.
void Filter::ReadCoeff(char* fileName)
{
ifstream myfile (fileName);
if (myfile.is_open())
{
//Read length of coeffcients
myfile>>m_coeffLen;
//Allocate memory for coeffcients
m_coeff = new double[m_coeffLen];
//Reads all coefficients
for(int i=0;((i<m_coeffLen) && (!myfile.eof()));i++)
{
myfile>> m_coeff[i];
}
myfile.close();
}
else
{
throw(“Can not open coefficient file”);
}
}
//Read Input speech samples
void Filter::ReadSpeechInput(char *fileName)
{
ifstream::pos_type size;
char* memblock;
int index=0;
ifstream file (fileName, ios::in|ios::binary|ios::ate);
WavHeader *hdr = new WavHeader;
ChunkHeader *hdr1 = new ChunkHeader;
int chunkhdrSize = sizeof(ChunkHeader);
ofstream inFile;
inFile.open(“input.txt”);
if (file.is_open())
{
//Get the size of wav file
size = file.tellg();
//Allocate memory for memblock
memblock = new char [size];
file.seekg (0, ios::beg);
//reads all data from file
file.read (memblock, size);
file.close();
}
else
{
throw(“Unable to open file”);
}
//Read wave header
memcpy(hdr,memblock,sizeof(WavHeader));
//Check wave header
hdr->ConfirmHeader();
index = sizeof(WavHeader);
memblock += index;
// read chunks until a ‘data’ chunk is found
int data_chunk = 1;
while(index<(int)size)
{
if(data_chunk > 10)
{
throw(“Too many chunks”);
}
if(((int)size – index) > chunkhdrSize)
{
//read the chunk header
data_chunk++;
index +=chunkhdrSize;
memcpy(hdr1,memblock,chunkhdrSize);
memblock+=chunkhdrSize;
}
else
{
throw(“Wrong data”);
}
//Breaks the loop if , got data chunk
if(hdr1->IsDataChunk()==1)
{
break;
}
}
//Calculate the length of samples
m_inputLen = hdr1->dLen * 8/hdr->nBitsPerSample;
//Allocate memory for input samples
m_input = new double[m_inputLen];
//Reads data in m_input samples
if(hdr->nBitsPerSample == 16)
{
short *temp = (short*)memblock;
for(int i=0;i<m_inputLen;i++)
{
m_input[i] = (double)temp[i];
//Each 64th sample of sound is added to file.
if((i%64)== 0)
{
inFile<<m_input[i]<<endl;
}
}
}
else
{
unsigned char* temp = (unsigned char*) memblock;
for(int i=0;i<m_inputLen;i++)
{
m_input[i] = (double)temp[i];
//Each 64th sample of sound is added to file.
if((i%64)== 0)
{
inFile<<m_input[i]<<endl;
}
}
}
inFile.close();
}
//Convolution of two arrays
void Filter::convol()
{
//Calculate the length of output samples.
int outLen = m_inputLen + m_coeffLen -1;
m_output = new double[outLen];
ofstream outFile;
outFile.open(“output.txt”);
for(int i=0;i<outLen;i++)
{
m_output[i] = 0;
for(int j=0;j<m_coeffLen;j++)
{
if(((i-j)>=0) && ((i-j)<m_inputLen))
{
m_output[i]+=(m_input[i-j]*m_coeff[j]);
}
}
//Each 64th sample of sound is added to file.
if((i%64)== 0)
{
outFile<<m_output[i]<<endl;
}
}
outFile.close();
}
//Filter the input samples
void Filter::Filtering(char* coeffFile,char*wavFile)
{
//Read coefficients
ReadCoeff(coeffFile);
//Read input speech sample
ReadSpeechInput(wavFile);
//Convolution of two arrays
convol();
}