[JAVA] [Kostenlose Studie für Erwachsene] Akustische Kommunikation mit Android

Einführung

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.

Was wurde verwendet

Bildschirmaufnahme

Von oben Zeitwellenform, Hüllkurve, Frequenzwellenform. Obwohl der Name SoundLocater ist, ist es niedlich, dass er überhaupt nicht positionieren kann.

Wo du "Ja" sagst

Wo ich "Wow" sage

ASK moduliert mit 18kHz Ultraschall

――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

Versuch es

――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

Implementierung

Mit einigen Auszügen. Ich habe nicht genug Energie, um das Ganze zu platzieren \ _ (: 3 "∠) \ _

Empfänger

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();

Referenz

Es ist ungefähr wie folgt.

Das ist FFT.

Sender

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();

Referenz

Ich habe mich auf diesen Bereich um AudioTrack bezogen. Fast so wie es ist.

Alle, die sich um mich gekümmert haben

Digitale Kommunikation studieren

Wiedergabebeziehungen

Aufnahmebezogen

FFT bezogen

Grafikzeichnung bezogen

Recommended Posts

[Kostenlose Studie für Erwachsene] Akustische Kommunikation mit Android
Verwenden Sie die serielle Kommunikation unter Android
Versuchen Sie die Kommunikation mit gRPC auf einem Android + Java-Server
[Android] Hinweise zu XML