Je voulais faire du positionnement en intérieur avec des ondes sonores, mais je pensais que ce serait un problème d'acheter un haut-parleur à ultrasons, mais j'essayais de le faire, mais apparemment, j'ai trouvé que les haut-parleurs et les microphones Android peuvent couvrir même les hautes fréquences. Alors j'ai essayé.
Cependant, malheureusement, le temps était écoulé car la période des vacances d'été n'était pas suffisante et ASK (OOK) était fait avec des ondes ultrasonores.
Du haut, forme d'onde temporelle, enveloppe, forme d'onde de fréquence. Même si le nom est SoundLocater, c'est mignon qu'il ne puisse même pas se positionner.
――C'est vraiment beau parce que vous l'éteignez avec votre propre haut-parleur et le prenez avec votre propre microphone ―― Je pourrais capter le son d'autres appareils dans une pièce d'environ 10 m. ――Le son des autres appareils n'est pas si beau
――Je ne voulais pas faire de lecture de porteuse ou de détection synchrone, j'ai donc choisi ASK. ――Mais après tout, il est impossible de distinguer l'atténuation de la distance, donc après tout c'est un niveau de jeu ――FSK utilise certaines bandes, et PSK peut être identifié sur Android, donc c'est assez difficile.
à partir de maintenant
--Je veux détecter exactement le début ―― Y a-t-il une bonne modulation autre que ASK? ――Je veux mettre dans un protocole simple de type CSMA / CA et bien m'éviter.
Avec quelques extraits. Je n'ai pas assez d'énergie pour tout mettre \ _ (: 3 "∠) \ _
Les deux suivants sont importants.
--Utiliser la classe AudioRecord --Fourier transformation (FFT)
La transformée de Fourier inverse n'a pas fonctionné et j'étais vraiment dedans, mais à la fin il semble que fft.rdft (-1, données FFT)
était bon.
De plus, les deux éléments suivants ont été ajoutés qui n'étaient pas inclus dans la source de référence.
--Réglez la bande inutile à 0 dans la gamme de fréquences pour ne laisser passer que la bande souhaitée
//Créer un enregistrement audio
audioRec = new AudioRecord(MediaRecorder.AudioSource.MIC, SAMPLING_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, 2*bufSize);
audioRec.startRecording();
isRecording = true;
//Fil d'analyse de Fourier
fft = new Thread(new Runnable() {
@Override
public void run() {
byte buf[] = new byte[bufSize * 2];
while (isRecording) {
audioRec.read(buf, 0, buf.length);
//Conversion endian
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();
}
//Créer une classe FFT et transmettre des valeurs
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);
//Calcul des décibels
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
)
);
//★★ Réglez la bande inutile sur 0 dans la gamme de fréquences pour passer une bande spécifique
if ( width/2 < Math.abs(rxFreq-resol*i/2) ) {
FFTdata[i] = 0;
FFTdata[i+1] = 0;
}
}
//FFT inversé
fft.rdft(-1, FFTdata);
//★★ Moyenne mobile avec valeur absolue pour la détection d'enveloppe
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);
}
//Arrête d'enregistrer
audioRec.stop();
audioRec.release();
}
});
//Début du fil
fft.start();
C'est à peu près comme suit.
C'est FFT.
Par rapport à la partie réceptrice, la partie émettrice était considérablement plus difficile.
Les choses importantes sont les suivantes.
--Utiliser la classe AudioTrack
Ingéniosité etc.
--Pour la détection de tête, 16 bits de 01 sont ajoutés à plusieurs reprises au début en tant que préambule.
//Réglage de la fréquence
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;
//Génération de données
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;
//Génération de transporteurs
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;
}
//Modulation AM (préambule)
int rolloffSamples = samplesPerSymbol/8;
for (int i=0; i<preamble.length; i++) {
for (int j=0; j<samplesPerSymbol; j++) {
double factor = 1.0;
//Filtre cosinus surélevé
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 );
}
}
//Modulation AM (partie données)
for (int i=0; i<data.length; i++) {
for (int j=0; j<samplesPerSymbol; j++) {
double factor = 1.0;
//Filtre cosinus surélevé
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 );
}
}
//Répéter 10 fois
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];
}
}
//Constructeur AudioTrack
final AudioTrack mTrack = new AudioTrack(
AudioManager.STREAM_MUSIC,
samplingRate,
AudioFormat.CHANNEL_OUT_MONO,
AudioFormat.ENCODING_PCM_8BIT,
txsamples.length,
AudioTrack.MODE_STATIC
);
//Lecture des paramètres d'écoute complets
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;
}
}
}
);
//Écriture et lecture de données de forme d'onde
track = new Thread(new Runnable() {
@Override
public void run() {
mTrack.reloadStaticData();
mTrack.write(txsamples, 0, txsamples.length);
mTrack.play();
}
});
//Début du fil
track.start();
J'ai fait référence à ce domaine autour d'AudioTrack. Presque comme ça.
--Version portée par Java de la bibliothèque FFT du Dr Oura - Ooura-FFT-Library-by-Other-Language/fft4g.java at master · YSRKEN/Ooura-FFT-Library-by-Other-Language - FFT4g.java