matlab ellip函数 C实现

继上一篇实现matlab cheby2函数 C实现

这篇实现ellip(椭圆)

特点

椭圆滤波器提供比巴特沃斯或切比雪夫滤波器更陡峭的滚降特性,但在通带和阻带都是等纹的。
椭圆滤波器满足给定的性能规格,具有任何滤波器类型中最低的阶数。

C代码

void ellip(int n, double rp, double rs, double Wn[], int type, int analog, double *ab, double *bb)
{
    double fs = 2;
    double u[2] = {0.0, 0.0};
    // step 1: get analog, pre-warped frequencies
    if (!analog)
    {
        if (type == 1 || type == 2)
        {
            fs = 2;
            u[0] = 2 * fs * tan(PI * Wn[0] / fs);
        }
        else
        {
            fs = 2;
            u[0] = 2 * fs * tan(PI * Wn[0] / fs);
            u[1] = 2 * fs * tan(PI * Wn[1] / fs);
        }
    }
    else if (type == 3 || type == 4)
    {
        if (type == 1 || type == 2)
        {
            u[0] = Wn[0];
        }
        else
        {
            u[1] = Wn[1];
        }
    }

    // step 2: convert to low-pass prototype estimate
    double Bw = 0.0;
    if (type == 1 || type == 2)
    {
        Wn = u;
    }
    else if (type == 3 || type == 4)
    {
        Bw = u[1] - u[0];
        Wn[0] = sqrt(u[0] * u[1]); // center frequency
        Wn[1] = 0.0;
    }

    // step 3: Get N-th order Butterworth analog lowpass prototype
    int nz = n % 2 == 0 ? n : n - 1;
    ZPK zpk = ellipap(n, rp, rs);

    double k = zpk.k;
    // Transform to state-space
    int a_size = n;
    double *a = (double *)malloc(sizeof(double) * n * n);
    double *b = (double *)malloc(sizeof(double) * n);
    double *c = (double *)malloc(sizeof(double) * n);
    double d;

    zp2ss(zpk.z, zpk.p, zpk.nz, zpk.np, k, a, b, c, &d);

    switch (type)
    {
    default:
    case 1: // Lowpass
        lp2lp(n, a, b, Wn[0]);
        break;
    case 2: // highpass
        lp2hp(n, a, b, c, &d, Wn[0]);
        break;
    case 3: // Bandpass
        lp2bp(n, &a, &b, &c, &d, Wn[0], Bw);
        a_size = 2 * n;
        break;
    case 4: // Bandstop
        lp2bs(n, &a, &b, &c, &d, Wn[0], Bw);
        a_size = 2 * n;
        break;
    }

    if (!analog)
    {
        bilinear(a_size, a, b, c, &d, fs);
    }

    Complex *p1 = (Complex *)malloc(sizeof(Complex) * a_size);

    Complex *z1 = (Complex *)malloc(sizeof(Complex) * a_size);
    ss2zp(a, b, c, &d, a_size, z1, p1, &k); // 需要完善

    Complex *tempa = (Complex *)malloc(sizeof(Complex) * (a_size + 1));
    Complex *tempb = (Complex *)malloc(sizeof(Complex) * (a_size + 1));

    complex_poly(p1, a_size, tempa);
    complex_poly(z1, a_size, tempb);

    for (size_t i = 0; i < a_size + 1; i++)
    {
        ab[i] = tempa[i].real;
        bb[i] = tempb[i].real * k;
    }

    free(a);
    free(b);
    free(zpk.p);
    free(zpk.z);
    free(z1);
    free(p1);
    free(tempa);
    free(tempb);
}

其中ellipap

ZPK ellipap(int n, double rp, double rs)
{
    ZPK temp;
    double Gp = pow(10, -1.0 * rp / 20.0);
    double ep = sqrt(pow(10, rp / 10.0) - 1.0);
    double es = sqrt(pow(10, rs / 10.0) - 1.0);
    double k1 = ep / es;
    double k0 = ellipdeg(n, k1);

    int L = floor(n / 2);
    double r = n % 2;
    double *ui = (double *)malloc(sizeof(double) * L);
    for (size_t i = 0; i < L; i++)
    {
        ui[i] = (2.0 * (i + 1.0) - 1.0) / n;
    }

    double *zeta_i = cde(ui, L, k0, EPS);

    Complex *zt = (Complex *)malloc(sizeof(Complex) * L);
    Complex *pt = (Complex *)malloc(sizeof(Complex) * L);
    Complex c = create(0, 1.0);
    for (size_t i = 0; i < L; i++)
    {
        zt[i] = complex_divide_double(c, k0 * zeta_i[i]);
    }

    Complex v0 = asne(complex_divide_double(c, ep), k1, EPS);
    v0 = complex_multiply(create(0, -1), v0);
    v0 = complex_divide_double(v0, n);
    // p = j*cde(ui-1i*v0, k);
    for (size_t i = 0; i < L; i++)
    {
        pt[i] = complex_subtract(create(ui[i], 0), complex_multiply(create(0, 1), v0));
    }

    pt = complex_cde(pt, L, k0, EPS);

    // pt = complex_cde(pt, L, k0, EPS);
    for (size_t i = 0; i < L; i++)
    {
        pt[i] = complex_multiply(c, pt[i]);
    }

    Complex p0 = complex_multiply(create(0, 1), v0);
    p0 = complex_sne(p0, k0, EPS);
    p0 = complex_multiply(c, p0);

    //(L+1)*3的矩阵 A,B其实可以省略
    double *A = (double *)malloc(sizeof(double) * (L + 1) * 3);
    double *B = (double *)malloc(sizeof(double) * (L + 1) * 3);
    for (int i = 3; i < 3 * (L + 1); i++)
    {
        if ((i + 1) % 3 == 0)
        {
            A[i] = pow(get_modulus(complex_divide(create(1.0, 0.0), pt[i - L])), 2);
            B[i] = pow(get_modulus(complex_divide(create(1.0, 0.0), zt[i - L])), 2);
        }
        else if ((i + 1) % 3 % 2 == 0)
        {
            A[i] = -2 * complex_divide(create(1.0, 0.0), pt[i - L]).real;
            B[i] = -2 * complex_divide(create(1.0, 0.0), zt[i - L]).real;
        }
        else
        {
            A[i] = 1;
            B[i] = 1;
        }
    }

    if (r == 0)
    {
        A[0] = 1;
        A[1] = 0;
        A[2] = 0;
        B[0] = Gp;
        B[1] = 0;
        B[2] = 0;
    }
    else
    {
        A[0] = 1;
        A[1] = -complex_divide(create(1.0, 0.0), p0).real;
        A[2] = 0;
        B[0] = 1;
        B[1] = 0;
        B[2] = 0;
    }

    Complex *z = (Complex *)malloc(sizeof(Complex) * L * 2);
    Complex *p = (Complex *)malloc(sizeof(Complex) * L * 2);
    for (size_t i = 0; i < L; i++)
    {
        z[i] = zt[i];
        z[L + i] = complex_conj(zt[i]);
        p[i] = pt[i];
        p[L + i] = complex_conj(pt[i]);
    }
    cplxpair(z, 2 * L);
    cplxpair(p, 2 * L);

    temp.nz = 2 * L;
    temp.z = (Complex *)malloc(sizeof(Complex) * 2 * L);
    for (size_t i = 0; i < temp.nz; i++)
    {
        temp.z[i].real = z[i].real;
        temp.z[i].imaginary = z[i].imaginary;
    }

    if (r == 1)
    {
        temp.np = 2 * L + 1;
        temp.p = (Complex *)malloc(sizeof(Complex) * (2 * L + 1));
        for (size_t i = 0; i < 2 * L; i++)
        {
            temp.p[i] = p[i];
        }

        temp.p[2 * L].real = p0.real;
        temp.p[2 * L].imaginary = p0.imaginary;
    }
    else
    {
        temp.np = 2 * L;
        temp.p = (Complex *)malloc(sizeof(Complex) * 2 * L);
        for (size_t i = 0; i < 2 * L; i++)
        {
            temp.p[i] = p[i];
        }
    }

    double H0 = pow(Gp, 1 - r);
    Complex zprod=create(1.0,0.0);
    if(temp.nz>0)
    {
        zprod=complex_array_prod(temp.z, temp.nz);
    }
    temp.k = fabs(complex_multiply_double(complex_divide(complex_array_prod(temp.p, temp.np), zprod), H0).real);

    free(ui);
    free(zeta_i);
    free(zt);
    free(pt);
    free(z);
    free(p);

    return temp;
}

ellipdeg

double ellipdeg(int n, double k1)
{

    if (k1 < KMIN)
    {
        return ellipdeg2(n, k1);
    }
    else
    {
        double k;
        int L = floor(n / 2);

        double kc = sqrt(1 - pow(k1, 2));
        double *ui = (double *)malloc(sizeof(double) * L);
        for (size_t i = 0; i < L; i++)
        {
            ui[i] = (2.0 * (i + 1.0) - 1.0) / n;
        }

        double *w = sne(ui, L, kc, EPS);
        double kp = pow(kc, n) * pow(double_array_prod(w, L), 4);
        k = sqrt(1 - pow(kp, 2));

        free(ui);
        return k;
    }
}

ellipdeg2:

double ellipdeg2(int n, double k1)
{
    double k;
    double M = 7; // 默认值
    double K, Kprime;
    ellipk(k1, EPS, &K, &Kprime);
    double q = exp(-PI * Kprime / K);
    double q1 = pow(q, n);
    // k = 4 * sqrt(q1) * ((1 + sum(q1.^(m.*(m+1))))/(1 + 2*sum(q1.^(m.*m))))^2;
    double *temp1 = (double *)malloc(sizeof(double) * M);
    double *temp2 = (double *)malloc(sizeof(double) * M);
    double sum1 = 0;
    double sum2 = 0;
    for (size_t i = 0; i < M; i++)
    {
        sum1 += pow(q1, (i + 1) * (i + 2));
        sum2 += pow(q1, (i + 1) * (i + 1));
    }

    k = 4 * sqrt(q1) * (1 + sum1) / pow(1 + 2 * sum2, 2);
    free(temp1);
    free(temp2);
    return k;
}

ellipk:

void ellipk(double k, double tol, double *K, double *Kprime)
{
    if (k == 0)
    {
        *K = INFINITY;
    }
    else if (k > KMAX)
    {
        double kp = sqrt(1 - pow(k, 2));
        double L = -log(kp / 4.0);
        *K = L + (L - 1) * pow(kp, 2) / 4.0;
    }
    else
    {
        int nv = 0;
        double *v = landen(k, tol, &nv);
        for (size_t i = 0; i < nv; i++)
        {
            v[i] += 1;
        }

        *K = double_array_prod(v, nv) * PI / 2.0;
        free(v);
    }

    if (k == 0)
    {
        *Kprime = INFINITY;
    }
    else if (k < KMIN)
    {
        double L = -log(k / 4.0);
        *Kprime = L + (L - 1) * pow(k, 2) / 4.0;
    }
    else
    {
        double kp = sqrt(1 - pow(k, 2));
        int nvp = 0;
        double *vp = landen(kp, tol, &nvp);
        for (size_t i = 0; i < nvp; i++)
        {
            vp[i] += 1.0;
        }

        *Kprime = double_array_prod(vp, nvp) * PI / 2.0;

        free(vp);
    }
}

cde为带复参数的归一化Jacobi椭圆函数,代码如下:

double *cde(double *u, int nu, double k1, double tol)
{
    int nv = 0;
    double *v = landen(k1, tol, &nv);

    double *w = (double *)malloc(sizeof(double) * nu);
    for (size_t i = 0; i < nu; i++)
    {
        w[i] = u[i] * PI / 2.0;
        w[i] = cos(w[i]);
    }

    for (int i = nv - 1; i >= 0; i--)
    {
        for (size_t j = 0; j < nu; j++)
        {
            w[j] = (1 + v[i]) * w[j] / (1 + v[i] * pow(w[j], 2));
        }
    }

    free(v);

    return w;
}

复数形式代码:

Complex *complex_cde(Complex *u, int nu, double k1, double tol)
{
    int nv = 0;
    double *v = landen(k1, tol, &nv);
   
    Complex *w = (Complex *)malloc(sizeof(Complex) * nu);
    for (size_t i = 0; i < nu; i++)
    {
        w[i] = complex_multiply_double(u[i], PI / 2.0);
        w[i] = complex_cosine(w[i]);
    }

    for (int i = nv - 1; i >= 0; i--)
    {
        for (size_t j = 0; j < nu; j++)
        {
            Complex t1 = complex_multiply_double(w[j], 1 + v[i]);
            Complex t2 = complex_multiply_double(complex_power(w[j], 2), v[i]);
            t2 = complex_add_double(t2, 1.0);
            w[j] = complex_divide(t1, t2);
        }
    }

    free(v);
    return w;
}

landen:

double *landen(double k, double tol, int *n)
{
    double tempv[1000];
    *n = 0;
    while (k > tol)
    {
        k = pow(k / (1 + sqrt(1 - pow(k, 2))), 2);
        tempv[*n] = k;
        *n = *n + 1;
    }
    int length=*n;
    double *temp = (double *)malloc( length* sizeof(double));
   
    for (size_t i = 0; i < *n; i++)
    {
        temp[i] = tempv[i];
    }

    return temp;
}

sne为正弦振幅的Jacobi椭圆函数,代码如下:

double *sne(double *u, int nu, double k, double tol)
{
    int nv = 0;
    double *v = landen(k, tol, &nv);
    double *w = (double *)malloc(sizeof(double) * nu);
    for (size_t i = 0; i < nu; i++)
    {
        w[i] = sin(u[i] * PI / 2.0);
    }

    for (int i = nv - 1; i >= 0; i--)
    {
        for (size_t j = 0; j < nu; j++)
        {
            w[j] = ((1.0 + v[i]) * w[j]) / (1.0 + v[i] * pow(w[j], 2.0));
        }
    }

    free(v);
    return w;
}

asne为正弦振幅的Jacobi椭圆函数的逆,代码如下:

Complex asne(Complex w, double k1, double tol)
{
    Complex rst = acde(w, k1, tol);
    rst = complex_subtract(create(1.0, 0.0), rst);
    return rst;
}

Complex acde(Complex w, double k1, double tol)
{
    int nv = 0;
    double *v = landen(k1, tol, &nv);
    Complex wt;
    wt.real = w.real;
    wt.imaginary = w.imaginary;
    for (size_t i = 0; i < nv; i++)
    {
        double v1 = i == 0 ? k1 : v[i - 1];
        // w = w./(1 + sqrt(1 - w.^2 * v1^2)) * 2/(1+v(n))
        //(1 + sqrt(1 - w.^2 * v1^2))
        Complex temp = complex_power(w, 2);
        temp = complex_multiply_double(temp, pow(v1, 2));
        temp = complex_subtract(create(1.0, 0.0), temp);
        temp = complex_square_root(temp);
        temp = complex_add_double(temp, 1.0);
        temp = complex_divide(w, temp);
        w = complex_multiply_double(temp, 2.0 / (1.0 + v[i]));
    }

    Complex u = complex_arccosine(w);
    u = complex_multiply_double(u, 2.0 / PI);
    double K, Kprime;
    ellipk(k1, tol, &K, &Kprime);
    double R = Kprime / K;

    u = complex_add_double(complex_multiply_double(create(0, 1.0), srem(u.imaginary, 2 * R)), srem(u.real, 4));

    free(v);

    return u;
}

acde:

Complex acde(Complex w, double k1, double tol)
{
    int nv = 0;
    double *v = landen(k1, tol, &nv);
    Complex wt;
    wt.real = w.real;
    wt.imaginary = w.imaginary;
    for (size_t i = 0; i < nv; i++)
    {
        double v1 = i == 0 ? k1 : v[i - 1];
        // w = w./(1 + sqrt(1 - w.^2 * v1^2)) * 2/(1+v(n))
        //(1 + sqrt(1 - w.^2 * v1^2))
        Complex temp = complex_power(w, 2);
        temp = complex_multiply_double(temp, pow(v1, 2));
        temp = complex_subtract(create(1.0, 0.0), temp);
        temp = complex_square_root(temp);
        temp = complex_add_double(temp, 1.0);
        temp = complex_divide(w, temp);
        w = complex_multiply_double(temp, 2.0 / (1.0 + v[i]));
    }

    Complex u = complex_arccosine(w);
    u = complex_multiply_double(u, 2.0 / PI);
    double K, Kprime;
    ellipk(k1, tol, &K, &Kprime);
    double R = Kprime / K;

    u = complex_add_double(complex_multiply_double(create(0, 1.0), srem(u.imaginary, 2 * R)), srem(u.real, 4));

    free(v);

    return u;
}

srem:

double srem(double X, double Y)
{
    double Z;

    Z = fmod(X, Y);

    // Bring into interval [-Y/2, Y/2]
    Z -= Y * ((Z > Y / 2) - (Z < -Y / 2));

    return Z;
}

测试

与matlab测试结果对比,matlab中最高阶49阶,C代码可确保47阶,且误差小于小数点后10位小数

下一篇: matlab besself函数 C实现

  • 13
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值