Sound processing III – Przesyłamy dane

Trzecia część serii. Tym razem prześlemy litery pomiędzy komputerami za pomocą naszego dźwiękowego modemu. Zapraszam


W ostatniej części napisaliśmy modulator, który zamienia ciąg zer i jedynek na odpowiadające mu częstotliwości i wytwarza je w głośniku w ustalonym wcześniej porządku, tj. z częstotliwością pauzy pomiędzy nimi.

Co nowego w kodzie

Przed nami zostało napisanie części kodu odpowiadającej za  interpretację częstotliwości które docierają do mikrofonu. Do tego celu skorzystam z biblioteki TarsosDSP, którą wykorzystaliśmy już w ostatnim poście do wykazania, że nasze częstotliwości da się odczytać na komputerze.

Nie przewidziałem wtedy jednej rzeczy. Nasłuchujący program nie będzie wiedział w którym momencie zaczynam, a kiedy kończę transmisję, w końcu nie każdy znak ASCII będzie miał binarnie 7 bitów, do tego (np. z powodu szumów) nie wszystkie znaki muszą trafić. Z tego powodu dodałem dodatkową częstotliwość 3500[Hz] którą wysyłam na początku i końcu transmisji.

Skorzystałem z kodu wykorzystującego Tarsos obsługującego panel pokazany na poprzednim odcinku. W momencie wykrycia dowolnej częstotliwości, tworzy nowy obiekt typu DetectedFrequency i dodaje go do tablicy. W obiekcie DetectedFrequency, który napisałem wcześniej, zapisane są na stałe częstotliwości dla zera, jedynki, pauzy i znaku początku/końca transmisji, odczytana częstotliwość porównywana jest z nimi i przypisuje obiektowi odpowiednią literę. Dla częstotliwości nieopisanej naszymi zmiennymi (np. 123 [Hz] albo 456 [Hz]) przypisywany jest pusty znak, co jest istotne w późniejszej części kodu.

detectedfreq

Przypisywanie znaku do danej częstotliwości

Aby w miarę na bieżąco analizować nadchodzące znaki, ustawiłem timer i co 5 sekund sprawdzam zawartość tablicy z obiektami DetectedFrequency. Wtedy tworzę nowy obiekt String do przechowywania tekstu i sumuję w nim wszystkie litery z tablicy DetectedFrequency. W ten sposób, dla przykładu, otrzymuję ciąg znaków:

000000     11111      00                11111

Dlaczego dostaję wielokrotności znaków? Ponieważ Tarsos tworzy obiekt za każdym razem, gdy wykryje jakąś częstotliwość. Ponieważ wykrywa ją praktycznie za każdym swoim odświeżeniem, a ja nadaję ją dłuższą chwilę, to właśnie z czymś takim kończę.

Następnie trafia to do obiektu typu DetectedMessageFormatter, gdzie pętlą while załatwiam sprawę i tworzę z tego ciąg znaków:

0101

formatstring

Formatowanie otrzymuję w bardzo prosty sposób, iteruję po każdym elemencie ciągu znaków i sprawdzam czy poprzedni element jest taki sam jak obecny. Jeśli tak, to nie dodaję go do nowego, sformatowanego ciągu. Cała magia.

Następnie, jeśli w otrzymanym ciągu można wyróżnić 2 znaki początku/końca transmisji (zapisywane jako ‘/’), to próbuję zinterpretować znaki między nimi, po czym dodaję efekt do tablicy odczytanych wiadomości i szukam odpowiedniego kodu ASCII dla tej liczby.

Należy pamiętać, że w odczytanym w danym momencie ciągu wcale nie muszą znajdować się dwa znaki ‘/’. W końcu odświeżamy bufor co 5 sekund, bardzo możliwe że akurat sekundę przed odświeżeniem ktoś rozpoczął nadawanie i jeszcze go nie skończył. W takiej sytuacji w buforze znajdzie się ciąg liter, powiedzmy:

/// 0000 11

Z którego nie powinniśmy niczego interpretować, bo transmisja jeszcze się nie skończyła.

Co do samego tworzenia wiadomości, obeszło się bez większych zmian względem wcześniejszej części. Po każdym wysłaniu wiadomości, jesteśmy znowu pytani o kolejną literę do wysłania, aż do wyłączenia programu, przy czym jednocześnie w drugim wątku uruchomione jest nasłuchiwane i co 5 sekund daje znać o odczytanych wiadomościach.

snifferKlasa Sniffer obsługjąca przechwytywanie dźwięku i interpretowanie go w tle.

Nasz program skopiowałem na inny komputer wyposażony w mikrofon i zestawiłem je dość blisko siebie. Efekty przesyłania pojedynczych liter nagrałem i wrzuciłem poniżej:

Jak widać, przy 4 przesłanych znakach mieliśmy 100% dokładności. Pomyłki czasem się zdarzają (np. z 7 znaków przyjdzie tylko 6, co już zmieni liczbę względem której program będzie próbował odczytać znak), ale przy dużej głośności i małej odległości między komputerami zdarza się to bardzo rzadko. Do tego czasem trafiają się błędy dostępu do głośnika z nadal nieznajomych mi powodów.

Co dalej?

TarsosDSP ma całkiem dobrą dokładność, kiedy moduluję dźwięk o (teoretycznie) częstotliwości 2500 [Hz], Tarsos odczytuje wartości wahające się o 0-20 [Hz] od tej modulowanej. To daje całkiem spore pole do popisu. Na ten moment przesłanie 7 bitów zajmuje około 4 sekundy. 7*(60/4)*60 = 6300 bitów w ciągu godziny, podzielić przez 8 czyli 787.5 bajta na godzinę, podzielić na 1024 daje 0.76 kB na godzinę. Dla skali, ile danych można przesłać naszym programem w ciągu godziny (zakładając 100% bezbłędności przy transmisji) – poniższy śmieszny obrazek waży 17 kB.

zbrodniarz

Jaki jest mój pierwszy pomysł na przyśpieszenie tego – wykorzystanie dziesięciu częstotliwości. Ponieważ Tarsos ma sporą dokładność, to zmieszczenie 10 częstotliwości w nadal wystarczająco dużych odstępach na paśmie 2-4 [kHz] nie będzie problemem. Ale dlaczego 0-10? Ponieważ tym sposobem, będzie można wysyłać dane nie tak jak teraz, binarnie, ale decymalnie, czyli w ludzkim, dziesiątkowym systemie. Dla przykładu, aby wysłać literę A (w kodzie ASCII jest to 65) na ten moment musimy wysłać 1000001 + dodatkowe częstotliwości na pauzę i znak początku i końca transmisji. Przy decymalnym wysyłaniu, byłyby to tylko znaki 6 i 5 (+ te pomocnicze, czyli łącznie 5 zamiast 15)!

Do tego przydałoby się zabezpieczyć przed awaryjnością transmisji, chociażby zamiast tego samego znaku dla początku i końca transmisji wprowadzić 2 oddzielne.

Ale to już w następnym odcinku. Przy okazji, coraz bliżej praktycznego zastosowania naszego modemu.


Odnośniki:

Kod pisany w tej serii jak zawsze dostępny jest za darmo na moim GitHubie:

https://github.com/dbeef/soundcoding

Kilkuminutowy filmik opisujący odczytywanie znaków ASCII z ciągu z liczbami zapisanymi binarnie, czyli dokładnie to co robi na ten moment nasz program:

https://www.youtube.com/watch?v=wCQSIub_g7M

(polecam cały kanał)

dsp2017-1

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s