超声波调制解调信号

本文最后更新于:2022年7月30日 下午

完成使用超声波调制发送解调IP地址的任务。

主要流程

1、 在电脑使用matlab,将提供的IP转换为32位二进制。将每一位0或1分别调制成480/48000=0.1s的正弦波,进行拼接。

2、 使用安卓手机发射调制的正弦波,使用麦克风接收声波信号。

3、 将麦克风收到的信号通过高通滤波器得到高频信号,根据信号的滑动均值和阈值提取收集到的整段信号,将根据信号窗口提取FFT能量作为0或1的解调。

4、 根据01串还原IP,完成超声波传输IP地址。

实现效果

在每秒100bits的情况,传输距离最高1m,超过这个距离接受的质量下降会导致有些bits识别错误,如果把窗口加长为每秒50bits,传输距离可以达到1.8m准确。

Thinking

除了分辨率会影响发射距离,发射手机的扬声器和接收手机的麦克风质量都会有影响。

考虑如何把发射距离提升到10m?

  • 使用更大功率的发射设备和接收设备
  • 考虑使用lora调制
  • 考虑改变发射频率

目前使用超声波发送调制信号可以使用lora调制,lora调制方法是商业的没有公布源码,可靠的实现可以参考清华博士的解析和实现

代码实现

调制发送信号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
f1 = 17e3;   
f2 = 18e3;
fs = 48e3;
A=350;
time=960;
sendSignal = zeros(1, time*32);

% 把ip转换为二进制
ipFields = uint8(str2double(split('173.33.45.29', '.')))'
temp=dec2bin(typecast(fliplr(ipFields), 'uint32'))
symbal = double(temp)-'0';

% 根据二进制生成正弦波
t = 0:1/fs:(time-1)/fs;
for i=symbal
if i==0
temp=A*cos(2*pi*f1*t);
else
temp=A*cos(2*pi*f2*t);
end
sendSignal = [sendSignal temp];
end
plot(sendSignal)
stft(sendSignal, fs)
dlmwrite("send/chirp.txt", sendSignal')

解调信号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
fs=48000;
f1 = 17e3;
f2 = 18e3;
chirp_len=960;
mode='s7/';
% 读取文件
fileFolder = fullfile(['receive/', mode]);
dirOutput = dir(fullfile(fileFolder,'*.pcm'));
fileNames = {dirOutput.name};
file_name = fileNames{end}
file=['receive/' , mode, file_name];
data= importdata(file);

% 去掉头尾信息
data=data(15000:end-50000);
stft(data, fs, "FFTLength", 1024)

time = length(data);
t = 0:1/fs:(time-1)/fs;
% 获得超声波部分
data=highpass(data, 15000, fs);
% stft(data, fs, "FFTLength", 1024)

% 获得有效数据
A = movmean(abs(data), 20);
thresh = (max(A) - min(A))/7 + min(A);
inds = find(A > thresh); % 找信号高于thre的下标位置
valid_data = data(inds(1):inds(end)); % 截取信号
if(length(valid_data)<32*chirp_len)
valid_data=padarray(valid_data,32*chirp_len-length(valid_data), "pre");
else
valid_data=valid_data(1:32*chirp_len);
end
%
% stft(valid_data, fs, "FFTLength", 1024)

% 解调01信号
res=[];
for i= 1:chirp_len:length(valid_data)
temp=valid_data(i:i+chirp_len-1);
[argv, argmin]=max(abs(fft(temp, fs)));
if(abs(argmin-f1)<abs(argmin-f2))
res= [res 0];
else
res=[res 1];
end
end

% 转换为ip
res;
str_res= sprintf('%1d', res)
deci_res=bin2dec(str_res)
IPVector= deci_res;
test=strcat(num2str(bitand(bitshift(IPVector,-24), 255)),'.',num2str(bitand(bitshift(IPVector,-16), 255)) ,'.',num2str(bitand(bitshift(IPVector,-8), 255)) ,'.',num2str(bitand(bitshift(IPVector,0), 255)) )