4

我做了一个小信号处理应用程序。它使用 Goerztel 算法处理特定频率的音频信号(莫尔斯电码)。应用程序将临时文件保存到文件系统,并在录制完成后开始检测信号。现在我得到了很多数量级的结果。

我真的不知道从这些量级中读取什么。我怎样才能从这些量级解码莫尔斯电码?我怎样才能阅读它们?试图找到参考资料,但没有解释结果是什么以及如何阅读它。

编辑:

我的摩尔斯电码应用程序是用 Delphi 制作的,并使用 Windows Beep 功能以一定频率发送信号。我正在使用 1200 Hz 的信号。信号和单词之间的停顿和莫尔斯哔哔声就像维基百科描述的那样。一切都是准确的。

Goertzel.java:

 public class Goertzel {

        private float samplingRate;
        private float targetFrequency;
        private int n;

        private double coeff, Q1, Q2;
        private double sine, cosine;

        public Goertzel(float samplingRate, float targetFrequency, int inN) {
            this.samplingRate = samplingRate;
            this.targetFrequency = targetFrequency;
            n = inN;

            sine = Math.sin(2 * Math.PI * (targetFrequency / samplingRate));
            cosine = Math.cos(2 * Math.PI * (targetFrequency / samplingRate));
            coeff = 2 * cosine;
        }

        public void resetGoertzel() {
            Q1 = 0;
            Q2 = 0;
        }

        public void initGoertzel() {
            int k;
            float floatN;
            double omega;

            floatN = (float) n;
            k = (int) (0.5 + ((floatN * targetFrequency) / samplingRate));
            omega = (2.0 * Math.PI * k) / floatN;
            sine = Math.sin(omega);
            cosine = Math.cos(omega);
            coeff = 2.0 * cosine;

            resetGoertzel();
        }

        public void processSample(double sample) {
            double Q0;

            Q0 = coeff * Q1 - Q2 + sample;
            Q2 = Q1;
            Q1 = Q0;
        }

        public double[] getRealImag(double[] parts) {
            parts[0] = (Q1 - Q2 * cosine);
            parts[1] = (Q2 * sine);

            return parts;
        }

        public double getMagnitudeSquared() {
            return (Q1 * Q1 + Q2 * Q2 - Q1 * Q2 * coeff);
        }
    }

SoundCompareActivity.java

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.app.Activity;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

    public class SoundCompareActivity extends Activity {

        private static final int RECORDER_SAMPLE_RATE = 8000; // at least 2 times
                                                                // higher than sound
                                                                // frequency,
        private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_CONFIGURATION_MONO;
        private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;

        private AudioRecord recorder = null;
        private int bufferSize = 0;
        private Thread recordingThread = null;
        private boolean isRecording = false;

        private Button startRecBtn;
        private Button stopRecBtn;

        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);

            startRecBtn = (Button) findViewById(R.id.button1);
            stopRecBtn = (Button) findViewById(R.id.button2);

            startRecBtn.setEnabled(true);
            stopRecBtn.setEnabled(false);

            bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLE_RATE,
                    RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);

            startRecBtn.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Log.d("SOUNDCOMPARE", "Start Recording");

                    startRecBtn.setEnabled(false);
                    stopRecBtn.setEnabled(true);
                    stopRecBtn.requestFocus();

                    startRecording();
                }
            });

            stopRecBtn.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {
                    Log.d("SOUNDCOMPARE", "Stop recording");

                    startRecBtn.setEnabled(true);
                    stopRecBtn.setEnabled(false);
                    startRecBtn.requestFocus();

                    stopRecording();
                }
            });
        }

        private void startRecording() {
            recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
                    RECORDER_SAMPLE_RATE, RECORDER_CHANNELS,
                    RECORDER_AUDIO_ENCODING, bufferSize);

            recorder.startRecording();

            isRecording = true;

            recordingThread = new Thread(new Runnable() {

                @Override
                public void run() {
                    writeAudioDataToTempFile();
                }
            }, "AudioRecorder Thread");

            recordingThread.start();
        }

        private String getTempFilename() {
            File file = new File(getFilesDir(), "tempaudio");

            if (!file.exists()) {
                file.mkdirs();
            }

            File tempFile = new File(getFilesDir(), "signal.raw");

            if (tempFile.exists())
                tempFile.delete();

            return (file.getAbsolutePath() + "/" + "signal.raw");
        }

        private void writeAudioDataToTempFile() {
            byte data[] = new byte[bufferSize];
            String filename = getTempFilename();
            FileOutputStream os = null;

            try {
                os = new FileOutputStream(filename);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }

            int read = 0;

            if (os != null) {
                while (isRecording) {
                    read = recorder.read(data, 0, bufferSize);

                    if (read != AudioRecord.ERROR_INVALID_OPERATION) {
                        try {
                            os.write(data);
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        private void deleteTempFile() {
            File file = new File(getTempFilename());

            file.delete();
        }

        private void stopRecording() {
            if (recorder != null) {
                isRecording = false;

                recorder.stop();
                recorder.release();

                recorder = null;
                recordingThread = null;
            }

            new MorseDecoder().execute(new File(getTempFilename()));    
        }
    }

MorseDecoder.java:

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.ShortBuffer;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.os.AsyncTask;
import android.util.Log;

public class MorseDecoder extends AsyncTask<File, Void, Void> {
    private FileInputStream is = null;

    @Override
    protected Void doInBackground(File... files) {
        int index;
        //double magnitudeSquared; 
        double magnitude; 

        int bufferSize = AudioRecord.getMinBufferSize(8000,
                AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);

        Goertzel g = new Goertzel(8000, 1200, bufferSize);
        g.initGoertzel();

        for (int i = 0; i < files.length; i++) {
            byte[] data = new byte[bufferSize];

            try {
                is = new FileInputStream(files[i]);

                while(is.read(data) != -1) {
                    ShortBuffer sbuf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
                    short[] audioShorts = new short[sbuf.capacity()];
                    sbuf.get(audioShorts);

                    float[] audioFloats = new float[audioShorts.length];

                    for (int j = 0; j < audioShorts.length; j++) {
                        audioFloats[j] = ((float)audioShorts[j]) / 0x8000;
                    }

                    for (index = 0; index < audioFloats.length; index++) { 
                        g.processSample(data[index]); 
                    }

                    magnitude = Math.sqrt(g.getMagnitudeSquared());


                    Log.d("SoundCompare", "Relative magnitude = " + magnitude);

                    g.resetGoertzel();
                }

                is.close();

            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return null;
    }
}

编辑2:

注意到处理样本中的一些错误。更改了 while 循环中的代码。

while(is.read(data) != -1) {
                    ShortBuffer sbuf = ByteBuffer.wrap(data).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
                    short[] audioShorts = new short[sbuf.capacity()];
                    sbuf.get(audioShorts);

                    float[] audioFloats = new float[audioShorts.length];

                    for (int j = 0; j < audioShorts.length; j++) {
                        audioFloats[j] = ((float)audioShorts[j]) / 0x8000;
                    }

                    for (index = 0; index < audioFloats.length; index++) { 
                        g.processSample(audioFloats[index]); 

                        magnitude = Math.sqrt(g.getMagnitudeSquared());
                        Log.d("SoundCompare", "Relative magnitude = " + magnitude);
                    }

                    //magnitude = Math.sqrt(g.getMagnitudeSquared());


                    //Log.d("SoundCompare", "Relative magnitude = " + magnitude);

                    g.resetGoertzel();
                }

问候,邪恶的

4

2 回答 2

7

当存在通带内的音调时, Goertzel 滤波器的输出将增加,然后在去除该音调时减小。为了检测音调的脉冲,例如摩尔斯电码,您需要在滤波器的输出上安装某种阈值检测器,它只会在采样上给出“音调存在”/“音调不存在”的布尔值 -样本基础。尝试绘制输出值,一旦您以图形形式看到它应该很明显。

于 2011-09-07T20:12:55.230 回答
0

在图表上绘制信号幅度与时间的关系(一些用于 PC 的 CW 解码应用程序实时执行此操作)。现在找出每个摩尔斯电码符号的图形应该是什么样子。然后研究一些模式匹配算法。如果存在足够多的噪声,您可能需要尝试一些统计模式匹配方法。

这是正确的摩尔斯电码计时的维基百科链接

于 2011-09-08T01:42:02.487 回答