18

I need some help drawing a block diagram using TiKz.

I want draw something similar to this:

enter image description here

However, I'm struggling to go further than this so far:

enter image description here

using the code below:

\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}

Namely, I would like to find how to:

  • Place a the rectangle called Measurement between the two blocks. Preferably, this rectangle would be filled with light gray color and would be bordered by a dashed line. Note: I don't mind the rectangle cover the vertical lines. I just want these to keep its vertical direction

  • Place the sum circle exactly behind the fork so as to have a vertical line connecting t' to this circle

  • Have the u and t placed correctly (e.g. like they are in the first picture)

  • Have the +and - signs where the arrows meet the circle

3
  • 1
    Should get the TikZ code to display the diagram as your handwriting. Looks awesome!
    – Holene
    Commented Apr 19, 2015 at 17:12
  • @Holene Thanks :) Surprisingly, it's not the first time someone notices my hand-made drawings: tex.stackexchange.com/q/198775/52288
    – POliveira
    Commented Apr 19, 2015 at 20:22
  • Maybe it's too late to say this but you should just use your hand drawn image; it looks amazing.
    – Elias
    Commented Oct 1, 2017 at 19:34

5 Answers 5

15

None of the answers here capture the hand drawn look of the original. Here is a Metapost solution that uses mp-sketch to get the hand drawn look. I also use Comic Neue and Euler fonts. Here is the result:

enter image description here

    \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
14

Is this what you were looking for?

Fixes:

  1. Added a node Measurement positioning it halfway between the nodes System and Model using this syntax: \node ... at ($(system)!.5!(model)$) {};. This requires calc to be added to the Tikz libraries.
  2. Changed your diagonal path to \draw [->] (outfork) -| (sum.north) node [very near end] {\(t\)}; so that the node stops exactly at the north point of sum.
  3. The [very near end] above ensures that the node appears very close to the arrow tip.
  4. Removed minimal size for your nodes that makes them look square (it's a bit ugly), and replaced it with inner sep which adds space inside the node consistently so that the rectangle borders are equally far from the node text.
  5. For the node u (the path on the left), I added the key [anchor=south west] so that it moves it right and up a bit and appears next to the path.
  6. Used labels for the - and + symbols. Originally they were nodes but it looks better like this and the code is cleaner and shorter.

figure 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}
12

For whom it may interest, here is a solution with MetaPost and the MetaObj package, inside a LuaLaTeX program. It is based on the s and m parameters which allow to locate the “System” and “Model” boxes, respectively centered at points (s,0) and (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}

enter image description here

9

You almost did it!.

What I've changed from your code:

1- Used \coordinate instead of \node[coordinate]. It's shorter.

2- Used perpendicular coordinates |- -| to better align outputs and also for drawing the perpendicular line from sum.

3- Added + and - as labels to sum.

4- measurement node added at central position from a path starting at symbol and ending at model.

\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) {};
    \coordinate[left=of infork] (input);
    \coordinate[right=of system] (outfork);
    \coordinate[right=of outfork] (output);
    \coordinate[above=of system] (disturbances);
    \node [block, below=of system] (model) {Model};
    \node [joint, right=of model, label={[inner sep=1pt]215:$+$}, label={[inner sep=1pt]60:$-$}] (sum) {};
    \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) -- (output);
    \draw [->] (model) -- node {\(y\)} (sum);
    \draw [->] (sum) -- node {\(\epsilon\)} (error);
    \draw [->] (infork) |- node[above right] {\(u\)} (model);
    \draw [<-] (sum) -- node[near end] {\(t\)} (outfork-|sum) node[above]{\(t`\)};
    \path (system) -- node[draw, dashed, fill=gray, anchor=center] (measurements) {Measurements} (model);
\end{tikzpicture}

\end{document}

enter image description here

4

Thank you, I ended up mixing both answers from Ignasi and Alenanno as follows:

\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}

obtaining the next diagram (ignore the frame all around):

enter image description here

  1. I followed Ignasi's suggestion of using \coordinate instead of \node [coordinate].

  2. I also used |-and -| for better alignment, as Ignasi suggested. By the way, this was the reason I ended up not accepting Alenanno's solution, since the Measurements block was not perfectly center aligned and the output fork was not exactly above the sum node. (Not sure if it is visible the edge overlap in the picture below)

enter image description here

  1. Used the angle reference to place the + and - signs just like Ignasi did, however shortened the font a little bit, as Alenanno did.

  2. For the Measurements block, positioning, I followed Alenanno's approach. This part was the one preventing me for accepting Ignasi's solution, since I was looking for a Measurements block spanning over the vertical lines as in the hand-made picture above. Hacking a bit Alenanno's code, I just created a new block style.

  3. Furthermore, Alenanno's tips on the very near end and anchor=south west options were extremely useful! (and this was another detail where Ignasi's solution was not 100% satisfying).

Thanks again to both. I wasn't sure which answer to accept because both were pretty helpful, but then decided to mix them and present the solution I ended to use, hoping to help someone else.

3
  • 3
    I wasn't sure which answer to accept because both were pretty helpful <- This is why we prefer that each question focus on some single targeted issue. You asked a bunch of questions at once and each post had a slightly different take on each one. Commented Apr 19, 2015 at 20:20
  • 1
    @PaulGessler You're right and I recognize it, but it is a dilemma after all. I'll try to be more focused henceforth though.
    – POliveira
    Commented Apr 19, 2015 at 20:57
  • @POliveira "By the way, this was the reason I ended up not accepting Alenanno's solution, since the Measurements block was not perfectly center aligned" - Sorry, but the Measurement block is perfectly center aligned on both the X and the Y axis. I'm not sure what you mean there.
    – Alenanno
    Commented Apr 20, 2015 at 14:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .