APRS功能可以用对讲机来传输数字信息,以便在没有运营商网络的环境下共享位置,实现类似微信的位置共享功能,也可以用它来发短消息。
有人买直接带aprs的对讲机,比较贵。也有人用普通对讲机和手机通过音频线对接,然后手机上运行aprsdroid软件来实现同样的功能。

它的原理跟sstv比较类似,都是两次fm,把数据进行编码(手机中完成),然后用音频的高低音来表示编码10101(手机中完成),再把这个编码再次做fm调制(对讲机中实现)最终发射出去。
portapack可以把手机和对讲机合并在一起,还是利用sstv中类似的方法就能完成。
furrtek固件里已经有一个aprs tx软件,虽然是黄色图标(代表不完善),但是根据一位朋友的反馈,已经可以用它发射信号,然后用对讲机+aprsdroid来成功解码。
现在我来做一个aprs rx就行。
我打算先用一个portapack的aprs tx来发射,然后用hackrf+电脑来做fm解调代替对讲机,然后用aprsdroid来解码体验一下。
然后把aprsdroid解码部分用c++实现,再往portapack移植就行了。
但是我发现aprsdroid程序虽然开源,但是用scala语法写的,我还不太熟悉。
所以我就直接看了portapack里的各种代码,我发现portapack中的aprs tx程序只是做了上层编码,它的底层是afsk tx。
发射部分调用关系如下:
ui_aprs_tx.cpp (make_aprs_frame) -> aprs.cpp (make_ui_frame) -> ax25.cpp (shared_memory.bb_data.data) -> proc_afsk.cpp (word_ptr)
而portapack的接收部分里已经有了一个afsk rx了,用它来解调,只要做好上层解码就行了。
我仔细看了一下proc_afsk.cpp(发射调制)和proc_afskrx.cpp(接收调制)。
proc_afsk.cpp(execute函数)
if (cur_bit)
tone_phase += afsk_phase_inc_mark;
else
tone_phase += afsk_phase_inc_space;
tone_sample = sine_table_i8[(tone_phase & 0xFF000000U) >> 24];
delta = tone_sample * fm_delta;
phase += delta;
sphase = phase + (64 << 24);
re = (sine_table_i8[(sphase & 0xFF000000U) >> 24]);
im = (sine_table_i8[(phase & 0xFF000000U) >> 24]);
buffer.p[i] = {re, im};
这部分代码跟sstv发射的对应部分差不多,通过操作tone_phase,就能发射两次fm的信号,只不过sstv里影响tone_phase的是像素点的颜色值,而这里是mark和space。我觉得它们就对应1和0。
porc_afskrx.cpp (execute函数)
一开始在做第一次的fm解调,从无线电信号变为音频信号,相当于是一个对讲机。
得到音频信号后要再做一次fm解调。下方代码就在做这个事,跟我sstv接收里的音频fm解调效果差不多的,早知道我就直接参考它这里代码了。
原理就是sdrsharp讲解里也讲过的,把信号作延迟再乘以本身的信号就行,这个delay line在rtlsdr的那本书里也讲过。
// Delay line put
delay_line[delay_line_index & 0x3F] = current_sample;
// Delay line get, and LPF
sample_mixed = (delay_line[(delay_line_index - (samples_per_bit/2)) & 0x3F] * current_sample) / 4;
sample_filtered = prev_mixed + sample_mixed + (prev_filtered / 2);
delay_line_index++;
prev_filtered = sample_filtered;
prev_mixed = sample_mixed;
// Slice
sample_bits <<= 1;
sample_bits |= (sample_filtered < -20) ? 1 : 0;
// Check for "clean" transition: either 0011 or 1100
if ((((sample_bits >> 2) ^ sample_bits) & 3) == 3) {
// Adjust phase
if (phase < 0x8000)
phase += 0x800; // Is this a proper value ?
else
phase -= 0x800;
}
phase += phase_inc;
sample_filtered里面是解调出来的音频频率,照道理这里要根据设置的mark和space频率值来灵活配置,不知道为啥只是以-20作为阈值来判断当前采样对应1或0。
下面这段根据不同的协议来把sample_bits转为word_bits然后传送给程序的其他部分。
if (trigger_word) {
// Continuous-stream value-triggered mode (AX.25) - UNTESTED
word_bits <<= 1;
word_bits |= (sample_bits & 1);
bit_counter++;
if (triggered) {
if (bit_counter == word_length) {
bit_counter = 0;
data_message.is_data = true;
data_message.value = word_bits & word_mask;
shared_memory.application_queue.push(data_message);
}
} else {
if ((word_bits & word_mask) == trigger_value) {
triggered = !triggered;
bit_counter = 0;
data_message.is_data = true;
data_message.value = trigger_value;
shared_memory.application_queue.push(data_message);
}
}
} else {

最低0.47元/天 解锁文章
6632

被折叠的 条评论
为什么被折叠?



