TikZ:稳健且自动化地创建信号流图(并行形式)

TikZ:稳健且自动化地创建信号流图(并行形式)

跟进我之前的问题,我想知道如何自动且稳健地创建以下信号流图的并行形式,而无需手动绘制线条/节点:

考虑一个没有重复极点的传递函数

在此处输入图片描述

每个项都是以 R(s) 为输入的一阶子系统,输出C(s)可以视为三个项之和

在此处输入图片描述

因此,这导致了以下期望信号流图的并行形式

在此处输入图片描述

关于我的以下代码,我有以下疑问:

1-为什么foreach我的代码不起作用?

2-如何微调amark标签的位置,使它们稍微远离曲线?

3-如何才能在没有手动绘制线条/节点的情况下自动完成绘制图表的过程?

4-下面的代码是否有使用tikz-cdmatrix of nodes或的更简化的代码chains

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{calc,decorations.markings,positioning,arrows.meta,matrix}
\newif\iflabrev
\begin{document}
    \begin{tikzpicture}[
        node distance = 15mm and 15mm, 
        relative = false,
        label revd/.is if = labrev,
        label revd/.default = true,
        amark/.style = {
            decoration={             
                markings,   
                mark=at position {0.5} with { 
                    \arrow{stealth},
                    \iflabrev \node[below] {#1};\else \node[above] {#1};\fi
                }
            },
            postaction={decorate}
        },
    terminal/.style 2 args={draw,alias=ln,circle,inner sep=2pt,label={#1:#2}},
        ]
        \path
        node[terminal={left}{$R(s)$}] (R) {}
        node[above right=of R, terminal={}{}] (sX-1) {}
        node[right=of sX-1, terminal={}{}] (X-1) {}
        node[right=of R, terminal={}{}] (sX-2) {}
        node[right=of sX-2, terminal={}{}] (X-2) {}
        node[right=of X-2, terminal={right}{$C(s)$}] (C) {}
        node[below right=of R, terminal={}{}] (sX-3) {}
        node[right=of sX-3, terminal={}{}] (X-3) {}
        ;
        %
        \foreach \X in {1,...,3}{
            (sX-\X) edge[amark=1/s] (X-\X)
        };
    \path (R) edge[out=90,in=180,amark=12] (sX-1) (X-1) edge[out=-90,in=-90,amark=-2] (sX-1) edge[out=0,in=90,amark=1] (C);
    \path (R) edge[amark=-24] (sX-2) (X-2) edge[out=-90,in=-90,amark=-3] (sX-2) edge[amark=1] (C);
    \path (R) edge[out=-90,in=180,amark=12,label revd] (sX-3) (X-3) edge[out=-90,in=-90,amark=-4] (sX-3) edge[out=0,in=-90,amark=1,label revd] (C);
    \end{tikzpicture}
\end{document}

答案1

这些只是一些快速修复方法。

  1. foreach不起作用,因为没有\path命令。
  2. 您可以使用edge label来实现更好的定位。

第 3 项和第 4 项需要更多思考。但如果清楚这些图表的整体结构,这将更有意义。这将使人们能够判断哪种策略可能是最合适的。

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{calc,decorations.markings,positioning,arrows.meta,matrix}
\makeatletter
\pgfmathdeclarefunction{Dim}{1}{%
  \begingroup%
    \pgfmath@count=0\relax
    \edef\pgfutil@tmpb{#1}%
    \pgfutil@for\pgfutil@tmpa:={\pgfutil@tmpb}\do{%
      \advance\pgfmath@count by1\relax}%
    \edef\pgfmathresult{\the\pgfmath@count}% 
    \pgfmath@smuggleone\pgfmathresult% 
  \endgroup}  
\makeatother
\begin{document}
    \begin{tikzpicture}[
        node distance = 15mm and 15mm, 
        relative = false,
        amark/.style = {
            decoration={             
                markings,   
                mark=at position {0.5} with { 
                    \arrow{stealth},
                }
            },
            postaction={decorate},
            edge label={#1}
        },
        amark'/.style = {
            decoration={             
                markings,   
                mark=at position {0.5} with { 
                    \arrow{stealth},
                }
            },
            postaction={decorate},
            edge label'={#1}
        },
    terminal/.style 2 args={draw,alias=ln,circle,inner sep=2pt},
        ]
        % input
        \def\GraphInput{12/-2,-24/-3,12/-4}
        %\def\GraphInput{12/-2,-24/-3,12/-4,5/-7}
        %\def\GraphInput{12/-2,-24/-3,12/-4,5/-7,3/-3}
        % number of insertion
        \pgfmathtruncatemacro{\mydim}{Dim("\GraphInput")}
        % local bounding box is a trick that all distances derive from node distance
        \path[local bounding box=graph] 
         foreach \X/\Y [count=\Z] in \GraphInput {
         % draw the inner nodes in a loop
          \ifnum\Z=1
          node[terminal] (sX-\Z){} node[right=of sX-\Z,terminal] (X-\Z){}
          \else
          node[terminal,below=of sX-\the\numexpr\Z-1] (sX-\Z){} 
          node[right=of sX-\Z,terminal] (X-\Z){}
          \fi
        }
        % draw R and S nodes
        node[left=of graph,terminal,label=left:{$R(s)$}] (R){}
        node[right=of graph,terminal,label=right:{$C(s)$}] (C){}
        % loop for connections
        foreach \X/\Y [count=\Z] in \GraphInput {
        % bug in pgf, out does not get parsed properly
        [/utils/exec=\pgfmathsetmacro{\myout}{90-(\Z-1)*180/(\mydim-1)}]
        (sX-\Z) edge[amark={$1/s$}] (X-\Z)
        (X-\Z) edge[amark'={$\Y$},out=-90,in=-90] (sX-\Z)
        \ifnum\Z>\numexpr\mydim/2
         (R) edge[amark'={$\X$},out=\myout,in=180] (sX-\Z)
         (X-\Z) edge[amark'={$1$},out=0,in=180-\myout] (C)
        \else
         (R) edge[amark={$\X$},out=\myout,in=180] (sX-\Z)
         (X-\Z) edge[amark={$1$},out=0,in=180-\myout] (C)
        \fi
        };
 \end{tikzpicture}
\end{document}

在此处输入图片描述

这是一个根据一些输入绘制图形的程序,比如

\def\GraphInput{12/-2,-24/-3,12/-4}

我尝试添加一些解释。不幸的是,解析边inout边时也存在 pgf 问题。此代码还将边标签放置得更紧密。

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{calc,decorations.markings,positioning,arrows.meta,matrix}
\makeatletter
\pgfmathdeclarefunction{Dim}{1}{%
  \begingroup%
    \pgfmath@count=0\relax
    \edef\pgfutil@tmpb{#1}%
    \pgfutil@for\pgfutil@tmpa:={\pgfutil@tmpb}\do{%
      \advance\pgfmath@count by1\relax}%
    \edef\pgfmathresult{\the\pgfmath@count}% 
    \pgfmath@smuggleone\pgfmathresult% 
  \endgroup}  
\makeatother
\begin{document}
    \begin{tikzpicture}[
        node distance = 15mm and 15mm, 
        relative = false,
        amark/.style = {
            decoration={             
                markings,   
                mark=at position {0.5} with { 
                    \arrow{stealth},
                }
            },
            postaction={decorate},
            nodes={inner xsep=0pt},
            edge label={#1}
        },
        amark'/.style = {
            decoration={             
                markings,   
                mark=at position {0.5} with { 
                    \arrow{stealth},
                }
            },
            postaction={decorate},
            nodes={inner xsep=0pt},
            edge label'={#1}
        },
    terminal/.style 2 args={draw,alias=ln,circle,inner sep=2pt},
        ]
        % input
        %\def\GraphInput{12/-2,-24/-3,12/-4}
        \def\GraphInput{12/-2,-24/-3,12/-4,5/-7}
        % number of insertions
        \pgfmathtruncatemacro{\mydim}{Dim("\GraphInput")}
        % local bounding box is a trick that all distances derive from node distance
        \path[local bounding box=graph] 
         foreach \X/\Y [count=\Z] in \GraphInput {
         % draw the inner nodes in a loop
          \ifnum\Z=1
          node[terminal] (sX-\Z){} node[right=of sX-\Z,terminal] (X-\Z){}
          \else
          node[terminal,below=of sX-\the\numexpr\Z-1] (sX-\Z){} 
          node[right=of sX-\Z,terminal] (X-\Z){}
          \fi
        }
        % draw R and S nodes
        node[left=of graph,terminal,label=left:{$R(s)$}] (R){}
        node[right=of graph,terminal,label=right:{$C(s)$}] (C){}
        % loop for connections
        foreach \X/\Y [count=\Z] in \GraphInput {
        % bug in pgf, out does not get parsed properly
        [/utils/exec=\pgfmathsetmacro{\myout}{90-(\Z-1)*180/(\mydim-1)}]
        (sX-\Z) edge[amark={$1/s$}] (X-\Z)
        (X-\Z) edge[amark'={$\Y$},out=-90,in=-90] (sX-\Z)
        \ifnum\Z>\numexpr\mydim/2
         (R) edge[amark'={$\X$},out=\myout,in=180] (sX-\Z)
         (X-\Z) edge[amark'={$1$},out=0,in=180-\myout] (C)
        \else
         (R) edge[amark={$\X$},out=\myout,in=180] (sX-\Z)
         (X-\Z) edge[amark={$1$},out=0,in=180-\myout] (C)
        \fi
        };
 \end{tikzpicture}
\end{document}

在此处输入图片描述

答案2

使用这个tiz-cd包(它专门用于绘制此类图表)可以避免这些问题。代码相对简单明了,而且更短:

在此处输入图片描述

\documentclass[border=5mm]{standalone}
\usepackage{tikz-cd}
\usetikzlibrary{arrows.meta,
                decorations.markings}
\newif\iflabrev

\begin{document}
\begin{tikzcd}[
    cells={nodes={circle, draw, inner sep=2pt}},
    every arrow/.append style = {decoration={markings, 
                                             mark=at position .5 with {\arrow{Straight Barb[scale=0.5]}}},
                                 postaction={decorate}, -
                                },
    every label/.append style = {font=\footnotesize}                
                ]
    & \ar[r,"1/s"]
            & \ar[l,"-2",bend left=60]
              \ar[rd,"1",bend left]
                    &                       \\
|[label=left:R(s)]| 
 \ar[ru,"12",bend left] 
 \ar[rd,"12",bend right]
 \ar[r,"-24"]       
    & 
      \ar[r,"1/s"]
            & \ar[l,"-3", bend left=60]
              \ar[r,"1"]
                    & |[label=right:C(s)]|  \\
    & \ar[r,"1/s"]
            & \ar[l,"-4",bend left=60]
              \ar[ru,"1",bend right]
                    &                       \\
\end{tikzcd}
\end{document}

注意,如果您想改变节点之间的距离,那么您只需要添加tikzcd选项:

column sep=<desired distance between columns>,
row sep=<desired distance between rows>,

相关内容