Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added atopile/guides/parameters.mdx
Empty file.
1 change: 1 addition & 0 deletions videos/.python-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.13
3 changes: 3 additions & 0 deletions videos/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Videos Directory

This directory contains the source for video explainers for atopile.
Binary file added videos/__pycache__/main.cpython-313.pyc
Binary file not shown.
6 changes: 6 additions & 0 deletions videos/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def main():
print("Hello from videos!")


if __name__ == "__main__":
main()
1 change: 1 addition & 0 deletions videos/params-explainer/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
media/
Binary file not shown.
209 changes: 209 additions & 0 deletions videos/params-explainer/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
import numpy as np
from manim import (
BLUE,
DOWN,
LEFT,
ORANGE,
PINK,
PI,
RIGHT,
WHITE,
TAU,
UP,
Arrow,
ArrowTriangleFilledTip,
ArrowTip,
Brace,
Circle,
Create,
Dot,
FadeOut,
Group,
NumberLine,
Rectangle,
Scene,
Square,
Text,
Transform,
Line,
VMobject,
GREEN,
)
from manim.utils.space_ops import angle_of_vector


class SubsetIndicator(VMobject):
def __init__(
self,
start,
end,
tip_length=0.25,
tip_shape=ArrowTriangleFilledTip,
color=WHITE,
**kwargs,
):
super().__init__(**kwargs)

s = np.array(start)
e = np.array(end)

self.line = Line(s, e, color=color, **kwargs)

line_vector = e - s
if np.allclose(line_vector, np.zeros(3)):
# Handle cases where start and end points are the same
line_angle = 0.0
else:
line_angle = angle_of_vector(line_vector)

# Tip at start, pointing outwards (away from end)
self.tip_at_start = tip_shape(length=tip_length, color=color, **kwargs)
# Rotate tip to align correctly: line_angle + PI (opposite to line dir)
self.tip_at_start.rotate(line_angle + PI)
self.tip_at_start.move_to(s)

# Tip at end, pointing outwards (away from start)
self.tip_at_end = tip_shape(length=tip_length, color=color, **kwargs)
# Rotate tip to align correctly: line_angle (same as line dir)
self.tip_at_end.rotate(line_angle)
self.tip_at_end.move_to(e)

self.add(self.line, self.tip_at_start, self.tip_at_end)


class SupersetIndicator(VMobject):
def __init__(
self,
start,
end,
tip_length=0.25,
tip_shape=ArrowTriangleFilledTip,
color=WHITE,
**kwargs,
):
super().__init__(**kwargs)

s = np.array(start)
e = np.array(end)

self.line = Line(s, e, color=color, **kwargs)

line_vector = e - s
if np.allclose(line_vector, np.zeros(3)):
# Handle cases where start and end points are the same
line_angle = 0.0
else:
line_angle = angle_of_vector(line_vector)

# Tip at start, pointing inwards (towards end)
self.tip_at_start = tip_shape(length=tip_length, color=color, **kwargs)
# Rotate tip to align correctly: line_angle (same as line dir)
self.tip_at_start.rotate(line_angle)
self.tip_at_start.move_to(s)

# Tip at end, pointing inwards (towards start)
self.tip_at_end = tip_shape(length=tip_length, color=color, **kwargs)
# Rotate tip to align correctly: line_angle + PI (opposite to line dir)
self.tip_at_end.rotate(line_angle + PI)
self.tip_at_end.move_to(e)

self.add(self.line, self.tip_at_start, self.tip_at_end)


class Parameters(Scene):
def construct(self):
domain = NumberLine(
x_range=[2.5, 4, 0.1],
include_numbers=True,
font_size=24,
length=12,
)
self.play(Create(domain))
multimeter_dot = Dot(domain.n2p(3.3), color=BLUE)
self.play(Create(multimeter_dot))

self.wait(1)
self.next_section()
self.play(FadeOut(multimeter_dot))

power_supply_brace = Brace(
Group(domain.get_tick(3.1), domain.get_tick(3.5)), UP
)
power_supply_brace_text = Text("Power Supply Voltage", font_size=24).next_to(
power_supply_brace, UP
)
self.play(Create(power_supply_brace), Create(power_supply_brace_text))

braces = [power_supply_brace, power_supply_brace_text]

self.wait(1)
self.next_section()

microcontroller_brace = Brace(
(Group(domain.get_tick(3.2), domain.get_tick(3.4)).shift(DOWN * 0.5)), DOWN
)
microcontroller_brace_text = Text(
"Microcontroller Rated Voltage", font_size=24
).next_to(microcontroller_brace, DOWN)

braces.append(microcontroller_brace)
braces.append(microcontroller_brace_text)

self.play(Create(microcontroller_brace), Create(microcontroller_brace_text))

self.wait(1)
self.next_section()

multimeter_dot = Dot(domain.n2p(3.45), color=BLUE)
multimeter_annotation = Text("Oops!", font_size=24).next_to(
microcontroller_brace_text
)
multimeter_dot_arrow = Arrow(
multimeter_annotation.get_edge_center(UP), multimeter_dot.get_center()
)
self.play(Create(multimeter_dot))
self.play(Create(multimeter_dot_arrow), Create(multimeter_annotation))

self.wait(1)
self.next_section()

self.play(
FadeOut(multimeter_dot_arrow),
FadeOut(multimeter_annotation),
FadeOut(multimeter_dot),
)

# Add superset and subset constraints to the domain
superset = SupersetIndicator(domain.n2p(3.1), domain.n2p(3.5), color=ORANGE)
superset_title = Text("voltage ⊇ 3.1 to 3.5V", font_size=24, color=ORANGE)
and_title = Text("&&", font_size=24).next_to(superset_title, RIGHT)
subset = SubsetIndicator(domain.n2p(3.2), domain.n2p(3.4), color=GREEN)
subset_title = Text("voltage ⊆ 3.2 to 3.4V", font_size=24, color=GREEN).next_to(
and_title, RIGHT
)

title_group = (
Group(superset_title, and_title, subset_title).center().shift(UP * 2)
)

self.play(Create(subset), Create(subset_title))
self.wait(1)

self.play(Create(superset), Create(superset_title), Create(and_title))
self.wait(1)

self.play(FadeOut(b) for b in braces)

self.wait(1)

new_subset = SubsetIndicator(domain.n2p(2.7), domain.n2p(3.7), color=GREEN)
new_subset_title = Text(
"voltage ⊆ 2.7 to 3.7V", font_size=24, color=GREEN
).next_to(and_title, RIGHT)

self.play(
Transform(subset, new_subset),
Transform(subset_title, new_subset_title),
)

self.wait(1)
7 changes: 7 additions & 0 deletions videos/params-explainer/manim.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[CLI]
frame_rate = 30
pixel_height = 1080
pixel_width = 1920
background_color = BLACK
background_opacity = 1
scene_names = Default
43 changes: 43 additions & 0 deletions videos/params-explainer/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# Script

## Uncertainty

Let's check out a real-life parameter in your circuit - the voltage on your power rail.
You whip out your trusty cheap-o multimeter and check the voltage between vcc and gnd.

You see 3.3V {enter number line - mark 3.3V on the number line}

Perfect! Right?

Well... sometimes, but, often, not really. {fade out multimeter dot}

You know that right now, under these conditions, this specific power supply is putting out something around 3.3V, down to the precision of your power supply and multimeter.

For all of these reasons, we typically think of a measurement as having some **uncertainty** or range of possible values {number line add brace}
This represents the set of possible values this power supply will output, under rated conditions.

## Perspectives

Now, only the deepest of electronics nerds build a power supply for power-supply's sake! Let's plug it into this microcontroller. Annd... bang! There goes the blue smoke.

What happened? Well, doing my homework, it turns out that this microcontroller is only rated for this {add another brace} subset of voltages, and my multimeter is now saying the power supply is putting out {add dot} too much for it.

We need a good way to express two constraints of this voltage:
- The microcontroller needs the voltage to be within a range to operate correctly
- The power supply will, under rated conditions, output a voltage within this range, but we can't say exactly where

Looking at these as separate constraints, implies there is *something* that is constrained. In `atopile`, we refer to specific attributes of the design, like this voltage, as a `Parameter`.

With that, we can say:
- From the microcontroller: the voltage must be a **subset** of 3.2 to 3.3V
- From the power supply: the voltage is a **superset** of 3.1 to 3.5V

{fade out braces}

Now, this cannot be satisfied! There is a contradiction here. Which is exactly why the compiler will throw a contradiction error.

Instead, if buy a microcontroller with much more sane tolerances {widen microcontroller subset}, thing will work just fine.

## Correlation

Conveniently, this constraint-based thinking propagates super clearly too!
13 changes: 13 additions & 0 deletions videos/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[project]
name = "videos"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = ["manim>=0.19.0"]

[tool.ruff.format]
line-length = 88

[dependency-groups]
dev = ["ruff>=0.11.8"]
Loading
Loading