C++代码实现MATLAB中的pade函数功能

cpp 复制代码
// pade.cpp
// 用 C++ 实现 MATLAB 的 pade 函数(幂级数版本 + 纯延时版本)
// 编译: g++ -std=c++17 -O2 pade.cpp -o pade
#include <vector>
#include <complex>
#include <iostream>
#include <iomanip>
#include <cmath>
#include <stdexcept>
#include <algorithm>
#include <string>

namespace mpad {

using Complex = std::complex<double>;
using VecC    = std::vector<Complex>;
using MatC    = std::vector<VecC>;

// ------------------------------------------------------------------
// 列主元高斯消元求解 A*x = b
// ------------------------------------------------------------------
VecC solveLinearSystem(const MatC& A_in, const VecC& b_in)
{
    const int n = static_cast<int>(A_in.size());
    if (n == 0) return {};

    MatC A = A_in;
    VecC b = b_in;
    for (int i = 0; i < n; ++i) A[i].push_back(b[i]);   // 增广矩阵

    for (int c = 0; c < n; ++c) {
        int piv = c;
        double best = std::abs(A[c][c]);
        for (int r = c + 1; r < n; ++r) {
            if (std::abs(A[r][c]) > best) { best = std::abs(A[r][c]); piv = r; }
        }
        if (best < 1e-14)
            throw std::runtime_error("pade: 线性方程组奇异,无法求得 Pade 系数");

        if (piv != c) std::swap(A[c], A[piv]);

        for (int r = c + 1; r < n; ++r) {
            Complex f = A[r][c] / A[c][c];
            for (int k = c; k <= n; ++k) A[r][k] -= f * A[c][k];
        }
    }

    VecC x(n);
    for (int r = n - 1; r >= 0; --r) {
        Complex s = A[r][n];
        for (int c = r + 1; c < n; ++c) s -= A[r][c] * x[c];
        x[r] = s / A[r][r];
    }
    return x;
}

// ------------------------------------------------------------------
// 核心:由幂级数系数(升幂)c[0..L+M] 求 [L/M] 阶 Pade 逼近
//   输出 P(分子系数,升幂,长度 L+1)
//        Q(分母系数,升幂,长度 M+1,Q[0] == 1)
// ------------------------------------------------------------------
void padeLM(const VecC& c, int L, int M, VecC& P, VecC& Q)
{
    const int N = L + M;
    if (static_cast<int>(c.size()) < N + 1)
        throw std::runtime_error("pade: 幂级数系数个数不足 (需要 >= L+M+1)");

    // 解 Q(x) = 1 + q1 x + ... + qM x^M
    // 匹配方程 (k = L+1 .. L+M): q1*c[k-1] + ... + qM*c[k-M] = -c[k]
    MatC A(M, VecC(M, Complex(0.0, 0.0)));
    VecC rhs(M, Complex(0.0, 0.0));
    for (int r = 0; r < M; ++r) {
        const int k = L + 1 + r;
        for (int j = 0; j < M; ++j) {
            const int idx = k - (j + 1);
            A[r][j] = (idx >= 0) ? c[idx] : Complex(0.0, 0.0);
        }
        rhs[r] = -c[k];
    }

    Q.assign(M + 1, Complex(0.0, 0.0));
    Q[0] = Complex(1.0, 0.0);
    if (M > 0) {
        VecC q = solveLinearSystem(A, rhs);
        for (int j = 0; j < M; ++j) Q[j + 1] = q[j];
    }

    // 回代 P(x) = p0 + p1 x + ... + pL x^L
    //   p_k = sum_{i=0..min(k,M)} q_i * c_{k-i}
    P.assign(L + 1, Complex(0.0, 0.0));
    for (int k = 0; k <= L; ++k) {
        Complex s(0.0, 0.0);
        const int imax = std::min(k, M);
        for (int i = 0; i <= imax; ++i) s += Q[i] * c[k - i];
        P[k] = s;
    }
}

// 升幂 -> 降幂(MATLAB 传递函数约定)
std::vector<double> toDescending(const VecC& a)
{
    const int n = static_cast<int>(a.size());
    std::vector<double> out(n);
    for (int i = 0; i < n; ++i) out[i] = a[n - 1 - i].real();
    return out;
}

// ------------------------------------------------------------------
// [num,den] = pade(coeffs, N)
//   coeffs : f(x) 幂级数系数(升幂)
//   N      : 总阶数,L = floor(N/2),M = N - L
// ------------------------------------------------------------------
void pade(const std::vector<double>& coeffsAscending, int N,
          std::vector<double>& num, std::vector<double>& den)
{
    if (N < 0) throw std::runtime_error("pade: N 必须为非负整数");
    const int L = N / 2;
    const int M = N - L;

    VecC c(coeffsAscending.begin(), coeffsAscending.end());
    VecC P, Q;
    padeLM(c, L, M, P, Q);

    num = toDescending(P);
    den = toDescending(Q);
}

// ------------------------------------------------------------------
// [num,den] = pade(T, N)  ------ exp(-T*s) 的 N 阶 Pade 逼近
// ------------------------------------------------------------------
void padeDelay(double T, int N,
               std::vector<double>& num, std::vector<double>& den)
{
    if (N < 0) throw std::runtime_error("pade: N 必须为非负整数");
    const int L = N / 2;
    const int M = N - L;

    // exp(-T*s) 在 s=0 的泰勒系数 c_k = (-T)^k / k!
    std::vector<double> c(L + M + 1);
    c[0] = 1.0;
    for (int k = 1; k <= L + M; ++k)
        c[k] = c[k - 1] * (-T) / static_cast<double>(k);

    pade(c, N, num, den);
}

void printVector(const std::string& name, const std::vector<double>& v)
{
    std::cout << name << " = [";
    for (size_t i = 0; i < v.size(); ++i) {
        std::cout << v[i];
        if (i + 1 < v.size()) std::cout << ", ";
    }
    std::cout << "]\n";
}

} // namespace mpad

// ==================================================================
int main()
{
    using namespace mpad;
    std::cout << std::setprecision(10);

    // 例 1:exp(x) 的 [2/3] Pade
    //   coeffs = 1./factorial(0:5)
    std::vector<double> coeffs = {1.0, 1.0, 0.5, 1.0/6.0, 1.0/24.0, 1.0/120.0};
    std::vector<double> num, den;
    pade(coeffs, 5, num, den);
    std::cout << "--- [2/3] Pade of exp(x) ---\n";
    printVector("num", num);
    printVector("den", den);

    // 例 2:exp(-s) 的 [2/2] Pade(等价 pade(1,4))
    padeDelay(1.0, 4, num, den);
    std::cout << "\n--- [2/2] Pade of exp(-s) ---\n";
    printVector("num", num);
    printVector("den", den);

    // 例 3:exp(-0.1s) 的 [1/2] Pade(等价 pade(0.1,3))
    padeDelay(0.1, 3, num, den);
    std::cout << "\n--- [1/2] Pade of exp(-0.1s) ---\n";
    printVector("num", num);
    printVector("den", den);

    return 0;
}
相关推荐
学逆向的1 分钟前
C printf原型解析
c语言·开发语言·网络安全
纪念 2291 分钟前
C++ list讲解
c++·windows·list
\光辉岁月/3 分钟前
5.math类
java·开发语言
不像程序员的程序媛11 分钟前
mybatisplus insert dto未指定id时会如何
java·开发语言
BeiGuTing_code27 分钟前
C字符输出:一个换行符引发的“失踪案”
c语言·开发语言
零基础12328 分钟前
基于模型的强化学习与不基于模型的强化学习:核心区别与实战选择
python·算法
我命由我1234530 分钟前
5-2.Python 编码进阶 - 字符串进阶(拼接、普通格式化、普通格式化数字精度控制、快速格式化、遍历、常用方法)
java·开发语言·后端·python·学习·java-ee·学习方法
http阿拉丁神猫5 小时前
Go语言入门笔记:从基础到开发环境搭建(二)
开发语言·笔记·golang
不会就选b6 小时前
C++补充部分(一)--lambda 表达式
开发语言·c++
Pniubi8 小时前
HashMap的扩容和树化边界
java·开发语言