📄 286-293.html
字号:
<HTML>
<HEAD>
<META name=vsisbn content="1558515682"><META name=vstitle content="Java Digital Signal Processing"><META name=vsauthor content="Douglas A. Lyon"><META name=vsimprint content="M&T Books"><META name=vspublisher content="IDG Books Worldwide, Inc."><META name=vspubdate content="11/01/97"><META name=vscategory content="Web and Software Development: Programming, Scripting, and Markup Languages: Java"><TITLE>Java Digital Signal Processing:Digital Audio Transform Recipes</TITLE>
<!-- HEADER --><STYLE type="text/css"> <!-- A:hover { color : Red; } --></STYLE><META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
<!--ISBN=1558515682//-->
<!--TITLE=Java Digital Signal Processing//-->
<!--AUTHOR=Douglas A. Lyon//-->
<!--PUBLISHER=IDG Books Worldwide, Inc.//-->
<!--IMPRINT=M & T Books//-->
<!--CHAPTER=6//-->
<!--PAGES=286-293//-->
<!--UNASSIGNED1//-->
<!--UNASSIGNED2//-->
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="282-286.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="293-300.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<P><BR></P>
<H4 ALIGN="LEFT"><A NAME="Heading18"></A><FONT COLOR="#000077">A Noise Filter Using the FFT</FONT></H4>
<P>The basic idea of providing a noise filter is that you begin with a signal, add noise, perform an FFT on the signal, remove all spectral harmonics that have a PSD below some threshold, and then take the IFFT. Selecting the PSD threshold for noise can be tricky. What works well on a synthetic sound might turn a sampled sound into silence.
</P>
<P>There are limits to the amount of noise that can be filtered out. A block diagram of the process appears in Figure 6.7. The following code adds noise to the waveform stored in the <I>AudioFrame</I> instance.</P>
<P><A NAME="Fig7"></A><A HREF="javascript:displayWindow('images/06-07.jpg',330,58 )"><IMG SRC="images/06-07t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/06-07.jpg',330,58)"><FONT COLOR="#000077"><B>Figure 6.7</B></FONT></A> The noise filter.</P>
<!-- CODE SNIP //-->
<PRE>
public void addNoise() {
double r_d[] = getDoubleData();
for (int i = 0; i< r_d.length; i++)
r_d[i] = r_d[i] + 0.1*(Math.random() -0.5);
ulc = new UlawCodec(r_d);
}
</PRE>
<!-- END CODE SNIP //-->
<P>The <I>Math.random</I> method returns a random value between zero and 1. Thus, the sampled data is summed with time-domain uniformly distributed noise (also known as <I>white noise</I>) that varies from -0.10 to 0.10. The following code performs a PSD-based cutoff after taking the FFT of the sound samples:</P>
<!-- CODE //-->
<PRE>
public void removeNoise() {
double noisePowerCutoff = 0.05;
fftInstance = new FFT();
double r_d[] = getTruncatedDoubleData();
double i_d[] = new double[r_d.length];
fftInstance.forwardFFT(r_d, i_d);
double psd[] = fftInstance.computePSD();
for (int i = 0; i < psd.length; i++) {
if (psd[i] < noisePowerCutoff) {
r_d[i] = 0;
i_d[i] = 0;
}
}
fftInstance.reverseFFT(r_d,i_d);
ulc = new UlawCodec(r_d);
ulc.play();
}
</PRE>
<!-- END CODE //-->
<P>The <I>removeNoise</I> and <I>addNoise</I> methods are placed under interactive user control via the main menu bar entries:</P>
<!-- CODE SNIP //-->
<PRE>
MenuItem addNoise_mi = addMenuItem(m,”[A] Add Noise”);
MenuItem removeNoise_mi = addMenuItem(m,”[R] Remove Noise”);
</PRE>
<!-- END CODE SNIP //-->
<P>The initial waveform is a sine wave of 400 Hz. A graph of the sine wave with PSD is shown in Figure 6.8.
</P>
<P><A NAME="Fig8"></A><A HREF="javascript:displayWindow('images/06-08.jpg',395,202 )"><IMG SRC="images/06-08t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/06-08.jpg',395,202)"><FONT COLOR="#000077"><B>Figure 6.8</B></FONT></A> Graph of the sine tone at 400 Hz with PSD.</P>
<P>Figure 6.9 shows the sine wave after noise is added.
</P>
<P><A NAME="Fig9"></A><A HREF="javascript:displayWindow('images/06-09.jpg',107,201 )"><IMG SRC="images/06-09t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/06-09.jpg',107,201)"><FONT COLOR="#000077"><B>Figure 6.9</B></FONT></A> Sine wave after the addition of noise.</P>
<P>The PSD of the sine wave plus noise is shown in Figure 6.10.
</P>
<P><A NAME="Fig10"></A><A HREF="javascript:displayWindow('images/06-10.jpg',312,262 )"><IMG SRC="images/06-10t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/06-10.jpg',312,262)"><FONT COLOR="#000077"><B>Figure 6.10</B></FONT></A> The PSD of the sine wave plus noise.</P>
<BLOCKQUOTE>
<P><FONT SIZE="-1"><HR><B>NOTE: </B>Figure 6.10 shows the clean spectral break between the noise and the sine wave. The removal of noise from such a waveform is performed with a trivial frequency-based amplitude detector.<HR></FONT>
</BLOCKQUOTE>
<P>Figure 6.11 should be the reconstructed sine wave with its PSD. Nose removal is not nearly as straight forward when waveforms have complex harmonic content.
</P>
<P><A NAME="Fig11"></A><A HREF="javascript:displayWindow('images/06-11.jpg',328,135 )"><IMG SRC="images/06-11t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/06-11.jpg',328,135)"><FONT COLOR="#000077"><B>Figure 6.11</B></FONT></A> The reconstructed waveform and its PSD.</P>
<H3><A NAME="Heading19"></A><FONT COLOR="#000077">Spectral Leakage of the DFT</FONT></H3>
<P>Recall that in Equation 6.6 we can compute the frequency of the kth sample of a spectrum.
</P>
<P ALIGN="CENTER"><IMG SRC="images/06-56d.jpg"></P>
<P>For example, when the number of samples, <I>N</I> = 2,048, the smallest change in frequency is 8,000/2,048 = 3.9 Hz. For the spectrum shown in Figure 6.5, the central point is given by <I>N/</I>2 = 2,048/2 = 1,024. By Equation 6.6, therefore, we compute the highest frequency that can be represented by 2,048 samples (with 8KHz sampling rate) as (8,000/2,048) *1,024 = 4,000 Hz. Also, we can solve for any sample using Equation 6.25:</P>
<P ALIGN="CENTER"><IMG SRC="images/06-57d.jpg"></P>
<P>(6.25)
</P>
<P>Thus, for the 400-Hz saw wave spectrum shown in Figure 6.8, we expect the maximum amplitude to occur at <I>k</I> = <I>Nf<SUB>k</SUB></I> / <I>f<SUB>s</SUB></I> = 2,048*400/8,000 = 102.4. How can the FFT (or DFT, for that matter) represent energy at <I>k</I> = 102.4? The answer is that the energy is spread around <I>k</I>=102 and 103. Often the <I>k</I>th array element in the frequency domain is referred to as a frequency <I>bin</I>. Because the 400-Hz tone is in both bins 102 and 103, the phenomenon is called <I>spectral leakage</I>. The problem with spectral leakage is that it is different for different frequencies. For example, at 390.625 Hz, <I>k</I> = 2,048*390.625/8,000 = 10, <I>exactly</I>. Thus, there is no spectral leakage for some frequencies, and a great deal of spectral leakage for others. This is the frequency-domain rationale for spectral leakage.</P>
<P>The time-domain rationale for spectral leakage is that, for a waveform that is not periodic in time, the temporal effect of the sample window becomes visible in the Fourier transform [Walker].</P>
<P>A common procedure known as <I>windowing</I> predistorts the input samples so that the spectral leakage is evened out (spreading on-bin signals more and off-bin signals less). Windowing is typically performed with one of a variety of possible filters (Cesáro, Hann, Hamming, Parzen, Welch, and so on). It is beyond the scope of this book to cover all the filters. The popular Hann filter is applied in the sample domain by a complex multiplication. When the input signal is real (as in audio), only a single multiplication is required. The equation for the Hann filter is as follows:</P>
<P ALIGN="CENTER"><IMG SRC="images/06-58d.jpg"></P>
<P>(6.26)
</P>
<P>Figure 6.12 shows a 256-sample version of the Hann window, in the frequency domain, generated by the DiffCAD program.</P>
<P><A NAME="Fig12"></A><A HREF="javascript:displayWindow('images/06-12.jpg',244,224 )"><IMG SRC="images/06-12t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/06-12.jpg',244,224)"><FONT COLOR="#000077"><B>Figure 6.12</B></FONT></A> The Hann window.</P>
<P>The main point of windowing is that it reduces the amplitude of the samples at the beginning and end of the window. The following code, from the <I>AudioFrame</I> class, will make and graph the Hann window:</P>
<!-- CODE SNIP //-->
<PRE>
public void makeHann() {
double window[];
window = makeHann(256);
Graph.graph(window,
“The Hann window”,”f”);
}
</PRE>
<!-- END CODE SNIP //-->
<P>The method returns an array of doubles that can be stored for later use, permitting reuse of the window for production code.
</P>
<!-- CODE //-->
<PRE>
public double[] makeHann(int n) {
double window[] = new double[n];
double arg = 2.0 * Math.PI/ (n - 1);
for (int i = 0; i < n; i++)
window[i] = 0.5 - 0.5 * Math.cos(arg*i);
return window;
}
</PRE>
<!-- END CODE //-->
<P>To apply the window to the samples, we have devised a <I>windowArray</I> method in the <I>AudioFrame</I> class:</P>
<!-- CODE //-->
<PRE>
public void multHann() {
double[] r_d = getTruncatedDoubleData();
double[] window = makeHann(r_d.length);
windowAudio(r_d, window, “hann”);
}
public void windowArray(double window[],double r_d[]) {
for (int i = 0; i < window.length; i++) {
r_d[i] *= window[i];
}
}
</PRE>
<!-- END CODE //-->
<P>The primary difference between the various windows is the way a window tapers off at the ends of the samples. The Bartlett window (Figure 6.13) is a linear window that is described by
</P>
<P><A NAME="Fig13"></A><A HREF="javascript:displayWindow('images/06-13.jpg',184,219 )"><IMG SRC="images/06-13t.jpg"></A>
<BR><A HREF="javascript:displayWindow('images/06-13.jpg',184,219)"><FONT COLOR="#000077"><B>Figure 6.13</B></FONT></A> The Bartlett window.</P>
<P ALIGN="CENTER"><IMG SRC="images/06-59d.jpg"></P>
<P>(6.27)
</P><P><BR></P>
<CENTER>
<TABLE BORDER>
<TR>
<TD><A HREF="282-286.html">Previous</A></TD>
<TD><A HREF="../ewtoc.html">Table of Contents</A></TD>
<TD><A HREF="293-300.html">Next</A></TD>
</TR>
</TABLE>
</CENTER>
<hr width="90%" size="1" noshade><div align="center"><font face="Verdana,sans-serif" size="1">Copyright © <a href="/reference/idgbooks00001.html">IDG Books Worldwide, Inc.</a></font></div>
<!-- all of the reference materials (books) have the footer and subfoot reveresed --><!-- reference_subfoot = footer --><!-- reference_footer = subfoot --></BODY></HTML><!-- END FOOTER -->
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -