使用 TikZ 复制傅里叶变换时频域对应图

使用 TikZ 复制傅里叶变换时频域对应图

下图为时频对应图傅里叶变换的维基百科条目

转换函数

另附gif动画版本(若动画不显示,请在新窗口中打开以下图片):

t-fgif

这张图片具有很强的解释力,我想复制它TikZ以供将来使用。

以下是我的想法:

\documentclass{minimal}
\usepackage{tikz}

\begin{document}
\begin{tikzpicture}
[x={(1cm,0.5cm)},z={(0cm,0.5cm)},y={(1cm,-0.2cm)}]
\draw[->,thick,blue!90] (0,6.5,0) -- (6.2,6.5,0) node[right] {Frequency};
\draw[->,thick,red!90] (0,0,0) -- (0,6.5,0) node[below] {Time};
\draw[->,thick] (0,0,0) -- (0,0,2) node[above] {Magnitude};
\foreach \x in {0.5,1.5,2.5,3.5,4.5,5.5}{
  \draw[blue!50] (\x,0,0)
  \foreach \y in {0,0.02,...,6.28}{ 
   -- ({\x},{\y},{sin(\x*\y*(157))/sqrt(2*\x)})
  };
  \draw[blue!90, thick] (\x,6.5,0) -- (\x,6.5,1/\x);
}

\end{tikzpicture}
\end{document}

这是迄今为止的输出。

傅立叶

我有两个问题:

  • 如何生成所有蓝色正弦波叠加的红色正弦波?我不知道是否有求和函数,或者我必须再次使用循环?

  • 如何使相机投影TikZ更类似于维基百科插图中的透视?

我也欢迎对样本绘图中使用的参数提出任何建议和调整。

提前致谢!


更新 1: 这是使用 的新版本tikz,比第一个版本更易读。然而,正弦波的叠加是手动完成的……我仍然不知道如何使用 来foreach产生总和。

\begin{tikzpicture}[x={(1cm,0.5cm)},z={(0cm,0.5cm)},y={(1cm,-0.2cm)}]
\draw[->,thick,black!70] (0,6.5,0) -- (6.2,6.5,0) node[right] {Frequency};
\draw[->,thick,black!70] (0,0,0) -- (0,6.5,0) node[below right] {Time};
\draw[->,thick] (0,0,0) -- (0,0,2) node[above] {Magnitude};
\foreach \y in {0.5,1.5,...,5.5}{
\draw [cyan!50, domain=0:2*pi,samples=200,smooth] 
 plot (\y,\x, {sin(4*\y*\x r)/\y });
\draw[blue, ultra thick] (\y,6.5,0) -- (\y,6.5,1/\y);
}
\draw [red, thick, domain=0:2*pi,samples=200,smooth] 
plot (0,\x, {sin(4*0.5*\x r)/0.5 + sin(4*1.5*\x r)/1.5 + sin(4*2.5*\x r)/2.5 + sin(4*3.5*\x r)/3.5 + sin(4*4.5*\x r)/4.5 + sin(4*5.5*\x r)/5.5} );
\end{tikzpicture}

结果如下:fourier2

答案1

这是使用 PGFPlots 绘制此图的方法。您可以在使用 循环遍历各个组件时收集红色曲线的表达式\xdef

不幸的是,PGFPlots 不能使用透视投影(即使在普通的 TikZ 中,我认为你也必须经过很多麻烦才能模拟它)。

\documentclass[border=5mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.8}

\begin{document}
\begin{tikzpicture}
\begin{axis}[
    set layers=standard,
    domain=0:10,
    samples y=1,
    view={40}{20},
    hide axis,
    unit vector ratio*=1 2 1,
    xtick=\empty, ytick=\empty, ztick=\empty,
    clip=false
]
\def\sumcurve{0}
\pgfplotsinvokeforeach{0.5,1.5,...,5.5}{
    \draw [on layer=background, gray!20] (axis cs:0,#1,0) -- (axis cs:10,#1,0);
    \addplot3 [on layer=main, blue!30, smooth, samples=101] (x,#1,{sin(#1*x*(157))/(#1*2)});

    \addplot3 [on layer=axis foreground, very thick, blue,ycomb, samples=2] (10.5,#1,{1/(#1*2)});
    \xdef\sumcurve{\sumcurve + sin(#1*x*(157))/(#1*2)}
}
\addplot3 [red, samples=200] (x,0,{\sumcurve});

\draw [on layer=axis foreground]  (axis cs:0,0,0) -- (axis cs:10,0,0);
\draw (axis cs:10.5,0.25,0) -- (axis cs:10.5,5.5,0);
\end{axis}
\end{tikzpicture}
\end{document}

答案2

一个(可动画)派克斯版本如下。(我无法查看原始动画,但已从波动方程推断出来。)

例如,使用

flix --frames 120 -o fourier.gif fourier.flx

编译。

傅里叶频谱

/* -*-flix-*- */
#include "epix.h"
using namespace ePiX;

// n treated throughout as an integer
double freq(double n) { return 2*n - 1; }
double ampl(double n) { return 1.0/freq(n); }

const unsigned int N(6); // number of harmonics
const unsigned int num_pts(120);

double MAX(2*M_PI), // max spatial coordinate
  dX(1), dY(0.5); // offsets for spectrum/frequency screens

P sw1(-MAX, 0, -2), // "waveform screen" corners
  ne1( MAX, 0,  2),
  sw2(MAX + dX,           dY, -2), // "spectrum screen" corners
  ne2(MAX + dX, freq(N) + dY,  2);

// standing sine waves of specified frequency, amplitude
P waves(double x, double n)
{
  return P(x, freq(n), ampl(n)*Sin(freq(n)*x)*Cos(freq(n)*full_turn()*tix()));
}

// sum of waves, in (x, y)-plane
P waveform(double x)
{
  double val(0);
  for (int i=1; i <= N; ++i)
    val += waves(x, i).x3();

  return P(x, 0, val);
}

domain R(P(-MAX, 1), P(MAX, N), mesh(num_pts, N - 1));

int main(int argc, char* argv[])
{
  if (argc == 3)
    {
      char* arg;
      double temp1(strtod(argv[1], &arg)), temp2(strtod(argv[2], &arg));

      tix()=temp1/temp2;
    }
  picture(P(-6,-3), P(12, 3), "6 x 2in");

  begin();
  camera.at(P(12, -8, 4)).look_at(P(0, 0.5*N, 0)).range(25);

  // frequancy components
  bold(Blue());
  plot(waves, R.slices2());

  // "screens"
  plain(Black(0.5));
  fill(Black(0.1));
  rect(sw2, ne2); // spectrum
  rect(sw1, ne1); // waveform

  // frequency components
  plain(Blue(1.5));
  plot(waves, R.slices2());
  for (int i=1; i <= N; ++i)
    line(P(-MAX, freq(i), 0), P(MAX, freq(i), 0));

  // spectrum
  bold(Blue());
  line(P(MAX + dX, dY, 0), P(MAX + dX, freq(N) + dY, 0));
  for (int i=1; i <= N; ++i)
    {
      P loc(MAX + dX, freq(i), 0);
      line(loc, loc + ampl(i)*E_3);
    }

  // waveform
  bold(Red());
  plot(waveform, -MAX, MAX, 2*num_pts);

  tikz_format();
  end();
}

答案3

这是我刚刚使用这篇文章制作的一些东西,用于显示时间域中的建设性干扰。

在此处输入图片描述

\documentclass{standalone}
\usepackage{tikz}


\begin{document}
    \begin{tikzpicture}[x={(1cm,0.5cm)},z={(0cm,1cm)},y={(1cm,-0.2cm)}]

        %repere
        \draw[->] (0,-pi,0) --++ (6,0,0) node[above right] {Frequency};
        \draw[->] (0,-pi,0) --++ (0,6.5,0) node[right] {Time};
        \draw[->] (0,-pi,0) --++ (0,0,1.5) node[above] {Magnitude};

        \draw [dashed] (1,0,0.2) --++ (4,0,0);          
        \foreach \y in {1,2,...,5}{
            %sinusoides
            \draw[blue] plot[domain = -pi:+pi, samples = 300] 
            (\y,\x,{0.2*cos(10*\y/2*(\x) r)});
            \draw[blue] (\y,-pi-0.15,0) node [left]{$f_{\y}$};
            \draw[red] (\y,0,{0.2*cos(10*\y/2*(0) r)}) node {\textbf{.}};
        }

        %sinc
        \draw[red, thick] plot[domain = -pi:+pi, samples = 2000] 
        (0,\x,{0.02*sin(50*(\x) r)/(\x))});

    \end{tikzpicture}
\end{document}

答案4

我根据 Jake 的版本制作了以下 FFT,但尝试使其更具视觉吸引力:我使用随机变量为信号添加了噪声。频率中的信号只是一个正弦平方函数,我使用指数函数对其进行了相当经验性的调制以满足我的需求。对此肯定存在更优雅的解决方案。


% Schematic Fourier Analysis
% Author: Tobit Flatscher
%
% Disclaimer
% The following code is based on a previous version of tex-stackexchange community 
% member Jake but I tried to make it more visually appealing. Some noise is added 
% to the curves in order to make them look more realistic.
%
% Description
% This code creates a schematic representation of an FFT analysis. A signal 
% over time is decomposed into its harmonic oscillations with a corresponding 
% frequency using a Fourier series. The amplitude of the frequency components 
% is plotted.


\documentclass[border=10pt]{standalone}

\usepackage{pgfplots}
\pgfplotsset{compat=1.8}
\usepgfplotslibrary{fillbetween} %for fill under curve

\begin{document}

    %define colors
    \definecolor{lightgray}{rgb}{0.8, 0.8, 0.8} %grid of coordinate system, axes
    \definecolor{midgray}{rgb}{0.6, 0.6, 0.6} %layer of border
    \definecolor{darkgray}{rgb}{0.4, 0.4, 0.4} %curves, fill under curve

    \begin{tikzpicture} %create tikz picture
    \begin{axis}[ %create 3d plot within tikz
        set layers=standard, %use predefined layers
        view={50}{30}, %perspective adjustment
        domain=0:10, %plot limit in time direction
        samples y=1, %samples for frequency direction
        unit vector ratio*=1 2 1, %rescale unit vectors
        hide axis, %do not plot axes
        xtick=\empty, ytick=\empty, ztick=\empty, %no ticks on coordinate axes
        clip=false %let me plot outside the coordinate system
    ]
        %limit variables
        \def\xmax{100} %limits for curves and layers
        \def\xmin{0}
        \def\ymax{35}
        \def\ymin{5}
        \def\zmax{25}
        \def\zmin{-5}
        \def\xlayer{110} %frequency layer
        \def\sumcurve{0} %sum curve of time signal

        %frequency curves
        \pgfplotsinvokeforeach{1,2,3}{ %for each frequency component
            \draw [on layer=background, lightgray] (axis cs:0,#1,0) -- (axis cs:10,#1,0); %axes
            \addplot3 [on layer=main, darkgray, smooth, samples=200] (x,#1,{1.3*sin(2*#1*x*(157))/(#1*2)}); %plot curves (curves are somewhat arbitrary)

            \xdef\sumcurve{\sumcurve + sin(#1*x*(157))/(#1*2)} %add current curve to sumcurve
        }

        %transparent layers
        \fill[white,opacity=0.7] (\xmin,0,\zmin) -- (\xmin,0,\zmax) -- (\xmax,0,\zmax) -- (\xmax,0,\zmin) -- cycle; %transparent layer in time space
        \fill[white,opacity=0.7] (\xlayer,\ymin,\zmin) -- (\xlayer,\ymin,\zmax) -- (\xlayer,\ymax,\zmax) -- (\xlayer,\ymax,\zmin) -- cycle; % transparent layer for frequency space

        %grid lines
        \pgfplotsinvokeforeach{\xmin,\xmin+5,...,\xmax}{ %create horizontal grid lines (time layer)
            \draw[lightgray,opacity=0.6] (#1,0,\zmin) -- (#1,0,\zmax);
        }
        \pgfplotsinvokeforeach{\ymin,\ymin+2.5,...,\ymax}{ %create horizontal grid lines (frequency layer)
            \draw[lightgray,opacity=0.6] (\xlayer,#1,\zmin) -- (\xlayer,#1,\zmax);
        }
        \pgfplotsinvokeforeach{\zmin,\zmin+5,...,\zmax}{ %create vertical grid lines (both layers)
            \draw[lightgray,opacity=0.6] (\xmin,0,#1) -- (\xmax,0,#1);
            \draw[lightgray,opacity=0.6] (\xlayer,\ymin,#1) -- (\xlayer,\ymax,#1);
        }

        %borders layer
        \draw[midgray] (\xmin,0,\zmin) -- (\xmin,0,\zmax) -- (\xmax,0,\zmax) -- (\xmax,0,\zmin) -- cycle; %time space layer border line
        \draw[midgray] (\xlayer,\ymin,\zmin) -- (\xlayer,\ymin,\zmax) -- (\xlayer,\ymax,\zmax) -- (\xlayer,\ymax,\zmin) -- cycle; %frequency space layer border line

        %sum curve
        \addplot3 [samples=200] (x,0,{\sumcurve+rand/7+0.2*sin(x*400)}); %sum curve time space with added random noise

        % frequency curve
        \addplot3 [name path=f,samples=200,domain=0.5:3.5] (11,x,{rand/30+2*sin((x-0.7)*180)^200*e^(-x/2)-0.3}); %experimentally modified curve with noise

        %create fill under curve
        \addplot3 [name path=ax,draw=none,samples=2,domain=0.5:3.5] (11,x,-0.5); %create fill axis
        \addplot3 [darkgray] fill between [of=f and ax]; %create fill between curve and axis

        %create coordinate axis
        \draw[-{stealth}] (\xmin,0,\zmin-7) -- (\xmax/5.3,0,\zmin-7); %time axis
        \draw[-{stealth}] (\xlayer,\ymin,\zmin-7) -- (\xlayer,\ymin+\ymax/4,\zmin-7); %frequency axis

        %axis labels
        \node[scale=0.7] at (0,0,-21) {Time}; %axis time space
        \node[scale=0.7] at (100,22,-32) {Frequency}; %axis frequency space

    \end{axis}
    \end{tikzpicture}

\end{document}

使用 TikZ 进行 2-bt FFT

相关内容