Bonjour cher!
Aujourd'hui, nous transmettrons à nouveau l'image aux ultrasons dans l'eau: nous verrons littéralement la réverbération et l'écho, et même leur évolution en fonction des conditions. Tout ce que je vais vous dire est simple, il est intéressant de le répéter moi-même et peut être fait par presque n'importe qui.
Si quelque chose flotte dans votre âme à cause de ces mots, bienvenue à Kat, dans les eaux sombres de notre étang!

"Le meilleur repos est d'interpréter des vérités bien connues." (C) ABS, midi, XXIIe siècle
Foreplay
La règle de base du club des témoins de l'hydroacoustique est que la vidéo utilisant l'hydroacoustique à une distance plus ou moins importante (plus de quelques mètres) dans le milieu de l'eau ne peut pas être transmise, et sera toujours impossible.
Il y a de sérieuses raisons à cela - un canal de communication avec une très faible bande passante, une faible vitesse de propagation du signal (dans l'eau seulement 1 500 m / s) et une forte probabilité d'erreur. La bande de fréquences disponible n'est que de quelques dizaines de kilohertz.
Mais ce n'est pas tout - si, relativement parlant, un signal à des fréquences de l'ordre de 10 kHz se propage dans l'eau à une distance d'environ 8-10 km, alors à une fréquence de 20 kHz il est déjà de 3 à 5 km, et plus la fréquence est élevée, plus l'atténuation est forte . Par exemple, nos plus
petits modems
uWAVE au monde fonctionnent dans la bande 20-30 kHz et transmettent des données à une vitesse de 78 bit / s par 1000 mètres, et
RedLINE avec une bande de 5-15 à 8000 mètres. Le record parmi les appareils commerciaux appartient à
EvoLogics - 68 kBits par 300 mètres.
La physique, hélas, ne peut pas être trompée et il est impossible d'être d'accord avec elle - elle peut être transmise très lentement et insensible au bruit, ou rapidement, mais sur de courtes distances.
Cependant, dans certains cas, il est possible de «couper certains coins», lesquels coins que nous allons couper cette fois sont plus bas.
Que ferons-nous aujourd'hui et que faut-il pour cela?
Dans les articles précédents, nous avions déjà
transmis de la «vidéo» avec du son à travers l'eau , je vous rappelle que là la trame était «tracée sur le spectre», c'est-à-dire que le spectre, ou plutôt le spectrogramme du signal était une image.
Plus tard, nous avons
fabriqué de simples antennes hydroacoustiques à partir de déchets et fabriqué le
modem hydroacoustique le
plus simple . Là, nous avons également fait un préampli pour l'antenne (la conception du PCB pour l'auto-production par LUT-ohm est toujours
là ).
Nous avons pensé comment autrement vous pourriez essayer de transmettre l'image afin que même un élève de
maternelle puisse le comprendre, et comme il nous semble, ils ont trouvé un moyen encore plus simple qu'auparavant.
Donc, pour résumer, établissez une liste de ce dont nous avons besoin:
- une paire d'
antennes sonar de pie pickers-
préamplificateur fabriqué par LUT
-
Code source du projet C #
- une paire de batteries au plomb à 12 volts
- un amplificateur sur TDA, j'en ai pris
un pour seulement 50 roubles sur Ali
Un peu de théorie
Rappelons que notre
modem sonar était basé sur un simple détecteur de tonalité, dont la fréquence est 4 fois inférieure à la fréquence d'échantillonnage. Rappelez brièvement comment cela fonctionne.

L'image montre deux oscillations décalées l'une par rapport à l'autre sur Pi / 2 - c'est-à-dire les phases sinus et cosinus. Et si la fréquence est exactement quatre fois inférieure à la fréquence d'échantillonnage, alors seulement 4 échantillons tombent sur la période.
Un habuchitel attentif a certainement remarqué que les deux signaux sont décalés vers Pi / 4. Avec ce décalage, le signal ne prend que deux valeurs: √2 / 2 et -√2 / 2.
Et les valeurs spécifiques ne sont même pas importantes, il est important que vous ne puissiez utiliser que les signes: "+" et "-".
Maintenant, nous pouvons représenter la phase sinusoïdale comme une séquence de signes "+" "+" "-" "-", et la phase cosinusoïdale comme "+" "-" "-" "+".
Sous le becquet, répétez le détecteur:Que le signal d'entrée soit dans le tampon sn, nous avons deux tampons de moyenne en anneau pour les phases sinus et cosinus - bs et bc de taille N. Ils ont des pointeurs de tête et de queue communs - bH et bT. Au moment initial du temps, bH = N-1, bT = 0. Compteur de cycle de moyenne C = 0.
Nous prenons 4 échantillons du tampon d'entrée et les ajoutons en fonction des séquences de caractères.
a = sn(i)
bs(bH) = a
bc(bH) = a
s1 = s1 + a - bs(bT)
s2 = s2 + a - bc(bT)
bH = (bH + 1) % N
bT = (bT + 1) % N
a = sn(i+1)
bs(bH) = a
bc(bH) = -a
s1 = s1 + a - bs(bT)
s2 = s2 - a - bc(bT)
bH = (bH + 1) % N
bT = (bT + 1) % N
a = sn(i+2)
bs(bH) = -a
bc(bH) = -a
s1 = s1 - a - bs(bT)
s2 = s2 - a - bc(bT)
bH = (bH + 1) % N
bT = (bT + 1) % N
a = sn(i+3)
bs(bH) = -a
bc(bH) = a
s1 = s1 - a - bs(bT)
s2 = s2 + a - bc(bT)
bH = (bH + 1) % N
bT = (bT + 1) % N
Après avoir traité chacun quatre échantillons, nous vérifions le compteur des cycles de moyenne et s'il a dépassé N, nous calculons ensuite l'amplitude de la porteuse cA:
if ++cycle >= N
cA = sqrt(s1 * s1 + s2 * s2)
cycle = 0
end
Nous prenons cette méthode comme base, elle sera chargée de la «synchronisation».
Voyons maintenant comment l'image est encodée. Je suggère d'utiliser
la manipulation d'amplitude . La manipulation se produit lorsqu'un signal est divisé en segments égaux appelés puces ou symboles, et qu'un certain paramètre variable (dans notre cas, l'amplitude) est stocké sur la longueur de la puce.
Si, par exemple, nous pouvons faire varier l'amplitude dans la plage de 0 à 32767 (échantillons 16 bits), et que nous devons transmettre 255 valeurs de luminosité des pixels, puis par unité de changement de luminosité du pixel, l'amplitude de la puce passera à 32768/255 = 128.
Un autre paramètre important est la longueur de la puce, nous commençons par une période de support - quatre échantillons dans notre cas.
Ainsi, l'image sera transmise pixel par pixel, chaque pixel dure 4 échantillons et l'amplitude pour cette période sera b [x, y] * 128, où b [x, y] est la valeur de luminosité du pixel avec les coordonnées x et y dans l'image b.
Estimons quelle sera la vitesse de transmission.
Dans l'exemple, j'ai utilisé une taille d'image de 120x120 pixels. Cela signifie que pour transférer une image, nous avons besoin
120x120x4 = 57600 échantillons,
Si la fréquence d'échantillonnage est de 96 kHz, la transmission d'une trame prendra du temps:
57600/96000 = 0,6 seconde
Évidemment, nous avons besoin d'une sorte de pause, d'un certain intervalle de garde, pour que le détecteur puisse déterminer le début de la trame suivante. Pour des raisons humaines, supposons que 0,1 seconde nous suffit, pendant laquelle tous les échos s'éteignent (en fait pas). Ensuite, au final, le taux de transfert se révélera:
1 / (0,6 + 0,1) = 1,428 images par seconde.
Il est très facile de se tromper ici et d'essayer de calculer la vitesse en bits par seconde. Voyez à quel point la vitesse de transmission est incroyable:
120 * 120 * 8 / 1,428 = 80 627 bps
Mais que se passe-t-il si je n'ai pas des pixels 8 bits, mais des pixels 16 bits?
120 * 120 * 16 / 1,428 = 161344 bps
Le hic ici est que, encore une fois, cette méthode de transmission ne peut pas être appelée numérique, et le concept de débit binaire n'est pas entièrement valable pour cela.
Essayez de calculer le débit binaire d'un signal de télévision analogique. Et pour le récepteur du détecteur? :)
Ainsi, par exemple, un morceau du signal ressemblera, transmettant la luminosité de 10 pixels, dont les valeurs changent alternativement: 1 2 1 2 1 2 1 2 1 2

Voyons maintenant comment cela fonctionne dans l'exemple. Les méthodes Encode et Decode vivent dans la classe
Encoder et sont responsables de la modulation et de la démodulation de l'image:
public double[] Encode(Bitmap source, double carrier, int pSize, int interframePauseMs) { Bitmap frame; if (source.PixelFormat != System.Drawing.Imaging.PixelFormat.Format8bppIndexed) frame = Grayscale.CommonAlgorithms.RMY.Apply(source); else frame = source; if (!frame.Size.Equals(frameSize)) frame = resizer.Apply(frame); int cols = frameSize.Width; int rows = frameSize.Height; int col = 0; int row = 0; double delta = Math.PI * 2 * carrier / sampleRate; double alpha = 0; double phase = 0; double pxAmplitude = 0; double chipLimit = Math.PI * 2 * chipSize; double pLimit = Math.PI * 2; List<double> samples = new List<double>(); bool isFinished = false; for (int i = 0; i < pSize; i++) { alpha = Math.Sin(phase); phase += delta; if (phase >= pLimit) { phase -= pLimit; } samples.Add(alpha * short.MaxValue); } while (!isFinished) { alpha = Math.Sin(phase); phase += delta; if (phase >= chipLimit) { phase -= chipLimit; pxAmplitude = (((double)frame.GetPixel(col, row).R) / 255.0) * short.MaxValue; if (++col >= cols) { if (++row >= rows) isFinished = true; else col = 0; } } samples.Add(alpha * pxAmplitude); } if (interframePauseMs > 0) { samples.AddRange(new double[(int)((((double)interframePauseMs) / 1000.0) * (double)sampleRate)]); } return samples.ToArray(); }
On peut voir d'après le code qu'avant de moduler l'image, un préfixe de synchronisation composé de tons purs (échantillons pSize) est ajouté au signal de sortie - cela est nécessaire pour que, du côté de la réception, la synchronisation puisse avoir lieu avant l'image elle
- même
et en général, se produire dans des conditions défavorables.
La méthode Decode est la suivante:
public Bitmap Decode(double[] samples, double carrier, int pSize) { int cols = frameSize.Width; int rows = frameSize.Height; int col = 0; int row = 0; Bitmap result = new Bitmap(cols, rows); double delta = Math.PI * 2 * carrier / sampleRate; double alpha = 0; double phase = 0; double chipLimit = Math.PI * 2 * chipSize; double chipAmplitude = 0; double maxAmplitude = WaveUtils.GetMaxAmplitude(samples); double pxMax = -maxAmplitude; double pxMin = maxAmplitude; double smp; for (int i = pSize; (i < samples.Length) && (row < rows); i++) { alpha = Math.Sin(phase); phase += delta; if (phase >= chipLimit) { phase -= chipLimit; chipAmplitude = (Math.Max(Math.Abs(pxMax), Math.Abs(pxMin)) / maxAmplitude); pxMin = maxAmplitude; pxMax = -maxAmplitude; var gs = Convert.ToByte(chipAmplitude * 255); result.SetPixel(col, row, Color.FromArgb(255, gs, gs, gs)); if (++col >= cols) { col = 0; row++; } } else { smp = samples[i] * alpha; if (smp > pxMax) pxMax = smp; if (smp < pxMin) pxMin = smp; } } return result; }
On peut voir que les deux méthodes ne sont liées à aucune fréquence particulière et peuvent être utilisées avec un autre détecteur.
La recherche de signal elle-même (détection, synchronisation) se produit également comme dans notre
modem hydroacoustique le plus simple , à la seule différence que je le mets dans une classe distincte
FsBy4CarrierDetector pour un changement.
Toute magie simple se produit dans la méthode bool ProcessSample (abrégé a)
public bool ProcessSample(short a) { bool result = false; if (smpCount == 0) { ring1[ringHead] = a; ring2[ringHead] = a; s1 += a - ring1[ringTail]; s2 += a - ring2[ringTail]; } else if (smpCount == 1) { ring1[ringHead] = a; ring2[ringHead] = -a; s1 += a - ring1[ringTail]; s2 += - a - ring2[ringTail]; } else if (smpCount == 2) { ring1[ringHead] = -a; ring2[ringHead] = -a; s1 += -a - ring1[ringTail]; s2 += -a - ring2[ringTail]; } else if (smpCount == 3) { ring1[ringHead] = -a; ring2[ringHead] = a; s1 += -a - ring1[ringTail]; s2 += a - ring2[ringTail]; } ringHead = (ringHead + 1) % ringSize; ringTail = (ringTail + 1) % ringSize; if (++smpCount >= 4) { smpCount = 0; if (++cycle >= ringSize) { s = Math.Sqrt(s1 * s1 + s2 * s2) / ringSize; cycle = 0; result = (s - sPrev) >= Threshold; sPrev = s; } } return result; }
Il est appelé sur chaque échantillon entrant et retourne vrai en cas de détection de porteuse.
Étant donné que le détecteur est loin d'être parfait et peut facilement être synchronisé au milieu de la ligne, j'ai ajouté un curseur spécial, mobile, ce qui vous permet d'obtenir une synchronisation plus précise.
Maintenant, après avoir brièvement examiné comment tout cela fonctionne, passons à la partie la plus délicieuse: ce qui peut être obtenu à partir de tout cela.
Un peu de pratique
Tout d'abord, vérifions comment tout fonctionne sans canal sonar - simplement en reliant les antennes de réception et de transmission.
Tout d'abord, l'image est plus grande (240x120) de sorte qu'au moins quelque chose peut être distingué:

Et puis rapidement, pour qu'il y ait
plus de vie plus comme une vidéo:

Ça semble pas mal? Mais ne vous précipitez pas vers les conclusions et allez à la piscine:

Et ici, comme je l'ai promis dans le titre, nous verrons un écho de nos propres yeux:

Ça
vous plaît, Elon Musk? vous aimez la HD? Pourquoi en est-il ainsi?
Et tout est très simple - l'écho est en fait les copies retardées du signal d'origine, interférant avec lui au point de réception, se pliant dans une phase différente et donnant une telle image. Puisque nous transférons l'image, nous obtenons finalement beaucoup de nombreuses images superposées les unes aux autres avec des amplitudes différentes. Tout cela conduit finalement au flou et à la reproduction.
Avec le recul, vérifions tout sur la grande image du modèle. J'ai pris une photo au hasard:

Je l'ai modulé, puis ajouté un écho et un peu de bruit, puis il a été décodé, et oui - le résultat ressemble à ce que nous avons obtenu dans la piscine:

En principe, il est possible d'effectuer une
déconvolution et de soustraire des réflexions, mais
que ce soit des personnes extérieures à notre zone qui laissent ce point à un travail indépendant.
Soit dit en passant, la
méthode précédente dans le pool fonctionne un peu mieux, mais aussi mal - sur les signaux à large bande, les trajets multiples et la réverbération conduisent à un fondu sélectif en fréquence, qui dans l'image (lu sur le spectre) ressemble à des bandes noires et blanches - où le signal est en antiphase, et où il s'est développé en phase (en fait, il y a encore un tas d'options intermédiaires):

En avril, nous avons saisi l'occasion et sommes allés à l'étang avec une maquette de planche à pain et vous y dorloter aussi:


Le résultat n'est pas très différent des résultats obtenus dans le pool:


Et immédiatement pour comparaison, la méthode précédente:

Et voici les animations gif collectées à partir des images enregistrées, méthode 1:

Et la méthode 2, dont nous discutons dans cet article:

En conclusion
Comme promis, nous avons montré à quoi ressemblent l'écho et la réverbération, avons passé du temps avec profit et avons fait quelque chose avec nos mains.
Sous cette forme, bien sûr, la méthode n'est pas applicable dans la pratique, mais travailler avec elle sera très utile pour les débutants.
En général, nous avons vérifié dans un étang peu profond, où les conditions sont très défavorables, et ce serait cool si quelqu'un répétait nos expériences dans d'autres réservoirs et raconterait certainement leurs résultats.
Si le lecteur veut juste essayer (même dans les airs avec un microphone et des haut-parleurs), voici les liens vers les versions:
Méthode 1Méthode 2 (de cet article)PS
Nous attendons vraiment avec impatience les commentaires des lecteurs, car il est très important de comprendre que vous faites quelque chose en vain (ou en vain, et cela devrait être arrêté immédiatement).
PS / 2
Je répondrai tout de suite à une question commune: pour les poissons et autres animaux marins dans ces installations pour enfants, tout cela est tout simplement imperceptible.