一种复数求模的实用方法

一种复数求模的实用方法


        在DSP中,经常遇到复数求模的问题。对于复数X

                        X = R+j*I   (1)

其幅度magX为:

                     magX = sqrt(R^2+I^2)  (2)

由上式可知,复数求模的问题可看做是一个实数求根的问题。对这个问题有一些成熟算法,如博文所述:http://blog.csdn.net/deepdsp/article/details/7539823

       这里,针对复数求模这种特殊情况,在精度要求不太高的情况下,可用如下近似方法计算:

                     MagX = Alpha * max(|R|, |I|) + Beta * min(|R|, |I|)  (3)

其中Alpha和Beta为系数,根据不同的准则,如均方根误差最小,峰值误差最小等,这两个系数的取值有所不同。具体数值参见下表。最简单的情况,选取Alpha=1,Beta=0.25,也能得到很不错的结果。

 

=====================================================================
             Alpha * Max + Beta * Min Magnitude Estimator
 
Name                  Alpha           Beta       Avg Err   RMS   Peak
                                                 (linear)  (dB)  (dB)
---------------------------------------------------------------------
Min RMS Err      0.947543636291 0.392485425092   0.000547 -32.6 -25.6
Min Peak Err     0.960433870103 0.397824734759  -0.013049 -31.4 -28.1
Min RMS w/ Avg=0 0.948059448969 0.392699081699   0.000003 -32.6 -25.7
1, Min RMS Err   1.000000000000 0.323260990000  -0.020865 -28.7 -23.8
1, Min Peak Err  1.000000000000 0.335982538000  -0.025609 -28.3 -25.1
1, 1/2           1.000000000000 0.500000000000  -0.086775 -20.7 -18.6
1, 1/4           1.000000000000 0.250000000000   0.006456 -27.6 -18.7
Frerking         1.000000000000 0.400000000000  -0.049482 -25.1 -22.3
1, 11/32         1.000000000000 0.343750000000  -0.028505 -28.0 -24.8
1, 3/8           1.000000000000 0.375000000000  -0.040159 -26.4 -23.4
15/16, 15/32     0.937500000000 0.468750000000  -0.018851 -29.2 -24.1
15/16, 1/2       0.937500000000 0.500000000000  -0.030505 -26.9 -24.1
31/32, 11/32     0.968750000000 0.343750000000  -0.000371 -31.6 -22.9
31/32, 3/8       0.968750000000 0.375000000000  -0.012024 -31.4 -26.1
61/64, 3/8       0.953125000000 0.375000000000   0.002043 -32.5 -24.3
61/64, 13/32     0.953125000000 0.406250000000  -0.009611 -31.8 -26.6
=====================================================================

 

 

附录:C实现代码

/*(代码来源于网络,版权归原作者所有)*/


#include <math.h>
#include <stdio.h>
/*********************************************************************
*
*
* Name: mag_est.c
*
* Synopsis:
*
*   Demonstrates and tests the "Alpha * Min + Beta * Max" magnitude
*   estimation algorithm.
*
* Description:
*
*   This program demonstrates the "Alpha, Beta" algorithm for 
*   estimating the magnitude of a complex number.  Compared to
*   calculating the magnitude directly using sqrt(I^2 + Q^2), this
*   estimation is very quick.
*
*   Various values of Alpha and Beta can be used to trade among RMS
*   error, peak error, and coefficient complexity.  This program
*   includes a table of the most useful values, and it prints out the
*   resulting RMS and peak errors.
*
* Copyright 1999  Grant R. Griffin
*
*********************************************************************/
/********************************************************************/
double alpha_beta_mag(double alpha, double beta, double inphase,
                      double quadrature)
{
   /* magnitude ~= alpha * max(|I|, |Q|) + beta * min(|I|, |Q|) */
   double abs_inphase = fabs(inphase);
   double abs_quadrature = fabs(quadrature);
   if (abs_inphase > abs_quadrature) {
      return alpha * abs_inphase + beta * abs_quadrature;
   } else {
      return alpha * abs_quadrature + beta * abs_inphase;
   }
}
/*********************************************************************/
double decibels(double linear)
{
   #define SMALL 1e-20
   if (linear <= SMALL) {
      linear = SMALL;
   }
   return 20.0 * log10(linear);
}
/*********************************************************************/
void test_alpha_beta(char *name, double alpha, double beta,
                     int num_points)
{
   #define PI 3.141592653589793
   int ii;
   double phase, real, imag, err, avg_err, rms_err;
   double peak_err = 0.0;
   double sum_err = 0.0;
   double sum_err_sqrd = 0.0;
   double delta_phase = (2.0 * PI) / num_points;
   for (ii = 0; ii < num_points; ii++) {
      phase = delta_phase * ii;
      real = cos(phase);
      imag = sin(phase);
      err = sqrt(real * real + imag * imag)
            - alpha_beta_mag(alpha, beta, real, imag);
      sum_err += err;
      sum_err_sqrd += err * err;
      err = fabs(err);
      if (err > peak_err) {
         peak_err = err;
      }
   }
   avg_err = sum_err / num_points;
   rms_err = sqrt(sum_err_sqrd / num_points);
   printf("%-16s %14.12lf %14.12lf  %9.6lf %4.1lf %4.1lf\n",
          name, alpha, beta, avg_err, decibels(rms_err),
          decibels(peak_err));
}
/*********************************************************************/
void main(void)
{
   #define NUM_CHECK_POINTS 100000
   typedef struct tagALPHA_BETA {
      char *name;
      double alpha;
      double beta;
   } ALPHA_BETA;
   #define NUM_ALPHA_BETA 16
   const ALPHA_BETA coeff[NUM_ALPHA_BETA] = {
      { "Min RMS Err",      0.947543636291, 0.3924854250920 },
      { "Min Peak Err",     0.960433870103, 0.3978247347593 },
      { "Min RMS w/ Avg=0", 0.948059448969, 0.3926990816987 }, 
      { "1, Min RMS Err",              1.0,     0.323260990 },
      { "1, Min Peak Err",             1.0,     0.335982538 },
      { "1, 1/2",                      1.0,      1.0 / 2.0  },
      { "1, 1/4",                      1.0,      1.0 / 4.0  },
      { "Frerking",                    1.0,            0.4  },
      { "1, 11/32",                    1.0,     11.0 / 32.0 },
      { "1, 3/8",                      1.0,      3.0 / 8.0  },
      { "15/16, 15/32",        15.0 / 16.0,     15.0 / 32.0 },
      { "15/16, 1/2",          15.0 / 16.0,      1.0 / 2.0  },
      { "31/32, 11/32",        31.0 / 32.0,     11.0 / 32.0 },
      { "31/32, 3/8",          31.0 / 32.0,      3.0 / 8.0  },
      { "61/64, 3/8",          61.0 / 64.0,      3.0 / 8.0  },
      { "61/64, 13/32",        61.0 / 64.0,     13.0 / 32.0 }
   };
   int ii;
   printf("\n             Alpha * Max + Beta * Min Magnitude
Estimator\n\n");
   printf("Name                  Alpha           Beta       Avg Err  
RMS   Peak\n");
   printf("                                                 (linear) 
(dB)  (dB)\n");
  
printf("---------------------------------------------------------------------\n");
   for (ii = 0; ii < NUM_ALPHA_BETA; ii++) {
      test_alpha_beta(coeff[ii].name, coeff[ii].alpha, coeff[ii].beta,
                      1024);
   }
}

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,根据您的需求,我写出了以下的Java代码: ```java public class Complex { private double real; private double imag; public Complex(double real, double imag) { this.real = real; this.imag = imag; } public Complex add(Complex other) { double realPart = this.real + other.real; double imagPart = this.imag + other.imag; return new Complex(realPart, imagPart); } public static Complex add(Complex c1, Complex c2) { double realPart = c1.real + c2.real; double imagPart = c1.imag + c2.imag; return new Complex(realPart, imagPart); } public Complex subtract(Complex other) { double realPart = this.real - other.real; double imagPart = this.imag - other.imag; return new Complex(realPart, imagPart); } public static Complex subtract(Complex c1, Complex c2) { double realPart = c1.real - c2.real; double imagPart = c1.imag - c2.imag; return new Complex(realPart, imagPart); } public Complex multiply(Complex other) { double realPart = this.real * other.real - this.imag * other.imag; double imagPart = this.real * other.imag + this.imag * other.real; return new Complex(realPart, imagPart); } public static Complex multiply(Complex c1, Complex c2) { double realPart = c1.real * c2.real - c1.imag * c2.imag; double imagPart = c1.real * c2.imag + c1.imag * c2.real; return new Complex(realPart, imagPart); } public double modulus() { return Math.sqrt(this.real * this.real + this.imag * this.imag); } @Override public String toString() { if (this.imag >= 0) { return String.format("%.2f+%.2fi", this.real, this.imag); } else { return String.format("%.2f-%.2fi", this.real, -this.imag); } } } ``` 以上代码中,`Complex` 类表示复数,其中包含实部和虚部两个成员变量 `real` 和 `imag`。构造方法用于初始化实部和虚部。 `add()`、`subtract()`、`multiply()` 方法分别表示复数的加、减、乘运算。其中,`add()` 和 `subtract()` 方法提供了两种形式,一种是对象方法,将当前复数与参数中的复数进行运算,返回一个新的复数对象;另一种是静态方法,将两个参数代表的复数进行运算。 `modulus()` 方法用于求复数的模。 `toString()` 方法用于描述复数对象,返回一个字符串。 下面是一个测试类的代码: ```java public class Main { public static void main(String[] args) { Complex c1 = new Complex(3, 4); Complex c2 = new Complex(1, -2); Complex sum1 = c1.add(c2); Complex sum2 = Complex.add(c1, c2); Complex diff1 = c1.subtract(c2); Complex diff2 = Complex.subtract(c1, c2); Complex prod1 = c1.multiply(c2); Complex prod2 = Complex.multiply(c1, c2); double mod1 = c1.modulus(); double mod2 = c2.modulus(); System.out.println("c1 = " + c1); System.out.println("c2 = " + c2); System.out.println("c1 + c2 (object method) = " + sum1); System.out.println("c1 + c2 (static method) = " + sum2); System.out.println("c1 - c2 (object method) = " + diff1); System.out.println("c1 - c2 (static method) = " + diff2); System.out.println("c1 * c2 (object method) = " + prod1); System.out.println("c1 * c2 (static method) = " + prod2); System.out.println("|c1| = " + mod1); System.out.println("|c2| = " + mod2); } } ``` 以上代码中,首先创建了两个复数对象 `c1` 和 `c2`。然后分别使用对象方法和静态方法进行加、减、乘运算,并输出结果。最后求出了两个复数的模,并输出结果。 输出结果如下: ``` c1 = 3.00+4.00i c2 = 1.00-2.00i c1 + c2 (object method) = 4.00+2.00i c1 + c2 (static method) = 4.00+2.00i c1 - c2 (object method) = 2.00+6.00i c1 - c2 (static method) = 2.00+6.00i c1 * c2 (object method) = 11.00-2.00i c1 * c2 (static method) = 11.00-2.00i |c1| = 5.00 |c2| = 2.24 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值