关于除法电路

             除法,这个小学4年纪就开始学习和使用的方法却一直是我这个ASIC工程师心中的痛。我一直在思考如何能找到一个简单(硬件资源少)而快捷(时钟排数少)的通用除法电路。

            其实简单的说除法可以用迭代的减法来实现,但是对于硬件,这恐怕要花很多时间。我也一直没有找到实现任意除法的好方法。但是对于某些除数固定的除法还是有一些办法的。

 

            1)最容易想到的就是ROM查找表,但是ROM毕竟不是我们的目标,虽然ROM有时是不错的方法。

            2)我开始仔细考虑这个问题是在做264解码时必须要处理QP的问题。这是一个除以6的计算,由于被除数不会大于52(6bit),所以我简化了一个组合逻辑来实现。代码如下:

always@(idata)
begin
    case(idata[5:3])
        3'b000:  begin
                    oquotient[3:1] = 3'b000;
                    if (idata[2:1]==2'b11)
                    begin
                        oquotient[0] = 1'b1;
                    end
                    else
                    begin
                        oquotient[0] = 1'b0;
                    end
                end
        3'b001: begin
                    oquotient[3:2] = 2'b00;
                    if (idata[2]==1'b1)
                    begin
                        oquotient[1:0] = 2'b10;
                    end
                    else
                    begin
                        oquotient[1:0] = 2'b01;
                    end
                end
        3'b010: begin
                    oquotient[3:1] = 3'b001;
                    if (idata[2:1]!=2'b00)
                    begin
                        oquotient[0] = 1'b1;
                    end
                    else
                    begin
                        oquotient[0] = 1'b0;
                    end
                end
        3'b011: begin
                    oquotient[3:1] = 3'b010;
                    if (idata[2:1]==2'b11)
                    begin
                        oquotient[0] = 1'b1;
                    end
                    else
                    begin
                        oquotient[0] = 1'b0;
                    end
                end
        3'b100: begin
                    oquotient[3:2] = 2'b01;
                    if (idata[2]==1'b1)
                    begin
                        oquotient[1:0] = 2'b10;
                    end
                    else
                    begin
                        oquotient[1:0] = 2'b01;
                    end
                end
               
         3'b101: begin
                    oquotient[3:1] = 3'b011;
                    if (idata[2:1]!=2'b00)
                    begin
                        oquotient[0] = 1'b1;
                    end
                    else
                    begin
                        oquotient[0] = 1'b0;
                    end
                end
        3'b110: begin
                    oquotient[3:1] = 3'b100;
                    if (idata[2:1]==2'b11)
                    begin
                        oquotient[0] = 1'b1;
                    end
                    else
                    begin
                        oquotient[0] = 1'b0;
                    end
                end
        3'b111: begin
                    oquotient[3:2] = 2'b10;
                    if (idata[2]==1'b1)
                    begin
                        oquotient[1:0] = 2'b10;
                    end
                    else
                    begin
                        oquotient[1:0] = 2'b01;
                    end
                end     
        default:    oquotient[3:0] = 4'd0;
    endcase
end

 

//always@(idata)
//begin
//    case(idata[3:1])
//        3'b000: rem_temp[1:0] = 2'b00;
//        3'b001: rem_temp[1:0] = 2'b01;
//        3'b010: rem_temp[1:0] = 2'b10;
//        3'b011: rem_temp[1:0] = 2'b00;
//        3'b100: rem_temp[1:0] = 2'b01;
//        3'b101: rem_temp[1:0] = 2'b10;
//        3'b110: rem_temp[1:0] = 2'b00;
//        3'b111: rem_temp[1:0] = 2'b01;
//        default:rem_temp[1:0] = 2'b00;
//    endcase
//end
//
//always@(idata or rem_temp)
//begin
//    oremainder[0] = idata[0];
//    case(idata[5:4])
//        2'b00,2'b11:    oremainder[2:1] = rem_temp[1:0];
//        2'b01:          oremainder[2:1] = {(~(rem_temp[1] | rem_temp[0])),rem_temp[1]};
//        2'b10:          oremainder[2:1] = {rem_temp[0],(~(rem_temp[1] | rem_temp[0]))};
//        default:        oremainder[2:1] = rem_temp[1:0];
//    endcase
//end

          可见这个逻辑并不是很大,求商的逻辑不过是一个3bit的case里面套一级选择(if),FPGA里不过就是一个ALU。时序也很好,百兆的钟都没有问题。我由此想到了,对于除数固定,被除数有一定范围限制的除法,还是可以用一定简化了逻辑实现的。

             3)以下我们讨论的除法就由此先做一个前提的约束:被除数是8bit,除数我们将分别讨论3、5、7、11等质数的情况,其它的和数的除法可以分解成质数。

 

 

            4) 除数为3 (二进制2‘b11)

                  我最早的想法其实很简单,除以3是很困难的,但是除以4对于硬件确实非常简单的。所以也许可以通过对1/4进行一些调整来达到1/3的目的。这显然是要在1/4上加一点什么,加什么呢?我突然想到了无穷级数:

            1/4    1/16   1/64 .........

           其无穷级数求和和刚好是1/3。这似乎就简单了。不就是1/4 +1/16 +1/64 + .........

           有一件事情是可能的,我们不能求无穷的加和,但是如果我们只要整数位,那也许就不需要无穷的加完。

temp[14:0] = {number[7:0],6'd0} + {number[7:0],4'd0} + {number[7:0],2'd0} + number[7:0];
result1[7:0] = temp[14:8] + ((number[7]==1'b1 && number[6:0]!=7'd0)? temp[7] : temp[7]&temp[6]);
         

         number是8bit被除数,temp是number若干(这里这用了前4个)移位值的和,但是我们明白,这是不精确的,所以对此和进行一些调整。调整的方向一定是加一点什么(因为我们少加了很多数),result1就是这个调整的逻辑。

        从整体上看看这个逻辑:4个14位数的加法,一个选择逻辑和单bit加。逻辑不算太小(14bit加法电路还是不小的),但是也不算太大(毕竟就是4个加法)。时序由加法电路来限制,综合的好应该到百兆是没有问题的。

 

             5)除数为5(3'b101)

                  1/5显然和1/4比较近。我们仍然可以比较方便的写出这个无穷级数来:

                        1 - 1/4 + 1/16 - 1/64 ...........

                  这个的和是4/5不是1/5,但是再除个4就好了(这很方便的)。

temp[13:0]={number[7:0],6'd0} - {number[7:0],4'd0} + {number[7:0],2'd0} - number[7:0] + number[7:2] - number[7:4]; 
result1[7:0] = temp[13:6] + temp[5];
result2[5:0] = result1[7:2];

 

                     temp是number的6个移位值的和,result1是调整后的值,result2是result/4的商。这个逻辑怎么要加6个值的和呢?其实就是近似问题,如果加的个数少,那么后面那个调整电路就会复杂些。

 

               6)除数为7(3'b111)

                    这个和1/3其实是类似的,我就不赘述了。

          

               7)除数为11(4'b1011)

                   这个有点烦,和11近的2^n是8或16,这个级数似乎不好找。但是我一觉醒来突然明白了一个事情:任何一个小数都是可以化为2进制表示的,而其2进制表示其实就是一个2^n的数列的和,只不过是换了一种形式吧了。

                  于是1/11就是0.0001011101 | 0001011101 | 0001011101 | ...........

 

temp[14:0] = {number[7:0],6'd0} + {number[7:0],4'd0} + {number[7:0],3'd0} + {number[7:0],2'd0} + number[7:0] + number[7:4];


result1[7:0] = temp[14:10] + (temp[9]&temp[8]&temp[7]&temp[6]);

                精度仍然只取了前6个有效的(是1)的数,然后在result1上做了一些补足的调整。

 

 

               8)总结:其实到这里我们就已经清除了一件事----所有除数固定的除法都可以用上述确定的过程来实现。具体说就是:第一,将除数n变成乘以1/n,然后用2进制来表示这个1/n。第二,根据被除数的位数来选取合适的1/n的有效位数。第三,再根据具体的结果做一些调整。

                 1/N取多少有效位合适,取决与被除数的范围(被除数较大,就要多取几位)、逻辑大小的控制(加法越多,可能你的门数和时序多要付出代价)、一级最后那个调整的复杂程度(总不能太复杂吧)。

              

                好了,到这里就先告一段落吧,但是我仍然没有从根本上真正解决任意除法的问题。我心中的通看来还要持续。不知有谁能最终来替我排解。

<think>好的,我现在需要帮助用户查找关于使用运放设计除法电路的方法或方案。用户提到了运放设计除法电路的方法、教程和电路图。首先,我需要回忆一下运放的基本应用电路,特别是涉及运算功能的电路,比如加减乘除。 用户提供的引用中,提到了减法电路和对数运算电路。例如,引用[1]讨论了减法电路的阻抗问题,引用[2]提到对数运算电路使用二极管或三极管的PN结特性。这可能与除法电路的设计有关,因为乘法和除法通常可以通过对数和指数转换来实现。比如,对数相减再取指数可以实现除法。因此,可能需要结合对数运算电路和减法电路来设计除法电路。 接下来,我需要确认运放实现除法电路的常见方法。通常有两种方法:一种是用乘法电路作为运放的反馈元件,另一种是利用对数运算电路进行转换。第一种方法中,将乘法器放在反馈回路中,因为运放的虚短特性,输入电压与反馈电压的关系可以形成除法。例如,输入电压Vin通过电阻接到运放的反相端,反馈回路中使用乘法器,其输出连接到反馈电阻,这样输出电压与Vin和乘法器的另一个输入有关,从而实现除法。 第二种方法基于对数运算,因为对数转换可以将除法转换为减法。具体来说,对数的除法相当于减法,即ln(a/b) = ln(a) - ln(b)。因此,可以用两个对数电路分别处理被除数和除数的信号,然后将它们的输出相减,再通过指数电路恢复结果。引用[2]中提到的对数运算电路可能适用于这一步,但需要确认如何将减法结合进去。需要注意的是,这种方法需要考虑温度对PN结的影响,可能需要温度补偿电路。 现在,我需要验证这些方法的正确性。例如,第一种方法中使用乘法器在反馈回路中,假设乘法器的输出是Vout = (V1*V2)/K,其中K是常数。如果将其放在反馈回路中,根据运放的虚短,反相端的电压等于同相端(通常接地),那么输入电流Vin/R1等于反馈电流Vout*Vx/(K*R2),从而得到Vout = - (Vin*K)/(Vx*R2/R1)。这样确实实现了除法运算,但需要注意输入电压的范围,避免除以零的情况。 关于电路图,可能需要绘制一个运放反相配置,反馈回路中包含乘法器,其中一个输入来自输出端。或者,在使用对数方法时,绘制两个对数放大器,然后连接到一个减法器,再接入指数放大器。这部分需要参考典型的电路结构,确保各部分的连接正确。 用户可能还需要考虑实际设计中的问题,比如元件的选择(如乘法器芯片型号)、温度稳定性、频率响应等。例如,对数电路中的二极管或三极管对温度敏感,可能需要使用匹配的元件或温度补偿电路。此外,乘法器的线性范围和精度也会影响除法电路的性能。 最后,总结设计步骤:确定方法(乘法器反馈法或对数-减法-指数法),选择合适元件,设计电路参数,进行仿真验证,调整参数以优化性能。同时,提醒用户注意避免除以零的情况,确保输入信号在允许范围内。</think>### 运放设计除法电路的方法与实现 #### 1. **基本原理** 运放除法电路的核心是将乘法运算与反馈回路结合,利用运放的虚短特性实现除法功能。数学表达式为: $$V_{out} = k \cdot \frac{V_{in1}}{V_{in2}}$$ 其中$k$为比例系数,需避免$V_{in2}=0$导致输出饱和[^1]。 --- #### 2. **典型实现方案** **(1) 乘法器反馈法** 在反相放大电路中,将反馈电阻替换为**模拟乘法器**,实现除法功能。 - **电路结构**: - 输入$V_{in1}$通过电阻$R_1$接入运放反相端。 - 反馈回路使用模拟乘法器,其输出端连接运放输出端与反相端。 - 乘法器另一输入端接$V_{in2}$。 - **公式推导**: 根据虚短特性,反相端电压为0,输入电流与反馈电流相等: $$\frac{V_{in1}}{R_1} = -\frac{V_{out} \cdot V_{in2}}{k \cdot R_f}$$ 整理得: $$V_{out} = -\frac{k \cdot R_f}{R_1} \cdot \frac{V_{in1}}{V_{in2}}$$ - **注意事项**: - $V_{in2}$必须为正值,防止乘法器输出极性冲突[^3]。 - 需选择高精度乘法器(如AD633)。 **(2) 对数-减法-指数法** 利用对数运算电路除法转换为减法: $$ \ln\left(\frac{V_{in1}}{V_{in2}}\right) = \ln V_{in1} - \ln V_{in2} $$ - **电路结构**: 1. **对数电路**:用二极管或三极管实现$V_{in1}$和$V_{in2}$的对数转换。 2. **减法电路**:将两路对数信号相减。 3. **指数电路**:将差值转换为指数输出。 - **电路示例**: ```plaintext V_in1 → 对数电路 → 减法电路 → 指数电路 → V_out V_in2 → 对数电路 ─────────────┘ ``` - **缺点**: - 温度敏感,需温度补偿电路[^2]。 - 动态范围受限。 --- #### 3. **电路图示例(乘法器反馈法)** ```plaintext R1 Vin1 ──┬─────┤∑├───┐ │ - │ │ ├── Multiplier (Z = X*Y/k) │ │ Vin2 ──┴──────────┘ │ └── Vout ``` *说明:乘法器输出端连接运放反馈回路,Y输入端接Vin2,X输入端接Vout。* --- #### 4. **设计要点** 1. **元件选型**: - 运放选择高输入阻抗、低偏置电流型号(如TL072)。 - 乘法器需线性度好(如AD633,$k=10V$)。 2. **参数计算**: - 根据目标比例系数$k$调整$R_f/R_1$比值。 - 限制$V_{in2}$范围(例如0.1V~10V)。 3. **稳定性措施**: - 在乘法器输出端添加低通滤波器,抑制高频噪声。 - 输入级加入保护二极管,防止电压超限。 --- #### 5. **仿真验证建议** - 使用LTspice或Multisim搭建电路,验证以下场景: 1. $V_{in2}$固定,$V_{in1}$变化时的线性度。 2. $V_{in2}$接近零时输出的饱和特性。 3. 频率响应(适用于交流信号除法)。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值