
Мне нужна помощь в рисовании блок-схемы с использованием 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
Это то, что ты искал?
Исправления:
- Добавлен узел
Measurement
, расположенный посередине между узламиSystem
иModel
использующий следующий синтаксис:\node ... at ($(system)!.5!(model)$) {};
. Это необходимоcalc
добавить в библиотеки Tikz. - Измените диагональный путь так
\draw [->] (outfork) -| (sum.north) node [very near end] {\(t\)};
, чтобы узел останавливался точно в северной точке суммы. - Вышеуказанное
[very near end]
гарантирует, что узел будет располагаться очень близко к кончику стрелы. - Удалил
minimal size
для узлов значение, делающее их квадратными (это немного некрасиво), и заменил его на значение,inner sep
которое последовательно добавляет пространство внутри узла, так что границы прямоугольника находятся на одинаковом расстоянии от текста узла. - Для узла
u
(путь слева) я добавил ключ,[anchor=south west]
чтобы он переместил его немного вправо и вверх и чтобы он появился рядом с путем. - Использованы метки для символов
-
и+
. Изначально это были узлы, но так выглядит лучше, а код чище и короче.
\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}
получаем следующую диаграмму (не обращайте внимания на рамку вокруг):
Я последовал совету Игнаси и использовал
\coordinate
вместо\node [coordinate]
.Я также использовал
|-
и-|
для лучшего выравнивания, как предложил Игнаси. Кстати, именно по этой причине я в итоге не принял решение Аленанно, поскольку блокMeasurements
не был идеально выровнен по центру, а выходная вилка не была точно надsum
узлом. (Не уверен, видно ли перекрытие краев на рисунке ниже)
Использовал угловую ссылку для размещения знаков
+
и-
, как это сделал Игнаси, однако немного сократил шрифт, как это сделал Аленанно.Для
Measurements
блока, позиционирования, я следовал подходу Аленанно. Эта часть была той, которая помешала мне принять решение Игнаси, так как я искал блок,Measurements
охватывающий вертикальные линии, как на сделанной вручную картинке выше. Немного взломав код Аленанно, я просто создал новый стиль блока.Более того, советы Аленанно по параметрам
very near end
иanchor=south west
были чрезвычайно полезны! (и это была еще одна деталь, где решение Игнаси не было на 100% удовлетворительным).
Спасибо еще раз обоим. Я не был уверен, какой ответ принять, потому что оба были довольно полезными, но затем решил смешать их и представить решение, которым я в итоге воспользовался, надеясь помочь кому-то еще.