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
w = 1.5
h = 1.0
wire_x = w - 0.3 # x position of coupled wire at the top of the box
wire_y = 0.3 # y position of horizontal wire
r = 0.7 # radius of the rounded corner of the coupling
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(
center=(wire_x - r, wire_y + r),
width=2 * r,
height=2 * r,
theta1=-90,
theta2=0,
)
)
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)
ws = 0.25 # space between wires and edge of box
inner_w = 1.0 # space between vertical wires
inner_h = 0.3 # space between horizontal wire and top of the box
r = 0.2 # radius of the rounded corner of the coupling
term_size = 0.3 # size of the capping terminal
coupler_spacing = 0.25 # spacing between in/out wire and coupled wire
# total width of the box
w = 2 * ws + inner_w
# height of the box, excluding the terminator
h = ws + coupler_spacing + r + inner_h
# x coordinates of left and right wire
lx = ws
rx = w - ws
# y-coordinate of bottom endpoint of vertical wires
cpl_wire_y = coupler_spacing + ws + r
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([
(rx - 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),
]))
self.segments.append(Segment([(lx, cpl_wire_y), (lx, h)]))
self.segments.append(Segment([(rx, cpl_wire_y), (rx, h)]))
self.segments.append(
Segment([
(lx + r, coupler_spacing + ws),
(rx - r, coupler_spacing + ws),
])
)
self.segments.append(
SegmentArc(
center=(lx + r, cpl_wire_y),
width=2 * r,
height=2 * r,
theta1=180,
theta2=-90,
)
)
self.segments.append(
SegmentArc(
center=(rx - r, cpl_wire_y),
width=2 * r,
height=2 * r,
theta1=-90,
theta2=0,
)
)
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:
dc = DirectionalCoupler1()
l = 0.75 # arrow length
s = 0.15 # spacing between arrow and coupler
oy = 0.1 # label offsets for in/out
(
elm.Annotate(arrow="<-")
.at(dc.input + P(-s, 0))
.label("In / P1", valign="center", halign="right", ofst=(-0.1, oy))
.delta(dx=-l, dy=0)
)
(
elm.Annotate(arrow="->", th2=270)
.at(dc.output + P(s, 0))
.label("Out / P2", valign="center", halign="left", ofst=(0.05, oy))
.delta(dx=l, dy=0)
)
(
elm.Annotate(arrow="->", th2=270)
.at(dc.cpl + P(0, s))
.label("Coupled / P3", valign="bottom", ofst=(0, 0.2))
.delta(dx=0, dy=l)
)
d.save("my-coupler.svg")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.