tube improvements

This commit is contained in:
Bane Stojkovic
2026-11-02 14:40:23 +01:00
parent 1dfef6dd6b
commit 3e043a8387
10 changed files with 611 additions and 216 deletions
+2 -1
View File
@@ -19805,7 +19805,8 @@
"namePrefix" : "V",
"description" : "Various types of tube/valve sockets",
"creationMethod" : "SINGLE_CLICK",
"notes" : [ "The first control point is the socket centre, not a pin. Pins sit on a circle and are numbered clockwise, starting after the gap (B9A, B7G, B12C) or the key (OCTAL), which points right at 'Angle' 0; 'Angle' rotates the socket clockwise in degrees. This is the bottom view used for wiring" ],
"notes" : [ "The first control point is the socket centre, not a pin. Pins sit on a circle and are numbered clockwise, starting after the gap (B9A, B7G, B12C) or the key (OCTAL), which points right at 'Angle' 0; 'Angle' rotates the socket clockwise in degrees. This is the bottom view used for wiring", "'Electrode Labels' is a comma-separated list of electrode names in pin order starting at pin 1: P plate, G triode grid, G1/G2/G3 control, screen and suppressor grids, K cathode, BP beam plates, IS internal shield, HCT heater centre tap. Sections of a multi-section tube are numbered first (1P, 1G, 2P); heater ends are named after their pin (H4, H5) because they are separate nets; pins joined inside the tube end in _1, _2; NC and IC pins are never connected", "A datasheet model is a tube type such as 12AX7 or EL34 and sets 'Base', 'Electrode Labels' and 'Designation'. Set 'Designation' to the same tube type together with the model" ],
"datasheetModels" : [ "12AX7", "ECC83", "7025", "5751", "12AT7", "ECC81", "12AU7", "ECC82", "12AY7", "6072", "12BH7", "12DW7", "12AZ7", "5965", "ECC99", "6922", "E88CC", "6DJ8", "ECC88", "7308", "6CG7", "ECC85", "6FQ7", "5687", "6N1P", "6N2P", "6H30P", "6SN7", "6SL7", "6080", "6AS7", "6BX7", "6BL7", "12B4A", "6J5", "6C5", "EF86", "6267", "5879", "EF80", "EF184", "6AU6", "6BA6", "6AK5", "6SJ7", "12BE6", "6BE6", "12BA6", "6BD6", "12AV6", "12AT6", "6AV6", "6AT6", "50C5", "35W4", "6SA7", "12SA7", "6SK7", "12SK7", "6SG7", "6SQ7", "12SQ7", "50L6GT", "35Z5GT", "ECH81", "ECH83", "UCH81", "EF85", "EBF89", "UBF89", "EABC80", "UCL82", "EM84", "EM80", "EM81", "6AF6", "1629", "12K5", "12AD6", "12EG6", "12AF6", "12CX6", "12DZ6", "12EK6", "12AC6", "12BL6", "12AE6", "12FM6", "12FK6", "12EL6", "12FX8", "12DS7", "12EM6", "12J8", "12DL8", "EL84", "6BQ5", "7189", "7189A", "6CW5", "EL86", "6V6GT", "6V6", "6L6GC", "6L6", "5881", "7581A", "KT66", "EL34", "6CA7", "KT88", "6550", "KT120", "KT150", "7591", "6AQ5", "6BF5", "50B5", "6973", "12AB5", "6BM8", "ECL82", "ECL86", "6GW8", "6F6G", "6K6GT", "6Y6G", "6AS5", "6CU5", "35C5", "6EH5", "6CZ5", "6EM5", "6BW6", "6DL5", "EL95", "6AK6", "6AR5", "6CM6", "6CL6", "5AR4", "GZ34", "5V4G", "GZ32", "5Y3GT", "5U4GB", "EZ81", "EZ80", "6CA4", "6X4", "6X5GT", "6X5", "6AX5GT", "0A2", "0B2", "0D3", "0C3", "0A3", "6N2P-EV", "6N1P-EV", "6N6P", "6N23P", "6N23P-EV", "6N24P", "6N3P", "6N8S", "6N9S", "6N13S", "6N5S", "6S45P", "6S19P", "6S4S", "6Zh32P", "6Zh1P", "6P14P", "6P14P-EV", "6P18P", "6P15P", "EL91", "6AM5", "6P1P", "6P3S", "6P3S-E", "6P6S", "6P27S", "5C3S", "5C4S", "6C4P" ],
"properties" : [ {
"name" : "Alpha",
"type" : "Percentage",
@@ -39,7 +39,7 @@ public class Node implements Comparable<Node> {
/** Pin names that mark an absent connection, so repeats of them are not one net. */
private static final Set<String> NON_NET_NAMES =
new HashSet<String>(Arrays.asList("NC", "RSV"));
new HashSet<String>(Arrays.asList("NC", "RSV", "IC"));
private IDIYComponent<?> component;
private int pointIndex;
@@ -948,232 +948,27 @@
</org.diylc.core.Template>
<org.diylc.core.Template>
<name>Chassis Noval 9A (12A?7)</name>
<values>
<entry>
<string>Color</string>
<awt-color hex="f7f7ef"/>
</entry>
<entry>
<string>Mount</string>
<diylc.tube.TubeSocket_-Mount>CHASSIS</diylc.tube.TubeSocket_-Mount>
</entry>
<entry>
<string>Label</string>
<awt-color hex="acaca7"/>
</entry>
<entry>
<string>Electrode Labels</string>
<string>A,G,C,H,H,A,G,C,CT</string>
</entry>
<entry>
<string>Base</string>
<diylc.tube.TubeSocket_-Base>B9A</diylc.tube.TubeSocket_-Base>
</entry>
</values>
<points>
<point x="0.0" y="0.0"/>
<point x="0.2" y="0.145"/>
<point x="0.075" y="0.235"/>
<point x="-0.08" y="0.235"/>
<point x="-0.205" y="0.145"/>
<point x="-0.25" y="0.0"/>
<point x="-0.205" y="-0.15"/>
<point x="-0.08" y="-0.24"/>
<point x="0.075" y="-0.24"/>
<point x="0.2" y="-0.15"/>
</points>
<defaultFlag>false</defaultFlag>
<createdOn>2022-10-30T13:25:15.3894874</createdOn>
<deletedOn>2026-11-02T14:00:00</deletedOn>
</org.diylc.core.Template>
<org.diylc.core.Template>
<name>Chassis Noval 9CV (EL84)</name>
<values>
<entry>
<string>Color</string>
<awt-color hex="f7f7ef"/>
</entry>
<entry>
<string>Mount</string>
<diylc.tube.TubeSocket_-Mount>CHASSIS</diylc.tube.TubeSocket_-Mount>
</entry>
<entry>
<string>Label</string>
<awt-color hex="acaca7"/>
</entry>
<entry>
<string>Electrode Labels</string>
<string>n/c,G,C,H,H,n/c,P,n/c,S</string>
</entry>
<entry>
<string>Base</string>
<diylc.tube.TubeSocket_-Base>B9A</diylc.tube.TubeSocket_-Base>
</entry>
</values>
<points>
<point x="0.0" y="0.0"/>
<point x="0.2" y="0.145"/>
<point x="0.075" y="0.235"/>
<point x="-0.08" y="0.235"/>
<point x="-0.205" y="0.145"/>
<point x="-0.25" y="0.0"/>
<point x="-0.205" y="-0.15"/>
<point x="-0.08" y="-0.24"/>
<point x="0.075" y="-0.24"/>
<point x="0.2" y="-0.15"/>
</points>
<defaultFlag>false</defaultFlag>
<createdOn>2022-10-30T13:25:15.3894874</createdOn>
<deletedOn>2026-11-02T14:00:00</deletedOn>
</org.diylc.core.Template>
<org.diylc.core.Template>
<name>Chassis Octal 5T</name>
<values>
<entry>
<string>Color</string>
<awt-color hex="f7f7ef"/>
</entry>
<entry>
<string>Mount</string>
<diylc.tube.TubeSocket_-Mount>CHASSIS</diylc.tube.TubeSocket_-Mount>
</entry>
<entry>
<string>Label</string>
<awt-color hex="acaca7"/>
</entry>
<entry>
<string>Electrode Labels</string>
<string>n/c,H,n/c,P,n/c,P,n/c,H</string>
</entry>
<entry>
<string>Base</string>
<diylc.tube.TubeSocket_-Base>OCTAL</diylc.tube.TubeSocket_-Base>
</entry>
</values>
<points>
<point x="0.0" y="0.0"/>
<point x="0.315" y="0.13"/>
<point x="0.13" y="0.315"/>
<point x="-0.13" y="0.315"/>
<point x="-0.315" y="0.13"/>
<point x="-0.315" y="-0.13"/>
<point x="-0.13" y="-0.315"/>
<point x="0.13" y="-0.315"/>
<point x="0.315" y="-0.13"/>
</points>
<defaultFlag>false</defaultFlag>
<createdOn>2022-10-30T13:25:15.3894874</createdOn>
<deletedOn>2026-11-02T14:00:00</deletedOn>
</org.diylc.core.Template>
<org.diylc.core.Template>
<name>Chassis Octal 7AC (6?6)</name>
<values>
<entry>
<string>Color</string>
<awt-color hex="f7f7ef"/>
</entry>
<entry>
<string>Mount</string>
<diylc.tube.TubeSocket_-Mount>CHASSIS</diylc.tube.TubeSocket_-Mount>
</entry>
<entry>
<string>Label</string>
<awt-color hex="acaca7"/>
</entry>
<entry>
<string>Electrode Labels</string>
<string>n/c,H,P,S,G,n/c,H,C</string>
</entry>
<entry>
<string>Base</string>
<diylc.tube.TubeSocket_-Base>OCTAL</diylc.tube.TubeSocket_-Base>
</entry>
</values>
<points>
<point x="0.0" y="0.0"/>
<point x="0.315" y="0.13"/>
<point x="0.13" y="0.315"/>
<point x="-0.13" y="0.315"/>
<point x="-0.315" y="0.13"/>
<point x="-0.315" y="-0.13"/>
<point x="-0.13" y="-0.315"/>
<point x="0.13" y="-0.315"/>
<point x="0.315" y="-0.13"/>
</points>
<defaultFlag>false</defaultFlag>
<createdOn>2022-10-30T13:25:15.3894874</createdOn>
<deletedOn>2026-11-02T14:00:00</deletedOn>
</org.diylc.core.Template>
<org.diylc.core.Template>
<name>Chassis 7-pin 7BK</name>
<values>
<entry>
<string>Color</string>
<awt-color hex="f7f7ef"/>
</entry>
<entry>
<string>Mount</string>
<diylc.tube.TubeSocket_-Mount>CHASSIS</diylc.tube.TubeSocket_-Mount>
</entry>
<entry>
<string>Label</string>
<awt-color hex="acaca7"/>
</entry>
<entry>
<string>Electrode Labels</string>
<string>G,IS,H,H,P,S,C</string>
</entry>
<entry>
<string>Base</string>
<diylc.tube.TubeSocket_-Base>B7G</diylc.tube.TubeSocket_-Base>
</entry>
</values>
<points>
<point x="0.0" y="0.0"/>
<point x="0.165" y="0.165"/>
<point x="0.0" y="0.235"/>
<point x="-0.17" y="0.165"/>
<point x="-0.24" y="0.0"/>
<point x="-0.17" y="-0.17"/>
<point x="0.0" y="-0.24"/>
<point x="0.165" y="-0.17"/>
</points>
<defaultFlag>false</defaultFlag>
<createdOn>2022-10-30T13:25:15.3894874</createdOn>
<deletedOn>2026-11-02T14:00:00</deletedOn>
</org.diylc.core.Template>
<org.diylc.core.Template>
<name>Chassis Octal 8ET (EL34)</name>
<values>
<entry>
<string>Color</string>
<awt-color hex="f7f7ef"/>
</entry>
<entry>
<string>Mount</string>
<diylc.tube.TubeSocket_-Mount>CHASSIS</diylc.tube.TubeSocket_-Mount>
</entry>
<entry>
<string>Label</string>
<awt-color hex="acaca7"/>
</entry>
<entry>
<string>Electrode Labels</string>
<string>IS,H,P,S,G,n/c,H,C</string>
</entry>
<entry>
<string>Base</string>
<diylc.tube.TubeSocket_-Base>OCTAL</diylc.tube.TubeSocket_-Base>
</entry>
</values>
<points>
<point x="0.0" y="0.0"/>
<point x="0.315" y="0.13"/>
<point x="0.13" y="0.315"/>
<point x="-0.13" y="0.315"/>
<point x="-0.315" y="0.13"/>
<point x="-0.315" y="-0.13"/>
<point x="-0.13" y="-0.315"/>
<point x="0.13" y="-0.315"/>
<point x="0.315" y="-0.13"/>
</points>
<defaultFlag>false</defaultFlag>
<createdOn>2022-10-30T13:25:15.3894874</createdOn>
<deletedOn>2026-11-02T14:00:00</deletedOn>
</org.diylc.core.Template>
</list>
</entry>
@@ -525,6 +525,10 @@
<changeType>NEW_FEATURE</changeType>
<description>Added 'Pinout' property to 'Transistor (TO-3)' and a terminal in the mounting hole next to the pins, so the case (collector) can be wired and shows up in netlists and AI analysis</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>Added a datasheet to 'Tube Socket' - pick a tube by its type from the component's submenu to set its base and electrode labels at once - more than 180 preamp, power, rectifier, radio, space-charge and Soviet tubes; the AI Assistant can place these tubes by type too</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>NEW_FEATURE</changeType>
<description>'Chassis Panel' is now 'Enclosure' and can draw an exploded view of the whole box; set 'Height' and choose which 'Sides' to unfold</description>
@@ -573,6 +577,10 @@
<changeType>BUG_FIX</changeType>
<description>SPICE netlists listed the pins of transistors with E-C-B pinout in the wrong order</description>
</org.diylc.appframework.update.Change>
<org.diylc.appframework.update.Change>
<changeType>BUG_FIX</changeType>
<description>'Tube Socket' variants with electrode labels connected pins that share a label in netlists and AI analysis, e.g. both anodes of a 12AX7 or both heater ends; these variants are replaced by the datasheet</description>
</org.diylc.appframework.update.Change>
</changes>
<url>https://github.com/bancika/diy-layout-creator/releases</url>
</org.diylc.appframework.update.Version>
@@ -87,6 +87,8 @@ public class NodeNameTest {
public void railNameRejectsPinsThatNameNoNet() {
Assert.assertNull(Node.railName("NC_1"));
Assert.assertNull(Node.railName("RSV_2"));
// a tube pin marked "internal connection" must not be used as a tie point
Assert.assertNull(Node.railName("IC"));
Assert.assertNull(Node.railName(null));
}
@@ -30,6 +30,8 @@ import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.Arrays;
import org.diylc.appframework.miscutils.ConfigurationManager;
import org.diylc.awt.StringUtils;
@@ -38,8 +40,10 @@ import org.diylc.common.IPlugInPort;
import org.diylc.common.ObjectCache;
import org.diylc.common.VerticalAlignment;
import org.diylc.components.AbstractAngledComponent;
import org.diylc.components.AbstractMakerBoard;
import org.diylc.components.transform.AngledComponentTransformer;
import org.diylc.core.ComponentState;
import org.diylc.core.IDatasheetSupport;
import org.diylc.core.IDIYComponent;
import org.diylc.core.IDrawingObserver;
import org.diylc.core.Project;
@@ -55,11 +59,15 @@ import org.diylc.core.measures.SizeUnit;
import org.diylc.utils.Constants;
@AiNote("The first control point is the socket centre, not a pin. Pins sit on a circle and are numbered clockwise, starting after the gap (B9A, B7G, B12C) or the key (OCTAL), which points right at 'Angle' 0; 'Angle' rotates the socket clockwise in degrees. This is the bottom view used for wiring")
@AiNote("'Electrode Labels' is a comma-separated list of electrode names in pin order starting at pin 1: P plate, G triode grid, G1/G2/G3 control, screen and suppressor grids, K cathode, BP beam plates, IS internal shield, HCT heater centre tap. Sections of a multi-section tube are numbered first (1P, 1G, 2P); heater ends are named after their pin (H4, H5) because they are separate nets; pins joined inside the tube end in _1, _2; NC and IC pins are never connected")
@AiNote("A datasheet model is a tube type such as 12AX7 or EL34 and sets 'Base', 'Electrode Labels' and 'Designation'. Set 'Designation' to the same tube type together with the model")
@ComponentDescriptor(name = "Tube Socket", author = "Branislav Stojkovic", category = "Tubes",
instanceNamePrefix = "V", description = "Various types of tube/valve sockets",
zOrder = IDIYComponent.COMPONENT, keywordPolicy = KeywordPolicy.SHOW_VALUE, enableCache = true,
transformer = AngledComponentTransformer.class)
public class TubeSocket extends AbstractAngledComponent<String> implements IGerberComponentSimple {
transformer = AngledComponentTransformer.class, enableDatasheet = true,
datasheetCreationStepCount = 2, datasheetModelColumn = 1)
public class TubeSocket extends AbstractAngledComponent<String>
implements IGerberComponentSimple, IDatasheetSupport {
private static final Size B9A_PIN_SPACING_CHASSIS = new Size(12.5d, SizeUnit.mm);
private static final Size B9A_PIN_SPACING_PCB = new Size(21d, SizeUnit.mm);
@@ -103,6 +111,21 @@ public class TubeSocket extends AbstractAngledComponent<String> implements IGerb
updateControlPoints();
}
public TubeSocket(String[] model) {
this();
applyModel(model);
}
// columns: group, tube type, base, RETMA basing code, then one electrode name per pin in pin
// order
@Override
public void applyModel(String[] model) {
setValue(model[1]);
setBase(Base.valueOf(model[2]));
setElectrodeLabels(String.join(",", Arrays.copyOfRange(model, 4, model.length)));
}
@EditableProperty
public Base getBase() {
return base;
@@ -304,7 +327,7 @@ public class TubeSocket extends AbstractAngledComponent<String> implements IGerb
double electrodeLabelOffset = project.getFont().getSize2D() * (getBase() == Base.B9A && getMount() == Mount.PCB ? 1.5 : 1);
for (int i = 0; i < labels.length; i++) {
if (i < controlPoints.length - 1) {
String label = labels[i];
String label = AbstractMakerBoard.getDisplayPinLabel(labels[i]);
double theta = Math.atan2(controlPoints[i + 1].getY() - controlPoints[0].getY(), controlPoints[i + 1].getX() - controlPoints[0].getX());
double x = controlPoints[i + 1].getX() - Math.cos(theta) * electrodeLabelOffset;
double y = controlPoints[i + 1].getY() - Math.sin(theta) * electrodeLabelOffset;
@@ -0,0 +1,188 @@
Dual Triode,12AX7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,ECC83,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,7025,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,5751,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,12AT7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,ECC81,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,12AU7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,ECC82,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,12AY7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,6072,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,12BH7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,12DW7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,12AZ7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,5965,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,ECC99,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT
Dual Triode,6922,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,E88CC,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,6DJ8,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,ECC88,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,7308,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,6CG7,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,ECC85,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,6FQ7,B9A,9LP,2P,2G,2K,H4,H5,1P,1G,1K,NC
Dual Triode,5687,B9A,9H,2P,2G,2K,H4,H5,1K,1G,HCT,1P
Dual Triode,6N1P,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS
Dual Triode,6N2P,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS
Dual Triode,6H30P,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS
Dual Triode,6SN7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Dual Triode,6SL7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Dual Triode,6080,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Dual Triode,6AS7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Dual Triode,6BX7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Dual Triode,6BL7,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Triode,12B4A,B9A,9AG,K,G_1,HCT,H4,H5,NC,G_2,NC,P
Triode,6J5,OCTAL,6Q,SH,H2,P,NC,G,NC,H7,K
Triode,6C5,OCTAL,6Q,SH,H2,P,NC,G,NC,H7,K
Pentode,EF86,B9A,9CQ,G2,IS_1,K,H4,H5,P,IS_2,G3,G1
Pentode,6267,B9A,9CQ,G2,IS_1,K,H4,H5,P,IS_2,G3,G1
Pentode,5879,B9A,9AD,G1,NC,K,H4,H5,NC,G2,P,G3
Pentode,EF80,B9A,9AQ,K_1,G1,K_2,H4,H5,IS,P,G2,G3
Pentode,EF184,B9A,9AQ,K_1,G1,K_2,H4,H5,IS,P,G2,G3
Pentode,6AU6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Pentode,6BA6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Pentode,6AK5,B7G,7BD,G1,K_1,H3,H4,P,G2,K_2
Pentode,6SJ7,OCTAL,8N,SH,H2,G3,G1,K,G2,H7,P
Converter,12BE6,B7G,7CH,G1,K,H3,H4,P,G2,G3
Converter,6BE6,B7G,7CH,G1,K,H3,H4,P,G2,G3
Pentode (RF/IF),12BA6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Pentode (RF/IF),6BD6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Diode-Triode,12AV6,B7G,7BT,TG,K,H3,H4,2D,1D,TP
Diode-Triode,12AT6,B7G,7BT,TG,K,H3,H4,2D,1D,TP
Diode-Triode,6AV6,B7G,7BT,TG,K,H3,H4,2D,1D,TP
Diode-Triode,6AT6,B7G,7BT,TG,K,H3,H4,2D,1D,TP
Beam Tetrode,50C5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P
Rectifier,35W4,B7G,5BQ,NC,NC,H3,H4,P,HT,K
Converter,6SA7,OCTAL,8R,G5,H2,P,G2,G1,K,H7,G3
Converter,12SA7,OCTAL,8R,G5,H2,P,G2,G1,K,H7,G3
Pentode (RF/IF),6SK7,OCTAL,8N,SH,H2,G3,G1,K,G2,H7,P
Pentode (RF/IF),12SK7,OCTAL,8N,SH,H2,G3,G1,K,G2,H7,P
Pentode (RF/IF),6SG7,OCTAL,8BK,SH,H2,K_1,G1,K_2,G2,H7,P
Diode-Triode,6SQ7,OCTAL,8Q,SH,TG,K,2D,1D,TP,H7,H8
Diode-Triode,12SQ7,OCTAL,8Q,SH,TG,K,2D,1D,TP,H7,H8
Beam Tetrode,50L6GT,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Rectifier,35Z5GT,OCTAL,6AD,NC,H2,HT,NC,P,NC,H7,K
Converter,ECH81,B9A,9CA,HG2,HG1,K,H4,H5,HP,HG3,TP,TG
Converter,ECH83,B9A,9CA,HG2,HG1,K,H4,H5,HP,HG3,TP,TG
Converter,UCH81,B9A,9CA,HG2,HG1,K,H4,H5,HP,HG3,TP,TG
Pentode (RF/IF),EF85,B9A,9AQ,K_1,G1,K_2,H4,H5,IS,P,G2,G3
Diode-Pentode,EBF89,B9A,9HE,PG2,PG1,K,H4,H5,PP,1D,2D,PG3
Diode-Pentode,UBF89,B9A,9HE,PG2,PG1,K,H4,H5,PP,1D,2D,PG3
Diode-Triode,EABC80,B9A,9E,3D,2D,2DK,H4,H5,1D,K,TG,TP
Triode-Pentode,UCL82,B9A,9EX,TG,PK,PG1,H4,H5,PP,PG2,TK,TP
Tuning Indicator,EM84,B9A,9GA,G,IC,K,H4,H5,TA,DE,IC,P
Tuning Indicator,EM80,B9A,9DB,G,K,IC,H4,H5,IC,P,IC,TA
Tuning Indicator,EM81,B9A,9DB,G,K,IC,H4,H5,IC,P,IC,TA
Tuning Indicator,6AF6,OCTAL,7AG,NC,H2,2RC,1RC,TA,NC,H7,K
Tuning Indicator,1629,OCTAL,7AL,NC,H2,P,TA,G,NC,H7,K
Space-Charge,12K5,B7G,7FD,K,G2,H3,H4,G1_1,G1_2,P
Space-Charge,12AD6,B7G,7CH,G1,K,H3,H4,P,G2,G3
Space-Charge,12EG6,B7G,7CH,G1,K,H3,H4,P,G2,G3
Space-Charge,12AF6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Space-Charge,12CX6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Space-Charge,12DZ6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Space-Charge,12EK6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Space-Charge,12AC6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Space-Charge,12BL6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Space-Charge,12AE6,B7G,7BT,TG,K,H3,H4,2D,1D,TP
Space-Charge,12FM6,B7G,7BT,TG,K,H3,H4,2D,1D,TP
Space-Charge,12FK6,B7G,7BT,TG,K,H3,H4,2D,1D,TP
Space-Charge,12EL6,B7G,7FB,TG,TP,H3,H4,2D,1D,K
Space-Charge,12FX8,B9A,9KV,HG2,HG1,HP,H4,H5,TG,HK,TP,HG3
Space-Charge,12DS7,B9A,9JU,2D,NC,G1,H4,H5,P,G2,K,1D
Space-Charge,12EM6,B9A,9HV,G1,K,G2,H4,H5,P,IC,IC,D
Space-Charge,12J8,B9A,9GC,G1,K,G2,H4,H5,P,DK,2D,1D
Space-Charge,12DL8,B9A,9HR,2D,K,G1,H4,H5,P,G2,DK,1D
Power Pentode,EL84,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2
Power Pentode,6BQ5,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2
Power Pentode,7189,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2
Power Pentode,7189A,B9A,9LE,G1_1,G1_2,K,H4,H5,G2_1,P,IC,G2_2
Power Pentode,6CW5,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2
Power Pentode,EL86,B9A,9CV,IC,G1,K,H4,H5,IC,P,IC,G2
Beam Tetrode,6V6GT,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6V6,OCTAL,7AC,SH,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6L6GC,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6L6,OCTAL,7AC,SH,H2,P,G2,G1,NC,H7,K
Beam Tetrode,5881,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,7581A,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,KT66,OCTAL,7AC,IC,H2,P,G2,G1,NC,H7,K
Power Pentode,EL34,OCTAL,8ET,G3,H2,P,G2,G1,NC,H7,K
Power Pentode,6CA7,OCTAL,8ET,G3,H2,P,G2,G1,NC,H7,K
Beam Tetrode,KT88,OCTAL,7AC,SH,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6550,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,KT120,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,KT150,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Power Pentode,7591,OCTAL,8KG,NC,H2,P,G2_1,K,G1,H7,G2_2
Beam Tetrode,6AQ5,B7G,7BZ,G1_1,K,H3,H4,P,G2,G1_2
Beam Tetrode,6BF5,B7G,7BZ,G1_1,K,H3,H4,P,G2,G1_2
Beam Tetrode,50B5,B7G,7BZ,G1_1,K,H3,H4,P,G2,G1_2
Beam Tetrode,6973,B9A,9EU,G2_1,NC,G1_1,H4,H5,G1_2,K,G2_2,P
Beam Tetrode,12AB5,B9A,9EU,G2_1,NC,G1_1,H4,H5,G1_2,K,G2_2,P
Triode-Pentode,6BM8,B9A,9EX,TG,PK,PG1,H4,H5,PP,PG2,TK,TP
Triode-Pentode,ECL82,B9A,9EX,TG,PK,PG1,H4,H5,PP,PG2,TK,TP
Triode-Pentode,ECL86,B9A,9LZ,TG,TK,PG2,H4,H5,PP,PK,PG1,TP
Triode-Pentode,6GW8,B9A,9LZ,TG,TK,PG2,H4,H5,PP,PK,PG1,TP
Power Pentode,6F6G,OCTAL,7S,NC,H2,P,G2,G1,NC,H7,K
Power Pentode,6K6GT,OCTAL,7S,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6Y6G,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6AS5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P
Beam Tetrode,6CU5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P
Beam Tetrode,35C5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P
Power Pentode,6EH5,B7G,7CV,K,G1_1,H3,H4,G1_2,G2,P
Beam Tetrode,6CZ5,B9A,9HN,G2,NC,G1_1,H4,H5,G1_2,K,IC,P
Beam Tetrode,6EM5,B9A,9HN,G2,NC,G1_1,H4,H5,G1_2,K,IC,P
Beam Tetrode,6BW6,B9A,9AM,IC,G1,K,H4,H5,NC,P,G2,BP
Power Pentode,6DL5,B7G,7DQ,G1_1,K,H3,H4,P,G2,G1_2
Power Pentode,EL95,B7G,7DQ,G1_1,K,H3,H4,P,G2,G1_2
Power Pentode,6AK6,B7G,7BK,G1,G3,H3,H4,P,G2,K
Power Pentode,6AR5,B7G,6CC,G1,K,H3,H4,P,G2,NC
Beam Tetrode,6CM6,B9A,9CK,G2,NC,G1_1,H4,H5,G1_2,K,NC,P
Power Pentode,6CL6,B9A,9BV,K,G1_1,G2_1,H4,H5,P,G3,G2_2,G1_2
Rectifier,5AR4,OCTAL,5L,IC,H2,NC,1P,NC,2P,NC,HK8
Rectifier,GZ34,OCTAL,5L,IC,H2,NC,1P,NC,2P,NC,HK8
Rectifier,5V4G,OCTAL,5L,NC,H2,NC,1P,NC,2P,NC,HK8
Rectifier,GZ32,OCTAL,5L,NC,H2,NC,1P,NC,2P,NC,HK8
Rectifier,5Y3GT,OCTAL,5T,NC,F2,NC,2P,NC,1P,NC,F8
Rectifier,5U4GB,OCTAL,5T,NC,F2,NC,2P,NC,1P,NC,F8
Rectifier,EZ81,B9A,9M,1P,IC,K,H4,H5,IC,2P,IC,IC
Rectifier,EZ80,B9A,9M,1P,IC,K,H4,H5,IC,2P,IC,IC
Rectifier,6CA4,B9A,9M,1P,NC,K,H4,H5,NC,2P,NC,NC
Rectifier,6X4,B7G,7CF,2P,NC,H3,H4,NC,1P,K
Rectifier,6X5GT,OCTAL,6S,NC,H2,2P,NC,1P,NC,H7,K
Rectifier,6X5,OCTAL,6S,SH,H2,2P,NC,1P,NC,H7,K
Rectifier,6AX5GT,OCTAL,6S,NC,H2,2P,NC,1P,NC,H7,K
Voltage Reference,0A2,B7G,5BO,P_1,K_1,IC,K_2,P_2,IC,K_3
Voltage Reference,0B2,B7G,5BO,P_1,K_1,IC,K_2,P_2,IC,K_3
Voltage Reference,0D3,OCTAL,4AJ,NC,K,J_1,NC,P,NC,J_2,NC
Voltage Reference,0C3,OCTAL,4AJ,NC,K,J_1,NC,P,NC,J_2,NC
Voltage Reference,0A3,OCTAL,4AJ,NC,K,J_1,NC,P,NC,J_2,NC
Dual Triode,6N2P-EV,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS
Dual Triode,6N1P-EV,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS
Dual Triode,6N6P,B9A,-,1P,1G,1K,H4,H5,2P,2G,2K,IS
Dual Triode,6N23P,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,6N23P-EV,B9A,9AJ,2P,2G,2K,H4,H5,1P,1G,1K,IS
Dual Triode,6N24P,B9A,-,2K,2G,2P,H4,H5,1G,1K_1,1K_2,1P
Dual Triode,6N3P,B9A,-,H1,1K,1G,1P,IS,2P,2G,2K,H9
Dual Triode,6N8S,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Dual Triode,6N9S,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Dual Triode,6N13S,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Dual Triode,6N5S,OCTAL,8BD,2G,2P,2K,1G,1P,1K,H7,H8
Triode,6S45P,B9A,-,K_1,G_1,K_2,H4,H5,K_3,P,G_2,K_4
Power Triode,6S19P,B9A,-,P_1,G_1,P_2,H4,H5,P_3,G_2,P_4,K
Power Triode,6S4S,OCTAL,5S,NC,F2,P,NC,G,NC,F7,NC
Pentode,6Zh32P,B9A,9CQ,G2,IS_1,K,H4,H5,P,IS_2,G3,G1
Pentode,6Zh1P,B7G,-,G1,K_1,H3,H4,P,G2,K_2
Power Pentode,6P14P,B9A,9CV,NC,G1,K,H4,H5,NC,P,NC,G2
Power Pentode,6P14P-EV,B9A,9CV,NC,G1,K,H4,H5,NC,P,NC,G2
Power Pentode,6P18P,B9A,9CV,NC,G1,K,H4,H5,NC,P,NC,G2
Power Pentode,6P15P,B9A,-,G3_1,G1,K,H4,H5,G3_2,P,NC,G2
Power Pentode,EL91,B7G,-,G1,K,H3,H4,P,NC,G2
Power Pentode,6AM5,B7G,-,G1,K,H3,H4,P,NC,G2
Beam Tetrode,6P1P,B9A,-,P_1,G2_1,K_1,H4,H5,P_2,G1,K_2,G2_2
Beam Tetrode,6P3S,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6P3S-E,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6P6S,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Beam Tetrode,6P27S,OCTAL,7AC,NC,H2,P,G2,G1,NC,H7,K
Rectifier,5C3S,OCTAL,5T,NC,F2,NC,2P,NC,1P,NC,F8
Rectifier,5C4S,OCTAL,5L,NC,H2,NC,1P,NC,2P,NC,HK8
Rectifier,6C4P,B7G,-,1P,NC,H3,H4,K,NC,2P
@@ -0,0 +1,117 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2025 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components.tube;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.diylc.netlist.Node;
import org.diylc.presenter.DatasheetService;
import org.junit.Assert;
import org.junit.Test;
public class TubeSocketDatasheetTest {
private static final int FIRST_PIN_COLUMN = 4;
private static final Set<String> UNUSED_PIN_NAMES =
new HashSet<String>(Arrays.asList("NC", "IC", "SH"));
@Test
public void everyRowNamesEveryPinOfItsBase() {
for (String[] row : datasheet()) {
TubeSocket socket = new TubeSocket(row);
String context = String.join(",", row);
Assert.assertEquals(context, row[1], socket.getValue());
// control point 0 is the socket centre
Assert.assertEquals(context, row.length - FIRST_PIN_COLUMN,
socket.getControlPointCount() - 1);
}
}
@Test
public void designationsAreUnique() {
Set<String> tubes = new HashSet<String>();
for (String[] row : datasheet()) {
Assert.assertTrue("repeated tube " + row[1], tubes.add(row[1].toUpperCase()));
}
}
/** Two pins share a net only when both say so with a numbered suffix, like K_3 and K_8. */
@Test
public void pinsShareANetOnlyThroughTheSuffix() {
for (String[] row : datasheet()) {
for (int i = FIRST_PIN_COLUMN; i < row.length; i++) {
for (int j = i + 1; j < row.length; j++) {
String rail = Node.railName(row[i]);
if (rail != null && rail.equals(Node.railName(row[j]))) {
Assert.assertTrue(row[1] + " pins " + row[i] + " and " + row[j],
row[i].matches(".*_\\d+") && row[j].matches(".*_\\d+"));
}
}
}
}
}
/** A basing code fixes what each pin is, so every tube on one basing names its pins alike. */
@Test
public void tubesOnOneBasingNameTheirPinsAlike() {
Map<String, String[]> byBasing = new HashMap<String, String[]>();
for (String[] row : datasheet()) {
// "-" marks a tube with no RETMA basing, e.g. most Soviet types
if (row[3].equals("-")) {
continue;
}
String key = row[2] + " " + row[3];
String[] names = Arrays.copyOfRange(row, FIRST_PIN_COLUMN, row.length);
// a basing fixes the electrodes; an unused pin is the metal shell, a no-connect or an
// internal connection depending on the envelope and the maker
for (int i = 0; i < names.length; i++) {
if (UNUSED_PIN_NAMES.contains(names[i])) {
names[i] = "unused";
}
}
String[] first = byBasing.putIfAbsent(key, names);
if (first != null) {
Assert.assertArrayEquals(row[1] + " on " + key, first, names);
}
}
}
@Test
public void tubeIsFoundByTypeNotByGroup() {
DatasheetService service = DatasheetService.getInstance();
String[] first = datasheet().get(0);
Assert.assertEquals(1, service.findSeries(TubeSocket.class, first[1]).size());
Assert.assertTrue(service.findSeries(TubeSocket.class, first[0]).isEmpty());
}
private static List<String[]> datasheet() {
List<String[]> datasheet = DatasheetService.getInstance().loadDatasheet(TubeSocket.class);
Assert.assertNotNull(datasheet);
Assert.assertFalse(datasheet.isEmpty());
return datasheet;
}
}
@@ -0,0 +1,49 @@
/*
DIY Layout Creator (DIYLC).
Copyright (c) 2009-2025 held jointly by the individual authors.
This file is part of DIYLC.
DIYLC is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
DIYLC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with DIYLC. If not, see <http://www.gnu.org/licenses/>.
*/
package org.diylc.components.tube;
import org.diylc.components.tube.TubeSocket.Base;
import org.diylc.components.tube.TubeSocket.Mount;
import org.diylc.core.Angle;
import org.junit.Assert;
import org.junit.Test;
public class TubeSocketTest {
@Test
public void modelSetsBaseLabelsAndDesignation() {
TubeSocket socket = new TubeSocket();
socket.setMount(Mount.PCB);
socket.setAngle(Angle.of(45));
socket.applyModel(new String[] {"Power Pentode", "TEST", "OCTAL", "8XX", "NC", "H2", "P",
"G2", "G1", "NC", "H7", "K"});
Assert.assertEquals("TEST", socket.getValue());
Assert.assertEquals(Base.OCTAL, socket.getBase());
Assert.assertEquals("NC,H2,P,G2,G1,NC,H7,K", socket.getElectrodeLabels());
Assert.assertEquals(Mount.PCB, socket.getMount());
Assert.assertEquals(Angle.of(45), socket.getAngle());
// control point 0 is the socket centre, so pin 1 is control point 1
Assert.assertEquals("H2", socket.getControlPointNodeName(2));
Assert.assertEquals("K", socket.getControlPointNodeName(8));
}
}
+212
View File
@@ -0,0 +1,212 @@
# Tube Socket Datasheets
Naming every electrode of a `TubeSocket` from the tube that plugs into it.
## 1. Goal
Follows [DIP IC Pin Names](dip-ic-pin-names.md) and [Transistor Pinouts](transistor-pinouts.md). A
tube socket already carries a free-text "Electrode Labels" property, and every consumer reads it
through `getControlPointNodeName`: the netlist, hover tooltips, the AI project context and the
schematic view. In practice it is almost never filled in. Of 95 tube sockets in the sample corpus,
the user typed a designation on about half (12AY7 24 times, 6L6GT, 5Y3, KT88, 12AX7) but real
electrode names on only four; the rest carry the default `1,2,...,9`. A datasheet of the tubes
DIYers use (guitar amps, hi-fi, radio) sets the base, the electrode names and the designation in one
step, from the toolbox or from the AI.
### What is wrong today
Pins of one component that share a name are one net (`NetlistBuilder`, `Node.railName`). The six
factory variants that carry electrode names break that rule:
| Variant | Labels | Effect in the netlist |
|---|---|---|
| Chassis Noval 9A (12A?7) | `A,G,C,H,H,A,G,C,CT` | both anodes, both grids, both cathodes and both heater ends shorted together |
| Chassis Noval 9CV (EL84) | `n/c,G,C,H,H,n/c,P,n/c,S` | heater ends shorted; the three `n/c` pins joined (only `NC` and `RSV` are exempt) |
| Chassis Octal 5T | `n/c,H,n/c,P,n/c,P,n/c,H` | both rectifier plates shorted, filament ends shorted, `n/c` pins joined |
| Chassis Octal 7AC (6?6) | `n/c,H,P,S,G,n/c,H,C` | heater ends shorted, `n/c` pins joined |
| Chassis 7-pin 7BK | `G,IS,H,H,P,S,C` | heater ends shorted |
| Chassis Octal 8ET (EL34) | `IS,H,P,S,G,n/c,H,C` | heater ends shorted |
Heater ends are separate nets: a 12AX7 runs on 12.6 V across pins 4-5 or on 6.3 V with 4 and 5
joined against 9, and that choice is made by the wiring, not the tube.
## 2. Design decisions
| # | Decision | Choice | Rationale |
|---|---|---|---|
| V1 | Datasheet row | `group, tube, base, basing, name1, ..., nameN`, e.g. `Dual Triode,12AX7,B9A,9A,2P,2G,2K,H4,H5,1P,1G,1K,HCT`. `base` is a `TubeSocket.Base` constant; `basing` is the RETMA basing code, or `-` for a tube that has none (most Soviet types); the name count must equal the base's pin count | The trailing-names shape of the IC datasheets. The basing code is what tube data books print, so rows can be checked against them, and it lets a test assert that tubes sharing a basing share their names. |
| V2 | Model identity | `enableDatasheet = true`, `datasheetCreationStepCount = 2`, `datasheetModelColumn = 1` | The toolbox groups by family, the AI names the tube. |
| V3 | `applyModel` | Sets base, electrode labels and designation. Leaves mount, angle and colours alone | The datasheet says what the tube is, not how the user mounts the socket. |
| V4 | One row per tube | Equivalents get their own rows (12AX7, ECC83, 7025, 5751; 6L6GC, 5881, KT66), as the ICs list TL072 and NE5532 separately | Users and the AI look a tube up by the number printed on it. |
| V5 | Electrode names | Role letters as in American data books: `P` plate, `G` grid of a triode, `G1`/`G2`/`G3` control, screen and suppressor grids, `K` cathode, `BP` beam plates, `IS` internal shield, `SH` the metal shell or base sleeve (pin 1 of metal and GT octals), `HCT` heater centre tap. A tube with two or more sections puts the section number first, as the ICs do: `1P`, `1G`, `1K`, `2P` (and `T`/`P` prefixes for triode-pentodes: `TP`, `TG`, `PG1`) | Section-first keeps `G1` meaning control grid, never "grid of section 1". |
| V6 | Heater and filament ends | Named after their pin: `H4`, `H5` on a noval, `H2`, `H7` on an octal. A directly heated filament, which is also the cathode, is `F2`/`F8`. The `_n` suffix is never used for them | Each end is its own net (§1). Naming by pin follows `VCC+1`/`VCC+5` on the LM3886, the precedent for repeated roles that the package does not join. |
| V7 | Joined pins | A repeated name with the `_n` suffix, numbered by occurrence as on the ICs, only where the data book says the pins are connected inside the tube (e.g. the EF80 cathode on pins 1 and 3, `K_1`/`K_2`) | Same rule as the ICs, so `NetlistBuilder` joins exactly what the tube joins. |
| V8 | Unused pins | `NC` for no connection. Pins the data book marks "IC" (internal connection - do not use as a tie point) are `IC`, and `IC` joins `NC` and `RSV` in `Node.NON_NET_NAMES` | Several `IC` pins on one tube must not become one net. One-line core change. |
| V9 | Factory variants | The six named variants of §1 are retired (`deletedOn`), as the DIP8/DIP16 and resistor variants were; the four plain ones (PCB/Chassis Noval/Octal) stay as mount presets | The datasheet replaces them with correct names; leaving them would keep handing out shorted netlists. |
| V11 | Drawn labels | Drawn through `AbstractMakerBoard.getDisplayPinLabel`, so `G1_1` shows as `G1` and parenthesised notes are dropped, as on the ICs; node names keep the suffix | Joined pins carry one role; printing the suffix crowded small sockets (6S19P). |
| V12 | Equivalents on one basing | A tube given a RETMA basing takes that basing's names, including its section numbers, even where its own data sheet numbers the units the other way (6N8S and 6N9S use the 6SN7's); tubes with no RETMA code keep their sheet's numbering | Swapping a 6N8S for a 6SN7 must not relabel the socket; section numbers are labels, the pin grouping is identical. |
| V10 | Existing projects | Unchanged. A project placed from a retired variant keeps its labels and its shorted nets; nothing rewrites user data | Labels are user data. The release note can say how to re-apply a model. |
### Explicitly out of scope
- `Jumbo4PinTubeSocket` (fixed `G,F1,P,F2` for 211/805/845) and the UX4 base of 300B, 2A3 and 45:
a 4-pin base is not a `TubeSocket.Base`. Candidate for a second phase.
- Magnoval (B9D: EL509, PL519), loctal and the B12C compactrons: no datasheet rows until a user
asks; B12C exists as a base but few DIY tubes use it.
- `SubminiTube` and the tube schematic symbols.
- Translating group names, as for the ICs and transistors.
## 3. Changes
### diylc-core
- `Node.NON_NET_NAMES`: add `IC` (V8).
- `import-defaults/variants.xml`: retire the six named `TubeSocket` variants (V9).
### diylc-library
- `TubeSocket`: `implements IDatasheetSupport`, descriptor attributes (V2), `applyModel` (V3), a
`TubeSocket(String[] model)` constructor. `@AiNote` extended with the naming rules of V5-V8 and
the datasheet model.
- `datasheets/TubeSocket.datasheet`: rows per V1, each read from a manufacturer data sheet or a
tube data book (RCA, GE, Sylvania, Tung-Sol, Philips/Mullard, JJ, Svetlana, Electro-Harmonix), or
two independent agreeing sources.
### Generated
- `catalog_full.json` regenerated; `pinout-drivers.txt` updated if the analyzer starts reporting
"Electrode Labels" differently.
## 4. Datasheet inventory
`TubeSocket.datasheet` small-signal rows, 46 tubes:
| Group | Basing | Tubes |
|---|---|---|
| Dual Triode | 9A | 12AX7, ECC83, 7025, 5751, 12AT7, ECC81, 12AU7, ECC82, 12AY7, 6072, 12BH7, 12DW7, 12AZ7, 5965, ECC99 |
| Dual Triode | 9AJ | 6922, E88CC, 6DJ8, ECC88, 7308, 6CG7, ECC85 |
| Dual Triode | 9LP / 9H / - | 6FQ7 / 5687 / 6N1P, 6N2P, 6H30P |
| Dual Triode | 8BD | 6SN7, 6SL7, 6080, 6AS7, 6BX7, 6BL7 |
| Triode | 9AG / 6Q | 12B4A / 6J5, 6C5 |
| Pentode | 9CQ / 9AD / 9AQ | EF86, 6267 / 5879 / EF80, EF184 |
| Pentode | 7BK / 7BD / 8N | 6AU6, 6BA6 / 6AK5 / 6SJ7 |
Small-signal sourcing notes:
- Read from RCA, Tung-Sol, GE, Sylvania, Philips, Brimar and JJ sheets (frank.pocnet.net mirror,
tubebooks.org) cross-checked against TDSL basing codes. 6SL7, 6080, 6BL7, 6BA6 and 6C5 rest on
their basing code without the sheet opened; 6H30P on a blurry lead drawing - the weakest rows.
- Lookalikes that differ: 6FQ7 has pin 9 NC, not a shield, so it is 9LP, not 6CG7's 9AJ; 5687 is
not a 12AU7 (plate 1 on pin 9, centre tap on pin 8); 6N2P has a shield on pin 9 and no centre tap,
so it is not a 12AX7; 6N1P has the 9AJ functions but its sheet numbers the units the other way.
- 12DW7: unit 1 (pins 6-8) is the 12AX7-like section, unit 2 (pins 1-3) the 12AU7-like one.
- Left out: 6C45P (no pin list found), 6N8S (said to equal 6SN7, unit order unconfirmed), 6SF5.
`TubeSocket.datasheet` radio rows, 54 tubes:
| Group | Tubes |
|---|---|
| Converter | 12BE6, 6BE6, 6SA7, 12SA7, ECH81, ECH83, UCH81 |
| Pentode (RF/IF) | 12BA6, 6BD6, 6SK7, 12SK7, 6SG7, EF85 |
| Diode-Triode / Diode-Pentode | 12AV6, 12AT6, 6AV6, 6AT6, 6SQ7, 12SQ7, EABC80 / EBF89, UBF89 |
| Triode-Pentode | UCL82 |
| Beam Tetrode (radio output) | 50C5, 50L6GT |
| Rectifier | 35W4, 35Z5GT |
| Tuning Indicator | EM84, EM80, EM81, 6AF6, 1629 |
| Space-Charge | 12K5, 12AD6, 12EG6, 12AF6, 12CX6, 12DZ6, 12EK6, 12AC6, 12BL6, 12AE6, 12FM6, 12FK6, 12EL6, 12FX8, 12DS7, 12EM6, 12J8, 12DL8 |
`TubeSocket.datasheet` power, rectifier and reference rows, 63 tubes:
| Group | Tubes |
|---|---|
| Power Pentode | EL84, 6BQ5, 7189, 7189A, 6CW5, EL86, EL34, 6CA7, 7591, 6F6G, 6K6GT, 6EH5, 6DL5, EL95, 6AK6, 6AR5, 6CL6 |
| Beam Tetrode | 6V6GT, 6V6, 6L6GC, 6L6, 5881, 7581A, KT66, KT88, 6550, KT120, KT150, 6Y6G, 6AQ5, 6BF5, 50B5, 6973, 12AB5, 6AS5, 6CU5, 35C5, 6CZ5, 6EM5, 6BW6, 6CM6 |
| Triode-Pentode | 6BM8, ECL82, ECL86, 6GW8 |
| Rectifier | 5AR4, GZ34, 5V4G, GZ32, 5Y3GT, 5U4GB, EZ81, EZ80, 6CA4, 6X4, 6X5GT, 6X5, 6AX5GT |
| Voltage Reference | 0A2, 0B2, 0D3, 0C3, 0A3 |
Radio and power sourcing notes:
- Read from RCA, GE, Tung-Sol, Sylvania, Philips, Amperex, GEC/M-OV, JJ, Brimar and Svetlana sheets
(frank.pocnet.net), with TDSL as the second source. Where TDSL's basing code disagrees with the
printed data book the book wins: EL34 8ET (TDSL 8EP), 6X4 7CF (5BS), 6F6 7S (7AC), 7591 8KG
(Sylvania; TDSL 8KQ).
- A pin carrying several electrodes takes the main one's name: K for cathode + g3/beam plates/shield,
G3 for g3 + shield on 7BK, G5 for shell + g5 on 6SA7, H5 for heater end + triode cathode on 12FX8.
- Space-charge tubes follow each data book's grid numbering: on 12K5, 12DS7 and 12DL8 G1 is the
space-charge grid and G2 the control grid; on 12J8 and 12EM6 G1 is the control grid.
- Other names introduced: `HT` the panel-lamp heater tap on 35W4/35Z5GT (not a centre tap); `HK8`
the heater-cathode pin of 5AR4-type rectifiers; `J_1`/`J_2` the base jumper of octal regulators
(0A3/0C3/0D3), which opens the supply when the tube is pulled; `TA` target, `DE` deflection
electrode, `1RC`/`2RC` ray-control electrodes of tuning indicators; `DK` a separate diode cathode.
- Rectifier plate numbers follow each book: 5L (Amperex) has plate 1 on pin 4, 5T (RCA) plate 2.
- **KT88 conflict:** the row follows GEC (pin 1 base shell); JJ brings g3 out on pin 1.
- The same-basing test treats `NC`, `IC` and `SH` as interchangeable, because the unused pin 1 of a
basing is a shell, a no-connect or an internal connection depending on envelope and maker.
- Left out: EF89 (basing code and joined shield pins unconfirmed), 12DK6 (no sheet), metal 6F6
(shell pin assumed), 6V4 and 6005 (TDSL only), 6AV5 (octal TV sweep tube); 6E5 and 6U5 are on the
unsupported UX6 base - 1629 is their octal counterpart.
`TubeSocket.datasheet` Soviet rows and EL91, 30 tubes (6N1P and 6N2P are counted with the
small-signal rows):
| Group | Tubes |
|---|---|
| Dual Triode | 6N1P-EV, 6N2P-EV, 6N6P, 6N23P, 6N23P-EV, 6N24P, 6N3P, 6N8S, 6N9S, 6N13S, 6N5S |
| Triode / Power Triode | 6S45P / 6S19P, 6S4S |
| Pentode | 6Zh32P, 6Zh1P |
| Power Pentode | 6P14P, 6P14P-EV, 6P18P, 6P15P, EL91, 6AM5 |
| Beam Tetrode | 6P1P, 6P3S, 6P3S-E, 6P6S, 6P27S |
| Rectifier | 5C3S, 5C4S, 6C4P |
Soviet sourcing notes:
- Ranked by use in guitar and hi-fi DIY (6N2P, 6P14P, 6N23P, 6N1P, 6P3S, 6N8S lead); read from
Soviet reference sheets (magictubes.ru, r-type.org handbook scans, chipdip, radiolamps.ru) and
Voskhod/Svetlana/Sovtek sheets.
- Compatibility, never assumed: 6P14P and 6P18P are EL84 pinout; 6P15P is not (g3 + shield on pins 1
and 6); 6P3S/6P6S are 6L6/6V6 pinout; 6P27S fits an EL34 socket but is a 7AC beam tetrode, not
8ET; 6N8S/6N9S/6N13S/6N5S are 6SN7/6SL7/6AS7 pinout; 6N23P is 6922 pinout; 6N1P and 6N6P have the
9AJ functions but no RETMA code; 6Zh32P is EF86; 6Zh1P is close to 6AK5 but carries k + g3 +
shield on both pins 2 and 7; 6C4P is not a 6X4.
- 5C4S is indirectly heated with its cathode on pin 8, so it takes 5AR4's names. EL91/6AM5 is listed
as 7BZ by its source but does not match the 6AQ5, which is 7BZ, so its basing is left as `-`.
- Weakest rows: 6S19P and 6P27S (one sheet each), 6S45P (Sovtek sheet only), 5C3S and 6C4P (pinout
pictures without labels), 6P3S-E and the -EV grades (assumed identical to the base type).
- Left out: 6N30P (lead drawing unlabelled - the existing 6H30P row covers it), 6P43P, 6S41S,
6Zh52P, 6P9, 6Zh4 (not sourced or conflicting); 6S33S/6C33C, GU-50, GU-19, 6D22S and 6P45S sit on
bases `TubeSocket` does not have.
Rules for every row: names as in V5-V8; a part is added only after its basing diagram has been read
from a data book or manufacturer sheet, or from two independent sources; equivalents are listed only
where the basing is confirmed identical (the 6L6 family is not uniformly 7AC, and Russian
"equivalents" such as 6N1P are not pin-compatible with 6DJ8).
## 5. Tests
- `TubeSocketDatasheetTest`, after `SIL_ICDatasheetTest`: every row parses and applies; the name
count equals the base's pin count; designations are unique; within a row no two names share a net
unless both carry the `_n` suffix; rows sharing a basing code have identical names; `findSeries`
finds a tube and not a group.
- `TubeSocketTest`: `applyModel` sets base, labels and designation and leaves mount and angle;
`IC` and `NC` pins stay apart in the netlist.
## 6. Verification
- `mvn -q test` over the whole reactor (core and library change).
- Done: whole reactor passes (core 227, library 508, swing 29).
- Done: 12AX7, EL84, EL34, 5AR4, 6AQ5, 12K5, 0A2 and 6S19P rendered headlessly from the datasheet;
labels sit by their pins and fit once the suffix is dropped (V11).
- Regression suite: no rendering or netlist change is expected for existing projects (V10); the run
confirms it.
## 7. Phases
1. **Plan**: this document.
2. **Code**: done - V2, V3, V8 (`IC` in `Node.NON_NET_NAMES`, covered by `NodeNameTest`), V9 (six
variants retired 2026-11-02T14:00), `TubeSocketTest`, `TubeSocketDatasheetTest`, `@AiNote`s.
The datasheet test fails until the datasheet exists.
3. **Library**: done - 188 tubes (46 small-signal, 54 radio and space-charge, 58 power, rectifier
and reference, 30 Soviet and EL91). `catalog_full.json` regenerated; release notes in 6.10
(datasheet, and the shorted-variant fix).
4. **Later, on request**: the UX4/jumbo 4-pin bases (300B, 2A3, 211, 845), magnoval.