FPGA SDR(6)FIRフィルタ


2018/07/07 追記:自作FIRフィルタが完成しました。

 

CICフィルタは阻止域のレベルがあまり下がらないので、FIRフィルタでしっかり下げます。といってもまだ理解できていないのでフィルタの係数はツールの初期値のまま使っています。

`define CYCLE_1SEC 50000000


module SPIbridge
(
	input wire RST_N,
	input wire CLK,
	
	input wire SPI_NSS,
	input wire SPI_SCLK,
	output wire SPI_MISO,
	input wire SPI_MOSI,
	
	output wire [3:0] LED,
	
	input wire [7:0] ADC,
	output wire ENCODE,
	
	output reg [9:0] DAC,
	output wire DACCLK	
);


	wire [31:0] pio0;
	wire [31:0] pio1;

	reg [9:0] uadc_r;
	wire [9:0] adc;

	wire [9:0] sin;
	wire [9:0] cos;
	
	wire [19:0] i;
	wire [19:0] q;

	wire [18:0] icic;
	wire icic_valid;
	wire [18:0] qcic;
	wire qcic_valid;

	wire [9:0] ifir;
	wire ifir_valid;
	wire [9:0] qfir;
	wire qfir_valid;

	wire [9:0] dac;

	
	QsysCore QsysCore_inst (
		  .clk_clk                                                                                         (CLK),
		  .reset_reset_n                                                                                   (RST_N),
		  .spi_slave_to_avalon_mm_master_bridge_0_export_0_mosi_to_the_spislave_inst_for_spichain          (SPI_MOSI),
		  .spi_slave_to_avalon_mm_master_bridge_0_export_0_nss_to_the_spislave_inst_for_spichain           (SPI_NSS),
		  .spi_slave_to_avalon_mm_master_bridge_0_export_0_miso_to_and_from_the_spislave_inst_for_spichain (SPI_MISO),
		  .spi_slave_to_avalon_mm_master_bridge_0_export_0_sclk_to_the_spislave_inst_for_spichain          (SPI_SCLK),
		  .pio_0_external_connection_export                                                                (pio0),
		  .pio_1_external_connection_export                                                                (pio1)
	);


	assign LED = ~pio0[3:0];

	always @(posedge CLK) begin
		uadc_r <= { ADC, 2'b00 };
	end
	assign ENCODE = CLK;
	assign adc = 10'h1ff;//(uadc_r[9] == 0) ? uadc_r + 10'h200 : uadc_r - 10'h200;

	nco nco_inst (
		.clk       (CLK),
		.reset_n   (RST_N),
		.clken     (1'b1),
		.phi_inc_i (pio1),
		.fsin_o    (sin),
		.fcos_o    (cos),
		.out_valid ()
		);

	altmul altmul_inst_i (
		.clock0 (CLK),
		.dataa_0 (adc),
		.datab_0 (cos),
		.result (i)
		);

	altmul altmul_inst_q (
		.clock0 (CLK),
		.dataa_0 (adc),
		.datab_0 (sin),
		.result (q)
		);

	cic cic_inst_i (
		.clk       (CLK),
		.reset_n   (RST_N),
		.in_error  (2'b00),
		.in_valid  (1'b1),
		.in_ready  (),
		.in_data   (i),
		.out_data  (icic),
		.out_error (),
		.out_valid (icic_valid),
		.out_ready (1'b1)
	);

	cic cic_inst_q (
		.clk       (CLK),
		.reset_n   (RST_N),
		.in_error  (2'b00),
		.in_valid  (1'b1),
		.in_ready  (),
		.in_data   (q),
		.out_data  (qcic),
		.out_error (),
		.out_valid (qcic_valid),
		.out_ready (1'b1)
	);
 
	fir fir_inst_i (
		.clk       (CLK),
		.reset_n   (RST_N),
		.ast_sink_data (icic),
		.ast_sink_valid (icic_valid),
		.ast_sink_error (2'b00),
		.ast_source_data (ifir),
		.ast_source_valid (ifir_valid),
		.ast_source_error ()
	);
 
	fir fir_inst_q (
		.clk       (CLK),
		.reset_n   (RST_N),
		.ast_sink_data (qcic),
		.ast_sink_valid (qcic_valid),
		.ast_sink_error (2'b00),
		.ast_source_data (qfir),
		.ast_source_valid (qfir_valid),
		.ast_source_error ()
	);

	assign dac = ifir;
	always @(posedge CLK) begin
		if (ifir_valid) begin
			DAC <= (dac[9] == 0) ? dac + 10'h200 : dac - 10'h200;
		end
	end
	assign DACCLK = CLK;


endmodule

使用するリソースはこんな感じです。どこにも接続されないADC、Q信号関連のリソースは含まれていません。

CICフィルタ+FIRフィルタの特性を確認するため、ADCデータを最大値の10’h1ffに固定してNCOのCos、Sin出力がそのままCICフィルタに入力されるようにしています。

assign adc = 10’h1ff; // (uadc_r[9] == 0) ? uadc_r + 10’h200 : uadc_r – 10’h200;

Androidアプリ「GUI Maker for Avalon Bus – FPGA SPI Bridge Panel」に”NCO”パネルを追加して、NCOの周波数を0Hzから100kHzまでスイープさせてオシロのFFT表示でCICフィルタ+FIRフィルタの特性を確認します。FIRフィルタの係数はツールの初期値のままです。通過域のCICフィルタの形をFIRフィルタで補正できていません。

 

フィルタの特性を確認できたので、固定値(フルスケール)にしていたADCデータを元に戻します。

DAC <= (dac[9] == 0) ? dac + 10’h200 : dac – 10’h200;

また、固定値(フルスケール)でも出力がオーバーフローしないように上位6ビットだけ切り捨てていましたが、実際の放送波はずっと小さいので上位12ビット捨ててしまいます。オーバーフローしないように調整が必要です。