The orientation of directional couplers always confuses me, so I wrote some notes for myself to help me figure it out. Recently, I found out that I’m not alone—many of my colleagues are struggling with them as well. This motivated me to polish my notes and put them online. I hope you find them useful!
Often, directional couplers are drawn like this:
Or sometimes like this, with the coupled port confusingly on the other side:
Apart from the two symbols that are easy to mix up, I think the main source of confusion is that couplers have ports explicitly labeled “in” and “out”, but there are three different ways to use them, and the “in” and “out” labels only really apply in one configuration. When used for combining signals, the roles are actually completely reversed! Sometimes, the ports are labeled just P1, P2 and P3, but that’s even less meaningful in my opinion.
So here’s how to orient a directional coupler in all configurations. I’ve added the usual labels in parenthesis, so that you can compare to what’s written on your coupler.
The signal coming out of the coupled port is attenuated by the specified coupling of the coupler, usually 10 or 20 dB. For 10 dB coupling, 90% or about −0.46 dB of the power goes through port P2, and for 20 dB, 99% or about −0.044 dB goes through P2.
Note the reversed roles of “input” and “output”! The signal from the coupled port will be attenuated by the specified coupling. The rest of the power is absorbed in the terminated port.
Here also the input signal from the coupled port will be attenuated by the specified coupling. Usually we don’t care about that much, because the input power can be adjusted relatively freely in our measurements.
Here are just the couplers themselves if you want to use them in your own diagrams:
import schemdraw.elements as elm
from schemdraw.segments import (
Segment,
SegmentPoly,
SegmentArc,
)
class DirectionalCoupler1(elm.Element):
"""
Basic symbol
"""
= {
_element_defaults 'lblloc': 'bottom',
}def __init__(self, **kwargs):
super().__init__(**kwargs)
# width and height of box
= 1.5
w = 1.0
h = w - 0.3 # x position of coupled wire at the top of the box
wire_x = 0.3 # y position of horizontal wire
wire_y = 0.7 # radius of the rounded corner of the coupling
r
self.segments.append(SegmentPoly([(0, 0), (0, h), (w, h), (w, 0)]))
self.segments.append(Segment([(0, wire_y), (w, wire_y)]))
self.segments.append(
SegmentArc(=(wire_x - r, wire_y + r),
center=2 * r,
width=2 * r,
height=-90,
theta1=0,
theta2
)
)
self.anchors["input"] = (0, wire_y)
self.anchors["output"] = (w, wire_y)
self.anchors["cpl"] = (wire_x, h)
class DirectionalCoupler2(elm.Element):
"""
Terminated coupler
"""
= {
_element_defaults 'lblloc': 'bottom',
}def __init__(self, **kwargs):
super().__init__(**kwargs)
= 0.25 # space between wires and edge of box
ws = 1.0 # space between vertical wires
inner_w = 0.3 # space between horizontal wire and top of the box
inner_h = 0.2 # radius of the rounded corner of the coupling
r = 0.3 # size of the capping terminal
term_size = 0.25 # spacing between in/out wire and coupled wire
coupler_spacing
# total width of the box
= 2 * ws + inner_w
w # height of the box, excluding the terminator
= ws + coupler_spacing + r + inner_h
h # x coordinates of left and right wire
= ws
lx = w - ws
rx # y-coordinate of bottom endpoint of vertical wires
= coupler_spacing + ws + r
cpl_wire_y
self.segments.append(SegmentPoly([(0, 0), (0, h), (w, h), (w, 0)]))
self.segments.append(Segment([(0, ws), (w, ws)]))
# terminator
self.segments.append(Segment([
- 0.5 * term_size, h),
(rx - 0.5 * term_size, h + term_size),
(rx + 0.5 * term_size, h + term_size),
(rx + 0.5 * term_size, h),
(rx
]))
self.segments.append(Segment([(lx, cpl_wire_y), (lx, h)]))
self.segments.append(Segment([(rx, cpl_wire_y), (rx, h)]))
self.segments.append(
Segment([+ r, coupler_spacing + ws),
(lx - r, coupler_spacing + ws),
(rx
])
)self.segments.append(
SegmentArc(=(lx + r, cpl_wire_y),
center=2 * r,
width=2 * r,
height=180,
theta1=-90,
theta2
)
)self.segments.append(
SegmentArc(=(rx - r, cpl_wire_y),
center=2 * r,
width=2 * r,
height=-90,
theta1=0,
theta2
)
)
self.anchors["input"] = (0, ws)
self.anchors["output"] = (w, ws)
self.anchors["cpl"] = (lx, h)
from schemdraw.util import Point
def P(x, y):
return Point((x, y))
with schemdraw.Drawing(show=False) as d:
= DirectionalCoupler1()
dc
= 0.75 # arrow length
l = 0.15 # spacing between arrow and coupler
s = 0.1 # label offsets for in/out
oy
(="<-")
elm.Annotate(arrowinput + P(-s, 0))
.at(dc."In / P1", valign="center", halign="right", ofst=(-0.1, oy))
.label(=-l, dy=0)
.delta(dx
)
(="->", th2=270)
elm.Annotate(arrow+ P(s, 0))
.at(dc.output "Out / P2", valign="center", halign="left", ofst=(0.05, oy))
.label(=l, dy=0)
.delta(dx
)
(="->", th2=270)
elm.Annotate(arrow+ P(0, s))
.at(dc.cpl "Coupled / P3", valign="bottom", ofst=(0, 0.2))
.label(=0, dy=l)
.delta(dx
)
"my-coupler.svg") d.save(
The diagrams and code are licensed under CC-BY-SA 4.0 (the same license as Stack Overflow), so go ahead and grab a copy!
Thanks to Aashish Sah and Heikki Suominen for helpful comments.