ここでは、入力切替器とマトリクス回路と38kHzサブキャリアとの平衡変調器、19kHzステレオパイロット信号付加を行います。
マトリクス回路周りの信号処理の詳細を前回の記事から再掲します。
サブチャンネルの処理
サブチャンネルは、入力L/Rの差信号と38kHzサブキャリアの乗算で生成します。ここでサブキャリアの波形を考えます。サンプリング周波数152kHzのとき38kHzの正弦波は、わずか4点で表現することになります。下表を見るとサブキャリアがとる値としては0, 1, -1しかありませんから乗算といいながら、L-R信号をオンオフするか極性反転だけで済むことになります。
これを見て、スイッチング方式のステレオ変調そのものだなと感じました。
入力レベルと変調度の関係
アナログ入力端子があるので入力レベル -6dBFS で変調度100%を基本とすることにしました。
(1)ステレオモード
L/Rチャンネルが-6dBFSのとき、Lチャンネル45%・Rチャンネル45%・ステレオパイロット信号10%で合計100%変調。
(2)モノラルモード
Lチャンネルが-6dBFSのとき100%変調。
ステレオパイロット信号の発生
ステレオパイロット信号は、38kHzサブキャリアの半分の周波数で同位相です。振幅は、ステレオモードで入力信号0dBFSのときメインチャンネルの18分の1とします。ただし、処理の過程でシフト演算により振幅を1/16にすることを考慮して、下表では22ビットフルスケールの16/18としました。
特性実測値
まず、コーデックのアナログ出力でのコンポジット信号の波形です。Lチャンネルのみ1kHz 0dBFSでステレオパイロット信号は断にしています。
教科書によると、波形の交点が0基線(図では上にずらしています)と一致し一直線上にあるのでメインチャンネルとサブチャンネルで位相差がなく(基部にうねりがあるので)レベル差だけがある状態とのこと。
コンポジット信号波形(1kHz 0dBFS Lチャンネル)
2012.08.10追記 波形の うねり は、コーデックの周波数特性が原因でした。下図のとおり、コンポジット信号の最高周波数53kHz付近(0.35 fs)では、なんと-3dBも下がっています。これではコンポジット信号を扱うことができません。
CS4270の周波数特性
パイロット信号のレベルを確認するためスペクトルを確認しました。
(1)は、1kHz 0dBFS L/Rチャンネル同相です。メインチャンネル-12.53dB、パイロット-37.9dBで25.4dBのレベル差があります。メインチャンネル180%変調相当レベル、パイロット10%のレベル差は25.1dBなので概ね妥当です。L/Rチャンネル同相のためサブキャリアはありません。
(1)コンポジット信号(1kHz 0dBFS L/Rチャンネル)
(2)は、1kHz 0dBFS Lチャンネルのみです。メインチャンネル-18.55dB、パイロット -37.9dB、サブキャリアのうち37kHzは-24.51dB、39kHzは-25.4dBでした。サブキャリアの37/39kHzでレベル差0.9dBもあります。
(3)(4)は、周波数を1kHz/125Hzと切替え、さらにFFTのサンプル数を変えてみたところです。低域側/高域側のレベルは、(3)1kHz: -24.51/-25.4dBで+0.89dB、125Hz: -25.28dB/-24.56dBで-0.72dB。(4)1kHz: -25.93dB/-24.73dBで-1.2dB、125Hz: -24.7dB/-25.95dBで+1.25dB。
測定系の誤差もあるようですが、よくわからなくなってきました。普通に考えればアナログ周りの周波数特性差でしょうか。
(2)コンポジット信号(1kHz 0dBFS Lチャンネル)
(3)サブキャリア(赤1kHz/黒125Hzの比較 FFT:65536)
(4)サブキャリア(赤1kHz/黒125Hzの比較 FFT:8192)
(5)は、モノラルモード1kHz 0dBFSで200%変調相当レベルで-11.6dBでした。(1)のメインチャンネルの180%変調相当レベルより0.93dB高く、概ね設計通りであることが確認できました。
(5)モノラルモード(1kHz 0dBFS Lチャンネル)
mpx.v
module mpx(
mpx_l0_i, mpx_r0_i, mpx_l1_i, mpx_r1_i, mpx_o,
clk, reset, mpx_set, mpx_pilot_o
);
input [23:0] mpx_l0_i;
input [23:0] mpx_r0_i;
input [23:0] mpx_l1_i;
input [23:0] mpx_r1_i;
output [23:0] mpx_o;
input clk; // 64fs
input reset;
input [4:0] mpx_set;
output [23:0] mpx_pilot_o;
reg [8:0] state512;
wire [5:0] state64;
wire [1:0] sub38k_addr;
wire [2:0] pilot19k_addr;
wire [21:0] pilot19k;
wire latch_out;
wire INPUT_SEL;
wire MPX_MODE;
wire MAIN_CHANNEL_CONT;
wire SUB_CHANNEL_CONT;
wire PILOT_CONT;
reg [23:0] input_reg_l;
reg [23:0] input_reg_r;
reg [24:0] main_channel;
reg [24:0] sub_channel;
reg [24:0] diff;
reg [25:0] stereo_composite;
reg [25:0] stereo_composite2;
reg [23:0] mpx_o;
reg [23:0] mpx_pilot_o;
// State counter
always @(posedge clk or posedge reset)
begin
if (reset)
state512 <= 0;
else if (state512 == 511)
state512 <= 0;
else
state512 <= state512 + 1;
end
assign state64 = state512[5:0];
assign sub38k_addr = state512[7:6];
assign pilot19k_addr = state512[8:6];
assign pilot19k = pilot19k_coe(pilot19k_addr);
assign latch_out = (state64 == 9);
assign INPUT_SEL = mpx_set[4]; // Selector 0:IN0, 1: IN1
assign MPX_MODE = mpx_set[3]; // MPX mode 0: Stereo, 1: Mono
assign MAIN_CHANNEL_CONT = mpx_set[2]; // Main Channel 0: On, 1: Off
assign SUB_CHANNEL_CONT = mpx_set[1]; // Sub Channel 0: On, 1: Off
assign PILOT_CONT = mpx_set[0]; // Stereo Pilot 0: On, 1: Off
// Stereo MPX
always @(posedge clk or posedge reset)
begin
if (reset)
begin
input_reg_l <= 0;
input_reg_r <= 0;
main_channel <= 0;
sub_channel <= 0;
diff <= 0;
stereo_composite <= 0;
stereo_composite2 <= 0;
diff <= 0;
end
else
begin
case (state64)
0: begin
input_reg_l <= (INPUT_SEL)? mpx_l1_i : mpx_l0_i;
input_reg_r <= (INPUT_SEL)? mpx_r1_i : mpx_r0_i;
end
1: begin
// L + R
main_channel <= (MAIN_CHANNEL_CONT) ? 0
: {input_reg_l[23], input_reg_l}
+ {input_reg_r[23], input_reg_r};
// L - R
diff <= (SUB_CHANNEL_CONT) ? 0
: {input_reg_l[23], input_reg_l}
+ ~{input_reg_r[23], input_reg_r} + 1;
end
2: begin
case (sub38k_addr)
1: sub_channel <= diff;
3: sub_channel <= ~diff + 1;
default: sub_channel <= 0;
endcase
end
3: begin
// MAIN + SUB
stereo_composite <= {main_channel[24], main_channel}
+ {sub_channel[24], sub_channel};
end
4: begin
// MAIN + SUB + PILOT
if (~PILOT_CONT)
stereo_composite <= stereo_composite
+ {{5{pilot19k[21]}}, pilot19k[21:1]};
end
5: begin
// stereo_composite2 = stereo_composite * (115/128) -> (-0.93dB)
stereo_composite2 <= {stereo_composite[25], stereo_composite[25:1]}
+ {{2{stereo_composite[25]}}, stereo_composite[25:2]};
end
6: begin
stereo_composite2 <= stereo_composite2
+ {{3{stereo_composite[25]}}, stereo_composite[25:3]};
end
7: begin
stereo_composite2 <= stereo_composite2
+ {{6{stereo_composite[25]}}, stereo_composite[25:6]};
end
8: begin
stereo_composite2 <= stereo_composite2
+ {{7{stereo_composite[25]}}, stereo_composite[25:7]};
end
default: begin
stereo_composite2 <= 0;
end
endcase
end
end
// output data register
always @(posedge clk or posedge reset)
begin
if (reset)
begin
mpx_o <= 0;
mpx_pilot_o <= 0;
end
else if (latch_out)
begin
mpx_o <= (MPX_MODE) ? input_reg_l
: stereo_composite2[25:1];
mpx_pilot_o <= {pilot19k, 2'b0};
end
end
// stereo pilot 19kHz coef
function [21:0] pilot19k_coe;
input [2:0] addr;
case (addr)
0: pilot19k_coe = 0;
1: pilot19k_coe = 22'h141CFD;
2: pilot19k_coe = 22'h1C71C6;
3: pilot19k_coe = 22'h141CFD;
4: pilot19k_coe = 0;
5: pilot19k_coe = 22'h2BE303;
6: pilot19k_coe = 22'h238E3A;
7: pilot19k_coe = 22'h2BE303;
default: pilot19k_coe = 0;
endcase
endfunction
endmodule
ステートカウンタ state64 に従って、処理を進めるように書いていますが、FPGAなのにこういうマイコン的な書き方でいいのか?と疑問を感じています。まあ動いているので結果オーライでしょうか。
0 件のコメント:
コメントを投稿