2 bilgisayar arasındaki ses yoluyla veri aktarımı (çok yakın mesafe)


12

2 bilgisayar arasında ses yoluyla veri aktarımı için bir örnek yazıyorum. Bazı gereksinimler:

  • Mesafe çok yakın, yani 2 bilgisayar birbirine bitişik

  • Çok az gürültü (Öğretmenimin rock şarkısını gürültü kaynağı olarak açacağını sanmıyorum)

  • Hata kabul edilebilir: Örneğin, "Radyo iletişimi" gönderirsem diğer bilgisayar "RadiQ communEcation" alırsa sorun olmaz.

  • Mümkünse: Üstbilgi, bayrak, sağlama toplamı yok ... çünkü verileri ses yoluyla aktarmanın temellerini gösteren çok temel bir örnek istiyorum. Süslü olmaya gerek yok.

Bu bağlantıya göre Ses Frekansı Shift Anahtarlamayı kullanmayı denedim:

Lab 5 APRS (Otomatik Paket Raporlama Sistemi)

ve bazı sonuçlar aldım: Github sayfam

ama yeterli değil. Saat kurtarma, senkronizasyon, nasıl yapılacağını bilmiyorum (bağlantının zamanlama kurtarma mekanizması olarak bir Faz Kilitli Döngüsü vardır, ancak görünüşe göre yeterli değildi).

Bence daha basit bir yaklaşım bulmalıyım. Burada bir bağlantı bulundu:

Ses ve geri veri. Kaynak kodu ile modülasyon / demodülasyon

ancak OP cevapta önerilen yöntemi uygulamadı, bu yüzden çok karmaşık olabileceğinden korkuyorum. Ayrıca cevapta önerilen kod çözme yöntemini açıkça anlamıyorum:

Kod çözücü biraz daha karmaşıktır, ancak bir taslak:

İsteğe bağlı olarak, örneklenen sinyali 11Khz civarında bant geçiren filtre. Bu, gürültülü bir ortamda performansı artıracaktır. FIR filtreleri oldukça basittir ve filtreyi sizin için oluşturacak birkaç çevrimiçi tasarım uygulaması vardır.

Sinyali eşleştirin. 1/2 maksimum genliğin üzerindeki her değer, aşağıdaki her değer 1'dir. Bu, tüm sinyali örneklediğinizi varsayar. Bu gerçek zamanlı ise, sabit bir eşik seçer veya bir süre boyunca maksimum sinyal seviyesini izlediğiniz bir tür otomatik kazanç kontrolü yaparsınız.

Nokta veya çizgi başlangıcı için tarama yapın. Örnekleri bir nokta olarak değerlendirmek için nokta noktanızda muhtemelen en az belirli sayıda 1 görmek istersiniz. Ardından, bunun bir tire olup olmadığını görmek için taramaya devam edin. Mükemmel bir sinyal beklemeyin - 1'lerinizin ortasında birkaç 0 ve 0'larınızın ortasında birkaç 1 göreceksiniz. Çok az gürültü varsa, "açık" süreleri "kapalı" sürelerden ayırmak oldukça kolay olmalıdır.

Sonra yukarıdaki işlemi tersine çevirin. Kısa çizgi görürseniz, tamponunuza 1 bit itin, bir nokta sıfıra itti.

Bir nokta olarak sınıflandırmadan önce kaç tane 1 olduğunu anlamıyorum, ... Şu anda anlamadığım birçok şey var. İşlemi anlayabilmem için lütfen verileri ses yoluyla iletmek için basit bir yöntem önerin. Çok teşekkür ederim :)

GÜNCELLEME:

Ben (biraz) operasyonel gibi görünen bazı Matlab kodu yaptık. İlk önce Genlik kaydırma anahtarlamasını (örnekleme frekansı 48000 Hz, F_on = 5000 Hz, bit hızı = 10 bit / s) kullanarak sinyali modüle ederim, sonra bir başlık ve bir bitiş dizisi ile ekleyin (elbette bunları da modüle edin). Üstbilgi ve bitiş sırası geçici olarak seçildi (evet bir hack'ti):

header = [0 0 1 0 1 1 1 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 1 1 0 1 0 1];  
end_seq = [1 1 1 1 1 0 1 0 1  0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1     0 1 0 1 0 1 0 1    0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1  1 0 0 1 0 0 0 1];

Sonra onları sesle iletiyorum ve akıllı telefonumla kaydettim. Sonra kaydedilen sesi bilgisayarıma geri gönderiyorum, sesi okumak için başka bir kod parçası kullanıyorum. Daha sonra, başlangıç ​​ve sonu bulmak için alınan sinyali (henüz demodüle edilmemiş) modüle edilmiş başlık ve bitiş sekansı ile ilişkilendirdim. Bundan sonra sadece ilgili sinyali alıyorum (korelasyon bölümünde bulunan başından sonuna kadar). Sonra dijital veri bulmak için demodüle ve örnek. İşte 3 ses dosyası:

  • "DigitalCommunication_ask": Buraya bağlantı "Dijital iletişim" metnini gönderir. Başlangıçta ve sonunda bazı arka plan gürültülerini duyabilmenize rağmen nispeten gürültüsüz. Ancak sonuç sadece "Dijital Commincatio" gösterdi

  • "HelloWorld_ask": Buraya bağlantı "Merhaba dünya" metnini gönderir. "DigitalCommunication_ask" gibi gürültü yok. Ancak bunun sonucu doğruydu

  • "HelloWorld_noise_ask": Buraya bağlantı "Merhaba dünya" metnini gönderir. Ancak yaptığım bazı gürültü var (iletim sırasında sadece rastgele şeyler "A, B, C, D, E, ...." dedim). Maalesef bu başarısız oldu

Gönderenin kodu (sender.m):

 clear
fs = 48000;
F_on = 5000;
bit_rate = 10;

% header = [0 0 1 0 1 1 1 1  1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1     1 1 1 1 1 1 1 1      1 1 1 1 1 1 1 1    1 1 1 1 1 1 1 1     1 1 1 1 1 1 1 1    1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 ];
% header = [0 0 1 0 1 1 1 1  1 0 0 0 0 0 0 1   1 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1     1 0 0 0 0 0 0 1      1 0 0 0 0 0 0 1    1 0 0 0 0 0 0 1  1 0 0 0 0 0 0 1    1 0 0 0 0 0 0 1  1 1 1 1 1 1 1 1 ];
header = [0 0 1 0 1 1 1 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 1 1 0 1 0 1];  

% end_seq = [1 0 0 1 0 1 0 0  1 0 1 1 0 0 0 1  0 0 0 0 1 0 0 1  1 0 0 0 1 0 0 1];
% end_seq = [1 0 0 1 0 1 0 0  1 0 1 1 0 0 0 1  0 0 0 0 1 0 0 1  1 0 0 0 1 0 0 1   0 1 0 0 1  1 0 0   1 1 0 1 1 0 0 1  ];
% end_seq = [0 0 0 1 0 0 0 1  0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0   1 1 0 0 1 1 0 0];
end_seq = [1 1 1 1 1 0 1 0 1  0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1     0 1 0 1 0 1 0 1    0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1  1 0 0 1 0 0 0 1];


num_of_samples_per_bit = round(fs / bit_rate);
modulated_header = ask_modulate(header, fs, F_on, bit_rate);
modulated_end_seq = ask_modulate(end_seq, fs, F_on, bit_rate);
% input_str = 'Ah';
input_str = 'Hello world';
ascii_list = double(input_str); % https://www.mathworks.com/matlabcentral/answers/298215-how-to-get-ascii-value-of-characters-stored-in-an-array
bit_stream = [];
for i = 1:numel(ascii_list)
    bit = de2bi(ascii_list(i), 8, 'left-msb');
    bit_stream = [bit_stream bit];
end
bit_stream = [header bit_stream  end_seq];
num_of_bits = numel(bit_stream);
bandlimited_and_modulated_signal = ask_modulate(bit_stream, fs, F_on, bit_rate);
sound(bandlimited_and_modulated_signal, fs);

Alıcı için (alıcı.m):

clear
fs = 48000;
F_on = 5000;
bit_rate = 10;

% header = [0 0 1 0 1 1 1 1  1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1   1 1 1 1 1 1 1 1     1 1 1 1 1 1 1 1      1 1 1 1 1 1 1 1    1 1 1 1 1 1 1 1     1 1 1 1 1 1 1 1    1 1 1 1 1 1 1 1  1 1 1 1 1 1 1 1 ];
% header = [0 0 1 0 1 1 1 1  1 0 0 0 0 0 0 1   1 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1     1 0 0 0 0 0 0 1      1 0 0 0 0 0 0 1    1 0 0 0 0 0 0 1  1 0 0 0 0 0 0 1    1 0 0 0 0 0 0 1  1 1 1 1 1 1 1 1 ];
header = [0 0 1 0 1 1 1 1   1 0 0 0 0 0 0 1   1 0 0 0 0 0 0 1   1 0 1 1 0 1 0 1];  

% end_seq = [1 0 0 1 0 1 0 0  1 0 1 1 0 0 0 1  0 0 0 0 1 0 0 1  1 0 0 0 1 0 0 1];
% end_seq = [1 0 0 1 0 1 0 0  1 0 1 1 0 0 0 1  0 0 0 0 1 0 0 1  1 0 0 0 1 0 0 1   0 1 0 0 1  1 0 0   1 1 0 1 1 0 0 1  ];
% end_seq = [0 0 0 1 0 0 0 1  0 0 0 0 0 0 0 0    0 0 0 0 0 0 0 0   1 1 0 0 1 1 0 0];
end_seq = [1 1 1 1 1 0 1 0 1  0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1     0 1 0 1 0 1 0 1    0 1 0 1 0 1 0 1   0 1 0 1 0 1 0 1  1 0 0 1 0 0 0 1];


modulated_header = ask_modulate(header, fs, F_on, bit_rate);
modulated_end_seq = ask_modulate(end_seq, fs, F_on, bit_rate);

% recObj = audiorecorder(fs,8,1);
% time_to_record = 10; % In seconds
% recordblocking(recObj, time_to_record);
% received_signal = getaudiodata(recObj);

% [received_signal, fs] = audioread('SounddataTruong_Ask.m4a');
% [received_signal, fs] = audioread('HelloWorld_noise_ask.m4a');
% [received_signal, fs] = audioread('HelloWorld_ask.m4a');
[received_signal, fs] = audioread('DigitalCommunication_ask.m4a');
ereceived_signal = received_signal(:)';
num_of_samples_per_bit = round(fs / bit_rate);

modulated_header = ask_modulate(header, fs, F_on, bit_rate);
modulated_end_seq = ask_modulate(end_seq, fs, F_on, bit_rate);

y= xcorr(modulated_header, received_signal); % do cross correlation
[m,ind]=max(y); % location of largest correlation
headstart=length(received_signal)-ind+1;

z = xcorr(modulated_end_seq, received_signal);
[m,ind]=max(z); % location of largest correlation
end_index=length(received_signal)-ind+1; 

relevant_signal = received_signal(headstart + num_of_samples_per_bit * numel(header) : end_index - 1);
% relevant_signal = received_signal(headstart + num_of_samples_per_bit * numel(header): end);
demodulated_signal = ask_demodulate(relevant_signal, fs, F_on, bit_rate);
sampled_points_in_demodulated_signal = demodulated_signal(round(num_of_samples_per_bit / 2) :  num_of_samples_per_bit :end);
digital_output = (sampled_points_in_demodulated_signal > (max(sampled_points_in_demodulated_signal(:)) / 2));
% digital_output = (sampled_points_in_demodulated_signal > 0.05);

% Convert to characters 
total_num_of_bits = numel(digital_output);
total_num_of_characters = total_num_of_bits / 8;
first_idx = 0;
last_idx = 0;
output_str = '';
for i = 1:total_num_of_characters
    first_idx = last_idx + 1;
    last_idx = first_idx + 7;
    binary_repr = digital_output(first_idx:last_idx); 
    ascii_value = bi2de(binary_repr(:)', 'left-msb');  
    character = char(ascii_value);
    output_str = [output_str character];    
end
output_str

Modülasyon kodu ASK (ask_modulate):

function [bandlimited_and_modulated_signal] = ask_modulate(bit_stream, fs, F_on, bit_rate)
% Amplitude shift keying: Modulation
% Dang Manh Truong (dangmanhtruong@gmail.com)
num_of_bits = numel(bit_stream);
num_of_samples_per_bit = round(fs / bit_rate);
alpha = 0;
d_alpha = 2 * pi * F_on / fs;
A = 3;
analog_signal = [];
for i = 1 : num_of_bits
    bit = bit_stream(i);
    switch bit
        case 1
            for j = 1 : num_of_samples_per_bit
                analog_signal = [analog_signal A * cos(alpha)];
                alpha = alpha + d_alpha;

            end
        case 0
            for j = 1 : num_of_samples_per_bit
                analog_signal = [analog_signal 0];
                alpha = alpha + d_alpha;                
            end
    end    
end
filter_order = 15;
LP_filter = fir1(filter_order, (2*6000)/fs, 'low');
bandlimited_analog_signal = conv(analog_signal, LP_filter,'same');
% plot(abs(fft(bandlimited_analog_signal)))
% plot(bandlimited_analog_signal)
bandlimited_and_modulated_signal = bandlimited_analog_signal;

end

Demodülasyonu ASK (ask_demodulate.m) (Temelde sadece Hilbert dönüşümünü kullandığım zarf algılama)

function [demodulated_signal] = ask_demodulate(received_signal, fs, F_on, bit_rate)
% Amplitude shift keying: Demodulation
% Dang Manh Truong (dangmanhtruong@gmail.com)

demodulated_signal = abs(hilbert(received_signal));

end

Lütfen söyle bana neden çalışmıyor? Çok teşekkür ederim


Teoride (gürültüsüz bir ortamda), bunun uygulanması önemsiz olacaktır, ancak pratikte bu çok daha zordur. Yine de, göndermeye çalıştığınız bilgi türüne bağlıdır. Metnin güvenilir bir şekilde iletilmesi son derece zordur çünkü en küçük gürültü bile metni tanınmaz hale getirir.
dsp_user

@ dsp_user Metin göndermeye çalışıyorum. Bazı hatalarla yaşayabilirim ("Ses" -> "Apdio" gibi) :) Ayrıca, Genlik Kaydırma Tuşlaması için, örneğin 1 olduğunda, sinüs dalgası, 0 sonra hiçbir şey gönderemezsiniz. ilk 0'ı biliyor musun? Gürültüsüz bir ortamda yani ilk 1'den önce çok fazla 0 olur mu? Peki bunu nasıl biliyorsun?
Dang Manh Truong

Fikirler için eski moda 14.4 modem gibi bir şeye bakmanızı öneririm.

@StanleyPawlukiewicz Biraz ilerleme kaydettim. Lütfen güncellemeyi kontrol edin. Çok teşekkür ederim.
Dang Manh Truong

Yorum yapılacak çok şey var.

Yanıtlar:


8

Fark ettiğiniz gibi, dijital iletişim yapmanın zor kısmı taşıyıcı, sembol ve çerçeve senkronizasyonu ve kanal tahmini / eşitleme.

Kötü haber şu ki, bu sorunları çözemezsiniz. İyi haber şu ki, kendinizi dar bantlı BPSK ile sınırladığınız sürece bunları uygulamak o kadar da zor değil. Biliyorum, çünkü bunu kendim yaptım ve lisans öğrencilerim de var (bkz. Http://ieeexplore.ieee.org/document/5739249/ )

Taşıyıcı senkronizasyonu sorununu çözmek için basit bir öneri, temel bant sinyalinizi yukarı dönüştürmek için AM DSB-LC'yi kullanmaktır. Ardından, taşıyıcı ve faz senkronizasyonu olmadan bir zarf dedektörü kullanabilirsiniz. Bu, güç verimliliğinde size mal olacak, ancak bu sizin durumunuzda bir öncelik değildir.

Başka bir basit öneri, "gerçek zamanlı işleme" yerine "toplu işleme" yapmaktır; bunun anlamı, alınan sinyalin tamamını saklamak ve daha sonra işlemek. Bu, akış veya gerçek zamanlı işlemden çok daha kolaydır.

Benim daha önemli önerim şu kitabı okumak: Johnson, Sethares ve Klein, "Yazılım alıcı tasarımı", Cambridge. Alıcının her bir parçasını çok açık bir şekilde açıklar ve birçok örnek Matlab koduna sahiptir. Steven Tretter'in DSP'ye bir iletişim sistemi uygulama üzerine benzer bir kitabı var (şu anki tam başlığı hatırlayamıyorum).

İyi şanslar; ve yeni sorularınız varsa lütfen sorunuz.


Makaleni okudum. İyi işlere devam edin! Bir soru: Makalede, öğrencilerin kanal yanıtını bulmak için kullandıkları çeşitli yöntemlerden bahsettiniz (dürtü, sinüs dalgaları, vb. Kullanarak). Kanal yanıtını da bulmam gerekir mi? :)
Dang Manh Truong

1
Nazik sözleriniz için teşekkürler :) Şey, kanal yanıtının düz olduğu bir frekans bandı üzerinden ilettiğinizden emin olmak istediğinizdir; aksi takdirde, alıcıda bir ekolayzere ihtiyacınız olacaktır. Kanal yanıtını tahmin etmek istemiyorsanız, tüm ses donanımının rahat olması gereken bir frekansta (örneğin 5000 Hz) çok düşük bir veri hızı (örneğin, 100 b / s) kullanmaktır.
MBaz

1
@DangManhTruong Bir şey daha var: büyük bir bant genişliğine sahip ve büyük olasılıkla bozulmaya uğrayan kare darbeler değil, kare kök yükseltilmiş kosinüs gibi bant genişliği sınırlı darbeler kullandığınızdan emin olun.
MBaz

Önerdiğiniz gibi Yazılım alıcı tasarımı kitabını okudum (aslında çoğunu gözden geçirdim ve Bölüm 8: Sembollerden Sinyallere Bitti). Bazı sorularım var. Bakliyat hakkında bir şey söyledin, ama kitabın örneğinde bir Darbe olarak bir Hamming penceresi kullandılar, bunu yaparsam sorun olmaz mı? Benim anladığım doğru mu: Önce ASK kullanarak sinyali modüle edersiniz, sonra nabız şekillendirme kullanırsınız. Daha sonra alıcıda, modüle edilmiş sinyali almak için önce nabız sinyali ile ilişkilendirilirsiniz. Sonra demodüle ediyorsun. Doğru mu?
Dang Manh Truong

Ve veriyi bir paket formunda, başında ve sonunda bir başlık ile göndermek istersem, 1 1 1 1 1 1 1 1 diyelim, bu yüzden veriye eklemeli, modüle etmeli, sonra nabzını şekillendirmeliyim. Alıcıda, alınan sinyali nabız şekliyle (kare kök yükseltilmiş kosinüs, ..) ilişkilendiririm, daha sonra sinyali demodüle etmeliyim, bundan sonra başlık ile ilişkilendirilir. Anlayışım doğru mu?
Dang Manh Truong

4

Sonunda, DTMF (Çift Tonlu Çoklu Frekans sinyali) kullandım. Orijinal DTMF, her biri 2 frekans kombinasyonu kullanan 16 sinyale sahiptir. Ama burada sadece "1" (697 Hz ve 1209 Hz) ve "0" (941Hz ve 1336 Hz) kullandım

Kodun nasıl çalıştığının bir özeti:

  • Gönderen metni ikiye dönüştürür, sonra "0" / "1" DTMF sinyallerini iletir (burada zamanlama ton süresi için 0,3 sn ve tonlar arasındaki sessizlik süresi için 0,1 sn'dir). İletim kodu şu adresten alınır: https://sites.google.com/a/nd.edu/adsp-nik-kleber/home/advanced-digital-signal-processing/project-3-touch-tone . Görünüşe göre yazar, dijital bir osilatör uygulamak için marjinal olarak kararlı bir IIR filtresi kullandı.
  • Alıcı taraf ilk önce sırasıyla "0" ve "1" frekans bileşenlerini çıkarmak için gülünç derecede yüksek sıralı ve gülünç derecede dar bant geçiren filtreler kullanır:

    filtre_düzeni = 1000;

    one_band = [[((2696)/Fs) ((2698)/Fs)] [((21208)/Fs) ((21210)/Fs)]];
    
    one_dtmf_filter = fir1(filter_order, one_band);
    
    zero_band = [[((2940)/Fs) ((2942)/Fs)] [((21335)/Fs) ((21337)/Fs)]];
    
    zero_dtmf_filter = fir1(filter_order, zero_band);
    

Bu yapıldıktan sonra her bir "1" ve "0" sinyalinin başlangıcını ve sonunu bulacağız. Kod https://github.com/codyaray/dtmf-signaling adresinden alınmıştır . Temel olarak en az 10 ms sessizlik süresini ve 100 ms'den fazla ton süresini bulur):

resim açıklamasını buraya girin

(Yukarıdan aşağıya: Sıfır sinyali, ortalama filtreyi taşıdıktan sonra sinyal, eşiğin altındaki değerleri kaldırdıktan sonra sinyal farkı, eşikten sonra sinyal)

  • İlk olarak, önceki adımdaki sonuç normalleştirilir, daha sonra hareketli bir ortalama filtreden geçirilir (filtre boyutu 10ms * Fs'ye eşittir). Sonucu çizersek, "0" ve "1" şeklinin açıkça görülebileceğini görürüz. Bu yüzden bu durumda bir zarf dedektörü olarak çalıştığını düşünüyorum.
  • Sonra belirli bir eşiğin altındaki tüm sinyal kesilir (0.1'i seçtim).
  • Son olarak, 100 ms'den büyük bir zaman aralığı olan eşiğin üzerindeki tüm aralıkları bulun (görüntünün koddan tekrar üretilemediğini unutmayın, bunu yapmak için etrafta kazmanız gerekir)

Sonra bitleri birleştirip metne dönüştürüyoruz :)

Video demosu: https://www.youtube.com/watch?v=vwQVmNnWa4s , burada dizüstü bilgisayarım ve kardeşimin PC'si arasında "Xin chao" metnini gönderiyorum :)

P / S: Aslında bunu yaptım çünkü Dijital İletişim öğretmenim bunu yapan her kimsenin final sınavını yapmak zorunda kalmadan A alacağını söyledi, ancak bunu ancak sınavdan sonra yapabildim. İşte tüm çabalarım :(

P / S2: C + aldım :(


0

Çok iyi senkronizasyona sahip açık kaynaklı bir kütüphane istiyorsanız, hizalamak için msequences kullanan, sonra eşitleme yapan ve yükü demodüle eden https://github.com/jgaeddert/liquid-dsp'yi öneriyorum . Üstte çalışan bir ses modemi yaptım ve oldukça iyi çalışıyor, bu yüzden başka bir şey yoksa, sıvının yöntemleri biraz yardımcı olmalı

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.