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 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136
|
//
// Copyright 2014 Ettus Research LLC
// Copyright 2018 Ettus Research, a National Instruments Company
//
// SPDX-License-Identifier: LGPL-3.0-or-later
//
// Fast magnitude approximation.
//
// ALPHA_DENOM & BETA_DENOM should be a power of 2
// Multiplierless if ALPHA_NUM & BETA_NUM are 1
//
// Mag ~= Alpha * max(|I|, |Q|) + Beta * min(|I|, |Q|)
//
// (table taken from http://www.dspguru.com/dsp/tricks/magnitude-estimator)
// =========================================
// Alpha Beta Avg Err RMS Peak
// (linear) (dB) (dB)
// -----------------------------------------
// 1, 1/2 -0.086775 -20.7 -18.6
// 1, 1/4 0.006456 -27.6 -18.7
// 1, 11/32 -0.028505 -28.0 -24.8
// 1, 3/8 -0.040159 -26.4 -23.4
// 15/16, 15/32 -0.018851 -29.2 -24.1
// 15/16, 1/2 -0.030505 -26.9 -24.1
// 31/32, 11/32 -0.000371 -31.6 -22.9
// 31/32, 3/8 -0.012024 -31.4 -26.1
// 61/64, 3/8 0.002043 -32.5 -24.3
// 61/64, 13/32 0.009611 -31.8 -26.6
// =========================================
//
// Input: Complex, Output: Unsigned Int
`ifndef LOG2
`define LOG2(N) ( \
N < 2 ? 0 : \
N < 4 ? 1 : \
N < 8 ? 2 : \
N < 16 ? 3 : \
N < 32 ? 4 : \
N < 64 ? 5 : \
N < 128 ? 6 : \
N < 256 ? 7 : \
N < 512 ? 8 : \
N < 1024 ? 9 : \
10)
`endif
module complex_to_mag_approx #(
parameter ALPHA_NUM = 1,
parameter ALPHA_DENOM = 1,
parameter BETA_NUM = 1,
parameter BETA_DENOM = 4,
parameter LATENCY = 3, // 0, 1, 2, or 3
parameter SAMP_WIDTH = 16)
(
input clk, input reset, input clear,
input [2*SAMP_WIDTH-1:0] i_tdata, input i_tlast, input i_tvalid, output i_tready,
output [SAMP_WIDTH-1:0] o_tdata, output o_tlast, output o_tvalid, input o_tready
);
wire [2*SAMP_WIDTH-1:0] pipeline_i_tdata[0:2], pipeline_o_tdata[0:2];
wire [2:0] pipeline_i_tvalid, pipeline_i_tlast, pipeline_i_tready;
wire [2:0] pipeline_o_tvalid, pipeline_o_tlast, pipeline_o_tready;
wire signed [SAMP_WIDTH-1:0] i, q, max, max_int, min, min_int;
wire [SAMP_WIDTH-1:0] i_abs, q_abs, i_abs_int, q_abs_int, mag;
// Absolute value
assign i = i_tdata[2*SAMP_WIDTH-1:SAMP_WIDTH];
assign q = i_tdata[SAMP_WIDTH-1:0];
assign i_abs_int = i[SAMP_WIDTH-1] ? (~i + 1'b1) : i;
assign q_abs_int = q[SAMP_WIDTH-1] ? (~q + 1'b1) : q;
// First stage pipeline
assign pipeline_i_tdata[0] = {i_abs_int,q_abs_int};
assign pipeline_i_tlast[0] = i_tlast;
assign pipeline_i_tvalid[0] = i_tvalid;
assign pipeline_o_tready[0] = pipeline_i_tready[1];
axi_fifo_flop #(.WIDTH(SAMP_WIDTH*2+1))
pipeline0_axi_fifo_flop (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({pipeline_i_tlast[0],pipeline_i_tdata[0]}), .i_tvalid(pipeline_i_tvalid[0]), .i_tready(pipeline_i_tready[0]),
.o_tdata({pipeline_o_tlast[0],pipeline_o_tdata[0]}), .o_tvalid(pipeline_o_tvalid[0]), .o_tready(pipeline_o_tready[0]));
// Max & Min
assign i_abs = (LATENCY == 3) ? pipeline_o_tdata[0][2*SAMP_WIDTH-1:SAMP_WIDTH] : i_abs;
assign q_abs = (LATENCY == 3) ? pipeline_o_tdata[0][SAMP_WIDTH-1:0] : q_abs;
assign max_int = (i_abs > q_abs) ? i_abs : q_abs;
assign min_int = (i_abs > q_abs) ? q_abs : i_abs;
// Second stage pipeline
assign pipeline_i_tdata[1] = {max_int,min_int};
assign pipeline_i_tlast[1] = (LATENCY == 2) ? i_tlast : pipeline_o_tlast[0];
assign pipeline_i_tvalid[1] = (LATENCY == 2) ? i_tvalid : pipeline_o_tvalid[0];
assign pipeline_o_tready[1] = pipeline_i_tready[2];
axi_fifo_flop #(.WIDTH(SAMP_WIDTH*2+1))
pipeline1_axi_fifo_flop (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({pipeline_i_tlast[1],pipeline_i_tdata[1]}), .i_tvalid(pipeline_i_tvalid[1]), .i_tready(pipeline_i_tready[1]),
.o_tdata({pipeline_o_tlast[1],pipeline_o_tdata[1]}), .o_tvalid(pipeline_o_tvalid[1]), .o_tready(pipeline_o_tready[1]));
// Magnitude Approx
assign max = (LATENCY >= 2) ? pipeline_o_tdata[1][2*SAMP_WIDTH-1:SAMP_WIDTH] : max_int;
assign min = (LATENCY >= 2) ? pipeline_o_tdata[1][SAMP_WIDTH-1:0] : min_int;
assign mag = ALPHA_NUM * {{`LOG2(ALPHA_DENOM){1'b0}},max[SAMP_WIDTH-1:`LOG2(ALPHA_DENOM)]} +
BETA_NUM * {{`LOG2( BETA_DENOM){1'b0}},min[SAMP_WIDTH-1:`LOG2( BETA_DENOM)]};
// Third stage pipeline
assign pipeline_i_tdata[2][SAMP_WIDTH-1:0] = mag;
assign pipeline_i_tlast[2] = (LATENCY == 1) ? i_tlast : pipeline_o_tlast[1];
assign pipeline_i_tvalid[2] = (LATENCY == 1) ? i_tvalid : pipeline_o_tvalid[1];
assign pipeline_o_tready[2] = o_tready;
axi_fifo_flop #(.WIDTH(SAMP_WIDTH+1))
pipeline2_axi_fifo_flop (
.clk(clk), .reset(reset), .clear(clear),
.i_tdata({pipeline_i_tlast[2],pipeline_i_tdata[2][SAMP_WIDTH-1:0]}), .i_tvalid(pipeline_i_tvalid[2]), .i_tready(pipeline_i_tready[2]),
.o_tdata({pipeline_o_tlast[2],pipeline_o_tdata[2][SAMP_WIDTH-1:0]}), .o_tvalid(pipeline_o_tvalid[2]), .o_tready(pipeline_o_tready[2]));
// Output based on LATENCY mux
assign o_tdata = (LATENCY == 0) ? mag : pipeline_o_tdata[2][SAMP_WIDTH-1:0];
assign o_tlast = (LATENCY == 0) ? i_tlast : pipeline_o_tlast[2];
assign o_tvalid = (LATENCY == 0) ? i_tvalid : pipeline_o_tvalid[2];
assign i_tready = (LATENCY == 0) ? o_tready :
(LATENCY == 1) ? pipeline_i_tready[2] :
(LATENCY == 2) ? pipeline_i_tready[1] : pipeline_i_tready[0];
endmodule
|