Espirales cónicas y cilíndricas

Nov 25 2020

Quiero dibujar algo como lo siguiente en Ti k Z, pero, desafortunadamente, no estoy seguro de cómo llegar al resultado necesario. La figura muestra la trayectoria de los iones en un espectrómetro de masas de cuadrupolo. Fuera del cuadrupolo (esas 4 varillas) no se aplica ningún campo electromagnético a los iones y, por lo tanto, vuelan en línea recta. Si entran en el cuadrupolo, pueden entrar en resonancia con el campo electromagnético y, por lo tanto, estar en una trayectoria espiral cilíndrica o no estar en resonancia y, por lo tanto, estar en una trayectoria espiral cónica y, tarde o temprano, salir del cuadrupolo por un lado.

Mi opinión sobre este problema fue usar pgfplotspara dibujar las espirales usando un gráfico 3D con la función {x*cos(deg(x))},{x*sin(deg(x)},{x}para el gráfico cónico y {cos(deg(x))},{sin(deg(x)},{x}para el cilíndrico. Desafortunadamente, no puedo resolver los siguientes problemas:

  • colocar correctamente las espirales
  • dibujar una línea recta que se transforme en espiral y luego volver a una línea recta después de salir del cuadrupolo (solo para el cilíndrico)
  • detener la hélice cónica poco después de que la trayectoria haya salido del cuadrupolo

Soy consciente de que se trata de muchos problemas y, por lo tanto, estoy feliz por cualquier sugerencia.

Mi intento actual (miserable)

\documentclass{standalone}

\usepackage{xparse}
\usepackage{ifthen}
\usepackage{tikz}
\usepackage{pgfplots}

\pgfplotsset{compat=1.8}
\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings}

\begin{document}

\begin{tikzpicture}
    % General constants
    % %%%%%%%%%%%%%%%%%

    \coordinate (msOrigin) at (0,0);
    \pgfmathsetmacro{\msY}{3}

    \pgfmathsetmacro{\offsetX}{0.3}
    \pgfmathsetmacro{\offsetY}{0.2}
    \pgfmathsetmacro{\spacer}{0.75}
    \pgfmathsetmacro{\arrowLength}{1}
    \pgfmathsetmacro{\centerOffset}{0.3}


    % Quadrupole constants
    % %%%%%%%%%%%%%%%%%%%%

    \pgfmathsetmacro{\quadrupoleRadiusHorizontal}{0.08}
    \pgfmathsetmacro{\quadrupoleRadiusVertical}{0.2}
    \pgfmathsetmacro{\quadrupoleLength}{3}
    \pgfmathsetmacro{\quadrupolePathLength}{\quadrupoleLength - (2 * \quadrupoleRadiusHorizontal)}

    \pgfmathsetmacro{\quadrupoleTopFrontY}{0.5 * \msY + \centerOffset + 2 * \quadrupoleRadiusVertical}
    \pgfmathsetmacro{\quadrupoleTopBackY}{\quadrupoleTopFrontY + \offsetY}
    \pgfmathsetmacro{\quadrupoleBottomBackY}{0.5 * \msY - \centerOffset}
    \pgfmathsetmacro{\quadrupoleBottomFrontY}{\quadrupoleBottomBackY - \offsetY}
    
    \NewDocumentCommand{\cylinder}{m m m m m m m m}{%  coordX, coordY, length, radiusX, radiusY, colorCylinder, colorEllipse, opacity
        \fill [#6, fill opacity = #8]
            ($ (msOrigin) + ({#1},{#2}) $)
            --
            ++({#3},0)
            arc
            (90:270:-{#4} and {#5})
            --
            ++(-{#3},0)
            arc
            (270:90:-{#4} and {#5});

        \draw [fill = #7, fill opacity = #8]
            ($ (msOrigin) + ({#1},{#2}) + (0,{-#5}) $)
            ellipse
            ({#4} and {#5});

        \draw
            ($ (msOrigin) + ({#1},{#2}) $)
            --
            ++({#3},0)
            arc
            (90:270:-{#4} and {#5})
            --
            ++(-{#3},0);
    }

    \NewDocumentCommand{\quadrupoleRod}{m m m}{% segment, top/bottom, front/back
        \ifthenelse{\equal{#2}{top} \AND \equal{#3}{front}}{%
            \pgfmathsetmacro{\coordX}{\quadrupoleRadiusHorizontal + \offsetX}
            \pgfmathsetmacro{\coordY}{\quadrupoleTopFrontY}
        }{}

        \ifthenelse{\equal{#2}{top} \AND \equal{#3}{back}}{%
            \pgfmathsetmacro{\coordX}{\quadrupoleRadiusHorizontal}
            \pgfmathsetmacro{\coordY}{\quadrupoleTopBackY}
        }{}

        \ifthenelse{\equal{#2}{bottom} \AND \equal{#3}{front}}{%
            \pgfmathsetmacro{\coordX}{\quadrupoleRadiusHorizontal + \offsetX}
            \pgfmathsetmacro{\coordY}{\quadrupoleBottomFrontY}
        }{}

        \ifthenelse{\equal{#2}{bottom} \AND \equal{#3}{back}}{%
            \pgfmathsetmacro{\coordX}{\quadrupoleRadiusHorizontal}
            \pgfmathsetmacro{\coordY}{\quadrupoleBottomBackY}
        }{}

        \cylinder
            {\coordX}
            {\coordY}
            {\quadrupolePathLength}
            {\quadrupoleRadiusHorizontal}
            {\quadrupoleRadiusVertical}
            {gray}
            {white}
            {1}
    }

    \NewDocumentCommand{\quadrupolePair}{m m}{% segment, front/back
        \ifthenelse{\equal{#2}{front} \OR \equal{#2}{back}}{%
            \quadrupoleRod{#1}{top}{#2}
            \quadrupoleRod{#1}{bottom}{#2}
        }{}
    }
    
    \quadrupolePair{1}{back}
    \begin{axis}[
        rotate around={-90:(current axis.origin)},
        view = {30}{20},
        axis line style = {draw = none},
        tick style = {draw = none},
        zmax = 60,
        xtick=\empty,
        ytick=\empty,
        ztick=\empty
    ]
        \addplot3+[
            mark = none,
            thick,
            red,
            domain = 0:50*pi,
            samples = 1000,
            samples y = 0,
        ]
        % ({x*cos(deg(x))},{x*sin(deg(x)},{x});
        ({cos(deg(x))},{sin(deg(x)},{x});
    \end{axis}
    \quadrupolePair{1}{front}
\end{tikzpicture}

\end{document}

Actualización 2020-11-26

Encontré esta respuesta en TeX.SX ayudando a dibujar la bobina cilíndrica. Mediante algunas modificaciones, pude llegar relativamente lejos en el proceso. Un problema restante es la línea que conecta la ruta horizontal con la espiral ya que el código mark=at position #1 with \coordinate (#2);arroja un Dimension too large.error, incluso si no entiendo por qué. Las bobinas son pequeñas y definitivamente por debajo de los 19 pies ...

Otro tema que permanece es la espiral cónica. Tengo un punto de partida, pero lamentablemente parece asqueroso.

\documentclass{standalone}

\usepackage{xparse}
\usepackage{ifthen}
\usepackage{tikz}

\usetikzlibrary{calc}
\usetikzlibrary{decorations.markings}

\tikzset{
    mark position/.style args={#1(#2)}{
        postaction={
            decorate,
            decoration={
                markings,
                mark=at position #1 with \coordinate (#2);
            }
        }
    }
}

\NewDocumentCommand{\cylinder}{m m m m m m m m}{%  coordX, coordY, length, radiusX, radiusY, colorCylinder, colorEllipse, opacity
    \fill [#6, fill opacity = #8]
        ($ (msOrigin) + ({#1},{#2}) $)
        --
        ++({#3},0)
        arc
        (90:270:-{#4} and {#5})
        --
        ++(-{#3},0)
        arc
        (270:90:-{#4} and {#5});

    \draw [fill = #7, fill opacity = #8]
        ($ (msOrigin) + ({#1},{#2}) + (0,{-#5}) $)
        ellipse
        ({#4} and {#5});

    \draw
        ($ (msOrigin) + ({#1},{#2}) $)
        --
        ++({#3},0)
        arc
        (90:270:-{#4} and {#5})
        --
        ++(-{#3},0);
}

\NewDocumentCommand{\quadrupoleRod}{m m m}{% segment, top/bottom, front/back
    \ifthenelse{\equal{#2}{top} \AND \equal{#3}{front}}{%
        \pgfmathsetmacro{\coordX}{\quadrupoleRadiusHorizontal + \offsetX}
        \pgfmathsetmacro{\coordY}{\quadrupoleTopFrontY}
    }{}

    \ifthenelse{\equal{#2}{top} \AND \equal{#3}{back}}{%
        \pgfmathsetmacro{\coordX}{\quadrupoleRadiusHorizontal}
        \pgfmathsetmacro{\coordY}{\quadrupoleTopBackY}
    }{}

    \ifthenelse{\equal{#2}{bottom} \AND \equal{#3}{front}}{%
        \pgfmathsetmacro{\coordX}{\quadrupoleRadiusHorizontal + \offsetX}
        \pgfmathsetmacro{\coordY}{\quadrupoleBottomFrontY}
    }{}

    \ifthenelse{\equal{#2}{bottom} \AND \equal{#3}{back}}{%
        \pgfmathsetmacro{\coordX}{\quadrupoleRadiusHorizontal}
        \pgfmathsetmacro{\coordY}{\quadrupoleBottomBackY}
    }{}

    \cylinder
        {\coordX}
        {\coordY}
        {\quadrupolePathLength}
        {\quadrupoleRadiusHorizontal}
        {\quadrupoleRadiusVertical}
        {gray}
        {white}
        {1}
}

\NewDocumentCommand{\quadrupolePair}{m m}{% segment, front/back
    \ifthenelse{\equal{#2}{front} \OR \equal{#2}{back}}{%
        \quadrupoleRod{#1}{top}{#2}
        \quadrupoleRod{#1}{bottom}{#2}
    }{}
}

\begin{document}

% General constants
% %%%%%%%%%%%%%%%%%
\pgfmathsetmacro{\offsetX}{0.5}
\pgfmathsetmacro{\offsetY}{0.6}
\pgfmathsetmacro{\spacer}{0.75}
\pgfmathsetmacro{\centerOffset}{0.3}


% Quadrupole constants
% %%%%%%%%%%%%%%%%%%%%

\pgfmathsetmacro{\quadrupoleRadiusHorizontal}{0.08}
\pgfmathsetmacro{\quadrupoleRadiusVertical}{0.2}
\pgfmathsetmacro{\quadrupoleLength}{4}
\pgfmathsetmacro{\quadrupolePathLength}{\quadrupoleLength - (2 * \quadrupoleRadiusHorizontal)}

\pgfmathsetmacro{\quadrupoleTopFrontY}{\centerOffset + 2 * \quadrupoleRadiusVertical}
\pgfmathsetmacro{\quadrupoleTopBackY}{\quadrupoleTopFrontY + \offsetY}
\pgfmathsetmacro{\quadrupoleBottomBackY}{-\centerOffset}
\pgfmathsetmacro{\quadrupoleBottomFrontY}{\quadrupoleBottomBackY - \offsetY}

\begin{tikzpicture}
    \coordinate (msOrigin) at (0,0);
    
    % Define a formula for the coil.
    % This is what the numbers mean:
    % 0.25: the x offset
    % 0.13: how far the rings are apart
    % 0.30: how much from the side the rings are seen
    % 0.75: radius of the rings
    \def\coil#1{
        {0.25 + 0.13 * (2 * #1 + \t) + 0.30 * sin(- \t  *  pi r))},
        {0.75 * cos(-\t * pi r)}
    }

    % Draw the background-rods
    \quadrupolePair{1}{back}
    
    % Draw the part of the coil behind
    \foreach \n in {1,...,14} {
        \draw[domain={0:1},smooth,variable=\t,samples=15]
            plot (\coil{\n}); 
    }

    % Draw the part of the coil in front
    \foreach \n in {0,1,...,13} {
        \ifthenelse{\equal{\n}{0} \OR \equal{\n}{13}}
        {%
            \ifthenelse{\equal{\n}{0}}{%
                \draw[
                    domain = {1:2},
                    smooth,
                    variable = \t,
                    samples = 15,
                    % mark position = 0(start)
                ]
                    plot (\coil{\n});
            }{%
            \draw[
                    domain = {1:2},
                    smooth,
                    variable = \t,
                    samples = 15,
                    % mark position = 1(end)
                ]
                    plot (\coil{\n});
            }
        }{
            \draw[
                domain = {1:2},
                smooth,
                variable = \t,
                samples = 15
            ]
                plot (\coil{\n});
        }
    }
    
    % Draw the foreground-rods
    \quadrupolePair{1}{front}
    
    \draw 
        % (start) % to join the mark position "start"
        (0.25, -0.75)
        to [out = 180, in = 0] 
        ++(-1, 0.75);
    \draw 
        % (end) % to join the mark position "end"
        (4, -0.75) 
        to [out = 0, in = 180] 
        ++(1, 0.75);
\end{tikzpicture}

\hspace{1em}

\begin{tikzpicture}
    \coordinate (msOrigin) at (0,0);
    
    % Define a formula for the coil.
    % This is what the numbers mean:
    % 0.25: the x offset
    % 0.13: how far the rings are apart
    % 0.30: how much from the side the rings are seen
    % 0.75: radius of the rings
    \def\coil#1{
        {0.25 + 0.13 * (2 * #1 + \t) + 0.30 * sin(- \t  *  pi r)},
        {0.75 * #1/10 * \t * cos(-\t * pi r)}
    }

    % Draw the background-rods
    \quadrupolePair{1}{back}
    
    % Draw the part of the coil behind
    \foreach \n in {1,...,14} {
        \draw[domain={0:1},smooth,variable=\t,samples=15]
            plot (\coil{\n});
    }

    % Draw the part of the coil in front
    \foreach \n in {0,1,...,13} {
        \ifthenelse{\equal{\n}{0} \OR \equal{\n}{13}}
        {%
            \ifthenelse{\equal{\n}{0}}{%
                \draw[
                    domain = {1:2},
                    smooth,
                    variable = \t,
                    samples = 15,
                    % mark position = 0(start)
                ]
                    plot (\coil{\n});
            }{%
            \draw[
                    domain = {1:2},
                    smooth,
                    variable = \t,
                    samples = 15,
                    % mark position = 1(end)
                ]
                    plot (\coil{\n});
            }
        }{
            \draw[
                domain = {1:2},
                smooth,
                variable = \t,
                samples = 15
            ]
                plot (\coil{\n});
        }
    }
    
    % Draw the foreground-rods
    \quadrupolePair{1}{front}

\end{tikzpicture}

\end{document}

Respuestas

3 hpekristiansen Nov 26 2020 at 23:08

No veo ninguna razón para usar el código PGF: casi está allí con solo darse cuenta de que se puede trazar la espiral {cos(deg(x))},{sin(deg(x)},{x}. Normalmente me encanta PGFPlots, pero esto no es un gráfico (eje, escala, tics, etiquetas, ...). Creo que la plotfunción en TikZ es la forma correcta.

Para enderezar los extremos de la espiral, dejo que la amplitud decaiga al mismo tiempo que el tono de los bucles. No estoy seguro de cómo quiere que termine la cónica; una forma sencilla es dejar que la amplitud de la bobina aumente rápidamente y ajustar el dominio.

\documentclass[tikz, border=1cm]{standalone}
\begin{document}
\begin{tikzpicture}[ultra thick]
\newcommand{\domA}{-pi}
\newcommand{\domB}{0}
\newcommand{\domC}{2*pi}
\newcommand{\domD}{4*pi}
\newcommand{\domE}{\domC+0.5}
\newcommand{\pitch}{10}
\newcommand{\ampA}{(1/(1+\domB-\x))}
\newcommand{\ampB}{(1/(1-\domC+\x))}
\newcommand{\ampC}{(0.1*(\x-\domB)+1)}

\draw[red, domain={\domA:\domB}, smooth, samples=100] plot (\x, {\ampA*cos((\ampA*\pitch*\x+(1-\ampA)*\pitch*\domB) r)}, {\ampA*sin((\ampA*\pitch*\x+(1-\ampA)*\pitch*\domB) r)}  );
\draw[green, domain={\domB:\domC}, smooth, samples=200] plot (\x, {cos(\pitch*\x r)} , {sin(\pitch*\x r)} );
\draw[blue, domain={\domC:\domD}, smooth, samples=100] plot (\x, {\ampB*cos((\ampB*\pitch*\x+(1-\ampB)*\pitch*\domC) r)}, {\ampB*sin((\ampB*\pitch*\x+(1-\ampB)*\pitch*\domC) r)}  );

\begin{scope}[yshift=-4cm]
\draw[teal, domain={\domA:\domB}, smooth, samples=100] plot (\x, {cos((\ampA*\pitch*\x+(1-\ampA)*\pitch*\domB) r)}, {sin((\ampA*\pitch*\x+(1-\ampA)*\pitch*\domB) r)}  );
\draw[orange, domain={\domB:\domC}, smooth, samples=200] plot (\x, {\ampC*cos(\pitch*\x r)} , {\ampC*sin(\pitch*\x r)} );
\draw[violet, domain={\domC:\domE}, smooth, samples=100] plot (\x, {\ampC*1/\ampB*cos(\pitch*\x r)} , {\ampC*1/\ampB*sin(\pitch*\x r)} );
\end{scope}

\end{tikzpicture}
\end{document}

Editar:

El vector z predeterminado en TikZ apunta a (−3,85 mm, −3,85 mm). Para cambiar la perspectiva, puede usar, por ejemplo, z={(-3.85mm, 3.85mm)}así:

\documentclass[tikz, border=1cm]{standalone}
\begin{document}
\begin{tikzpicture}[z={(-3.85mm, 3.85mm)}]
\newcommand{\domA}{-pi}
\newcommand{\domB}{0}
\newcommand{\domC}{2*pi}
\newcommand{\domD}{4*pi}
\newcommand{\domE}{\domC+0.5}
\newcommand{\pitch}{10}
\newcommand{\ampA}{(1/(1+\domB-\x))}
\newcommand{\ampB}{(1/(1-\domC+\x))}
\newcommand{\ampC}{(0.1*(\x-\domB)+1)}

\draw[fill=gray] (-1,1.2,1) -- (7,1.2,1) arc[start angle=90, end angle=-90, x radius=0.1cm, y radius=0.2cm] -- (-1,0.8,1);
\draw[fill=white](-1,1,1) circle[x radius=0.1cm, y radius=0.2cm];
\draw[fill=gray] (-1,-1.2,1) -- (7,-1.2,1) arc[start angle=-90, end angle=90, x radius=0.1cm, y radius=0.2cm] -- (-1,-0.8,1);
\draw[fill=white](-1,-1,1) circle[x radius=0.1cm, y radius=0.2cm];

\draw[red, thick, domain={\domA:\domB}, smooth, samples=100] plot (\x, {\ampA*cos((\ampA*\pitch*\x+(1-\ampA)*\pitch*\domB) r)}, {\ampA*sin((\ampA*\pitch*\x+(1-\ampA)*\pitch*\domB) r)}  );
\draw[red, thick, domain={\domB:\domC}, smooth, samples=200] plot (\x, {cos(\pitch*\x r)} , {sin(\pitch*\x r)} );
\draw[red, thick, domain={\domC:\domD}, smooth, samples=100] plot (\x, {\ampB*cos((\ampB*\pitch*\x+(1-\ampB)*\pitch*\domC) r)}, {\ampB*sin((\ampB*\pitch*\x+(1-\ampB)*\pitch*\domC) r)}  );

\draw[fill=gray] (-1,1.2,-1) -- (7,1.2,-1) arc[start angle=90, end angle=-90, x radius=0.1cm, y radius=0.2cm] -- (-1,0.8,-1);
\draw[fill=white](-1,1,-1) circle[x radius=0.1cm, y radius=0.2cm];
\draw[fill=gray] (-1,-1.2,-1) -- (7,-1.2,-1) arc[start angle=-90, end angle=90, x radius=0.1cm, y radius=0.2cm] -- (-1,-0.8,-1);
\draw[fill=white](-1,-1,-1) circle[x radius=0.1cm, y radius=0.2cm];

\end{tikzpicture}
\end{document}

La torcedura en la espiral roja se debe a smoothque no funciona en diferentes parcelas. Puedo ver dos formas de corregir esto: eliminar la smoothopción y aumentar mucho las muestras. -o mejor: Use TikZ declare functionpara declarar una función por partes y solo haga una gráfica.