• Tidak ada hasil yang ditemukan

Reduksi Noise Dari Rekaman Suara Pernapasan Menggunakan Wavelet Transform Based Filter

N/A
N/A
Protected

Academic year: 2019

Membagikan "Reduksi Noise Dari Rekaman Suara Pernapasan Menggunakan Wavelet Transform Based Filter"

Copied!
14
0
0

Teks penuh

(1)

1.

Preprocess.java

public class Preprocess {

public static final int SAMPLE_RATE = 44100;

public static final double MAX_16_BIT = Short.MAX_VALUE;

/**

* Baca audio samples dari wav file dan kembalikan sebagai larik bertipe double

* dengan nilai antara -1.0 dan +1.0. *

* @return d */

public static double[] baca(String namafile) { byte[] data = bacaByte(namafile);

int N = data.length;

double[] d = new double[N/2]; for(int i=0; i<N/2; i++) {

d[i] = ((short) (((data[2*i+1] & 0xFF) << 8) + (data[2*i] &0xFF))) / ((double) MAX_16_BIT);

}

return d; }

/**

* Baca data dan kembalikan sebagai larik bertipe byte. *

* @return data */

private static byte[] bacaByte(String namafile) {

byte[] data = null;

AudioInputStream ais = null; try {

// Membaca file

File file = new File(namafile); if(file.exists()) {

ais = AudioSystem.getAudioInputStream(file);

data = new byte[ais.available()]; ais.read(data);

}

} catch (Exception ex) {

System.out.println(ex.getMessage());

throw new RuntimeException("Tidak dapat membaca " + namafile); }

return data; }

(2)

2.

SignalFilter.java

public class SignalFilter {

/** Koefisien untuk menandakan wavelet transform dengan berapa koefisien yang dipakai. */

public static final int DB_NO = 4;

/** Koefisien pertama Wavelet Transform Based Filter. */ public static final double k0 = (1+sqrt(3))/(4*sqrt(2));

/** Koefisien kedua Wavelet Transform Based Filter. */ public static final double k1 = (3+sqrt(3))/(4*sqrt(2));

/** Koefisien ketiga Wavelet Transform Based Filter. */ public static final double k2 = (3-sqrt(3))/(4*sqrt(2));

/** Koefisien keempat Wavelet Transform Based Filter. */ public static final double k3 = (1-sqrt(3))/(4*sqrt(2));

/**

* Method decomposition melakukan dekomposisi sinyal input menjadi dua bagian

* yang masing-masing bagian memiliki panjang setengah dari panjang sinyal input.

* Bagian pertama disebut low pass filter, sedangkan bagian kedua disebut high pass filter.

* Bagian low pass filter dapat didekomposisi lagi menjadi 2 bagian seperti sebelumnya.

* Iterasi dekomposisi ini dilakukan sebanyak level yang ditentukan. *

* @param si sinyal input yang akan didekomposisi. * @param level jumlah dilakukannya dekomposisi.

* @return sinyal yang didekomposisi yang dibangun oleh bagian low pass filter dan high pass filter,

* panjangnya sama dengan sinyal input. */

public static double[] decomposition(double[] si, int level) { int lth = si.length;

// Panjang matriks yang didekomposisi di suatu level int currentLevelLength = lth;

double[] result = new double[lth];

// Lakukan proses dekomposisi sebanyak level for(int i = 0; i < level; i++) {

double[] tmp = result.clone(); int index = 0;

// Lakukan dekomposisi

for(int j = 0; j < currentLevelLength; j+=2) { tmp[j] = k0*si[index] + k1*si[index+1] +

k2*si[(index+2)%currentLevelLength] + k3*si[(index+3)%currentLevelLength];

tmp[j+1] = k3*si[index] - k2*si[index+1] +

(3)

index+=2; }

index = 0;

result = tmp.clone();

// Atur output agar bagian low pass filter di setengah depan output // dan bagian high pass filter di setengah belakang output

for(int j = 0; j < currentLevelLength/2; j+=1) { result[index] = tmp[2*j];

result[index+currentLevelLength/2] = tmp[2*j+1];

index+=1; }

currentLevelLength = currentLevelLength / 2; si = result;

}

return result; }

/**

* Method getvbs melakukan threshold terhadap sinyal input dan memisahkan * sinyal suara pernapasan dan noise.

*

* @param si

* @return sinyal suara pernapasan */

public static double[] getvbs(double[] si) { int lth = si.length;

double t, sum = 0, sum2 = 0;

double[] tmp1 = si.clone();

double[] tmp2 = si.clone();

double[] tmp3 = si.clone();

double[] vbs = new double[lth];

double[] vn = new double[lth];

int x = 0, y = 0;

for(int i = 0; i < lth; i++) { sum += tmp1[i];

}

double mean = sum / lth;

for(int i = 0; i < lth; i++) {

tmp3[i] = (tmp2[i] - mean) * (tmp2[i] - mean); }

(4)

sum2 += tmp3[i]; }

double sd = Math.sqrt(sum2/lth);

// Hitung threshold

t = sd * sqrt((2 * Math.log(lth)));

for(int j = 0; j < lth; j++) { if(Math.abs(si[j]) >= t) { vn[x] = si[j];

x++; } else {

vbs[y] = si[j]; y++;

} }

return vbs; }

/**

* Method getvn melakukan threshold terhadap sinyal input dan memisahkan * sinyal suara pernapasan dan noise.

*

* @param si * @return noise */

public static double[] getvn(double[] si) { int lth = si.length;

double t, sum = 0, sum2 = 0;

double[] tmp1 = si.clone();

double[] tmp2 = si.clone();

double[] tmp3 = si.clone();

double[] vbs = new double[lth];

double[] vn = new double[lth];

int x = 0, y = 0;

for(int i = 0; i < lth; i++) { sum += tmp1[i];

}

double mean = sum / lth;

for(int i = 0; i < lth; i++) {

tmp3[i] = (tmp2[i] - mean) * (tmp2[i] - mean); }

for(int i = 0; i < lth; i++) { sum2 += tmp3[i];

(5)

double sd = Math.sqrt(sum2/lth);

// Hitung threshold

t = sd * sqrt((2 * Math.log(lth)));

for(int j = 0; j < lth; j++) { if(Math.abs(si[j]) >= t) { vn[x] = si[j];

x++; } else {

vbs[y] = si[j]; y++;

} }

return vn; }

/**

* Method reconstruction melakukan rekonstruksi sinyal suara pernapasan * dan noise dari tahap threshold.

*

* @param si sinyal input yang akan direkonstruksi. * @param level jumlah dilakukannya rekonstruksi. * @return sinyal yang telah direkonstruksi. */

public static double[] reconstrution(double[] si, int level) { int lth = si.length;

int currentLevelLength = lth / (int)Math.pow(2, level-1);

double[] result = si.clone();

// Lakukan proses rekonstruksi sebanyak level for(int i = 0; i < level; i++) {

int index = 0;

double[] tmp = result.clone();

// Ubah urutan sinyal dari sebelumnya terbagi dua,

// setengah low pass filter dan setengah high pass filter, menjadi // selang-seling low pass filter - high pass filter

for(int j = 0; j < currentLevelLength; j+=2) { tmp[j] = result[index];

tmp[j+1] = result[index+currentLevelLength/2]; index+=1;

}

index = currentLevelLength-2; result = tmp.clone();

// Lakukan proses rekonstruksi

for(int j = 0; j < currentLevelLength; j+=2) {

result[j] = k2*tmp[index] + k1*tmp[index+1] +

k0*tmp[(index+2)%currentLevelLength] +

k3*tmp[(index+3)%currentLevelLength];

result[j+1] = k3*tmp[index] - k0*tmp[index+1] +

k1*tmp[(index+2)%currentLevelLength] -

(6)

index = (index + 2)%currentLevelLength; }

currentLevelLength = currentLevelLength * 2; }

return result; }

}

3.

Finalprocess.java

public class Finalprocess {

public static final int SAMPLE_RATE = 44100;

public static final double MAX_16_BIT = Short.MAX_VALUE;

/**

* Simpan larik bertipe double sebagai file sound. */

public static void simpan(String namafile, double[] input) {

// 44,100 samples per second

// Gunakan 16-bit audio, mono, signed PCM, little Endian

AudioFormat format = new AudioFormat(SAMPLE_RATE, 16, 1, true,

false);

byte[] data = new byte[2 * input.length];

for (int i = 0; i < input.length; i++) {

int temp = (short) (input[i] * MAX_16_BIT);

data[2*i + 0] = (byte) temp;

data[2*i + 1] = (byte) (temp >> 8); }

// Simpan file try {

ByteArrayInputStream bais = new ByteArrayInputStream(data); AudioInputStream ais = new AudioInputStream(bais, format, input.length);

if (namafile.endsWith(".wav") || namafile.endsWith(".WAV")) {

AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new

File(namafile)); } else {

throw new RuntimeException("File format tidak dapat

digunakan: " + namafile); }

}

catch (Exception e) {

System.out.println(e);

System.exit(1);

(7)

4.

MainWindow.java

public class MainWindow extends JFrame implements ActionListener {

/**

* Aplikasi dijalankan. * @param args

*/

public static void main(String[] args) {

EventQueue.invokeLater(new Runnable() {

@Override

public void run() { new MainWindow(); }

}); }

public MainWindow() {

frmMain.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

series1 = new XYSeries("Signal");

series2 = new XYSeries("Signal");

dataset1 = new XYSeriesCollection(series1);

dataset2 = new XYSeriesCollection(series2);

waveform1 = createWaveform(title1, dataset1); waveform2 = createWaveform(title2, dataset2);

cpWaveform1 = new ChartPanel(waveform1);

cpWaveform1.setPreferredSize(new java.awt.Dimension(700, 200));

cpWaveform2 = new ChartPanel(waveform2);

cpWaveform2.setPreferredSize(new java.awt.Dimension(700, 200));

btnOpen = addButton("Open", tbButtons, true);

btnPlay = addButton("Play", tbButtons, false);

btnPause = addButton("Pause", tbButtons, false);

btnDenoise = addButton("Denoise", tbButtons, false);

btnCalculateSNR = addButton("Calculate SNR", tbButtons, false);

btnCleanCanvas = addButton("Clean Canvas", tbButtons, true);

tbButtons.setFloatable(false);

tbButtons.setBackground(Color.WHITE);

tbButtons.add(btnOpen);

tbButtons.add(btnPlay);

tbButtons.add(btnPause);

tbButtons.add(btnDenoise);

tbButtons.add(btnCalculateSNR);

tbButtons.add(btnCleanCanvas);

lblFile.setHorizontalAlignment(JLabel.LEFT);

spnCalculation = new JScrollPane();

gbc_scrollPane = new GridBagConstraints();

gbc_scrollPane.fill = GridBagConstraints.BOTH;

gbc_scrollPane.gridx = 0;

(8)

txtCalculation.setLineWrap(true);

txtCalculation.setFont(new Font("Arial", Font.PLAIN, 12));

txtCalculation.setColumns(50);

txtCalculation.setRows(5);

spnCalculation.setViewportView(txtCalculation);

spnCalculation.setBorder(eBorder);

pnlCalculation.add(spnCalculation, gbc_scrollPane);

pnlCalculation.setBackground(Color.WHITE);

pnlMiddle2.add(lblFile);

pnlMiddle2.setBackground(Color.WHITE);

pnlMiddle3.add(tbButtons);

pnlMiddle3.setBackground(Color.WHITE);

pnlMiddle4.add(lblCalculation);

pnlMiddle4.setBackground(Color.WHITE);

pnlSub.setLayout(new BoxLayout(pnlSub, BoxLayout.Y_AXIS));

pnlSub.add(cpWaveform1);

pnlSub.add(cpWaveform2);

pnlSub.add(pnlMiddle2);

pnlSub.add(pnlMiddle3);

pnlSub.add(pnlMiddle4);

pnlSub.add(pnlCalculation);

pnlContent.add(pnlSub);

frmMain.setContentPane(pnlContent);

frmMain.pack();

frmMain.setResizable(false);

frmMain.setLocationRelativeTo(getLayeredPane());

frmMain.setVisible(true); }

private JFreeChart createWaveform(String title, XYDataset dataset) { JFreeChart jfreechart = ChartFactory.createXYLineChart(title, "Waktu",

"Amplitudo", dataset, PlotOrientation.VERTICAL, false, false, false);

jfreechart.setBackgroundPaint(Color.WHITE);

XYPlot xyplot = (XYPlot) jfreechart.getPlot();

xyplot.setBackgroundPaint(Color.lightGray);

xyplot.setDomainGridlinePaint(Color.WHITE);

xyplot.setRangeGridlinePaint(Color.WHITE);

return jfreechart; }

private JButton addButton(String name, JToolBar jtb, boolean state) { // TODO Auto-generated method stub

JButton b = new JButton(name); b.addActionListener(this); b.setEnabled(state); jtb.add(b);

return b; }

@Override

public void actionPerformed(ActionEvent ae) { // TODO Auto-generated method stub

(9)

if(obj.equals(btnOpen)) {

player.stop();

loader.start();

btnPlay.setEnabled(false);

btnPause.setEnabled(false);

btnDenoise.setEnabled(false);

btnCalculateSNR.setEnabled(false);

} else if(obj.equals(btnPlay)) {

if(btnPlay.getText().startsWith("Play")) {

player.start();

btnPause.setEnabled(true);

btnPlay.setText("Stop"); } else {

player.stop();

btnPause.setEnabled(false);

btnPlay.setText("Play"); }

} else if(obj.equals(btnPause)) {

if(btnPause.getText().startsWith("Pause")) { if(player.trdPlayer != null) {

player.sdLine.stop(); }

btnPause.setText("Resume"); } else {

if(player.trdPlayer != null) {

player.sdLine.start(); }

btnPause.setText("Pause"); }

} else if(obj.equals(btnDenoise)) {

denoise.start();

} else if(obj.equals(btnCalculateSNR)) {

ratio.start();

} else if(obj.equals(btnCleanCanvas)) {

player.stop();

btnPlay.setEnabled(false);

btnPause.setEnabled(false);

btnDenoise.setEnabled(false);

btnCalculateSNR.setEnabled(false);

cleaner.start(); }

}

/**

* Loader class. Pengaturan membuka fie audio dan menggambar waveform. * @author Samuel Situmeang

* */

public class Loader implements Runnable { private Thread trdLoader;

public void start() {

trdLoader = new Thread(this);

trdLoader.setName("Loader");

trdLoader.start(); }

(10)

if(trdLoader != null) {

trdLoader.interrupt(); }

trdLoader = null; }

public void run() {

fc.setCurrentDirectory(new File(System.getProperty("user.dir"))); int a = fc.showOpenDialog(null);

if(a == JFileChooser.APPROVE_OPTION) { try {

url = fc.getSelectedFile().getPath();

File urlFile = new File(url);

String filename = urlFile.getName();

lblFile.setText(filename);

double[] signal = Preprocess.baca(url);

for (int i = 0; i < signal.length; i+=50) { double x = i;

double y = signal[i];

series1.addOrUpdate(x, y);

}

} catch(Exception ex) {

JOptionPane.showMessageDialog(null, "File tidak dapat dibuka.","Pesan",JOptionPane.ERROR_MESSAGE);

lblFile.setText(""); }

btnPlay.setEnabled(true);

btnDenoise.setEnabled(true); } else {

btnPlay.setEnabled(false);

btnDenoise.setEnabled(false); }

} }

/**

* Player class. Pengaturan memainkan file audio. * @author Samuel Situmeang

* */

public class Player implements Runnable { private SourceDataLine sdLine;

private Thread trdPlayer;

public void start() {

errStr = null;

trdPlayer = new Thread(this);

trdPlayer.setName("Player");

trdPlayer.start(); }

public void stop() {

trdPlayer = null; }

private void shutDown(String message) { if((errStr = message) != null) {

(11)

cpWaveform1.repaint();

cpWaveform2.repaint(); }

if(trdPlayer != null) {

trdPlayer = null;

btnPause.setEnabled(false);

btnPlay.setText("Play"); }

}

public void run() { try {

audioFile = new File(url); } catch(Exception ex) { ex.printStackTrace(); System.exit(1); }

try {

audioInputStream = AudioSystem.getAudioInputStream(audioFile); } catch(Exception ex) {

ex.printStackTrace(); System.exit(1); }

audioFormat = audioInputStream.getFormat();

DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);

try {

sdLine = (SourceDataLine) AudioSystem.getLine(info);

sdLine.open(audioFormat);

} catch(LineUnavailableException lue) { lue.printStackTrace();

System.exit(1);

} catch(Exception ex) { ex.printStackTrace(); System.exit(1); }

int frameSizeInBytes = audioFormat.getFrameSize(); int bufferLengthInFrames = sdLine.getBufferSize() / 8;

int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes; int nBytesRead = 0;

byte[] abData = new byte[bufferLengthInBytes];

sdLine.start();

while(trdPlayer != null) { try {

if((nBytesRead = audioInputStream.read(abData)) == -1) { break;

}

int nBytesRemaining = nBytesRead; while (nBytesRemaining > 0) {

nBytesRemaining -= sdLine.write(abData, 0, nBytesRemaining);

}

(12)

shutDown("Error sewaktu dimainkan: " + ex); break;

} }

if(trdPlayer != null) {

sdLine.drain(); }

sdLine.stop();

sdLine.close();

sdLine = null; shutDown(null); }

}

/**

* Denoise class. Pengaturan denoise file rekaman suara pernapasan. * @author Samuel Situmeang

* */

public class Denoise implements Runnable { private Thread trdDenoise;

public void start() {

trdDenoise = new Thread(this);

trdDenoise.setName("Denoise");

trdDenoise.start(); }

public void stop() { if(trdDenoise != null) {

trdDenoise.interrupt(); }

trdDenoise = null; }

public void run() {

double[] sinyalAudio = Preprocess.baca(url);

//PrintArray.print(sinyalAudio, "sinyalAudio.txt");

double[] dekomposisiSinyalAudio = SignalFilter.decomposition(sinyalAudio, 2);

//PrintArray.print(dekomposisiSinyalAudio, "dekomposisiSinyalAudio.txt");

double[] breathSignal = SignalFilter.getvbs(dekomposisiSinyalAudio); //PrintArray.print(breathSignal, "breathSignal.txt");

double[] noise = SignalFilter.getvn(dekomposisiSinyalAudio); //PrintArray.print(noise, "noise.txt");

double[] rekonstruksiSinyalAudio = SignalFilter.reconstrution(breathSignal, 2);

//PrintArray.print(rekonstruksiSinyalAudio, "rekonstruksiSinyalAudio.txt");

(13)

Finalprocess.simpan("src/Reducted.wav", rekonstruksiSinyalAudio);

Finalprocess.simpan("src/Noise.wav", rekonstruksiNoise);

double[] signal = Preprocess.baca("src/Reducted.wav"); for (int i = 0; i < signal.length; i+=50) { double x = i;

double y = signal[i];

series2.addOrUpdate(x, y);

}

btnCalculateSNR.setEnabled(true); }

}

/**

* Ratio class. Pengaturan perhitungan nilai Signal to Noise Ratio (SNR). * @author Samuel Situmeang

* */

public class Ratio implements Runnable { private Thread trdRatio;

public void start() {

trdRatio = new Thread(this);

trdRatio.setName("Ratio");

trdRatio.start(); }

public void stop() { if(trdRatio != null) {

trdRatio.interrupt(); }

trdRatio = null; }

public void run() {

double[] signalReducted = Preprocess.baca("src/Reducted.wav"); double[] signalNoise = Preprocess.baca("src/Noise.wav");;

double xisr = 1; double xrmssr = 1; double xisn = 1; double xrmssn = 1; double snr = 1.0; double snr_db = 1.0; int size = 0;

// Tentukan Root Mean Square Amplitude Sinyal Tereduksi for(int i = 0; i < signalReducted.length; i++) {

signalReducted[i] = signalReducted[i]*signalReducted[i]; xisr += signalReducted[i];

}

xrmssr = xisr/(signalReducted.length);

// Tentukan Root Mean Square Amplitude Noise for(int i = 0; i < size; i++) {

(14)

xisn += signalNoise[i]; }

xrmssn = xisn/(signalNoise.length);

snr = (xrmssr/xrmssn) * (xrmssr/xrmssn);

snr_db = 10 * Math.log10(snr);

txtCalculation.setText("Signal-to-noise ratio : " + FormatDesimal.twoDF(snr) + "\n"

+ "Signal-to-noise ratio_db : " + FormatDesimal.twoDF(snr_db) + " dB"); }

}

/**

* Cleaner class. Pengaturan membersihkan panel dari gambar sinyal. * @author Samuel Situmeang

* */

public class Cleaner implements Runnable { private Thread trdCleaner;

public void start() {

trdCleaner = new Thread(this);

trdCleaner.setName("Printer");

trdCleaner.start(); }

public void stop() { if(trdCleaner != null) {

trdCleaner.interrupt(); }

trdCleaner = null; }

public void run() {

series1.clear();

series2.clear();

lblFile.setText("No file Label");

txtCalculation.setText(null);

btnPlay.setEnabled(false);

btnDenoise.setEnabled(false);

btnCalculateSNR.setEnabled(false);

btnPause.setEnabled(false); }

Referensi

Dokumen terkait

Ini bisa dilihat dari tata bahasa sopan yang digunakan pada waktu berbicara pada orang yang lebih tua , dan bisa dilihat dari posisi tubuh ketika melakukan ojiki ( memberi

Penulis melakukan wawancara dengan pihak UPT Bimbingan Konseling untuk melihat apa permasalahan yang ada dan kebutuhan yang diperlukan untuk menyelesaikan masalah

Berdasarkan model di atas, maka dapat dikatakan bahwa penggunaan web terhadap kepuasan aktivitas belajar bagi pengguna wanita variabel Performance Expectancy (PE) yang

Berdasarkan hasil pengujian hipotesis Pengaruh ekspor, impor, kurs nilai tukar rupiah dan tingkat inflasi terhadap cadangan devisa Indonesia, maka dapat ditarik

Fendidikan Frespaktif Global bertolak dari anggapan bahwa pada saat sekarang telah terjadi keadaan saling ketergantungan (interdependeosi) di antara bangsa- bangsa dan

Puji syukur penulis panjatkan kepada Allah SWT atas segala karunia-NYA sehingga skripsi dengan judul &#34;Pengaruh senam rematik dan doa terhadap penurunan tingkat nyeri

Uji path analisis menunjukkan variabel kualitas produk yang dipengaruhi kepercayaan ada pengaruh mediasi terhadap keputusan nasabah menabung di Bank BRI Syariah

Pejabat, yang berusaha untuk mengatur warga Negara untuk berindak dalam bentuk tertentu tentang bagaimana mereka mengatur modalnya, bukan hanya membuat dirinya mendapat