LaTeX - Logiska kretsar. [Löst, förbättring önskas om möjligt]

Permalänk
Medlem

LaTeX - Logiska kretsar. [Löst, förbättring önskas om möjligt]

Vet i tusan var jag skulle placera den här, men jag får hoppas att det duger här.

Sitter och tänkte rita mig ett kombinatoriskt nät och hankar mig så sakteliga fram, men går bet på hur jag ska få till det sista som jag vill.

Som det ser ut just nu:

\begin{circuitikz} \draw (0,2) node[european nor port] (mynor) {} (mynor.in 1) node [left] (a) {a} (0,0) node[european and port] (myand) {} (myand.in 2) node [left] (c) {c} (2,1) node[european or port] (myor) {} (myor.out) node [right] (u) {u} (mynor.out) -- (myor.in 1) (myand.out) -- (myor.in 2); \end{circuitikz}

En signal "b" ska gå in i såväl nor- som and-grinden, och visst kan man i det här enkla fallet skriva in b-signalen två gånger - en till varje grind - men det skulle vara lite snyggare att rita in en enda signal som grenas av till de två, om ni förstår vad jag menar.

Edit: Löste det, men det känns som att det skulle kunna lösas på något snyggare sätt, så den som kan komma på någon förbättring är högst välkommen att posta.

\begin{circuitikz} \draw (1,2) node[european nor port] (mynor) {} (mynor.in 1) node [left=".5cm"] (a) {$a$} (1,0) node[european and port] (myand) {} (myand.in 2) node [left=".5cm"] (c) {$c$} (3,1) node[european or port] (myor) {} (myor.out) node [right] (u) {$u$} (-.8,1) node [left=".5cm"] (b) {$b$} (b) -| (mynor.in 2) (b) -| (myand.in 1) (a) -| (mynor.in 1) (c) -| (myand.in 2) (mynor.out) -- (myor.in 1) (myand.out) -- (myor.in 2); \end{circuitikz}

Visa signatur

Desktop: AMD 3950X, 64 GB RAM, Nvidia 4070 ... (Ubuntu 24.04)
Serverdesktop: AMD 5600G, 96 GB RAM (Proxmox)
Labbmiljö: Supermicro SC825 X9DRi-F 2xE5-2667v2 64GB RAM
Kamera: Canon R5, Canon RF 100-500, Laowa 100mm f/2.8, Canon RF 24-70 f/2,8

Permalänk
Hedersmedlem
  • Jag skulle gärna dela upp det i separata kommandon snarare än skriva en lång kedja i ett enda `\draw`-kommando. Det blir bra mycket lättare att felsöka och ändra något litet, skulle jag säga. Dessutom så kan man enkelt logiskt separera vad de olika kodraderna gör, vilket underlättar för en själv (inte minst om man ska titta på koden igen i framtiden).

  • Det är mer eller mindre alltid bra att definiera "stilar" så att man undviker hårdkodade och upprepade parametrar inne i ritningssteget. Ifall man ser att man upprepar någon kodbit ofta så är det trevligt att definiera ett nytt kommando, men man ska inte gå till överdrift med att abstrahera bort fundamentala TikZ-kommandon, så här ser jag ingen anledning till det.

  • Jag använder en `path` för att sätta "b"-etiketten dynamiskt mellan de båda komponenternas ingångar (men jag löser detta på ett annat sätt i det senare exemplet).

  • Jag ändrade vänsteravståndet till "10" (vilket implicerar "pt", om jag inte har fel för mig) i stället för att ange det i "cm". Det det är lite vanskligt att ange fysiska enheter, då kopplingen till storlek på papper ändå inte är helt trivial. Vill man ändra avståndet till inparametrarna så är det bara att ändra "10" till något annat, så positionerar allt om sig magiskt .

  • `--` på dina sista två rader innan `\end{circuitikz}` borde varit `-|` för att skapa räta vinklar; så som det stod så blev de lite sneda om man zoomade in.

  • Jag ändrade koordinatsystemet så att komponenterna placeras på (−1, 1), (−1, −1) och (1, 0) — tycker det ser enklare ut personligen, men det spelar ingen större roll. Ett alternativ är att ange en komponent som referens och placera de övriga relativt denna, men i praktiken är det ofta smidigt att använda det implicita koordinatsystemet i stället.

\documentclass{article} \usepackage{circuitikz} \begin{document} \begin{circuitikz} \tikzset{% inlabel/.style={left=10}, outlabel/.style={right}, }; % Components \node[european nor="nor" port="port"] (mynor) at (-1, 1) {}; \node[european and="and" port="port"] (myand) at (-1, -1) {}; \node[european or="or" port="port"] (myor) at (1, 0) {}; % Labels \node[inlabel] (a) at (mynor.in 1) {$a$}; \path (mynor.in 2) -- node[inlabel] (b) {$b$} (myand.in 1); \node[inlabel] (c) at (myand.in 2) {$c$}; \node[outlabel] (u) at (myor.out) {$u$}; % Internal connections \draw (mynor.out) -| (myor.in 1); \draw (myand.out) -| (myor.in 2); % External connections \draw (a) -| (mynor.in 1); \draw (b) -| (mynor.in 2); \draw (b) -| (myand.in 1); \draw (c) -| (myand.in 2); \end{circuitikz} \end{document}

vilket ger:

Helt OK, men med lite OCD så ser man att det vågräta strecket från "b" är liiite tjockare än övriga ledningar. Detta är troligen en antialiasingartefakt av dubbelritningen som bara bör synas på skärmar (kanske även beroende på PDF-läsare) och inte vid utskrifter, och ovanstående zoomnivå är vald för att det ska synas så tydligt som möjligt.

I vilket fall så skulle man kunna tänka om den kopplingen lite, och dela upp den i en intern koppling mellan `mynor.in 2` och `myand.in 1`, och sedan en extern koppling som hakar in sig halvvägs på den interna kopplingen. Jag skulle gå så långt som att säga att det är logiskt bättre. Ritningsmässigt så ersätter vi då `path`-"hacket" med att definiera en `node` halvvägs på sträckan mellan ingångarna; för att ledningen ska nå ända fram så att det blir meningsfullt ur kretssynpunkt så behöver jag då manuellt minska ner nodens storlek och separation, men överlag kanske det ändå är ett bättre sätt att skriva saker på.

Syntaxen för att sätta noden "halvvägs" är lite udda, men kan ofta vara användbar. Notera att TikZ gör "fel" sak om man anger `|-` eller `-|`, av någon anledning; jag misstänker att det är för att TikZ då ritar strecket i två omgångar (först vertikalt, sedan horisontellt) och definierar "mittpunkten" efter det senast ritade interna strecket. Eftersom det ändå per konstruktion inte blir någon längd på det horisontella strecket här så kommer då mittpunkten bli den övre kopplingen för `-|` och den nedre kopplingen för `|-`. Mest en kuriositet .

På tal om detaljer så ser man med förstoringsglas även att de interna kopplingarna till terminalerna inte är "skarpa", utan aningens rundade. Det beror på att standardinställningen för linjers avslutningar är `butt`, vilket klipper linjen exakt på nodens koordinat. Vi vill hellre ha `rect` här. Visualisering med `butt` till vänster och `rect` till höger, där det överlappande strecket färgats grönt för exemplets skull:

Vi sätter enklast detta som en global stil för "varje nod".

Alltså, ny variant:

\documentclass{article} \usepackage{circuitikz} \begin{document} \begin{circuitikz} \tikzset{% inlabel/.style={left=10}, outlabel/.style={right}, every node/.style={line cap=rect}, }; % Components \node[european nor="nor" port="port"] (mynor) at (-1, 1) {}; \node[european and="and" port="port"] (myand) at (-1, -1) {}; \node[european or="or" port="port"] (myor) at (1, 0) {}; % Internal connections \draw (mynor.out) -| (myor.in 1); \draw (mynor.in 2) -- node[inner sep="0," minimum="minimum" size="0"] (mymid) {} (myand.in 1); \draw (myand.out) -| (myor.in 2); % Labels \node[inlabel] (a) at (mynor.in 1) {$a$}; \node[inlabel] (b) at (mymid) {$b$}; \node[inlabel] (c) at (myand.in 2) {$c$}; \node[outlabel] (u) at (myor.out) {$u$}; % External connections \draw (a) -| (mynor.in 1); \draw (b) -| (mymid); \draw (c) -| (myand.in 2); \end{circuitikz} \end{document}

vilket ger:

Man kan notera att antialiasing gör att det vågräta strecket vid `b` nu ser ut att penetrera ledningen någon pixel. Det slipper man om man behåller `butt` där, så man skulle i stället kunna definiera `line cap=rect` endast för de interna ledningarna om man vill; antingen genom att sätta en ny stil, eller bilda ett "scope" när de ritas, eller något. Man kan också troligen enklast bara ändra `\draw`-kommandot för den externa kopplingen till `\draw[line cap="butt"] (b) -| (mid);`, vilket lämnas som en uppgift åt läsaren . Det kan sägas att man snarare bråkar med PDF-läsarnas interna algoritmer än med den faktiska informationen här, dock.

Man hade också kunnat ändra ordning på definitionen av "Labels" och "External connections" om man definierar noderna annorlunda, vilket kanske sitter logiskt bättre.

Det enda jag har kvar att säga därefter handlar om rent personlig preferens: jag skulle nog valt andra nodnamn än "my"-prefix, men det spelar mindre eller noll roll . Man behöver ofta inte vara rädd för att dubblera namn så länge de betecknar olika saker (noder, stilar, färger, …), då TikZ allt som oftast har full koll på sina namnrymder. Om man helt enkelt skulle ta bort alla förekomster av "my" i koderna ovan så hade de fungerat på precis samma sätt.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Medlem
Skrivet av phz:

Shit, där fick jag så det räckte och blev över! Har inte hunnit analysera allt än, men stort tack för nedlagd tid!

Visa signatur

Desktop: AMD 3950X, 64 GB RAM, Nvidia 4070 ... (Ubuntu 24.04)
Serverdesktop: AMD 5600G, 96 GB RAM (Proxmox)
Labbmiljö: Supermicro SC825 X9DRi-F 2xE5-2667v2 64GB RAM
Kamera: Canon R5, Canon RF 100-500, Laowa 100mm f/2.8, Canon RF 24-70 f/2,8

Permalänk
Hedersmedlem
Skrivet av Crazy Ferret:

Shit, där fick jag så det räckte och blev över! Har inte hunnit analysera allt än, men stort tack för nedlagd tid!

Ingen fara, det är ofta ett rätt belönande pill . Att skriva koden gick snabbt; det som tog tid var snarare att formulera varför man skrev den på ett visst sätt, men det är bara nyttigt att behöva motivera sådant för sig själv i ord ibland.

En tumregel när man gör sådana bilder är att om det börjar bli grötigt så har man troligen gjort något på ett okonventionellt sätt någonstans. Man bör försöka separera presentationsdetaljer (färg, linjestil, etc.) och "logisk" uppritning (nodplacering, relativa förhållanden, etc.), och försöka beräkna så mycket som möjligt dynamiskt snarare än att ange fasta parametrar. Där man ändå behöver sådana så är det bra att definiera dem i ett makro, ett kommando, en stil eller liknande på en central plats.

Tipsar om QtikZ (officiella hemsidan verkar vara nere för stunden) för experimentfasen när man bygger upp sina TikZ-bilder, om du inte redan använder något liknande.

Kan bjuda på en annan variant som integrerar variabeltexterna med ritandet, och använder just ett kommando för att undvika upprepning:

\documentclass{article} \usepackage{circuitikz} \begin{document} \begin{circuitikz} \tikzset{% outlabel/.style={right}, every node/.style={line cap=rect} }; \newcommand\inlabel[2]{\draw (#1) -- +(180:10pt) node[left] {#2}}; % Components \node[european nor port] (nor) at (-1, 1) {}; \node[european and port] (and) at (-1, -1) {}; \node[european or port] (or) at (1, 0) {}; % Internal connections \draw (nor.out) -| (or.in 1); \draw (nor.in 2) -- node[inner sep="0," minimum size="0"] (mid) {} (and.in 1); \draw (and.out) -| (or.in 2); % External connections \inlabel {nor.in 1} {$a$}; \inlabel {mid} {$b$}; \inlabel {and.in 2} {$c$}; \node[outlabel] at (or.out) {$u$}; \end{circuitikz} \end{document}

Detta sätt undviker även `line cap=butt`-problemet för "b"-strecket, och renderar i övrigt identiskt. Har även strippat "my"-prefixen, ser jag.

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.

Permalänk
Medlem
Skrivet av phz:

Ingen fara, det är ofta ett rätt belönande pill . Att skriva koden gick snabbt; det som tog tid var snarare att formulera varför man skrev den på ett visst sätt, men det är bara nyttigt att behöva motivera sådant för sig själv i ord ibland.

Ja, att lära ut är ett av de bästa (om inte det bästa) sättet att lära sig.

Skrivet av phz:

En tumregel när man gör sådana bilder är att om det börjar bli grötigt så har man troligen gjort något på ett okonventionellt sätt någonstans. Man bör försöka separera presentationsdetaljer (färg, linjestil, etc.) och "logisk" uppritning (nodplacering, relativa förhållanden, etc.), och försöka beräkna så mycket som möjligt dynamiskt snarare än att ange fasta parametrar. Där man ändå behöver sådana så är det bra att definiera dem i ett makro, ett kommando, en stil eller liknande på en central plats.

Jo, tanken är ju just att det ska vara smidigt, därav att jag kände att jag behövde reda upp det hela lite. Din uppdelning underlättade en hel del för att förstå vad fan jag egentligen pysslade med. Har använt mig av LaTeX sedan förra hösten i många olika scenarion, men Circuitikz är helt nytt för mig och Tikz i allmänhet har jag använt högst marginellt, så det är mycket trial-and-error för stunden.

Skrivet av phz:

Tipsar om QtikZ (officiella hemsidan verkar vara nere för stunden) för experimentfasen när man bygger upp sina TikZ-bilder, om du inte redan använder något liknande.

Ska ta en titt på det framöver. Tack för tipset!

Visa signatur

Desktop: AMD 3950X, 64 GB RAM, Nvidia 4070 ... (Ubuntu 24.04)
Serverdesktop: AMD 5600G, 96 GB RAM (Proxmox)
Labbmiljö: Supermicro SC825 X9DRi-F 2xE5-2667v2 64GB RAM
Kamera: Canon R5, Canon RF 100-500, Laowa 100mm f/2.8, Canon RF 24-70 f/2,8

Permalänk
Hedersmedlem
Skrivet av Crazy Ferret:

Jo, tanken är ju just att det ska vara smidigt, därav att jag kände att jag behövde reda upp det hela lite. Din uppdelning underlättade en hel del för att förstå vad fan jag egentligen pysslade med. Har använt mig av LaTeX sedan förra hösten i många olika scenarion, men Circuitikz är helt nytt för mig och Tikz i allmänhet har jag använt högst marginellt, så det är mycket trial-and-error för stunden.

TikZ har en nästan smärtsam inlärningskurva, men det blir fint när det väl fungerar .

Kom på ytterligare en förenkling som faktiskt tar bort en del av "hackkänslan" i koden ovan gällande manuella nodparametrar för "dummy"-noden jag skapar halvvägs mellan terminalerna. Jag kan ange den som en koordinat i stället. Jag försökte detta tidigare, men glömde ta bort den tomma nodtexten och fick kryptiska felmeddelanden, så tänkte att det inte gick alls, men det var inga problem när man skrev rätt…

På köpet kan man då modifiera även de andra "tomma" noderna; filen växer något i byte, men minskar i komplexitet. Jag tror jag vågar säga att överallt där man skriver en `node` med tom text så kan den med fördel ersättas av `coordinate` som inte tar någon text till att börja med; båda uttrycken är egentligen bara alias för `path` med vissa specifika argument.

\documentclass{article} \usepackage{circuitikz} \begin{document} \begin{circuitikz} \tikzset{% outlabel/.style={right}, every node/.style={line cap=rect} }; \newcommand\inlabel[2]{\draw (#1) -- +(180:10pt) node[left] {#2}}; % Components \coordinate[european nor port] (nor) at (-1, 1); \coordinate[european and port] (and) at (-1, -1); \coordinate[european or port] (or) at (1, 0); % Internal connections \draw (nor.out) -| (or.in 1); \draw (nor.in 2) -- coordinate (mid) (and.in 1); \draw (and.out) -| (or.in 2); % External connections \inlabel {nor.in 1} {$a$}; \inlabel {mid} {$b$}; \inlabel {and.in 2} {$c$}; \node[outlabel] at (or.out) {$u$}; \end{circuitikz} \end{document}

Bästa varianten hittills!

Visa signatur

Nu med kortare användarnamn, men fortfarande bedövande långa inlägg.