Those solder joints and finicky little wires seem much too fragile on their own:

This should help:

Foam blocks hold the ribbon cable in place and provide a bit of strain relief around the hard plastic edge:

The brass inserts in the bottom block (on the left) got epoxied in place, because they must provide quite a bit of force to clamp the foam. Their larger knurled end sits flush with the outside surface and the smaller end has one thread thickness of clearance below the inner surface.
A last look at the wiring:

I think the preamp must sit at some distance from the antenna to prevent feedback, but that remains to be seen.
The M2’s nozzle accumulated a huge blob of PETG that turned into a giant smear:

Fortunately, it’s on the inside where nobody will ever see it. If you know where to look, it’s barely visible from the outside.
The solid model shows off the structure a bit better:

The inside view:

The OpenSCAD source code as a GitHub Gist:
| // Ribbon cable loop antenna splice | |
| // Ed Nisley KE4ZNU December 2016 | |
| Layout = "Text"; | |
| //- Extrusion parameters must match reality! | |
| ThreadThick = 0.25; | |
| ThreadWidth = 0.40; | |
| HoleWindage = 0.2; | |
| Protrusion = 0.1; // make holes end cleanly | |
| inch = 25.4; | |
| function IntegerMultiple(Size,Unit) = Unit * ceil(Size / Unit); | |
| //———- | |
| // Dimensions | |
| Cable = [200,48.0,1.5]; // X = longer than anything else | |
| Splice = [15.0,53.0,5.0]; // epoxy blob around joints | |
| Foam = [15.0,Splice[1],2.0]; | |
| CornerRadius = 5.0; | |
| ID = 0; | |
| OD = 1; | |
| LENGTH = 2; | |
| Insert = [3.9,4.6 – 0.1,5.8]; // 4-40 knurled brass insert | |
| Screw = [2.7,5.5,2.0]; // OD = head LENGTH = head thickness | |
| Washer = [3.0,8.0,0.8]; | |
| BlockOA = [60.0, // convenient length | |
| Splice[1] + 4*Washer[OD], // clearance around washer on top | |
| 2*(Insert[LENGTH] + 2*ThreadThick)]; // insert sets both thicknesses | |
| NumScrews = 2; // screws along each side of cable | |
| ScrewOC = [BlockOA[0] / NumScrews, | |
| BlockOA[1] – 2*Washer[OD], | |
| 2*BlockOA[2] // ensure complete holes | |
| ]; | |
| TextThick = 3*ThreadThick; // depth of text into surface | |
| TextFit = HoleWindage/2; // clearance around text polygons | |
| //———————- | |
| // Useful routines | |
| module PolyCyl(Dia,Height,ForceSides=0) { // based on nophead's polyholes | |
| Sides = (ForceSides != 0) ? ForceSides : (ceil(Dia) + 2); | |
| FixDia = Dia / cos(180/Sides); | |
| cylinder(d=(FixDia + HoleWindage),h=Height,$fn=Sides); | |
| } | |
| //—– | |
| // Blocky model of cable + splice + wire tap for subtraction | |
| module Antenna() { | |
| union() { | |
| cube(Cable,center=true); | |
| cube(Splice,center=true); | |
| for (i=[-1,1]) | |
| translate([0,-Splice[1]/2,0]) | |
| cube([Splice[0]/2,Splice[1],2*Foam[2]],center=true); | |
| } | |
| } | |
| // Outside shape of splice Block, less screw clearance | |
| module SpliceBlock() { | |
| difference() { | |
| hull() | |
| for (i=[-1,1], j=[-1,1]) | |
| translate([i*(BlockOA[0]/2 – CornerRadius),j*(BlockOA[1]/2 – CornerRadius),-BlockOA[2]/2]) | |
| cylinder(r=CornerRadius,h=BlockOA[2],$fn=4*8); | |
| for (i = [0:NumScrews – 1], j=[-1,1]) | |
| translate([-BlockOA[0]/2 + ScrewOC[0]/2 + i*ScrewOC[0],j*ScrewOC[1]/2,-(BlockOA[2]/2 + Protrusion)]) | |
| PolyCyl(Screw[ID],BlockOA[2] + 2*Protrusion,6); | |
| } | |
| } | |
| // Splice block less cable | |
| module ShapedBlock() { | |
| difference() { | |
| SpliceBlock(); | |
| Antenna(); | |
| } | |
| } | |
| // Bottom | |
| module BottomPlate() { | |
| difference() { | |
| ShapedBlock(); | |
| translate([0,0,BlockOA[2]/2]) | |
| cube(BlockOA + 2*[Protrusion,Protrusion,0],center=true); | |
| Antenna(Splice); | |
| for (i = [0:NumScrews – 1], j=[-1,1]) | |
| translate([-BlockOA[0]/2 + ScrewOC[0]/2 + i*ScrewOC[0],j*ScrewOC[1]/2,-(BlockOA[2]/2 + Protrusion)]) | |
| PolyCyl(Insert[OD],2*Insert[LENGTH],6); | |
| for (i=[-1,1]) | |
| translate([i*((BlockOA[0] – Foam[0] + Protrusion)/2),0,(BlockOA[2]/2 – Cable[2]/2 – Foam[2])]) | |
| cube([Foam[0] + Protrusion,Foam[1],BlockOA[2]],center=true); | |
| } | |
| } | |
| // Top | |
| module TopPlate() { | |
| difference() { | |
| ShapedBlock(); | |
| translate([0,0,-BlockOA[2]/2]) | |
| cube(BlockOA + 2*[Protrusion,Protrusion,0],center=true); | |
| Antenna(Splice); | |
| for (i=[-1,1]) | |
| translate([i*((BlockOA[0] – Foam[0] + Protrusion)/2),0,-(BlockOA[2]/2 – Cable[2]/2 – Foam[2])]) | |
| cube([Foam[0] + Protrusion,Foam[1],BlockOA[2]],center=true); | |
| rotate(90) { | |
| translate([0,6,BlockOA[2]/2 – TextThick]) | |
| TextHack("KE4ZNU",8,0.0,1.15,TextThick + Protrusion); | |
| translate([0,-6,BlockOA[2]/2 – TextThick]) | |
| TextHack("2016·12",6,0.0,1.20,TextThick + Protrusion); | |
| } | |
| } | |
| } | |
| module TextHack(Text="sample",Size=10,Offset=0.0,Space=1.0,Thick=ThreadThick) { | |
| linear_extrude(height=Thick,convexity=10) | |
| offset(r=Offset) | |
| text(Text,font=":bold",size=Size,spacing=Space,halign="center",valign="center"); | |
| } | |
| //———- | |
| // Build them | |
| if (Layout == "Antenna") | |
| Antenna(); | |
| if (Layout == "SpliceBlock") | |
| SpliceBlock(); | |
| if (Layout == "ShapedBlock") | |
| ShapedBlock(); | |
| if (Layout == "Bottom") | |
| BottomPlate(); | |
| if (Layout == "Top") | |
| TopPlate(); | |
| if (Layout == "Text") { | |
| translate([0,6,0]) | |
| TextHack("KE4ZNU",8,-TextFit,1.15,TextThick); | |
| translate([0,-6,0]) | |
| TextHack("2016·12",6,-TextFit,1.20,TextThick); | |
| } | |
| if (Layout == "Show") { | |
| translate([0,0,5]) | |
| TopPlate(); | |
| translate([0,0,-5]) | |
| BottomPlate(); | |
| color("Orange",0.2) | |
| Antenna(); | |
| } | |
| if (Layout == "Build") { | |
| translate([0,-0.6*BlockOA[1],BlockOA[2]/2]) | |
| rotate([180,0,0]) | |
| TopPlate(); | |
| translate([0,0.6*BlockOA[1],BlockOA[2]/2]) | |
| BottomPlate(); | |
| } |












