簡體   English   中英

使用 DFT 的一維熱方程產生不正確的結果 (FFTW)

[英]1D Heat Equation using DFT produces incorrect results (FFTW)

我正在嘗試使用復雜到復雜的 IDFT 來求解一維熱方程。 問題是單個時間步長后的輸出似乎不正確。 我在下面包含了一個簡單的例子來說明這個問題。

我初始化溫度狀態如下:
溫度域的初始狀態

頻域中的初始模式為:
k[ 0] = 12.5 + 0i
k[ 1] = 12.5 + 0i
k[ 2] = 12.5 + 0i
k[ 3] = 12.5 + 0i
k[ 4] = 12.5 + 0i
k[-3] = 12.5 + 0i
k[-2] = 12.5 + 0i
k[-1] = 12.5 + 0i

然后我使用標准的一維熱方程將頻域的狀態推進到t=0.02

double alpha = 0.2; // Thermal conductivity constant
double timestep = 0.02;

for (int i = 0; i < N; i++) {
    int k = (i <= N / 2) ? i : i - N;

    F[i][REAL] *= exp(-alpha * k * k * timestep); // Decay the real part
    F[i][IMAG] *= exp(-alpha * k * k * timestep); // Decay the imaginary part
}

t=0.02處的頻率模式變為:
k[ 0] = 12.5 + 0i
k[ 1] = 12.45 + 0i
k[ 2] = 12.3 + 0i
k[ 3] = 12.06 + 0i
k[ 4] = 11.73 + 0i
k[-3] = 12.06 + 0i
k[-2] = 12.3 + 0i
k[-1] = 12.45 + 0i

在執行 IDFT 以獲得t=0.02的溫度域狀態后,我得到:
t=0.02 時的空間域狀態

空間域和頻域似乎都是正確的周期性。 然而,熱量(空間域中的值)似乎不會根據高斯曲線消散。 更令人驚訝的是,一些溫度低於它們的初始值(它們變成負值!)。

能量守恆似乎是正確的:將所有溫度加在一起仍然是 100。

這是我的完整熱方程代碼:

double alpha = 0.2;     // Thermal conductivity constant
double timestep = 0.02; // Physical heat equation timestep
int N = 8;              // Number of data points

fftw_complex* T = (fftw_complex*)fftw_alloc_complex(N); // Temperature domain
fftw_complex* F = (fftw_complex*)fftw_alloc_complex(N); // Frequency domain

fftw_plan plan = fftw_plan_dft_1d(N, F, T, FFTW_BACKWARD, FFTW_MEASURE); // IDFT from frequency to temperature domain

// Initialize all frequency modes such that there is a peak of 100 at x=0 in the temperature domain
// All other other points in the temperature domain are 0
for (int i = 0; i < N; i++) {
    F[i][REAL] = 100.0 / N;
    F[i][IMAG] = 0.0;
}

// Perform the IDFT to obtain the initial state in the temperature domain
fftw_execute(plan);
printTime1d(T, N);
printFrequencies1d(F, N);

// Perform a single timestep of the heat equation to obtain the frequency domain state at t=0.02
for (int i = 0; i < N; i++) {
    int k = (i <= N / 2) ? i : i - N;

    F[i][REAL] *= exp(-alpha * k * k * timestep); // Decay the real part
    F[i][IMAG] *= exp(-alpha * k * k * timestep); // Decay the imaginary part
}

// Perform the IDFT to obtain the temperature domain state at t=0.02
fftw_execute(plan);
printTime1d(T, N);
printFrequencies1d(F, N);

printTime(...)printFrequencies(...)是:

void printTime1d(fftw_complex* data, int N) {
    int rounding_factor = pow(10, 2);

    for (int i = 0; i < N; i++) {
        std::cout << std::setw(8) << round(data[i][REAL] * rounding_factor) / rounding_factor;
    }

    std::cout << std::endl;
}

void printFrequencies1d(fftw_complex* data, int N) {
    int rounding_factor = pow(10, 2);

    for (int i = 0; i < N; i++) {
        int k = (i <= N / 2) ? i : i - N;

        double R = round(data[i][REAL] * rounding_factor) / rounding_factor;
        double I = round(data[i][IMAG] * rounding_factor) / rounding_factor;

        std::cout << "k[" << std::setw(2) << k << "]: " << std::setw(2) << R << ((I < 0) ? " - " : " + ") << std::setw(1) << abs(I) << "i" << std::endl;
    }

    std::cout << std::endl;
}

也許值得注意的是,我還使用復雜到真實的 IDFT(使用fftw_plan_dft_c2r_1d()fftw_plan_dft_c2r_1d() )進行了這個實驗,它給出了完全相同的結果。

您的問題是您沒有解決所需的頻率,而是在乘以衰減系數后得到函數的以下傅立葉圖像:

IDFT之前的原始數據

上面的結果與你應該得到的結果相差太遠了——一個高斯——至少是這樣的(使用 80 個點而不是 8 個):

IDFT前的80點數據

請注意上面第一個圖表中的振幅是如何甚至沒有機會接近零,而是撞到奈奎斯特頻率。 很明顯,您會得到類似於吉布斯現象的偽像:這是傅立葉部分和的常見行為。

80 點數據版本的傅里葉逆變換則如下:

80點空間域函數

這個結果仍然有負分量(因為我們使用了有限數量的諧波),但它們的幅度比你只用 8 個諧波得到的小得多。

請注意,這確實意味着,如果您增加感興趣的時間值,則可以減少考慮的諧波數量。 起初這可能是出乎意料的,但這僅僅是因為高次諧波比低次諧波衰減得快得多,而且它們永遠不會增加。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM