AnyMath 文档
Notebook

MATLAB和AnyMath在频谱和时频分析问题中的比较

比较MATLAB和AnyMath在频谱分析和时频分析领域,我们将考虑它们在两个任务中的能力和方法:正向和反向傅立叶变换和时频分析。

让我们设置一个随机输入信号。

In [ ]:
Pkg.add(["DSP"])
   Resolving package versions...
Warning: detected a stack overflow; program state may be corrupted, so further execution might be unreliable.
     Project No packages added to or removed from `~/.project/Project.toml`
    Manifest No packages added to or removed from `~/.project/Manifest.toml`
In [ ]:
x_in = randn(300)
plot(x_in)
Out[0]:

频谱傅立叶变换(FFT和IFFT)

AnyMath使用FFTW包中的函数:

  1. FFT:直接快速傅立叶变换。
  2. ifft:逆傅立叶变换。
In [ ]:
using FFTW

# 直接傅立叶变换
X = fft(x_in)

# 傅里叶逆变换
x_e = ifft(X)
Out[0]:
300-element Vector{ComplexF64}:
   0.3979493700936538 - 1.0954200509634878e-16im
  -0.4848600811102097 - 1.556162045853668e-16im
   1.5842814778290957 - 3.5071455278969295e-16im
   1.0508752491852456 - 2.391742695653933e-17im
  -1.2366907113199697 - 4.071259559251789e-17im
 -0.36960235504034455 + 1.4595447252478719e-16im
  -1.1426283543776241 + 4.3707707580700186e-17im
   0.8564914272398407 + 1.2805741139866173e-16im
 -0.12485768932464274 - 5.477902093541194e-17im
   0.3697754344032267 - 1.117313298369714e-16im
   0.5155016257717131 + 1.116622300172914e-16im
   2.2484859491160183 - 3.921415399333804e-17im
   1.4148589776607792 - 6.505444427416594e-17im
                      ⋮
   1.1048524345297837 + 2.0287474369405695e-17im
  0.42662339105753333 + 1.0892700921806983e-16im
  -1.1609732505396098 - 1.8753233893151456e-16im
    0.706873531822772 + 2.324088774315001e-16im
   0.5593066641593584 + 3.0191244662088247e-16im
   1.2912310062932724 - 1.0528583049558412e-16im
   -0.449143888716872 + 1.2244696865724196e-16im
    1.078424926289395 - 1.0546692614961304e-16im
   1.2499823098900609 - 1.7038939789605642e-16im
    0.319974449064981 + 5.9782005894739336e-18im
  -0.6473573556894365 - 1.3769334329958588e-16im
  -0.7737153966819301 + 1.2003344690763118e-16im

MATLAB具有用于快速傅里叶变换的内置函数:

  1. FFT:直接快速傅立叶变换。
  2. Ifft:快速傅里叶逆变换。
In [ ]:
using MATLAB

# 直接傅立叶变换
mat"""X = fft($(x_in));"""

# 傅里叶逆变换
x_m=mat"""ifft(X);"""
Out[0]:
300-element Vector{Float64}:
  0.39794937009365344
 -0.48486008111020956
  1.5842814778290955
  1.0508752491852458
 -1.2366907113199697
 -0.3696023550403446
 -1.1426283543776241
  0.8564914272398406
 -0.1248576893246431
  0.36977543440322674
  0.515501625771713
  2.2484859491160183
  1.4148589776607792
  ⋮
  1.1048524345297834
  0.4266233910575327
 -1.1609732505396104
  0.7068735318227719
  0.5593066641593588
  1.291231006293272
 -0.4491438887168719
  1.078424926289395
  1.2499823098900606
  0.3199744490649812
 -0.6473573556894366
 -0.7737153966819301

让我们比较结果并计算误差范围。

In [ ]:
plot(x_in)
plot!(real(x_e))
plot!(x_m)
Out[0]:
In [ ]:
error_e = abs.(x_in-real(x_e))
error_m = abs.(x_in-x_m)
println("Средняя ошибка Engee: $(sum(error_e)/length(error_e))")
println("Средняя ошибка MATLAB: $(sum(error_m)/length(error_m))")
Средняя ошибка Engee: 1.6997615699213912e-16
Средняя ошибка MATLAB: 2.294193481022777e-16

在两种环境中,正向傅立叶变换的结果都是复数,而反向变换返回具有与数值舍入相关的小误差的原始信号。
所以你可以看到代码的语法和逻辑是相同的。

时频傅立叶变换

AnyMath中没有用于此类转换的标准函数,必须手动实现。

In [ ]:
using DSP
# 用于产生线性调频信号的函数
function chirp(t::AbstractVector{T}, f0::T, t1::T, k::T) where T<:Real
    return cos.(2π * (f0 .* t .+ 0.5 * k .* t.^2))
end

# 汉明窗
function hamming(N::Int)
    n = 0:N-1
    return 0.54 .- 0.46 .* cos.(2π * n / (N - 1))
end

x = chirp(0:0.001:1, 0.0, 1.0, 100.0)  # 线性调频信号
l=500 # 窗口大小
window=vcat(hamming(l),zeros(length(x)-l))

P = DSP.periodogram(x; fs=1000, window=window, nfft=length(x))

# 光谱的可视化
plot(freq(P), 20*log10.(power(P)), xlabel="Frequency (Hz)", ylabel="Power Spectrum (dB)", title="Power Spectrum", linewidth=2)
Out[0]:

MATLAB具有pspectrum功能,允许您对信号进行时频分析。
pspectrum自动选择合适的分析方法。
支持各种可视化(频谱图,功率密度)。

In [ ]:
using Images
mat"""cd($(@__DIR__))"""
mat"""
% 时频分析
x = chirp(0:0.001:1, 0, 1, 100);
pspectrum(x, 1000); % 时频频谱
saveas(gcf, 'frequency_time_spectrum.jpg'); % 将当前形状保存为JPG
"""
load( "$(@__DIR__)/frequency_time_spectrum.jpg" )
Out[0]:
No description has been provided for this image

根据这些图表,可以看出信号行为的主要趋势反映在AnyMath中。 为了更详细的绘图,有必要另外实现对周期图函数的窗口的更详细的计算。

另外,让我们比较MATLAB和AnyMath中生成的输入数据的正确性。

In [ ]:
plot(mat"chirp(0:0.001:1, 0, 1, 100)"[:])
plot!(chirp(0:0.001:1, 0.0, 1.0, 100.0))
title!("Sum_error: $(sum(mat"chirp(0:0.001:1, 0, 1, 100)"[:]-chirp(0:0.001:1, 0.0, 1.0, 100.0)))")
Out[0]:

正如我们所看到的,输入信号是相同的。

结论

MATLAB具有用于执行这些操作的内置函数。 在AnyMath中,您可以使用第三方库来完成此任务,例如DSP或FFTW来进行更复杂的信号操作。 同样重要的是要考虑到AnyMath在如何实现转换方面提供了更大的灵活性。 要简化AnyMath任务的这些操作,请使用本演示中描述的现成方法。

比较两种环境功能的另一个方面表明,MATLAB针对处理矩阵和信号进行了优化。 然而,如果考虑到这种环境的具体情况编写代码,AnyMath在计算方面通常会更快,这大大提高了大型系统中执行和测试算法的速度。