Home Transmit data through sound between 2 computers in close distance - in need of a very simple method
Reply: 1

Transmit data through sound between 2 computers in close distance - in need of a very simple method

Dang Manh Truong
1#
Dang Manh Truong Published in 2017-12-05 11:14:26Z

I have a project that requires transmitting sound data between two computers. One computer emits sound while the other one listens and reads the data. I've done some research and decided on using Audio Frequency Shift Keying for modulation/demodulation, since I've found a course here which goes into details about the method:

Lab 6 Audio frequency shift keying

Lab 5 Audio frequency shift keying

Lab 5 APRS (Automatic package reporting system

These were useful links, thanks to them I've been able to successfully modulate and demodulate the signal, and also timing recovery using Phase-Locked Loop (PLL), here is my results:

Transmit data through sound using AFSK1200

Some screenshots:

However this is not enough, I need to perform the experiment in a real life condition (transmit data as sound between 2 computers). But the thing is the description about this part on the links above were very difficult to understand, for example here is some code on the 3rd link that is supposed to read the data from the demodulated signal:

def findPackets(bits):
        # function take a bitarray and looks for AX.25 packets in it. 
        # It implements a 2-state machine of searching for flag or collecting packets

        flg = bitarray.bitarray([0,1,1,1,1,1,1,0])
        packets = []
        n = 0
        pktcounter = 0
        packet = []
        state = 'search'

        # Loop over bits
        while (n < len(bits)-7) :

            # default state is searching for packets
            if state is 'search':

                # look for 1111110, because can't be sure if the first zero is decoded
                # well if the packet is not padded.
                if bits[n:n+7] == flg[1:]:

                    # flag detected, so switch state to collecting bits in a packet
                    # start by copying the flag to the packet
                    # start counter to count the number of bits in the packet
                    state = 'pkt'
                    packet=flg.copy()
                    pktcounter = 8                    
                    # Advance to the end of the flag
                    n = n + 7
                else:
                    # flag was not found, advance by 1
                    n = n + 1            

            # state is to collect packet data. 
            elif state is 'pkt':

                # Check if we reached a flag by comparing with 0111111
                # 6 times ones is not allowed in a packet, hence it must be a flag (if there's no error)
                if bits[n:n+7] == flg[:7]:
                    # Flag detected, check if packet is longer than some minimum
                    if pktcounter > 200:
                        # End of packet reached! append packet to list and switch to searching state
                        # We don't advance pointer since this our packet might have been
                        # flase detection and this flag could be the beginning of a real packet
                        state = 'search'
                        packet.extend(flg)
                        packets.append(packet.copy())
                    else:
                        # packet is too short! false alarm. Keep searching 
                        # We don't advance pointer since this this flag could be the beginning of a real packet
                        state = 'search'
                # No flag, so collect the bit and add to the packet
                else:
                    # check if packet is too long... if so, must be false alarm
                    if pktcounter < 2680:
                        # Not a false alarm, collect the bit and advance pointer                        
                        packet.append(bits[n])
                        pktcounter = pktcounter + 1
                        n = n + 1
                    else:  
                        #runaway packet, switch state to searching, and advance pointer
                        state = 'search'
                        n = n + 1
        return packets

I tried but it did not work! And I really do not know why. Perharps it has to do with the Morse code ? (they encoded data as Morse code before sending it, but I did not). They used the AX.25 protocol but I did not use it but only the essential part (bit stuffing, then convert to Non Return to Zero Inverted). Another method was described here: Lab 5 APRS

but it also did not work! So I think it was because I did not really understand how to read the data from the demodulated signal. I checked around on the web and found this link:

ChirpCast: Data transmission via Audio

They did implement Frequency Shift Keying but they used a separate CLOCK signal as synchronization mechanism:

Our implementation consists of two simultaneously transmitted bit streams, a DATA signal on the left speaker channel and a CLOCK signal on the right signal channel. The decision to send a separate clock signal simplifies the sender and receiver synchronization, since the clock signal informs the receiver when it should sample the data without requiring a receiver-maintained reference clock.

Which is not suitable for my use case since I need to transmit just sound and have the receiving computer read it on its own. I also found a link on Stack Exchange:

Data to audio and back. Modulation / demodulation with source code

The answer suggested using Amplitude Shift Keying, however the OP did not implement that method, so I'm afraid it may be quite complex. And also the answer did not give details about whether one should send the data in a packet (header, flag,...). I really don't know if sending in a packet is a must or not. Also I did not really understand how to decode the message:

The decoder is a bit more complicated but here's an outline:

Optionally band-pass filter the sampled signal around 11Khz. This will improve performance in a noisy enviornment. FIR filters are pretty simple and there are a few online design applets that will generate the filter for you.

Threshold the signal. Every value above 1/2 maximum amplitude is 1 every value below is 0. This assumes you have sampled the entire signal. If this is in real time you either pick a fixed threshold or do some sort of automatic gain control where you track the maximum signal level over some time.

Scan for start of dot or dash. You probably want to see at least a certain number of 1's in your dot period to consider the samples a dot. Then keep scanning to see if this is a dash. Don't expect a perfect signal - you'll see a few 0's in the middle of your 1's and a few 1's in the middle of your 0's. If there's little noise then differentiating the "on" periods from the "off" periods should be fairly easy.

Then reverse the above process. If you see dash push a 1 bit to your buffer, if a dot push a zero.

I do not understand how many 1's before classifying it as a dot,... So there are many things that I do not understand right now. I'm not asking everyone to solve my homework, I just want someone to point me in the right direction. Here is the requirements:

  • The distance is very close , i.e the 2 computers are basically adjacent to each other
  • Very little noise (I do not think my teacher would turn on a rock song as a noise source)
  • Error is acceptable: For example if I send "Radio communication" then if the other computer receives "RadiQ communEcation" it's alright as well.
  • If possible: No header, flag, checksum,.... since I just want a very basic example demonstrating the basics of transmitting data through sound. No need to be fancy.

I'm not asking for everyone to solve my homeworks, just to help me find the right direction. Please help me, thank you very much :)

UPDATE:

I have made some Matlab code which appear to be (somewhat) operational. I first modulate the signal using Amplitude shift keying (sampling frequency 48000 Hz, F_on = 5000 Hz, bit rate = 10 bits/s), then add it with a header and an end sequence (of course modulate them as well). The header and the end sequence was chosen on an ad-hoc basis (yeah it was a hack):

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];

Then I transmit them through sound, and recorded it with my smartphone . Then I send the recorded audio back to my computer, use another piece of code to read the audio. Here are 3 audio files:

  • "DigitalCommunication_ask": Link here it sends the text "Digital communication". Relatively noise-free although you can hear some background noise at the beginning and the end. However the result showed only "Digital Commincatio"

  • "HelloWorld_ask": Link here it sends the text "Hello world". Noise free like "DigitalCommunication_ask". However the result for this one was correct

  • "HelloWorld_noise_ask": Link here it sends the text "Hello world". However there is some noise that I've made (I just said some random stuff "A,B,C,D,E,...." during the transmission). Unfortunately this one failed

Here is the code for the sender (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);

For the receiver (receiver.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

ASK modulation code (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

ASK demodulation (ask_demodulate.m) (Basically it is just envelope detection, for which I used the Hilbert transform)

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

Please tell me why is it not working? Thank you very much

Omkaar.K
2#
Omkaar.K Reply to 2017-12-16 10:55:04Z

When communicating for information, we need 5 components.

  1. Message source(in this case, it's the "Hello world".)

  2. Transmitter which encodes your message into signals(in this case, first translate to ASCII, then ASFK)

  3. Channel which signals can pass(this case, it's sound)

  4. A receiver which decodes signal and gets the message.

  5. Message target(this case, the other computer)

So, you can do all this when there is no noise. It means you already have a basic communication system and you have problem when the Channel has noise, your signal is distorted, you send 1001, and you get 011100, you need error correction, that's fancy stuff, so I suggest just send the message length and message digest before the message, so you receiver can know whether message is correct or not. This simple approach may require you Transmitter send the signal many times. If you need real stuff, then read Error_detection_and_correction and build your own protocol.

You need to login account before you can post.

About| Privacy statement| Terms of Service| Advertising| Contact us| Help| Sitemap|
Processed in 0.336945 second(s) , Gzip On .

© 2016 Powered by mzan.com design MATCHINFO