TikZ: 信号フローグラフ (位相変数形式) の堅牢かつ自動的な作成

TikZ: 信号フローグラフ (位相変数形式) の堅牢かつ自動的な作成

採用この答え、次の状態方程式のセットを表すことによって、次の信号フロー図が作成されました。

ここに画像の説明を入力してください

私はしたいと思います:

1- 手動で編集することなく、ノードの数と接続信号が異なる場合に、コードを最適化および一般化してより堅牢にする方法を知る。

2- 可能であれば、現在の出力をよりクリーンにします。

ここに画像の説明を入力してください

\documentclass[border=5mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.markings,positioning,arrows.meta}
\newif\iflabrev
\begin{document}
    \begin{tikzpicture}
        [
        relative = false,
        node distance = 15 mm,
        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,circle,inner sep=2pt,label={#1:#2}},
        ]
        %
        %Place the nodes
        \node[terminal={left}{$R(S)$}] (a) at (0,0) {};
        \node[terminal={below right}{$sX_3(s)$}] (b) [right=of a] {};
        \node[terminal={below right}{$X_3(S)$}] (c) [right=of b] {};
        \node[terminal={[xshift=-4mm]below right}{$sX_2(s)$}] (d) [right=of c] {};
        \node[terminal={[xshift=-4mm]below right}{$X_2(s)$}] (e) [right=of d] {};
        \node[terminal={[xshift=-4mm]below right}{$sX_1(s)$}] (f) [right=of e] {};
        \node[terminal={[xshift=-4mm]below right}{$X_1(s)$}] (g) [right=of f] {};
        \node[terminal={right}{$Y(s)$}] (h) [right=of g] {};
        %
        %Draw the connections
        \foreach \target/\bend/\text/\loose in {b/0/7/0, d/90/5/1.5, f/90/2/1.5}
        \draw[amark=\text] (a) to[bend left=\bend,looseness=\loose] (\target);
        
        \draw[amark=1/s] (b) to (c);
        \foreach \source/\text/\loose in {c/-4/2, e/-3/1.5, g/1/1.5}
        \draw[amark=\text] (\source) to[bend left=90, looseness=\loose] (b);
        
        \foreach \target/\text/\loose in { d/-6/1.5, f/2/2}
        \draw[amark=\text] (g) to[bend left=90, looseness=\loose] (\target);
        
        \foreach \source/\text in {c/9, e/6}
        \draw[amark=\text] (\source) to[bend left=90, looseness=1.5] (h);
        
        \draw[amark=2] (c) to (d);
        \draw[amark=3] (c) to[bend right=90, looseness=1.5] (f);
        \draw[amark=1/s] (d) to (e);
        \draw[amark=-5] (e) to (f);
        \draw[amark=-2,label revd] (e) to[bend left=90, looseness=2] (d);
        \draw[amark=1/s] (f) to (g);
        \draw[amark=-4] (g) to (h);
    \end{tikzpicture}
\end{document}

答え1

この投稿では、より良いレイアウトを実現するという問題については触れません。目的は、行列からグラフを自動的に生成することです。行列は次のように定義できます。

\edef\mmat{{2,-5,3,2},{-6,-2,2,5},{1,-3,-4,7},{-4,6,9,0}}

そして、foreach ループによってグラフが作成されます。コードにはいくつかの注釈があります。おそらく最も重要な新しい要素は、pmark行列のエントリからラベルを取得するスタイル (つまり、その引数は行と列のインデックス) と、semicircleエッジで使用できる半円を挿入するスタイルです。

\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{calc,decorations.markings,positioning,arrows.meta}
\newif\iflabrev
\begin{document}
    \begin{tikzpicture}[node distance = 15 mm,
        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}
        }, % make the mark an entry of the \mmat matrix
        pmark/.style n args={2}{amark={$%
            \pgfmathparse{int({\mmat}[\numexpr#1][\numexpr#2])}%
                \pgfmathresult$}},
        terminal/.style 2 args={draw,alias=ln,circle,inner sep=2pt,label={#1:#2}},
        % semicircle path
        semicircle/.style={to path={let \p1=($(\tikztotarget)-(\tikztostart)$)
            in \ifdim\x1>0pt
              (\tikztostart.north) arc[start angle=180,end angle=0,radius=0.5*\x1]
            \else
              (\tikztostart.south) arc[start angle=0,end angle=-180,radius=-0.5*\x1]
            \fi}}
        ]
        % define the  matrix 
        \edef\mmat{{2,-5,3,2},{-6,-2,2,5},{1,-3,-4,7},{-4,6,9,0}}
        \pgfmathtruncatemacro{\dimy}{dim({\mmat})} % number of rows
        \pgfmathtruncatemacro{\dimx}{dim({\mmat}[0])} % number of columns
        % create the graph
        \path % R node
        node[terminal={left}{$R(S)$},alias={X-\dimy}] (R) {}
        % loop over matrix entries
        foreach \Y [evaluate=\Y as \X using {int(\dimy-\Y)}]
        in {1,...,\numexpr\dimy-1}
        {node[right=of ln,terminal={below right}{% sX_i node
            $sX_{\X}(s)$}](sX-\X){}
        node[right=of ln,terminal={below right}{% X_i node
            $X_{\X}(s)$}](X-\X){}
        % ege from sX_i to X_i  
        (sX-\X) edge[amark={$\frac{1}{s}$}] (X-\X)
        % edge from X_{i+1} to X_i  (R had an alias)
        (X-\the\numexpr\X+1) edge[pmark={\X-1}{\X}] (sX-\X)
        % semicircle edge from X_i to sX_i
        (X-\X) edge[semicircle,label revd,pmark={\X-1}{\X-1}] (sX-\X)
        % various semicircles
        \ifnum\Y>1
         (R) edge[semicircle,pmark={\X-1}{\dimx-1}] (sX-\X) 
         foreach \Z in {1,...,\numexpr\Y-1} {
          (X-\X) edge[semicircle,pmark={\X+\Z-1}{\X-1}] (sX-\the\numexpr\X+\Z)
         }
        \fi
        }% the Y node
        node[right=of ln,terminal={right}{$Y(s)$}](Y){}
        (X-1) edge[pmark={\dimy-1}{0}] (Y)
        % semicircles goint to Y
        foreach \Y [evaluate=\Y as \X using {int(\dimy-\Y)}]
         in {1,...,\numexpr\dimy-2}
        {(X-\X) edge[semicircle,pmark={\dimy-1}{\X-1}] (Y)};
    \end{tikzpicture}
\end{document}

ここに画像の説明を入力してください

関連情報