Ich wollte Indoor-Positionierung mit Schallwellen durchführen, aber ich dachte, es wäre mühsam, einen Ultraschalllautsprecher zu kaufen, aber ich habe versucht, dies zu tun, aber anscheinend stellte ich fest, dass Android-Lautsprecher und -Mikrofone sogar die hohen Frequenzen abdecken können. Also habe ich es versucht.
Leider war die Zeit vorbei, da die Sommerferien nicht ausreichten und ASK (OOK) mit Ultraschallwellen durchgeführt wurde.
Von oben Zeitwellenform, Hüllkurve, Frequenzwellenform. Obwohl der Name SoundLocater ist, ist es niedlich, dass er überhaupt nicht positionieren kann.
――Es ist wirklich schön, weil Sie es mit Ihrem eigenen Lautsprecher löschen und mit Ihrem eigenen Mikrofon aufnehmen ――Ich konnte den Ton von anderen Geräten in einem Raum von ca. 10 m aufnehmen. ――Der Sound von anderen Geräten sieht nicht so schön aus
――Ich wollte keine Trägerwiedergabe oder synchrone Erkennung durchführen, also habe ich ASK gewählt. ――Aber es ist doch nicht von der Distanzdämpfung zu unterscheiden, also ist es immerhin ein Spiellevel ――FSK verwendet einige Bänder, und PSK kann auf Android identifiziert werden, daher ist es ziemlich schwierig.
von jetzt an
Mit einigen Auszügen. Ich habe nicht genug Energie, um das Ganze zu platzieren \ _ (: 3 "∠) \ _
Die folgenden zwei sind wichtig.
--Verwenden Sie die AudioRecord-Klasse
Die inverse Fourier-Transformation hat nicht funktioniert und ich war wirklich begeistert, aber am Ende scheint es, dass "fft.rdft (-1, FFT-Daten)" gut war.
Außerdem wurden die folgenden zwei Elemente hinzugefügt, die nicht in der Referenzquelle enthalten waren.
//Erstellen einer Audioaufnahme
audioRec = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLING_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, 2*bufSize);
audioRec.startRecording();
isRecording = true;
//Fourier-Analyse-Thread
fft = new Thread(new Runnable() {
@Override
public void run() {
byte buf[] = new byte[bufSize * 2];
while (isRecording) {
audioRec.read(buf, 0, buf.length);
//Endian-Konvertierung
ByteBuffer bf = ByteBuffer.wrap(buf);
bf.order(ByteOrder.LITTLE_ENDIAN);
short[] s = new short[bufSize];
for (int i = bf.position(); i < bf.capacity() / 2; i++) {
s[i] = bf.getShort();
}
//Erstellen einer FFT-Klasse und Übergeben von Werten
FFT4g fft = new FFT4g(FFT_SIZE);
double[] FFTdata = new double[FFT_SIZE];
for (int i = 0; i < bufSize; i++) {
FFTdata[i] = (double) s[i];
}
fft.rdft(1, FFTdata);
//Dezibelberechnung
short[] dbfs = new short[FFT_SIZE / 2];
for (int i = 0; i < FFT_SIZE; i += 2) {
dbfs[i / 2] = (short) (
20 * Math.log10(
Math.sqrt( Math.pow(FFTdata[i], 2) + Math.pow(FFTdata[i + 1], 2) )
/dB_baseline
)
);
//★★ Setzen Sie das unnötige Band im Frequenzbereich auf 0, um ein bestimmtes Band zu passieren
if ( width/2 < Math.abs(rxFreq-resol*i/2) ) {
FFTdata[i] = 0;
FFTdata[i+1] = 0;
}
}
//FFT umkehren
fft.rdft(-1, FFTdata);
//★★ Gleitender Durchschnitt mit absolutem Wert für die Hüllkurvenerkennung
short[] s2 = new short[bufSize];
for (int i=16; i<bufSize; i++) {
for (int j=0; j<16; j++) {
s2[i-16] += (Math.abs(FFTdata[i-j]) * 2.0 / FFT_SIZE) /16;
}
}
updateChart(mChartTime, s);
updateChart(mChartTime2, s2);
updateChart(mChartFreq, dbfs);
}
//Höre auf, aufzunehmen
audioRec.stop();
audioRec.release();
}
});
//Fadenstart
fft.start();
Es ist ungefähr wie folgt.
Das ist FFT.
Im Vergleich zum empfangenden Teil war der sendende Teil erheblich schwieriger.
Die wichtigen Dinge sind wie folgt.
--Verwenden Sie die AudioTrack-Klasse
Einfallsreichtum usw.
//Frequenzeinstellung
int durationPerSymbol = 40;
int samplesPerT = 4;
int samplesPerSymbol = (int)( (double)( freq * durationPerSymbol) / 1000.0 );
samplesPerSymbol = samplesPerT * (int) Math.ceil(samplesPerSymbol / samplesPerT);
int samplingRate = samplesPerT * freq;
//Datengenerierung
Random rnd = new Random();
byte[] preamble = new byte[]{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
byte[] data = new byte[64-preamble.length];
for (int i=0; i<data.length; i++) {
data[i] = (byte)rnd.nextInt(2);
}
int length = preamble.length + data.length;
//Trägergenerierung
byte[] samples = new byte[samplesPerSymbol*length];
for (int i=0; i<samplesPerSymbol/samplesPerT*length; i++) {
samples[samplesPerT * i + 0] = (byte) 0x70;
samples[samplesPerT * i + 1] = (byte) 0x70;
samples[samplesPerT * i + 2] = (byte) 0x00;
samples[samplesPerT * i + 3] = (byte) 0x00;
}
//AM-Modulation (Präambel)
int rolloffSamples = samplesPerSymbol/8;
for (int i=0; i<preamble.length; i++) {
for (int j=0; j<samplesPerSymbol; j++) {
double factor = 1.0;
//Erhöhter Kosinusfilter
if (j<rolloffSamples) {
factor = (1 - Math.cos( Math.PI/(double)rolloffSamples * (double)j )) /2;
} else if (samplesPerSymbol-rolloffSamples<j) {
factor = (1 - Math.cos( Math.PI/(double)rolloffSamples * (double)(samplesPerSymbol-j) )) /2;
}
samples[samplesPerSymbol * i + j] = (byte)( (double)(samples[samplesPerSymbol * i + j] * preamble[i]) * factor );
}
}
//AM-Modulation (Datenteil)
for (int i=0; i<data.length; i++) {
for (int j=0; j<samplesPerSymbol; j++) {
double factor = 1.0;
//Erhöhter Kosinusfilter
if (j<rolloffSamples) {
factor = (1 - Math.cos( Math.PI/(double)rolloffSamples * (double)j )) /2;
} else if (samplesPerSymbol-rolloffSamples<j) {
factor = (1 - Math.cos( Math.PI/(double)rolloffSamples * (double)(samplesPerSymbol-j) )) /2;
}
samples[samplesPerSymbol * (preamble.length+i) + j] = (byte)( (double)(samples[samplesPerSymbol * (preamble.length+i) + j] * data[i]) * factor );
}
}
//10 mal wiederholen
final byte[] txsamples = new byte[10*samples.length];
for (int i=0; i<10; i++) {
for (int j=0; j<samples.length; j++) {
txsamples[samples.length*i+j] = samples[j];
}
}
//AudioTrack-Konstruktor
final AudioTrack mTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
samplingRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_8BIT,
txsamples.length,
AudioTrack.MODE_STATIC
);
//Wiedergabe vollständiger Hörereinstellungen
mTrack.setNotificationMarkerPosition(txsamples.length);
mTrack.setPlaybackPositionUpdateListener(
new AudioTrack.OnPlaybackPositionUpdateListener() {
public void onPeriodicNotification(AudioTrack track) {}
public void onMarkerReached(AudioTrack track) {
if (track.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) {
track.stop();
track.release();
track = null;
}
}
}
);
//Schreiben und Wiedergeben von Wellenformdaten
track = new Thread(new Runnable() {
@Override
public void run() {
mTrack.reloadStaticData();
mTrack.write(txsamples, 0, txsamples.length);
mTrack.play();
}
});
//Fadenstart
track.start();
Ich habe mich auf diesen Bereich um AudioTrack bezogen. Fast so wie es ist.