Skip to content

Instantly share code, notes, and snippets.

@uwezi
Last active September 16, 2025 07:33
Show Gist options
  • Save uwezi/65d3a635674757388484e66c305ea29b to your computer and use it in GitHub Desktop.
Save uwezi/65d3a635674757388484e66c305ea29b to your computer and use it in GitHub Desktop.
[NPN transistor] Current flows in a common-emitter NPN transistor. #manim #animation #physics #electronics
Display the source blob
Display the rendered blob
Raw
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
version="1.1"
id="d:/xc/20250606_npn" width="100%" height="100%" viewBox="-6 -6 582 268">
<desc>
XCircuit Version 3.8
File "d:/xc/20250606_npn.eps" Page 1
</desc>
<g stroke="black">
<path d="M32,186 L32,176 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M32,208 L32,198 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M54,176 L54,160 " fill="none" stroke-width="3" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M46,168 L62,168 " fill="none" stroke-width="3" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M46,212 L62,212 " fill="none" stroke-width="3" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M50,198 L50,200 14,200 14,196 50,196 50,198 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M14,196 L50,196 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M50,196 L50,200 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M50,200 L14,200 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M14,200 L14,196 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M0,184 L0,186 64,186 64,184 0,184 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M0,184 L0,186 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M0,186 L64,186 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M64,186 L64,184 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M64,184 L0,184 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M544,98 L544,80 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M544,122 L544,110 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M544,146 L544,134 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M544,176 L544,158 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M566,88 L566,72 " fill="none" stroke-width="3" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M558,80 L574,80 " fill="none" stroke-width="3" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M558,172 L574,172 " fill="none" stroke-width="3" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,98 L512,100 576,100 576,98 512,98 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,98 L512,100 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,100 L576,100 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M576,100 L576,98 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M576,98 L512,98 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,122 L512,124 576,124 576,122 512,122 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,122 L512,124 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,124 L576,124 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M576,122 L512,122 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M576,124 L576,122 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,146 L512,148 576,148 576,146 512,146 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,146 L512,148 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M512,148 L576,148 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M576,146 L512,146 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M576,148 L576,146 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,108 L526,112 562,112 562,108 526,108 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,108 L526,112 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,112 L562,112 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M562,112 L562,108 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M562,108 L526,108 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,132 L526,136 562,136 562,132 526,132 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,132 L526,136 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,136 L562,136 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M562,132 L526,132 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M562,136 L562,132 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,156 L526,160 562,160 562,156 526,156 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,156 L526,160 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M526,160 L562,160 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M562,156 L526,156 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M562,160 L562,156 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M272,96 L272,160 " fill="none" stroke-width="4" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M272,112 L304,96 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M272,144 L304,160 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M272,128 L256,128 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M284,150 L286,146 296,156 282,154 284,150 " fill="#000000" stroke-width="0.2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M296,156 L286,146 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M296,156 L282,154 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M282,154 L286,146 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M32,176 L32,128 256,128 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M32,208 L32,256 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M0,256 L576,256 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M544,176 L544,256 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<path d="M304,160 L304,256 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
<ellipse cx="304" cy="256" rx="6" ry="6" fill="#000000" stroke="none" />
<ellipse cx="32" cy="256" rx="6" ry="6" fill="#000000" stroke="none" />
<ellipse cx="544" cy="256" rx="6" ry="6" fill="#000000" stroke="none" />
<path d="M544,80 L544,0 304,0 304,96 " fill="none" stroke-width="2" stroke-linejoin="bevel" stroke-linecap="round" stroke="#000000" />
</g>
</svg>
from manim import*
class AnalogMeter(VGroup):
def __init__(self,
value = 0,
width=4,
height=3.5,
corner_radius=0.5,
outer_stroke_width=5,
outer_stroke_color=GRAY,
frame_color=BLACK,
scale_aspect=4/2.5,
scale_background_color=0xffffcc,
scale_color=0x000099,
scale_range=[0,10,2],
scale_mtics=5,
scale_format="{:.0f}",
scale_fontsize=18,
scale_unit="mA",
scale_unit_fontsize=28,
scale_unit_pos=(0.5,0.4),
pointer_color=BLACK,
pointer_stroke_width=3,
frame_width=0.2,
**kwargs
):
self.frame = RoundedRectangle(
width=width, height=height,
corner_radius=corner_radius,
)
self.scale_background = RoundedRectangle(
width=width-2*frame_width, height=(width-2*frame_width)/scale_aspect,
corner_radius=corner_radius-frame_width if frame_width<corner_radius else 0.1,
fill_opacity=1.0, fill_color=scale_background_color,
stroke_width=0,
).set_z_index(0)
self.scale_background.shift(self.frame.get_top()-self.scale_background.get_top()+frame_width*DOWN)
self.frame = Difference(
self.frame,
self.scale_background
).set_stroke(
width=outer_stroke_width, color=outer_stroke_color,
).set_fill(
opacity=1.0, color=frame_color
).set_z_index(2)
self.pivot = VGroup(
Circle(
radius=frame_width/2,
stroke_width=outer_stroke_width/2, color=outer_stroke_color,
),
Line(
frame_width/2*LEFT,
frame_width/2*RIGHT,
stroke_width=outer_stroke_width,
).rotate(30*DEGREES)
).set_z_index(3)
self.pivot.shift((self.frame.get_bottom()+self.scale_background.get_bottom())/2-self.pivot[0].get_center())
self.value = ValueTracker(value)
self.pointer = Line(
ORIGIN,1.3*0.5*self.scale_background.width*RIGHT,
color = pointer_color,
stroke_width=pointer_stroke_width,
).shift(
self.pivot[0].get_center()
).rotate(
135*DEGREES, about_point=self.pivot[0].get_center()
).set_z_index(1)
self.scale_values = np.arange(start=scale_range[0],stop=scale_range[1]+scale_range[2]/2,step=scale_range[2])
self.scale_arc = VGroup(
Arc(
radius=0.9*self.pointer.get_length(),
start_angle=45*DEGREES,
angle=90*DEGREES,
arc_center=self.pivot.get_center(),
stroke_width=3,
stroke_color=scale_color,
),
*[
VGroup(
Line(
self.pointer.point_from_proportion(0.85),
self.pointer.point_from_proportion(0.95),
stroke_width=3,
stroke_color=scale_color,
),
MathTex(
scale_format.format(value),
font_size=scale_fontsize,
color=scale_color,
).rotate(45*DEGREES).shift(self.pointer.point_from_proportion(1))
).rotate(-i*90*DEGREES/(len(self.scale_values)-1), about_point=self.pivot.get_center())
for i,value in enumerate(self.scale_values)
],
*[
VGroup(
Line(
self.pointer.point_from_proportion(0.90),
self.pointer.point_from_proportion(0.95),
stroke_width=1,
stroke_color=scale_color,
),
).rotate(-(i+j/scale_mtics)*90*DEGREES/(len(self.scale_values)-1), about_point=self.pivot.get_center())
for i in range(len(self.scale_values)-1) for j in range(scale_mtics)
],
Tex(
scale_unit, font_size=scale_unit_fontsize,color=scale_color
).shift(
[
self.scale_background.get_left()[0]+scale_unit_pos[0]*self.scale_background.width,
self.scale_background.get_bottom()[1]+scale_unit_pos[1]*self.scale_background.height,
0
]
),
).set_z_index(1)
super().__init__(
self.frame,
self.scale_background,
self.pivot,
self.pointer,
self.scale_arc,
**kwargs
)
self.add_updater(self.updater, call_updater=True)
def updater(self, mobj):
newangle = 135*DEGREES-90*DEGREES*self.value.get_value()
self.pointer.rotate(
angle=newangle-self.pointer.get_angle(),
about_point=self.pivot[0].get_center()
)
def scale(self, scale_factor, scale_stroke = True, **kwargs):
return super().scale(scale_factor=scale_factor, scale_stroke=scale_stroke, **kwargs)
class metertest(Scene):
def construct(self):
ampmeter = AnalogMeter(scale_color=0x003399, scale_unit="µA", scale_range=[0,100,20])
voltmeter = AnalogMeter(scale_color=0xb30000, scale_unit="V").next_to(ampmeter,RIGHT)
self.add(ampmeter,voltmeter)
for _ in range(5):
self.play(
ampmeter.value.animate.set_value(np.random.uniform(0,1)),
voltmeter.value.animate.set_value(np.random.uniform(0,1)),
)
self.wait()
class Charge(Mobject):
def __init__(self, object=None, color=RED, symbol=r"\bfseries +", symbol_color=WHITE, diameter=0.2, trace=None, pos=0, speed=1, **kwargs):
super().__init__(**kwargs)
self.pos = pos
self.speed = speed
self.trace = trace
if object == None:
self.add(Dot(color=color, radius=diameter/2))
if symbol != None:
self.add(Tex(symbol, color=symbol_color).scale_to_fit_width(0.8*diameter))
else:
self.add(object.copy())
self.add_updater(self.updater, call_updater=True)
def updater(self, mobj, dt):
self.pos = (self.pos+dt*self.speed) % 1.0
self.move_to(self.trace.point_from_proportion(self.pos))
class carriers2(Scene):
def construct(self):
trace1 = RoundedRectangle(width=5,height=2.5, stroke_width=1).reverse_points().shift(2.5*LEFT+1.25*DOWN)
trace2 = RoundedRectangle(width=5,height=5, stroke_width=1).shift(2.5*RIGHT)
dia = .15
obj = VGroup(
Line(dia/2.4*LEFT, dia/2.4*RIGHT, stroke_width=dia*20, cap_style=CapStyleType.ROUND,color=WHITE).set_z_index(2),
Line(dia/2.4*DOWN, dia/2.4*UP, stroke_width=dia*20, cap_style=CapStyleType.ROUND,color=WHITE).set_z_index(2),
*[
Dot(radius=r, fill_opacity=1 if r<(dia/2) else np.exp(-(r-dia)/(dia/10)), color=PURE_RED)
for r in np.linspace(0,2*dia,30)
]
)
charges1 = Group(
*[
Charge(object=obj, trace=trace1, pos=i*1/10, speed=0.1)
for i in range(10)
]
)
charges2 = Group(
*[
Charge(object=obj, trace=trace2, pos=i*1/40, speed=0.1)
for i in range(40)
]
)
self.add(trace1, charges1, trace2, charges2)
self.wait(5)
class npn_currents(Scene):
def construct(self):
dia = .15
chrg = VGroup(
Line(dia/2.4*LEFT, dia/2.4*RIGHT, stroke_width=dia*20, cap_style=CapStyleType.ROUND,color=WHITE).set_z_index(2),
Line(dia/2.4*DOWN, dia/2.4*UP, stroke_width=dia*20, cap_style=CapStyleType.ROUND,color=WHITE).set_z_index(2),
*[
Dot(radius=r, fill_opacity=1 if r<(dia/2) else np.exp(-(r-dia)/(dia/10)), color=PURE_RED)
for r in np.linspace(0,2*dia,30)
]
)
#npl = NumberPlane().add_coordinates()
#self.add(npl)
schematics = SVGMobject("bilder/20250606_npn.svg").scale_to_fit_height(5)
schematics.set_color(WHITE)
self.add(schematics)
base_ameter = AnalogMeter(
value = 0.5,
scale_color=0x003399,
scale_unit="µA", scale_range=[0,100,20],
scale_fontsize=30,
scale_unit_fontsize=45,
).scale_to_fit_width(1.5).move_to([-3,0.4,0]).set_z_index(5)
base_vmeter = AnalogMeter(
value = .65,
scale_color=0xb30000,
scale_unit="V", scale_range=[0,1,0.2],
scale_format="{:.1f}",
scale_fontsize=30,
scale_unit_fontsize=45,
).scale_to_fit_width(1.5).move_to([-1.5,-1.2,0]).set_z_index(5)
base_vmeter_cables = VGroup(
Arrow(
[-1.5,-1,0],
[-1.5,schematics[60].get_end()[1],0],
buff=0,
color=RED,
),
Arrow(
[-1.5,-1,0],
[-1.5,schematics[62].get_center()[1],0],
buff=0,
color=RED,
),
).set_z_index(-2)
collector_ameter = AnalogMeter(
value=0.7,
scale_color=0x003399,
scale_unit="mA", scale_range=[0,10,2],
scale_fontsize=30,
scale_unit_fontsize=45,
).scale_to_fit_width(1.5).move_to([2.5,2.8,0]).set_z_index(5)
self.add(base_ameter, base_vmeter, collector_ameter,base_vmeter_cables)
wire_base = VMobject().set_points_as_corners(
[
schematics[0].get_bottom(),
*schematics[60].get_all_points(),
schematics[55].get_start(),
]
)
wire_baseemitter = VMobject().set_points_as_corners(
[
schematics[55].get_start(),
schematics[54].get_start(),
schematics[54].get_end(),
schematics[64].get_start(),
schematics[64].get_end(),
schematics[65].get_center(),
schematics[66].get_center(),
schematics[1].get_end(),
]
)
wire_collector = VMobject().set_points_as_corners(
[
schematics[15].get_start(),
schematics[15].get_end(),
*schematics[68].get_all_points(),
schematics[53].get_end(),
schematics[53].get_start(),
]
)
wire_collectoremitter = VMobject().set_points_as_corners(
[
schematics[53].get_start(),
schematics[54].get_start(),
schematics[54].get_end(),
schematics[65].get_center(),
schematics[67].get_center(),
schematics[18].get_end(),
]
)
charges1 = Group(
*[
Charge(object=chrg, trace=wire_base, pos=i*1/4, speed=0.2)
for i in range(4)
]
)
charges2 = Group(
*[
Charge(object=chrg, trace=wire_baseemitter, pos=i*1/5, speed=0.2)
for i in range(5)
]
)
charges3 = Group(
*[
Charge(object=chrg, trace=wire_collector, pos=i*1/20, speed=0.2)
for i in range(20)
]
)
charges4 = Group(
*[
Charge(object=chrg, trace=wire_collectoremitter, pos=i*1/20, speed=0.2)
for i in range(20)
]
)
self.add(charges1,charges2,charges3,charges4)
self.wait(5)
class index(Scene):
def construct(self):
for x in range(-7, 8):
for y in range(-4, 5):
if (x==0) and (y==0):
self.add(Dot(np.array([x, y, 0]),radius=0.03, color=RED))
else:
self.add(Dot(np.array([x, y, 0]),radius=0.03, color=DARK_GREY))
circuit = SVGMobject(r"bilder/20250606_npn.svg",
stroke_color=WHITE, stroke_width=3, fill_color=WHITE,width=10)
self.add(circuit)
#self.wait(2)
bbox = Rectangle(height=circuit.height, width=circuit.width).move_to(circuit.get_center(),ORIGIN)
bbox.scale(1.4)
loc = bbox.get_critical_point(UL)
w = bbox.width
h = bbox.height
cf = 2*w + 2*h
dl = cf / (len(circuit)+3)
dir = [dl,0,0]
edge = 0
positions = []
for i in range(len(circuit)):
positions.append(loc)
loc = loc + dir
if (edge == 0) and (loc[0] > bbox.get_critical_point(UP+RIGHT)[0]):
edge = 1
loc = loc - dir
dir = [0,-dl,0]
loc = loc + dir
if (edge == 1) and (loc[1] < bbox.get_critical_point(DOWN+RIGHT)[1]):
edge = 2
loc = loc - dir
dir = [-dl,0,0]
loc = loc + dir
if (edge == 2) and (loc[0] < bbox.get_critical_point(DOWN+LEFT)[0]):
edge = 3
loc = loc - dir
dir = [0,+dl,0]
loc = loc + dir
for i in range(len(circuit)):
shortest = 1e6
found = 0
for j in range(len(positions)):
dist = np.sqrt((circuit[i].get_center()[0]-positions[j][0])**2 + (circuit[i].get_center()[1]-positions[j][1])**2)
if dist < shortest:
shortest = dist
found = j
color = [BLUE,GREEN,RED,YELLOW,PURPLE][i%5]
circuit[i].set_color(color)
txt = Text("{}".format(i)).scale(0.15).move_to(positions[found]).set_color(color)
line = Line(circuit[i].get_center(),end=txt.get_center(), stroke_width=1).set_color(color)
self.add(Tex(r"S", font_size=10, color=color).move_to(circuit[i].get_start()))
self.add(Tex(r"E", font_size=10, color=color).move_to(circuit[i].get_end()))
self.add(line)
self.add(txt)
# self.wait(1)
positions.pop(found)

Animation of the current flow in a common-emitter connected NPN transistor. Work in progress...

npn_currents_ManimCE_v0 19 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment