pgfmath 的declare function密钥

pgfmath 的declare function密钥

我的目的是绘制函数的一阶导数,如下所示方法:

f'(x) = (f(x + dx) - f(x))/dx

我的函数有点长,所以我想知道是否可以将其保存在宏(或类似的东西)中,然后稍后再调用它

\pgfmathsetmacro{\f}{\A * \b * ((exp(-\b*(x))/(\p-\b)) + (exp(-\p*(x))/(\b-\p)))}; 
produces the error 
*! Package PGF Math Error: Unknown function `x' (in '1* 0.7* ((exp(-0.7*(x))/(0.*

最小“工作”示例

\documentclass[12pt]{article}
\usepackage{tikz}
\usepackage{pgfplots}
\begin{document}
\begin{figure}
\centering
\begin{tikzpicture}
    \pgfmathsetmacro{\b}{0.7};
    \pgfmathsetmacro{\p}{0.4};
    \pgfmathsetmacro{\A}{1};
    %\pgfmathsetmacro{\f}{\A * \b * ((exp(-\b*(x))/(\p-\b)) + (exp(-\p*(x))/(\b-\p)))}; <-- failing attempt
    \begin{axis}[
    width=8cm, height=6cm,
    xmin=0.003, xmax=10,
    ymin=-0.2, ymax=0.8, 
    xtick=\empty, ytick=\empty,
    axis lines=middle,
    x label style={at={(axis cs:10,0)},anchor=west},
    y label style={at={(0,1)},above},
    xlabel={$t$}, ylabel={$r$},
    clip=false
    ]              
    \addplot [red, very thick, samples=100, smooth,domain=0.003:10]
        { \A * \b * ((exp(-\b*(x))/(\p-\b)) + (exp(-\p*(x))/(\b-\p))) }; %
    \end{axis}
    \end{tikzpicture}
\end{figure}
\end{document}

我希望可以计算导数

(\A * \b * ((exp(-\b*(x+0.01))/(\p-\b)) + (exp(-\p*(x+0.01))/(\b-\p))) - \f)/0.01

或者,如果可能的话,用更简单的方法

答案1

首先,请注意以下几点:

\pgfmathsetmacro{\b}{0.7};
\pgfmathsetmacro{\p}{0.4};
\pgfmathsetmacro{\A}{1};

这里不应该有,;因为这些不是 TiZ 也不是像、、等pgfplots语句。这些分号是导致 TeX 终端输出中出现以下错误信息(3 次)的原因:\path\draw\addplot

缺少字符:nullfont 字体中没有 ;!

另外,虽然使用\pgfmathsetmacro是正确的,但对于直接以十进制形式写入的简单常量来说,它是一种繁重的机器。我建议使用\def,这将是等效的,但速度更快。

(不过要小心单字母控制序列......宏就像\c\i在 LaTeX 中有一个标准定义;在某些情况下,覆盖它们时可能会遇到问题。也就是说,像这里这样的局部定义 + 大部分计算代码可能“不是太不安全”。)。

pgfmath 的declare function密钥

您正在寻找的工具是/pgf/declare function(参见自定义数学引擎在里面Z & PGF 手册)。

使用此工具和解析步长为 0.1,您的想法是:

\documentclass[tikz,border=2mm]{standalone}
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}

\begin{document}
\begin{tikzpicture}[
  declare function = {
    f(\x) = \A * \b * ((exp(-\b*(\x))/(\p-\b)) + (exp(-\p*(\x))/(\b-\p)));},
  ]
  \def\b{0.7}
  \def\p{0.4}
  \def\A{1}
  \begin{axis}[
    width=8cm, height=6cm, ymin=-0.15, ymax=0.7,
    axis lines=middle,
    x label style={at={(axis cs:10,0)}, anchor=west},
    y label style={at={(0,1)}, above},
    xlabel={$t$}, ylabel={$r$},
    ]
    \addplot[red, very thick, samples=100, smooth, domain=0.003:10]
      { f(x) };
    \addplot[blue, very thick, samples=100, smooth, domain=0.003:10]
      { (f(x + 0.1) - f(x)) / 0.1 };
  \end{axis}
\end{tikzpicture}
\end{document}

在此处输入图片描述

如果像您的问题中那样使用 0.01 步长,则计算精度较低会导致结果不太令人满意:

在此处输入图片描述

为了\fpeval获得更好的数值精度

\fpeval使用(不是来自pgfmath,特别是不使用库)以 0.01 步长可以获得良好的结果fpu。这种技术速度较慢,而且以这种方式给出“导数”的可用表达式更为麻烦,但结果看起来不错:

\documentclass[tikz,border=2mm]{standalone}
\usepackage{xfp}   % not needed if the LaTeX kernel is from 2022-06-01 or later
\usepackage{pgfplots}
\pgfplotsset{compat=1.18}

\pgfmathdeclarefunction{g}{1}{%
  \begingroup
  \pgfmathfloattofixed{#1}%
  \let\x\pgfmathresult
  \edef\pgfmathresult{%
    \fpeval{
      (\A * \b * ((exp(-\b*(\x + 0.01))/(\p-\b)) + (exp(-\p*(\x + 0.01))/(\b-\p)))
      - (\A * \b * ((exp(-\b*(\x))/(\p-\b)) + (exp(-\p*(\x))/(\b-\p)))))
      / 0.01}%
  }%
  \pgfmathsmuggle\pgfmathresult
  \endgroup
}

\begin{document}
\begin{tikzpicture}[
  declare function = {
    f(\x) = \A * \b * ((exp(-\b*(\x))/(\p-\b)) + (exp(-\p*(\x))/(\b-\p)));},
  ]
  \def\b{0.7}
  \def\p{0.4}
  \def\A{1}
  \begin{axis}[
    width=8cm, height=6cm, ymin=-0.15, ymax=0.7,
    axis lines=middle,
    x label style={at={(axis cs:10,0)}, anchor=west},
    y label style={at={(0,1)}, above},
    xlabel={$t$}, ylabel={$r$},
    ]
    \addplot[red, very thick, samples=100, smooth, domain=0.003:10]
      { f(x) };
    \addplot[blue, very thick, samples=100, smooth, domain=0.003:10]
      { g(x) };
  \end{axis}
\end{tikzpicture}
\end{document}

在此处输入图片描述

相关内容