距离非常近,即两台计算机基本上彼此相邻
噪音很小(我不认为我的老师会在一块岩石上转动歌曲作为噪声源)
可以接受的错误:例如,如果我发送“无线电通讯”,那么如果另一台计算机收到“ RadiQ通信”,也可以。
如果可能的话:没有标题,标志,校验和,...。因为我只想要一个非常基本的示例,演示通过声音传输数据的基础。不必花哨。
我尝试根据此链接使用音频频移键控:
Lab 5 APRS(自动包装报告系统)
>并得到一些结果:
我的Github页面
,但这还不够。我不知道如何进行时钟恢复,同步...(该链接具有锁相环作为定时恢复机制,但显然还不够)。
所以我认为我应该找到一种更简单的方法。在此处找到了一个链接:
数据到音频并返回。使用源代码进行调制/解调,但是OP并未实现答案中建议的方法,因此恐怕它可能非常复杂。另外,我也不清楚答案中建议的解码方法:
解码器稍微复杂一点,但这是一个概述:
可选带通对11Khz附近的采样信号进行滤波。这将
在嘈杂的环境中提高性能。 FIR滤波器很简单
,有一些在线设计小程序可以为您生成滤波器。
信号阈值。大于1/2最大幅度的每个值均为1
,小于1/2最大幅度的每个值均为0。这假设您已采样了整个
执行某种自动增益控制,在一段时间内跟踪最大信号电平。
扫描点或破折号的开始。您可能希望在点期间至少看到一个
1的一定数量,以将样本视为一个
点。然后继续扫描以查看是否是破折号。不要指望一个完美的信号-您会在1的中间看到几个0,而在0的中间看到一个
1。如果噪声很小,那么将“开启”时段与“关闭”时段区分开应该很容易。
然后颠倒上述过程。如果看到破折号将一个1推入您的
缓冲区,如果一个点将一个0推入了零。
在将其归类为点之前,我不知道有多少个1。 ..所以我现在不了解很多事情。请向我建议一种通过声音传输数据的简单方法,以便我能够理解该过程。非常感谢您:)
更新:
我制作了一些Matlab代码,这些代码似乎(可以)运行。我首先使用幅度移位键控(采样频率48000 Hz,F_on = 5000 Hz,比特率= 10 bits / s)调制信号,然后将其与标头和结束序列相加(当然也对它们进行调制)。标头和结尾序列是临时选择的(是的,这是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];
然后我通过声音传输它们,并用我的智能手机。然后,我将录制的音频发送回我的计算机,使用另一段代码读取音频。然后,我将接收到的信号(尚未解调)与已调制的标头和结束序列相关联,以找出开始和结束。之后,我仅获取相关信号(从开始到结束,如相关部分所述)。然后,我解调并采样以找到数字数据。这是3个音频文件:
“ DigitalCommunication_ask”:在此处链接发送文本“ Digital communication”。相对无噪音,尽管您可以在开始和结束时听到一些背景噪音。但是结果仅显示“ Digital Commincatio”
“ HelloWorld_ask”:在此处链接将发送文本“ Hello world”。无噪音,例如“ DigitalCommunication_ask”。但是,此结果是正确的
“ HelloWorld_noise_ask”:在此处链接,它将发送文本“ Hello world”。但是,我发出了一些噪音(在传输过程中,我只是说了一些随机的东西“ A,B,C,D,E ...”)。不幸的是,这失败了
这是发送方(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);
对于接收方(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调制代码(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解调(ask_demodulate.m)(基本上只是包络检测,我使用了希尔伯特变换。)
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
请告诉我为什么它不起作用?非常感谢
#1 楼
如您所知,进行数字通信的难点在于载波,符号和帧同步以及信道估计/均衡。坏消息是您无法解决这些问题。好消息是,只要您将自己限制在窄带BPSK上,实施这些并不难。我知道,因为我是自己做的,我的(本科)学生也是如此(请参阅http://ieeexplore.ieee.org/document/5739249/)。
一个简单的建议可以解决载波同步的问题是使用AM DSB-LC上变频您的基带信号。然后,您可以使用没有载波和相位同步的包络检波器。这会降低您的电源效率,但这并不是您的优先考虑。
另一个简单的建议是执行“批处理”而不是“实时处理”。这就是说,存储整个接收到的信号并随后对其进行处理。与流或实时处理相比,这更容易实现。
我更重要的建议是读这本书:Johnson,Sethares和Klein,“软件接收器设计”,剑桥。它以非常清晰的术语解释了接收器的每一部分,并提供了许多示例Matlab代码。史蒂文·特雷特(Steven Tretter)有一本类似的书,关于在DSP上实现通信系统(我现在不记得确切的标题)。
祝你好运;并请提出新的更具体的问题。
评论
$ \ begingroup $
我读了你的论文。保持良好的工作!一个问题:在本文中,您讨论了学生用来查找通道响应的几种方法(使用脉冲,正弦波等)。我也需要找到频道响应吗? :)
$ \ endgroup $
–邓敏(Dang Manh Truong)
17年5月5日在14:51
$ \ begingroup $
谢谢您的客气:)问题是您要确保在信道响应平坦的频带上进行传输;否则,您将在接收器中需要一个均衡器。如果您不想估计通道响应,您可以做的是在所有音频设备都应该适应的频率(例如5000 Hz)上使用非常低的数据速率(例如100 b / s)。
$ \ endgroup $
– MBaz
17-12-5在16:03
$ \ begingroup $
@DangManhTruong还有一件事:请确保使用带宽受限的脉冲(例如平方根升余弦),而不要使用带宽较大且很可能会失真的平方脉冲。
$ \ endgroup $
– MBaz
17年5月5日在19:15
$ \ begingroup $
我已经按照您的建议阅读了《软件接收器设计》一书(实际上我浏览了其中的大部分内容,并专注于第8章:从位到符号到信号)。所以我有一些问题。您说了一些关于脉冲的内容,但是在本书的示例中,他们使用了汉明窗作为脉冲,是否可以?我的理解是正确的:首先您使用ASK调制信号,然后使用脉冲整形。然后,在接收器上,您首先与脉冲信号相关以接收调制信号。然后您解调。这是对的吗?
$ \ endgroup $
–邓敏(Dang Manh Truong)
17年6月6日在16:55
$ \ begingroup $
如果我想以数据包的形式发送数据,在数据的开头和结尾都标有1 1 1 1 1 1 1 1,那么我应该将其附加数据,然后对其进行调制,然后脉冲整形吧。在接收器上,我将接收到的信号与脉冲形状(平方根升余弦,..)相关联,然后我必须对信号进行解调,然后再与标头相关联。我的理解正确吗?
$ \ endgroup $
–邓敏(Dang Manh Truong)
17年12月6日在16:57
#2 楼
最后,我使用了DTMF(双音多频信令)。原始DTMF具有16个信号,每个信号使用2个频率的组合。但是在这里,我只使用了“ 1”(697 Hz和1209 Hz)和“ 0”(941Hz和1336 Hz)代码的工作原理概述:
发送方将文本转换为二进制,然后发送“ 0” /“ 1” DTMF信号(此处的音调持续时间为0.3s,音调之间的静默时间为0.1s)。传输代码来自:https://sites.google.com/a/nd.edu/adsp-nik-kleber/home/advanced-digital-signal-processing/project-3-touch-tone。显然,作者使用了一个边际稳定的IIR滤波器来实现数字振荡器。
接收方首先使用2个离谱高阶和离谱窄带通滤波器来提取“ 0”和“ 1“频率分量分别为:
filter_order = 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);
完成此操作后,我们将找到起点和每个“ 1”和“ 0”信号的末尾。该代码来自https://github.com/codyaray/dtmf-signaling。基本上,它会找到至少10 ms的静默周期,以及任何大于100ms的音调周期):
(从上到下:零信号,移动后发出信号平均滤波器,去除低于阈值的信号后的信号差,阈值之后的信号)
首先将上一步的结果归一化,然后经过移动平均滤波器(滤波器大小等于10ms * Fs)。如果将结果绘制成图,我们将清楚地看到“ 0”和“ 1”的形状。所以我认为它在这种情况下可以用作包络检波器。
然后将低于某个阈值的所有信号都切断(我选择了0.1)。
最后找到高于阈值的所有时间间隔间隔大于100毫秒(请注意,该图像无法从代码中复制,您必须四处挖掘才能做到)
然后,我们将这些位组合起来并转换回文本:)
视频演示:https://www.youtube.com/watch?v=vwQVmNnWa4s,我在两人之间发送文本“ Xin chao”笔记本电脑和我哥哥的PC :)
P / S:最初我这样做是因为我的数字通信老师说,这样做的人都将获得A,而不必进行期末考试,但是我只能在考试后进行此操作。因此,我的所有努力都在这里:(
P / S2:我得到了C + :(
评论
从理论上(在无噪声的环境中),这将是微不足道的实现,但实际上这要困难得多。不过,这取决于您要发送的信息类型。很难可靠地传输文本,因为即使是最小的噪音也会使文本无法识别。@dsp_user我正在尝试发送文本。我可能会遇到一些错误(例如“音频”->“ Apdio”):)我也不是很明白,例如,对于幅移键控,当您发送1时,您发送正弦波;发送0时,则什么也没有,您知道第一个0吗?我的意思是在无噪声的环境中,但是在第一个1之前会有很多0,对吗?那你怎么知道呢?
我建议您看看类似老式的14.4调制解调器的想法。
@StanleyPawlukiewicz我取得了一些进展。请检查更新。非常感谢。
有很多评论。假设您正在使用前同步码,则可能需要查看Barker序列。