Рисование блок-схемы с помощью TiKz

Рисование блок-схемы с помощью TiKz

Мне нужна помощь в рисовании блок-схемы с использованием TiKz.

Я хочу нарисовать что-то похожее на это:

введите описание изображения здесь

Однако пока мне сложно продвинуться дальше этого:

введите описание изображения здесь

используя код ниже:

\documentclass{standalone}

\usepackage{tikz}       
\usetikzlibrary{arrows,positioning,patterns,decorations.pathmorphing}

\begin{document}

\tikzstyle{block} = [draw, rectangle, minimum size=5em]
\tikzstyle{joint} = [draw, circle, minimum size=1em]

\begin{tikzpicture}[>=stealth, auto, node distance=2cm]
    % Place nodes
    \node [block] (system) {System};
    \node [coordinate, left=of system] (infork) {};
    \node [coordinate, left=of infork] (input) {};
    \node [coordinate, right=of system] (outfork) {};
    \node [coordinate, right=of outfork] (output) {};
    \node [coordinate, above=of system] (disturbances) {};
    \node [block, below=of system] (model) {Model};
    \node [joint, right=of model] (sum) {};
    \node [coordinate, right=of sum] (error) {};
    % Connect nodes
    \draw [->, decorate, decoration={snake, post length=1mm}] (disturbances) -- node {\(d'\)} (system);
    \draw [->] (input) -- node {\(u'\)} (system);
    \draw [->] (system) -- node {\(t'\)} (output);
    \draw [->] (model) -- node {\(y\)} (sum);
    \draw [->] (sum) -- node {\(\epsilon\)} (error);
    \draw [->] (infork) |- node {\(u\)} (model);
    \draw [->] (outfork) -- node {\(t\)} (sum);
\end{tikzpicture}

\end{document}

А именно, я хотел бы узнать, как:

  • Поместите прямоугольник, называемый Measurementмежду двумя блоками. Предпочтительно, чтобы этот прямоугольник был заполнен светло-серым цветом и был ограничен пунктирной линией. Примечание: я не против того, чтобы прямоугольник закрывал вертикальные линии. Я просто хочу, чтобы они сохраняли вертикальное направление

  • Расположите sumкруг точно за развилкой так, чтобы получилась вертикальная линия, соединяющая t'этот круг.

  • Правильно разместите uи t(например, как на первой картинке)

  • Иметь знаки +и -там, где стрелки встречаются с кругом

решение1

Ни один из ответов здесь не передает нарисованный от руки вид оригинала. Вот решение Metapost, которое используетmp-скетччтобы получить вид, как от руки. Я также использую шрифты Comic Neue и Euler. Вот результат:

введите описание изображения здесь

    \usetypescriptfile[euler]
\definetypeface[mainfont][rm][specserif][ComicNeue][default]
\definetypeface[mainfont][mm][math] [pagellaovereuler][default]
\setupbodyfont[mainfont,12pt]

% Set upright style for Euler Math
\appendtoks \rm \to \everymathematics
\setupmathematics
  [lcgreek=normal, ucgreek=normal]

\startMPinclusions
  input rboxes;
  input mp-sketch;
\stopMPinclusions

\defineframed
  [labelframe]
  [
    background=color,
    backgroundcolor=gray,
    frame=off,
  ]

\starttext
\startMPpage[offset=3mm]
  sketchypaths;

  defaultdx := 16bp;
  defaultdy := 16bp;
  circmargin := 5bp;
  sketch_amount := 2bp;

  u := 1cm;
  drawoptions(withpen pencircle scaled 1bp);

  boxit.system("SYSTEM");
  boxit.model ("MODEL");
  circleit.adder("$\cdot$");

  system.c = origin;
  system.s - model.n = (0, 3u);

  z.0 = system.w - (2u, 0);
  z.1 = 0.5[  z.0, system.w ];
  z.2 = (x.1, ypart model.w);
  z.3 = system.e + (u, 0);
  z.4 = system.e + (2u, 0);
  z.5 = (x.4, y.2);

  adder.c = (x.3, ypart model.c);

  drawboxed(system, model, adder);

  z.6 = 0.5[system.s, model.n];
  stripe_path_n
    (withpen pencircle scaled 2 withcolor 0.5white)
    (draw)
    fullsquare xyscaled(x.3 - x.1 + u, 2*LineHeight) 
    shifted z.6 dashed evenly;

  label("\labelframe{Measurement}", z.6);


  % Reduce the amount of randomness for the lines
  sketch_amount := bp;

  drawarrow z.0 -- lft system.w;
  drawarrow z.1 -- z.2 -- lft model.w;
  drawarrow system.e -- z.4 ;
  drawarrow model.e -- lft adder.w ;
  drawarrow z.3 -- top adder.n ;
  drawarrow adder.e -- z.5 ;

  label.urt("$-$", adder.n);
  label.llft("$+$", adder.w);

  label.top("$u'$", z.1);
  label.top("$t'$", z.3);
  label.top("$ε$", 0.5[adder.e, z.5]);

  dx := 12bp;
  label.urt("$t$", adder.n + (0, dx));
  label.urt("$u$", z.2 + (0, dx));

\stopMPpage
\stoptext

решение2

Это то, что ты искал?

Исправления:

  1. Добавлен узел Measurement, расположенный посередине между узлами Systemи Modelиспользующий следующий синтаксис: \node ... at ($(system)!.5!(model)$) {};. Это необходимо calcдобавить в библиотеки Tikz.
  2. Измените диагональный путь так \draw [->] (outfork) -| (sum.north) node [very near end] {\(t\)};, чтобы узел останавливался точно в северной точке суммы.
  3. Вышеуказанное [very near end]гарантирует, что узел будет располагаться очень близко к кончику стрелы.
  4. Удалил minimal sizeдля узлов значение, делающее их квадратными (это немного некрасиво), и заменил его на значение, inner sepкоторое последовательно добавляет пространство внутри узла, так что границы прямоугольника находятся на одинаковом расстоянии от текста узла.
  5. Для узла u(путь слева) я добавил ключ, [anchor=south west]чтобы он переместил его немного вправо и вверх и чтобы он появился рядом с путем.
  6. Использованы метки для символов -и +. Изначально это были узлы, но так выглядит лучше, а код чище и короче.

Рисунок 1

\documentclass{standalone}

\usepackage{tikz}       
\usetikzlibrary{arrows,positioning,patterns,decorations.pathmorphing,calc}

\begin{document}

\tikzstyle{block} = [draw, rectangle, inner sep=6pt]
\tikzstyle{joint} = [draw, circle,minimum size=1em]

\begin{tikzpicture}[>=stealth, auto, node distance=2cm]
    % Place nodes
    \node [block] (system) {System};
    \node [coordinate, left=of system] (infork) {};
    \node [coordinate, left=of infork] (input) {};
    \node [coordinate, right=of system] (outfork) {};
    \node [coordinate, right=of outfork] (output) {};
    \node [coordinate, above=of system] (disturbances) {};
    \node [block, below=of system] (model) {Model};
    \node [joint, right=of model, anchor=center,label={[shift={(2mm,-1mm)}]-},label={[shift={(-3mm,-5.5mm)}]\tiny +}] (sum) {};

    \node [coordinate, right=of sum] (error) {};
    \node [block, dashed, fill=gray, anchor=center, text width=7cm, align=center] at ($(system)!.5!(model)$) {\textsc{Measurement}};

    % Connect nodes
    \draw [->, decorate, decoration={snake, post length=1mm}] (disturbances) -- node {\(d'\)} (system);
    \draw [->] (input) -- node {\(u'\)} (system);
    \draw [->] (system) -- node {\(t'\)} (output);
    \draw [->] (model) -- node {\(y\)} (sum);
    \draw [->] (sum) -- node {\(\epsilon\)} (error);
    \draw [->] (infork) |- node [anchor=south west] {\(u\)} (model);
    \draw [->] (outfork) -| (sum.north) node [very near end] {\(t\)};
\end{tikzpicture}

\end{document}

решение3

Для тех, кому это может быть интересно, вот решение сМетаПостиМетаОбъектПакет, внутри программы LuaLaTeX. Он основан на параметрах sи m, которые позволяют размещать блоки «Система» и «Модель», центрированные соответственно в точках (s,0)и (s, m).

\documentclass[border=2mm]{standalone}
\usepackage{luamplib}
  \mplibtextextlabel{enable}
\begin{document}
  \begin{mplibcode}
    input metaobj
    s := 4.5cm; m := -3cm; % locates upper and lower boxes
    beginfig(1);
      % Central box
      newBox.msrmt("Measurement") "filled(true)", "fillcolor(.8white)", 
        "dx(.6s)", "framestyle(dashed evenly)";
      msrmt.c = (s, .5m); drawObj(msrmt);
      % Upper and lower boxes
      newBox.syst("System") "dx(2mm)", "dy(3mm)"; 
      newBox.model("Model") "dx(2mm)", "dy(3mm)";
      syst.c = (s, 0); model.c = (s, m);
      drawObj(syst); drawBox(model);
      % Empty circle
      ep := .5(xpart syst.w); t := xpart syst.e + ep; u := xpart syst.w - ep;
      newCircle.circ("") "circmargin(1.5mm)";
      circ.c = (t, m);
      drawObj(circ);
      % Connections
      drawarrow origin -- syst.w;
      drawarrow (u, 0) -- (u, m) -- model.w;
      drawarrow syst.e -- (t+ep, 0);
      drawarrow (t, 0) -- circ.n;
      drawarrow model.e -- circ.w;
      drawarrow circ.e -- (t+ep, m);
      % The spring (and its label)
      newEmptyBox.upper(0, 0); upper.c = (s, -.75m);
      picture lab; lab = textext("$d'$");
      nczigzag(upper)(syst) "coilwidth(2.5mm)", "coilarmA(0mm)", 
        "coilarmB(3mm)", "linearc(.4mm)", "labpic(lab)", "labdir(rt)";
      % Other labels  
      label.top("$u'$", (u, 0)); label.urt("$u$", (u, m));
      label.top("$t'$", (t, 0));
      label.top("$y$", .5(model.e+circ.w));
      label.rt("$t$", (t, ypart(.5(msrmt.s+circ.n))));
      label.top("$\epsilon$", .5[(t,m), (t+ep, m)]);
      labeloffset := .5bp;
      label.llft("\tiny$+$", circ.sw);
      label.urt("\tiny$-$", circ.ne);
      labeloffset := 3bp;
    endfig; 
  \end{mplibcode}
\end{document}

введите описание изображения здесь

решение4

Спасибо, в итоге я смешал оба ответа от Игнаси и Аленанно следующим образом:

\documentclass{standalone}

\usepackage{tikz}       
\usetikzlibrary{arrows, positioning, patterns, calc, decorations.pathmorphing}

\begin{document}

\tikzstyle{block} = [draw, rectangle, inner sep=6pt, minimum width=2cm, minimum height=1cm, align=center]
\tikzstyle{joint} = [draw, circle, minimum size=1em, anchor=center]
\tikzstyle{layer} = [draw, rectangle, dashed, fill=gray!20, minimum width=7cm, minimum height=8mm, align=center, anchor=center]

\begin{tikzpicture}[>=stealth, auto, node distance=2cm]
    % Place nodes
    \node [block] (system) {System};
    \node [block, below=of system] (model) {Model};
    \node [layer] at ($(system)!.5!(model)$) {\textsc{Measurement}};
    \coordinate [left=of system] (infork) {};
    \coordinate [left=of infork] (input) {};
    \coordinate [right=of system] (outfork) {};
    \coordinate [right=of outfork] (output) {};
    \coordinate [above=of system] (disturbances) {};
    \node [joint, label={[inner sep=1pt]210:\tiny\(+\)}, label={[inner sep=1pt]60:\tiny\(-\)}] (sum) at (outfork|-model) {};
    \coordinate (error) at (output|-model) {};
    % Connect nodes
    \draw [->, decorate, decoration={snake, post length=1mm}] (disturbances) -- node {\(d'\)} (system);
    \draw [->] (input) -- node {\(u'\)} (system);
    \draw [->] (system) -- node {\(t'\)} (output);
    \draw [->] (model) -- node {\(y\)} (sum);
    \draw [->] (sum) -- node {\(\epsilon\)} (error);
    \draw [->] (infork) |- node [anchor=south west] {\(u\)} (model);
    \draw [->] (outfork) -| (sum.north) node [very near end] {\(t\)};
\end{tikzpicture}

\end{document}

получаем следующую диаграмму (не обращайте внимания на рамку вокруг):

введите описание изображения здесь

  1. Я последовал совету Игнаси и использовал \coordinateвместо \node [coordinate].

  2. Я также использовал |-и -|для лучшего выравнивания, как предложил Игнаси. Кстати, именно по этой причине я в итоге не принял решение Аленанно, поскольку блок Measurementsне был идеально выровнен по центру, а выходная вилка не была точно над sumузлом. (Не уверен, видно ли перекрытие краев на рисунке ниже)

введите описание изображения здесь

  1. Использовал угловую ссылку для размещения знаков +и -, как это сделал Игнаси, однако немного сократил шрифт, как это сделал Аленанно.

  2. Для Measurementsблока, позиционирования, я следовал подходу Аленанно. Эта часть была той, которая помешала мне принять решение Игнаси, так как я искал блок, Measurementsохватывающий вертикальные линии, как на сделанной вручную картинке выше. Немного взломав код Аленанно, я просто создал новый стиль блока.

  3. Более того, советы Аленанно по параметрам very near endи anchor=south westбыли чрезвычайно полезны! (и это была еще одна деталь, где решение Игнаси не было на 100% удовлетворительным).

Спасибо еще раз обоим. Я не был уверен, какой ответ принять, потому что оба были довольно полезными, но затем решил смешать их и представить решение, которым я в итоге воспользовался, надеясь помочь кому-то еще.

Связанный контент