[Tex/LaTex] Reusing circuit code with nodes in TikZ

nodestikz-pgf

I'm new to TikZ/PGF (a week or so in), and am loving it. I've had good success making figures so far, but have a question about best practices for including multiple copies of a sub-circuit in a single figure. And doing so in a way that allows simple connections to the input/output nodes of the sub-circuit.

As a very rudimentary example (please excuse the free-handed drawing) in which I have a drawing with two repeated sub-circuits (contained within a rectangle).

hand-drawn circuit

So in this example, I'd like to define the amplifier circuit once, and then place it twice in the picture and connect wires to its input and output nodes. Does this require me to develop a library, or can the sub-circuit be written into the .tex file directly and then reused?

I did see the post about using a \newsavebox here, but I'm not sure how I would access the nodes in the circuit using that approach.

Any help is greatly appreciated. Many thanks.

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{circuits.logic.US,circuits.ee.IEC,positioning,fit}

\begin{document}
\begin{tikzpicture}[circuit ee IEC,circuit logic US,x=3cm,y=2cm,semithick,
    set resistor graphic=var resistor IEC graphic]

  % Box on the left (non circuit stuff)                                     
  \draw (0,0) rectangle (2,2);
  \draw (1,1) rectangle (1.8,1.8);
  \draw (0.3,0.2) rectangle (0.5,0.5);

  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%                        
  % Begin the sub-circuit to be replicated                                  
  \node[contact] (A) at (2.5,0) {};
  \node[contact] [right=1.5cm of A] (B) {};
  \node[contact] [above=1.5cm of B] (C) {};
  \node[contact] [right=1.0cm of B] (D) {};
  \node[contact] [right=1.5cm of D] (E) {};
  \node[buffer gate] [right=0.1 of D] (amp) {};
  % Problem #1:  there is whitespace between the amp output and the line to node E
  \draw (A) to [resistor] (B) (B) to [capacitor] (D) (D) to (amp) (amp) to (E);
  \draw (B) to [resistor] (C);
  % Problem #2: had to tune 0.54 to get vertical line to node E.  (output of amp)
  % Must be a better way ...
  \draw (D) -- ++(0,0.5) to [capacitor] ++(right:0.54) to (E);
  \tikzset{black box/.style={draw=black, rectangle}};
  \node(preampbox) [black box, fit=(A) (C) (E) (amp), inner sep=0.4cm] {};
  %%%%%%%%%%%%%%  end subcircuit  %%%%%%%%%%%%%%%%%%                        

\end{tikzpicture}
\end{document}

code output

Best Answer

Drawing the node only produces the outer rectangle, but it is used to define all the internal coordinates and the contact anchor points. \drawMyamp does the internal circuitry. By tradition, the origin is aligned with all of the contact anchor points.

\documentclass{article}
\usepackage{tikz}

\usetikzlibrary{circuits.logic.US,circuits.ee.IEC,positioning,fit}

\newcommand{\UseGlobalScale}
 {\pgfgettransformentries{\xscale}{\@tempa}{\@tempa}{\yscale}{\@tempa}{\@tempa}}

\let\xscale=*
\let\yscale=*

% ***************************** myamp node *********************************
% contact anchor points: left, above, out
% internal anchor points: A, B, C, D, E, F, G

\pgfdeclareshape{myamp}{

\savedmacro{\resize}{   % restore global scale factor
 \if*\xscale \relax \else \pgftransformxscale{\xscale} \fi
 \if*\yscale \relax \else \pgftransformyscale{\yscale} \fi
}

\anchor{center}{\pgfpointorigin}    % within the node, (0,0) is the center

\anchor{text} % this is required to center text in the node (not used here)
 {\pgfpoint{-.5\wd\pgfnodeparttextbox}{-.5\ht\pgfnodeparttextbox}}

\anchor{left}{\pgfpoint{-2cm}{0cm}}
\anchor{above}{\pgfpoint{0cm}{2cm}}
\anchor{out}{\pgfpoint{3cm}{0cm}}

\anchor{A}{\pgfpoint{-1.5cm}{0cm}}
\anchor{B}{\pgfpointorigin}
\anchor{C}{\pgfpoint{0cm}{1.5cm}}
\anchor{D}{\pgfpoint{1cm}{0cm}}
\anchor{E}{\pgfpoint{2.5cm}{0cm}}
\anchor{F}{\pgfpoint{1cm}{1cm}}
\anchor{G}{\pgfpoint{2.5cm}{1cm}}

\foregroundpath{ % draw border 
 \pgfpathrectanglecorners{\pgfpoint{-1.75cm}{-1cm}}{\pgfpoint{2.75cm}{1.75cm}}
 \pgfusepath{draw}}
}

%************************ draw myamp components ****************************
% component names = #1 R1, #1 R2, #1 C1, #1 C2 and #1 opamp

\newcommand{\drawMyamp}[2]{ % #1 = node name, #2 = rotation angle
 \draw 
  node[contact] at(#1.A){}
  node[contact] at(#1.B){}
  node[contact] at(#1.C){}
  node[contact] at(#1.D){}
  node[contact] at(#1.E){}
  node[resistor,rotate=#2](#1 R1) at($(#1.A)!.5!(#1.B)$){}
  node[resistor,rotate={90+#2}](#1 R2) at($(#1.B)!.5!(#1.C)$){}
  node[capacitor,rotate=#2](#1 C1) at($(#1.B)!.5!(#1.D)$){}
  node[capacitor,rotate=#2](#1 C2) at($(#1.F)!.5!(#1.G)$){}
  node[buffer gate,rotate=#2](#1 opamp) at($(#1.D)!.5!(#1.E)$){};
 \draw[thin]
  (#1.left) -- (#1.A) -- (#1 R1.west)
  (#1 R1.east) -- (#1.B) -- (#1 R2.west)
  (#1 R2.east) -- (#1.C) -- (#1.above)
  (#1.B) -- (#1 C1.west)
  (#1 C1.east) -- (#1.D) -- (#1 opamp.west)
  (#1.D) -- (#1.F) -- (#1 C2.west)
  (#1 C2.east) -- (#1.G) -- (#1.E) -- (#1 opamp.east)
  (#1.E) -- (#1.out);
}

%*************************************************************************

\begin{document}

\begin{tikzpicture}[circuit ee IEC,circuit logic US,x=3cm,y=2cm,semithick,
 set resistor graphic=var resistor IEC graphic]

\UseGlobalScale % save scale factor for myamp

% Box on the left (non circuit stuff)                                     
  \draw (0,0) rectangle (2,2);
  \draw (1,1) rectangle (1.8,1.8);
  \draw (0.3,0.2) rectangle (0.5,0.5);

 \draw (3,0) node[myamp,thick,dashed](amp1){};
 \drawMyamp{amp1}{0}

 \draw (3.1,2) node[myamp,color=red,rotate=90](amp2){};
 \drawMyamp{amp2}{90}

 \draw (amp1 R1.south) node[below]{$100 K\Omega$};
\end{tikzpicture}

\end{document}

There are two ways to add labels to the components. You could add a lot of arguments to the macro, or you can put labels in nodes at the anchor points.