Dibujar un diagrama de bloques con TiKz

Dibujar un diagrama de bloques con TiKz

Necesito ayuda para dibujar un diagrama de bloques usando TiKz.

Quiero dibujar algo parecido a esto:

ingrese la descripción de la imagen aquí

Sin embargo, hasta ahora me cuesta ir más allá:

ingrese la descripción de la imagen aquí

usando el siguiente código:

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

Es decir, me gustaría saber cómo:

  • Coloque el rectángulo llamado Measuremententre los dos bloques. Preferiblemente, este rectángulo estaría relleno de color gris claro y estaría bordeado por una línea discontinua. Nota: No me importa que el rectángulo cubra las líneas verticales. Solo quiero que mantengan su dirección vertical.

  • Coloque el sumcírculo exactamente detrás del tenedor para que tenga una línea vertical que se conecte t'a este círculo.

  • Tener los uy tcolocados correctamente (por ejemplo, como están en la primera imagen)

  • Tenga los carteles +y -donde las flechas se encuentran con el círculo.

Respuesta1

Ninguna de las respuestas aquí captura el aspecto dibujado a mano del original. Aquí hay una solución Metapost que utilizamp-sketchpara conseguir el aspecto dibujado a mano. También utilizo las fuentes Comic Neue y Euler. Aquí está el resultado:

ingrese la descripción de la imagen aquí

    \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

Respuesta2

Esto es lo que estabas buscando?

Correcciones:

  1. Se agregó un nodo Measurementcolocándolo a medio camino entre los nodos Systemy Modelusando esta sintaxis: \node ... at ($(system)!.5!(model)$) {};. Esto debe calcagregarse a las bibliotecas de Tikz.
  2. Cambió su ruta diagonal para \draw [->] (outfork) -| (sum.north) node [very near end] {\(t\)};que el nodo se detenga exactamente en el punto norte de la suma.
  3. Lo [very near end]anterior asegura que el nodo aparezca muy cerca de la punta de la flecha.
  4. Se eliminó minimal sizepara sus nodos lo que los hace parecer cuadrados (es un poco feo) y se reemplazó con inner seplo que agrega espacio dentro del nodo de manera consistente para que los bordes del rectángulo estén igualmente lejos del texto del nodo.
  5. Para el nodo u(la ruta de la izquierda), agregué la clave [anchor=south west]para que se mueva un poco hacia la derecha y hacia arriba y aparezca al lado de la ruta.
  6. Etiquetas utilizadas para los símbolos -y +. Originalmente eran nodos pero se ve mejor así y el código es más limpio y corto.

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

Respuesta3

Para quien le pueda interesar, aquí tenéis una solución conMetapublicacióny elMetaObjpaquete, dentro de un programa LuaLaTeX. Se basa en los parámetros sy mque permiten ubicar las cajas “Sistema” y “Modelo”, respectivamente centradas en los puntos (s,0)y (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}

ingrese la descripción de la imagen aquí

Respuesta4

Gracias, terminé mezclando ambas respuestas de Ignasi y Alenanno de la siguiente manera:

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

obteniendo el siguiente diagrama (ignore el marco alrededor):

ingrese la descripción de la imagen aquí

  1. Seguí la sugerencia de Ignasi de usar \coordinateen lugar de \node [coordinate].

  2. También utilicé |-y -|para una mejor alineación, como sugirió Ignasi. Por cierto, esta fue la razón por la que terminé no aceptando la solución de Alenanno, ya que el Measurementsbloque no estaba perfectamente alineado en el centro y la bifurcación de salida no estaba exactamente encima del sumnodo. (No estoy seguro si es visible la superposición de los bordes en la imagen de abajo)

ingrese la descripción de la imagen aquí

  1. Usé la referencia del ángulo para colocar los signos +y -tal como lo hizo Ignasi, pero acorté un poco la fuente, como lo hizo Alenanno.

  2. Para el Measurementsbloqueo, el posicionamiento, seguí el planteamiento de Alenanno. Esta parte fue la que me impidió aceptar la solución de Ignasi, ya que buscaba un Measurementsbloque que se extendiera sobre las líneas verticales como en la imagen de arriba hecha a mano. Hackeando un poco el código de Alenanno, acabo de crear un nuevo estilo de bloque.

  3. Además, los consejos de Alenanno sobre las opciones very near endy anchor=south westfueron extremadamente útiles. (y este fue otro detalle donde la solución de Ignasi no fue 100% satisfactoria).

Gracias de nuevo a ambos. No estaba seguro de qué respuesta aceptar porque ambas eran bastante útiles, pero luego decidí mezclarlas y presentar la solución que terminé usando, con la esperanza de ayudar a alguien más.

información relacionada