我做了一个小信号处理应用程序。它使用 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();
}
问候,邪恶的