下图显示了支持两条信号数据通道的应用,其中一条通道拆分为两条低带宽通道,另一条则必须持续运行,不受任何干扰。此类动态重配置在无线应用中很常见。
图 1. 将 2 条 LTE20 通道动态重配置为 1 条 LTE20 和 2 条 LTE10 通道
在此图中,第一条通道负责处理 LTE20 数据(无更改),而中间通道则动态拆分为 2 条 LTE10 通道。标记为 carrier configuration RTP 的控制参数用于在块边界处拆分数据处理。在中间通道作为 LTE20 通道来工作的同时,绕过 11 抽头半带内核。但当中间通道的带宽在其本身与第三条通道之间进行拆分,形成 2 条 LTE10 通道时,这 2 条通道都需要 3 阶滤波器链才能将数据加以混合。具体达成方法是将 11 抽头半带滤波器切换回控制流程并重新配置混频器以处理 3 条(而不是 2 条)数据串流。
提示: 混用 LTE20 和 LTE10 信号时以及在控制流程中,由于需要在两者之间进行动态切换,因此都需要延迟对齐内核来平衡采样延迟。
以下代码中显示了以上应用的顶层输入 graph 规范。
class lte_reconfig : public graph {
private:
kernel demux;
kernel cf[3];
kernel interp0[3];
kernel interp1[2];
bypass bphb11;
kernel delay ;
kernel delay_byp ;
bypass bpdelay ;
kernel mixer ;
public:
input_port in;
input_port fromPS;
output_port out ;
lte_reconfig() {
// demux also handles the control
demux = kernel::create(demultiplexor);
connect< window<1536> >(in, demux.in[0]);
connect< parameter >(fromPS, demux.in[1]);
runtime<ratio>(demux) = 0.1;
source(demux) = "kernels/demux.cc";
// instantiate all channel kernels
for (int i=0;i<3;i++) {
cf[i] = kernel::create(fir_89t_sym);
source(cf[i]) = "kernels/fir_89t_sym.cc";
runtime<ratio>(cf[i]) = 0.12;
}
for (int i=0;i<3;i++) {
interp0[i] = kernel::create(fir_23t_sym_hb_2i);
source(interp0[i]) = "kernels/hb23_2i.cc";
runtime<ratio>(interp0[i]) = 0.1;
}
for (int i=0;i<2;i++) {
interp1[i] = kernel::create(fir_11t_sym_hb_2i);
source(interp1[i]) = "kernels/hb11_2i.cc";
runtime<ratio>(interp1[i]) = 0.1;
}
bphb11 = bypass::create(interp1[0]);
mixer = kernel::create(mixer_dynamic);
source(mixer) = "kernels/mixer_dynamic.cc";
runtime<ratio>(mixer) = 0.4;
delay = kernel::create(sample_delay);
source(delay) = "kernels/delay.cc";
runtime<ratio>(delay) = 0.1;
delay_byp = kernel::create(sample_delay);
source(delay_byp) = "kernels/delay.cc";
runtime<ratio>(delay_byp) = 0.1;
bpdelay = bypass::create(delay_byp) ;
// Graph connections
for (int i=0; i<3; i++) {
connect< window<512, 352> >(demux.out[i], cf[i].in[0]);
connect< parameter >(demux.inout[i], cf[i].in[1]);
}
connect< parameter >(demux.inout[3], bphb11.bp);
connect< parameter >(demux.inout[3], negate(bpdelay.bp)) ;
for (int i=0;i<3;i++) {
connect< window<512, 64> >(cf[i].out[0], interp0[i].in[0]);
connect< parameter >(cf[i].inout[0], interp0[i].in[1]);
}
// chan0 is LTE20 and is output right away
connect< window<1024, 416> >(interp0[0].out[0], delay.in[0]);
connect< window<1024> >(delay.out[0], mixer.in[0]);
// chan1 is LTE20/10 and uses bypass
connect< window<1024, 32> >(interp0[1].out[0], bphb11.in[0]);
connect< parameter >(interp0[1].inout[0], bphb11.in[1]);
connect< window<1024, 416> >(bphb11.out[0], bpdelay.in[0]);
connect< window<1024> >(bpdelay.out[0], mixer.in[1]);
// chan2 is LTE10 always
connect< window<512, 32> >(interp0[2].out[0], interp1[1].in[0]);
connect< parameter >(interp0[2].inout[0], interp1[1].in[1]);
connect< window<1024> >(interp1[1].out[0], mixer.in[2]);
//Mixer
connect< parameter >(demux.inout[3], mixer.in[3]);
connect< window<1024> >(mixer.out[0], out);
};
};
基于要绕过的内核,旁路规范编码为特殊的封装器。旁路的端口签名与其封装的内核的端口签名相匹配。它还会接收运行时参数以控制旁路:0
对应无旁路,1
对应旁路。通过使用所示取反函数还可反转控制。
此 graph 的旁路参数端口是普通的标量运行时参数,可由另一个内核驱动或者由 Arm® 处理器使用交互机制或脚本生成机制来驱动,如 运行时参数更新/读取机制 中所述。将其嵌入外包围的 graph 中还可按分层方式对其进行连接。