1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
|
import { format, number, type Choice, type Experiment, type Measurement, type Parameters, type Slider, type TestId } from './experiments';
import { type Charge } from './physics/electricField';
import { pairEnergy } from './physics/models';
import { assembledEnergy, centralWork, dipoleState, energyTransfer, uniformWork } from './physics/test4';
import questionUrl from '../docs/Test_4.md?url';
import answerUrl from '../docs/Test_Answers.md?url';
export { answerUrl };
export interface AnswerPart { title: string; steps: { why: string; math?: string }[] }
export interface TestLesson extends Experiment {
id: TestId;
points: number;
section: '4A' | '4B';
questions: string[];
answers: AnswerPart[];
prediction: string;
predictionAnswer: string;
observe: (p: Parameters) => string;
}
const slider = (id: string, label: string, min: number, max: number, step: number, value: number, unit: string): Slider => ({ kind: 'range', id, label, min, max, step, value, unit });
const choice = (id: string, label: string, value: string, options: [string, string][]): Choice => ({ kind: 'select', id, label, value, options: options.map(([value, label]) => ({ value, label })) });
const metric = (label: string, value: number, unit = 'nJ'): Measurement => ({ label, value: format(Math.abs(value) < 1e-10 ? 0 : value), unit });
const energy = (label: string, joules: number) => metric(label, joules * 1e9);
const radians = (degrees: number) => degrees * Math.PI / 180;
export const progress = (p: Parameters) => number(p, 'progress') / 100;
export const movingCharge = (p: Parameters) => number(p, 'q0') * 1e-9;
export function motionState(p: Parameters) {
const field = number(p, 'field');
const s = number(p, 'distance');
const angle = radians(number(p, 'angle') || 0);
const work = uniformWork(movingCharge(p), field, s, angle);
return { field, s, angle, work, dx: s * Math.cos(angle), dy: s * Math.sin(angle) };
}
export function centralState(p: Parameters) {
const q = number(p, 'source') * 1e-9, q0 = movingCharge(p);
const ra = number(p, 'ra');
const rb = p.destination === 'infinity' ? Infinity : number(p, 'rb');
return { q, q0, ra, rb, ua: pairEnergy(q, q0, ra), ub: rb === Infinity ? 0 : pairEnergy(q, q0, rb), work: centralWork(q, q0, ra, rb) };
}
export function conservationState(p: Parameters) {
const r = 1.2 + progress(p) * 4.3;
const q0 = movingCharge(p);
const ua = pairEnergy(3e-9, q0, 1.2), u = pairEnergy(3e-9, q0, r);
return { r, ua, u, ...energyTransfer(ua, u, number(p, 'kinetic') * 1e-9, 1e-6) };
}
export function assemblyCharges(p: Parameters): Charge[] {
const s = number(p, 'spacing');
return [
{ x: -s / 2, y: 0, z: -s / 3, coulombs: 3e-9 },
{ x: s / 2, y: 0, z: -s / 3, coulombs: -2e-9 },
{ x: 0, y: 0, z: s * 0.6, coulombs: 2e-9 },
{ x: 0, y: s * 0.8, z: 0, coulombs: movingCharge(p) },
];
}
export function assemblyState(p: Parameters) {
const charges = assemblyCharges(p), stage = Number(p.stage);
const base = assembledEnergy(charges.slice(0, 3));
const total = assembledEnergy(charges);
return { charges, stage, base, extra: total - base, current: assembledEnergy(charges.slice(0, stage)) };
}
export function rotationState(p: Parameters) {
const a = radians(number(p, 'thetaA')), b = radians(number(p, 'thetaB'));
const theta = a + (b - a) * progress(p);
const moment = number(p, 'charge') * 1e-9 * number(p, 'length');
const field = number(p, 'field');
return { a, b, theta, moment, field, ...dipoleState(moment, field, theta, a), endpointWork: dipoleState(moment, field, b, a).work };
}
const common = {
source: { title: 'Original question · Test_4.md', url: questionUrl },
legend: [['#ff967b', 'Positive charge'], ['#73d7ff', 'Negative charge'], ['#91e2cb', 'Electric field E'], ['#f5d58b', 'Path / force / energy']] as [string, string][],
};
const motionControls = [slider('q0', 'Moving charge q₀', -4, 4, 0.5, 2, 'nC'), slider('field', 'Electric field E', 0, 80, 5, 30, 'V/m'), slider('distance', 'Displacement s', 1, 6, 0.25, 4, 'm')];
const journey = () => slider('progress', 'Journey progress', 0, 100, 1, 35, '%');
export const testLessons: TestLesson[] = [
{
...common, id: 'test-work', title: 'Work along a path', shortTitle: 'Work & paths', points: 30, section: '4A',
description: 'Follow a charge from a to b. Only the component of force along each tiny step contributes to work.',
questions: [String.raw`What is the work done by the electric force, when $q_0$ is moved from a to b?`],
controls: [...motionControls, choice('path', 'Path shape', 'straight', [['straight', 'Straight path'], ['curved', 'Curved path · same endpoints']]), journey()],
equations: [String.raw`W_{ab} = \int_a^b \vec F_e\cdot\mathrm d\vec r = q_0\int_a^b \vec E\cdot\mathrm d\vec r`, String.raw`W_{ab} = U_a-U_b = q_0(V_a-V_b)`],
explanation: 'The dot product measures how much the electric force helps or opposes each step. Electrostatic work depends on the endpoints. Positive field work means a drop in electric potential energy.',
challenge: 'Switch between the two paths. Predict the final work before changing the moving charge from positive to negative.',
prediction: 'Does the longer, curved route require more work by the electric field?',
predictionAnswer: String.raw`No. In an electrostatic field, $W=U_a-U_b$. Both routes start and finish at the same positions. Sideways steps are perpendicular to $E$ and contribute no work. Any extra motion along $E$ cancels the motion back against $E$.`,
sceneNote: String.raw`Example: uniform $E$ along +x. Green arrows are $E$; the gold arrow is electric force. Both paths share a and b.`,
limits: String.raw`Electrostatic vacuum model; prescribed path, not a free-particle trajectory. Geometry is in metres; field and force arrows show direction with compressed lengths. The gold probe is scrubbed by journey progress; dotted endpoint markers stay fixed. Choose $U_a=0$.`,
measure: p => { const m = motionState(p); return [energy('Field work a → b', m.work), energy('Work to current position', m.work * progress(p)), energy('Potential energy Uᵦ', -m.work)]; },
observe: p => String.raw`${p.path === 'curved' ? 'The curved route adds sideways motion, but the final work stays the same.' : 'The straight route makes the force–displacement dot product easy to see.'} At b, the field does ${format(motionState(p).work * 1e9)} nJ of work; $U$ drops by that amount.`,
answers: [{ title: 'Question 1 · Work by the electric force · 30p', steps: [
{ why: 'Start with the definition of work: add the component of force along every small displacement.', math: String.raw`W_{ab} = \int_a^b\vec F_e\cdot\mathrm d\vec r` },
{ why: String.raw`Substitute the electric force on the moving charge, $\vec F_e=q_0\vec E$.`, math: String.raw`W_{ab} = q_0\int_a^b\vec E\cdot\mathrm d\vec r` },
{ why: 'The electrostatic force is conservative, so field work is the decrease in potential energy.', math: String.raw`W_{ab} = U_a-U_b = q_0(V_a-V_b)` },
] }],
},
{
...common, id: 'test-conservation', title: 'Where does the energy go?', shortTitle: 'Conservation', points: 15, section: '4A',
description: 'A positive charge moves away from a fixed positive source. Watch potential energy become kinetic energy.',
questions: ['Please write the condition for conservation of the total energy.'],
controls: [slider('q0', 'Moving charge q₀', 0.5, 4, 0.5, 2, 'nC'), slider('kinetic', 'Initial kinetic energy Kₐ', 0, 40, 1, 0, 'nJ'), journey()],
equations: [String.raw`\Delta E_{\mathrm{total}} = 0\quad\text{(isolated system)}`, String.raw`K_a+U_a = K_b+U_b`, String.raw`\Delta K = W_{ab} = -\Delta U`],
explanation: 'Total energy is conserved for an isolated system. If only the electric force does work on the moving charge, kinetic plus electric potential energy stays constant. The source is fixed; its support does no work.',
challenge: String.raw`Move the journey slider from 0% to 100%. Check that the total bar stays the same height as $K$ rises and $U$ falls.`,
prediction: 'If the particle starts at rest, can it gain speed without an energy supply?',
predictionAnswer: String.raw`Yes. Its initial electric potential energy supplies the increase in kinetic energy. Energy changes form while $K+U$ stays constant. The particle and source together are the electrostatic system; the moving particle alone does not have constant kinetic energy.`,
sceneNote: String.raw`Free radial motion away from +3 nC. Bars show $U$, $K$ and their constant sum; mass = 1 mg.`,
limits: String.raw`Source fixed, vacuum, nonrelativistic point particle of mass 1 mg. $U(\infty)=0$. Journey progress selects a position, not elapsed time; the speed is computed from energy, not from slider speed. Bar heights are normalized to the total energy; readouts are in nJ.`,
measure: p => { const s = conservationState(p); return [energy('Potential energy U', s.u), energy('Kinetic energy K', s.kinetic), energy('Total K + U', s.total), metric('Particle speed', s.speed, 'm/s')]; },
observe: p => { const s = conservationState(p); return String.raw`At $r$ = ${format(s.r)} m, $U$ = ${format(s.u * 1e9)} nJ and $K$ = ${format(s.kinetic * 1e9)} nJ. Their sum stays ${format(s.total * 1e9)} nJ. The work done so far is the increase in $K$.`; },
answers: [{ title: 'Question 2 · Conservation condition · 15p', steps: [
{ why: 'For an isolated system, no net energy crosses the system boundary.', math: String.raw`\Delta E_{\mathrm{total}} = 0` },
{ why: 'If the electric force is the only force doing work, the mechanical energy is conserved.', math: String.raw`K_a+U_a = K_b+U_b` },
{ why: String.raw`For a particle of mass $m$, substitute kinetic energy. The work–energy theorem connects the two changes.`, math: String.raw`\begin{aligned}\frac12 mv_a^2+U_a &= \frac12 mv_b^2+U_b\\\Delta K &= W_{ab} = -\Delta U\end{aligned}` },
] }],
},
{
...common, id: 'test-central', title: 'The field of a point charge', shortTitle: 'Central field', points: 55, section: '4A',
description: String.raw`Move $q_0$ radially through a central field. Connect the inverse-square force to an inverse-distance potential energy.`,
questions: [String.raw`When $q_0$ moves from a to b in an $E$-field from a point charge $q$ (“Central field”).`, 'a. (30p) Please derive the work done by the electric force.', String.raw`b. (25p) The work above is equal to the drop $U_a$ − $U_b$. What are $U_a$ and $U_b$ if $b\to\infty$?`],
controls: [slider('source', 'Source charge q', -4, 4, 0.5, 3, 'nC'), slider('q0', 'Moving charge q₀', -4, 4, 0.5, 2, 'nC'), slider('ra', 'Initial distance rₐ', 0.75, 4, 0.25, 1.5, 'm'), slider('rb', 'Final distance rᵦ', 0.75, 6, 0.25, 4.5, 'm'), choice('destination', 'Destination b', 'finite', [['finite', 'Finite final distance'], ['infinity', 'Infinity · final energy is zero']]), journey()],
equations: [String.raw`\vec E(r) = \frac{kq}{r^2}\hat r`, String.raw`W_{ab} = kqq_0\left(\frac1{r_a}-\frac1{r_b}\right)`, String.raw`U(r) = \frac{kqq_0}{r},\qquad U(\infty) = 0`],
explanation: String.raw`Only radial displacement contributes to work in a central field. Integrating $\frac1{r^2}$ gives $-\frac1r$. The zero at infinity fixes the energy reference; it is not an additional force law.`,
challenge: String.raw`Compare like and opposite charges. Send b to infinity and check that $W_{a\infty}=U_a$, including its sign.`,
prediction: String.raw`Is $U$ always positive when we choose $U(\infty)=0$?`,
predictionAnswer: String.raw`No. $U=\frac{kqq_0}{r}$ is positive for like charges and negative for opposite charges. A negative value means the configuration has less energy than the separated charges at infinity. Work by the field in separating opposite charges is negative.`,
sceneNote: String.raw`Radial path above; $U(r)$ curve below. Infinity mode shows an outward continuation, not a finite stand-in for infinity.`,
limits: String.raw`Fixed point source; vacuum Coulomb constant $k=\frac1{4\pi\varepsilon_0}$. Distances in metres. $U$ graph: 30 nJ per vertical scene unit, clipped outside ±2.5 units. Infinity has exactly $U_b=0$ analytically; the visible path stops at the edge of the diagram and does not locate b at a finite radius.`,
measure: p => { const s = centralState(p); return [energy('Potential energy Uₐ', s.ua), energy('Potential energy Uᵦ', s.ub), energy('Field work a → b', s.work)]; },
observe: p => { const s = centralState(p); return s.rb === Infinity ? String.raw`At infinity, $U_b=0$ exactly. $W_{a\infty}=U_a$ = ${format(s.work * 1e9)} nJ. The diagram’s edge is only a visual continuation toward infinity.` : String.raw`The field does ${format(s.work * 1e9)} nJ of work from $r_a$ = ${s.ra} m to $r_b$ = ${s.rb} m. Switching the sign of either charge reverses $U$ and $W$.`; },
answers: [
{ title: '3a · Derive the radial work · 30p', steps: [
{ why: 'Write the radial field and force of the fixed point charge.', math: String.raw`\vec E = \frac{kq}{r^2}\hat r,\qquad \vec F_e = \frac{kqq_0}{r^2}\hat r` },
{ why: String.raw`The radial component of the displacement is $\hat r\cdot\mathrm d\vec r=\mathrm dr$. Tangential steps do no work.`, math: String.raw`W_{ab} = kqq_0\int_{r_a}^{r_b}\frac1{r^2}\,\mathrm dr` },
{ why: 'Integrate and evaluate at the endpoints. The result depends only on their distances.', math: String.raw`W_{ab} = kqq_0\left[-\frac1r\right]_{r_a}^{r_b} = kqq_0\left(\frac1{r_a}-\frac1{r_b}\right)` },
] },
{ title: '3b · Set the zero at infinity · 25p', steps: [
{ why: String.raw`Choose $U(\infty)=0$. As $r_b\to\infty$, the reciprocal distance goes to zero.`, math: String.raw`W_{a\infty} = \frac{kqq_0}{r_a}` },
{ why: String.raw`Use $W_{a\infty}=U_a-U_\infty$ to identify the two endpoint energies.`, math: String.raw`U_a = \frac{kqq_0}{r_a},\qquad U_b = U_\infty = 0` },
{ why: String.raw`This gives the general interaction energy. Its sign is the sign of $qq_0$.`, math: String.raw`U(r) = \frac{kqq_0}{r}` },
] },
],
},
{
...common, id: 'test-assembly', title: 'Build a system of charges', shortTitle: 'Charge assembly', points: 25, section: '4B',
description: 'Bring charges in one at a time. Every connecting edge is one interaction energy, counted exactly once.',
questions: ['Bringing charges together.', String.raw`a. (15p) What is the total electric potential energy if $q_1$, $q_2$, $q_3$ are brought together from infinity?`, String.raw`b. (10p) What is the additional electric potential energy if $q_0$ is brought together with $q_1$, $q_2$, $q_3$?`],
controls: [choice('stage', 'Assembly stage', '3', [['1', '1 · Place first charge'], ['2', '2 · Add second charge'], ['3', '3 · Add third charge'], ['4', '4 · Add test charge']]), slider('spacing', 'Configuration size', 2, 5, 0.25, 3.5, 'm'), slider('q0', 'Added charge q₀', -4, 4, 0.5, 2, 'nC')],
equations: [String.raw`U_{123} = k\left(\frac{q_1q_2}{r_{12}}+\frac{q_1q_3}{r_{13}}+\frac{q_2q_3}{r_{23}}\right)`, String.raw`\Delta U_0 = k\left(\frac{q_0q_1}{r_{01}}+\frac{q_0q_2}{r_{02}}+\frac{q_0q_3}{r_{03}}\right)`, String.raw`\Delta U_0 = q_0V_{123}`],
explanation: String.raw`Place $q_1$ for free. Adding $q_2$ creates one pair; adding $q_3$ creates two more. The fourth charge creates three new pairs without changing the energy of the existing three. For quasistatic assembly, external work equals the increase in $U$.`,
challenge: String.raw`Step through all four assembly stages. Then reverse $q_0$ and watch the sign of its three new interactions reverse.`,
prediction: String.raw`Should the total energy contain both $\frac{q_1q_2}{r_{12}}$ and $\frac{q_2q_1}{r_{21}}$?`,
predictionAnswer: String.raw`No. Those describe the same pair. Sum only over $i<j$. Three charges have three distinct pairs; four charges have six. The additional energy from $q_0$ includes just its three new pairs, $\Delta U_0=q_0V_{123}$.`,
sceneNote: 'A tetrahedral arrangement. Mint edges: existing pairs. Gold edges: pairs introduced by the newest charge. Dashed markers: not yet assembled.',
limits: String.raw`Point charges fixed at distinct positions. $q_1$ = +3 nC, $q_2$ = −2 nC, $q_3$ = +2 nC. All coordinates scale with the configuration size in metres. Reference: all charges mutually separated at infinity. Self-energies are excluded. Later-stage totals are shown in readouts even before those charges are placed.`,
measure: p => { const s = assemblyState(p); return [energy('Energy of current assembly', s.current), energy('Three-charge energy U₁₂₃', s.base), energy('Additional energy ΔU₀', s.extra), metric('Pairs currently assembled', s.stage * (s.stage - 1) / 2, 'pairs')]; },
observe: p => { const s = assemblyState(p); return String.raw`Stage ${s.stage}: ${s.stage * (s.stage - 1) / 2} distinct pairs are present. $U_{123}$ = ${format(s.base * 1e9)} nJ; adding $q_0$ changes it by ${format(s.extra * 1e9)} nJ. Negative pair energy indicates opposite signs.`; },
answers: [
{ title: '4a · Assemble q₁, q₂, q₃ · 15p', steps: [
{ why: String.raw`Bring $q_1$ from infinity first. With no other charges present, its interaction energy is zero.`, math: String.raw`U_1 = 0` },
{ why: String.raw`Bring in $q_2$ against the potential due to $q_1$; then bring $q_3$ against the potential due to $q_1$ and $q_2$.`, math: String.raw`\begin{aligned}\Delta U_2 &= \frac{kq_1q_2}{r_{12}}\\\Delta U_3 &= \frac{kq_1q_3}{r_{13}}+\frac{kq_2q_3}{r_{23}}\end{aligned}` },
{ why: 'Add the contributions, counting each pair once.', math: String.raw`U_{123} = k\left(\frac{q_1q_2}{r_{12}}+\frac{q_1q_3}{r_{13}}+\frac{q_2q_3}{r_{23}}\right)` },
] },
{ title: '4b · Add q₀ to the fixed system · 10p', steps: [
{ why: String.raw`The existing three charges are held fixed. Add only the three new interactions involving $q_0$.`, math: String.raw`\Delta U_0 = k\left(\frac{q_0q_1}{r_{01}}+\frac{q_0q_2}{r_{02}}+\frac{q_0q_3}{r_{03}}\right)` },
{ why: String.raw`Factor out $q_0$. The remaining sum is the potential of the original three charges at the new position.`, math: String.raw`\begin{aligned}V_{123} &= k\left(\frac{q_1}{r_{01}}+\frac{q_2}{r_{02}}+\frac{q_3}{r_{03}}\right)\\\Delta U_0 &= q_0V_{123}\end{aligned}` },
] },
],
},
{
...common, id: 'test-uniform', title: 'Work in a uniform field', shortTitle: 'Uniform field', points: 25, section: '4B',
description: String.raw`Rotate the displacement relative to the field. The projection along $E$ sets the work, not the full path length.`,
questions: [String.raw`When $q_0$ moves from a to b in a uniform $E$-field.`, 'a. (15p) Please derive the work done by the electric force.', String.raw`b. (10p) What are $U_{\mathrm{pot},a}$ and $U_{\mathrm{pot},b}$?`],
controls: [...motionControls, slider('angle', 'Displacement angle α', 0, 180, 5, 35, '°'), journey()],
equations: [String.raw`W_{ab} = q_0\vec E\cdot(\vec r_b-\vec r_a) = q_0Es\cos\alpha`, String.raw`W_{ab} = q_0E(x_b-x_a)`, String.raw`U(x) = -q_0Ex+C`],
explanation: String.raw`A constant field can be taken outside the work integral. With x along $E$, the potential energy changes only with x. The energy zero is arbitrary; here a is the reference, so $U_a=0$.`,
challenge: String.raw`Set $\alpha$ to $90^\circ$. The charge travels a nonzero distance, but $E$ is perpendicular to every step: work is zero.`,
prediction: String.raw`If $\alpha$ exceeds $90^\circ$ for a positive charge, does the field give energy to the charge?`,
predictionAnswer: String.raw`The field does negative work because $\cos\alpha<0$. $U$ increases as the charge moves against the field. An external agent would need to supply that energy to move it slowly, or a freely moving particle would lose kinetic energy.`,
sceneNote: String.raw`Displacement is in the xy plane; $E$ points along +x. The blue segment is $\Delta x=s\cos\alpha$. Choose $U_a=0$.`,
limits: String.raw`Ideal constant field with no edge effects. Geometry in metres; arrows show direction with compressed lengths. Prescribed motion, not a free-particle trajectory. $U_a=0$ fixes $C=q_0Ex_a$; $x_a$ is shown explicitly by the a marker.`,
measure: p => { const m = motionState(p); return [energy('Field work a → b', m.work), metric('Projection Δx', m.dx, 'm'), energy('Potential energy Uₐ', 0), energy('Potential energy Uᵦ', -m.work)]; },
observe: p => { const m = motionState(p); return String.raw`$\alpha = ${number(p, 'angle')}^\circ$ projects $s$ = ${m.s} m onto $\Delta x$ = ${format(m.dx)} m. $W$ = ${format(m.work * 1e9)} nJ and $U_b$ = ${format(-m.work * 1e9)} nJ with $U_a=0$.`; },
answers: [
{ title: '5a · Derive uniform-field work · 15p', steps: [
{ why: String.raw`Start with the work integral. The field is constant, so take $\vec E$ outside the integral.`, math: String.raw`W_{ab} = q_0\int_a^b\vec E\cdot\mathrm d\vec r = q_0\vec E\cdot(\vec r_b-\vec r_a)` },
{ why: String.raw`Write the dot product using the displacement length and angle $\alpha$.`, math: String.raw`W_{ab} = q_0Es\cos\alpha` },
{ why: 'Choose the x-axis along the field. Only the x-displacement contributes.', math: String.raw`W_{ab} = q_0E(x_b-x_a)` },
] },
{ title: '5b · Endpoint potential energies · 10p', steps: [
{ why: 'The change in potential energy is the negative of the field work.', math: String.raw`U_b-U_a = -q_0E(x_b-x_a)` },
{ why: String.raw`Integrating with respect to x leaves an arbitrary reference constant $C$.`, math: String.raw`U_a = -q_0Ex_a+C,\qquad U_b = -q_0Ex_b+C` },
{ why: String.raw`A convenient choice is $U_a=0$. It changes no forces or energy differences.`, math: String.raw`U_a = 0,\qquad U_b = -q_0E(x_b-x_a)` },
] },
],
},
{
...common, id: 'test-dipole', title: 'Turn a dipole in a field', shortTitle: 'Dipole rotation', points: 50, section: '4B',
description: 'Two equal and opposite forces cancel in translation, yet form a torque. Rotate the dipole to explore work and stability.',
questions: [String.raw`The electric dipole in a uniform $E$-field.`, String.raw`a. (10p) Derive the torque vector and prove $\tau=p_eE\sin\theta$, where $\theta=\angle(\vec p_e,\vec E)$.`, String.raw`b. (30p) Derive $W_{ab}$ as the dipole rotates from $\theta_a$ to $\theta_b$. What are $U_a$ and $U_b$? You do not have to derive $\mathrm dW=-\tau\,\mathrm d\theta$.`, String.raw`c. (10p) Explain why $\theta_a$ = $90^\circ$ can be a reference, give $U_a$, and find the general $U$ also as a scalar product.`],
controls: [slider('charge', 'Dipole charge magnitude q', 0.5, 4, 0.5, 2, 'nC'), slider('length', 'Charge separation d', 0.5, 3, 0.25, 2, 'm'), slider('field', 'Electric field E', 0, 80, 5, 30, 'V/m'), slider('thetaA', 'Initial angle θₐ', 0, 180, 5, 90, '°'), slider('thetaB', 'Final angle θᵦ', 0, 180, 5, 15, '°'), slider('progress', 'Rotation progress', 0, 100, 1, 50, '%')],
equations: [String.raw`\vec p_e = q\vec d,\qquad \vec\tau = \vec p_e\times\vec E,\qquad |\vec\tau| = p_e E\sin\theta`, String.raw`W_{ab} = p_e E(\cos\theta_b-\cos\theta_a)`, String.raw`U(\theta) = -p_e E\cos\theta = -\vec p_e\cdot\vec E`],
explanation: String.raw`The dipole moment points from $-q$ to $+q$. The equal and opposite electric forces create a couple that tends to align $\vec p_e$ with $\vec E$. We use $U(90^\circ)=0$; alignment is the minimum energy state.`,
challenge: String.raw`Set the final angle to $0^\circ$, then $180^\circ$, with rotation progress at 100%. Both have zero torque. Compare their energy and stability.`,
prediction: String.raw`If the torque is zero at both $0^\circ$ and $180^\circ$, are both orientations stable?`,
predictionAnswer: String.raw`No. At $0^\circ$, $U=-p_eE$ is a minimum: a small angular displacement produces a restoring torque. At $180^\circ$, $U=+p_eE$ is a maximum: a small displacement drives the dipole farther away. At $90^\circ$, $U=0$ by convention but torque is largest, so this is not equilibrium. Without damping, a freely rotating dipole can oscillate about alignment.`,
sceneNote: String.raw`$E$ along $+x$; $\vec p_e$ points from − to +. Gold arrows show forces; the blue z-arrow shows signed torque. $U(\theta)$ below.`,
limits: String.raw`Ideal rigid dipole with fixed centre in a uniform field. Geometry in metres. No net force. Angle measured counterclockwise in xy, so $\tau_z=-p_eE\sin\theta$. The slider prescribes orientation, not a damped dynamical trajectory. Torque arrow length and graph height are normalized; readouts give magnitudes in SI-derived units. $U(90^\circ)=0$.`,
measure: p => { const s = rotationState(p); return [metric('Current angle θ', s.theta * 180 / Math.PI, '°'), metric('Torque τz', s.torqueZ * 1e9, 'nN·m'), energy('Potential energy U', s.energy), energy('Field work a → b', s.endpointWork), energy('Work to current angle', s.work)]; },
observe: p => { const s = rotationState(p); const degrees = s.theta * 180 / Math.PI; return s.field === 0 ? String.raw`$E=0$: both forces, torque, rotation work and dipole interaction energy vanish. There is no preferred orientation.` : degrees < 0.01 ? String.raw`Aligned at $0^\circ$: $U$ is minimum and torque is zero. This is stable equilibrium; a small rotation produces a restoring torque.` : degrees > 179.99 ? String.raw`Opposed at $180^\circ$: $U$ is maximum and torque is zero. This is unstable equilibrium; a small rotation takes it away from this position.` : String.raw`At $\theta = ${format(degrees)}^\circ$, $\tau_z$ = ${format(s.torqueZ * 1e9)} nN·m. The negative z direction reduces $\theta$ toward alignment. ${Math.abs(degrees - 90) < 0.01 ? String.raw`At $90^\circ$, $U=0$ by choice, but the torque is maximum: this is not equilibrium.` : 'Follow the point on the energy curve as you rotate.'}`; },
answers: [
{ title: '6a · Torque vector and magnitude · 10p', steps: [
{ why: String.raw`Let $\vec d$ point from the negative charge to the positive charge. Define the dipole moment.`, math: String.raw`\begin{aligned}\vec p_e &= q\vec d\\\vec F_+ &= q\vec E,\quad \vec F_- = -q\vec E\\\vec F_{\mathrm{net}} &= 0\end{aligned}` },
{ why: String.raw`Take moments about the midpoint. The two lever arms are $\pm\frac{\vec d}{2}$.`, math: String.raw`\vec\tau = \frac{\vec d}{2}\times q\vec E+\left(-\frac{\vec d}{2}\right)\times(-q\vec E) = q\vec d\times\vec E` },
{ why: 'The cross product gives the vector direction and magnitude. The two forces form a couple.', math: String.raw`\vec\tau = \vec p_e\times\vec E,\qquad |\vec\tau| = p_e E\sin\theta` },
] },
{ title: '6b · Rotation work and endpoint energies · 30p', steps: [
{ why: String.raw`The torque acts toward decreasing $\theta$. With $\tau$ as its positive magnitude, use the supplied relation.`, math: String.raw`\mathrm dW = -\tau\,\mathrm d\theta = -p_e E\sin\theta\,\mathrm d\theta` },
{ why: 'Integrate from the initial angle to the final angle.', math: String.raw`W_{ab} = -p_e E\int_{\theta_a}^{\theta_b}\sin\theta\,\mathrm d\theta = p_e E(\cos\theta_b-\cos\theta_a)` },
{ why: String.raw`Use $W_{ab}=U_a-U_b$. The reference constant is the same at both endpoints.`, math: String.raw`\begin{aligned}U_a &= -p_e E\cos\theta_a+C\\U_b &= -p_e E\cos\theta_b+C\end{aligned}` },
] },
{ title: '6c · Reference at 90° and scalar product · 10p', steps: [
{ why: String.raw`The zero of potential energy is arbitrary. At $90^\circ$ the two charges are at the same electric potential, so $+qV$ and $-qV$ cancel.`, math: String.raw`U_a = U(90^\circ) = 0` },
{ why: String.raw`Since $\cos90^\circ=0$, this reference sets $C=0$.`, math: String.raw`U(\theta) = -p_e E\cos\theta = -\vec p_e\cdot\vec E` },
{ why: 'Aligned is a stable energy minimum; opposed is an unstable maximum. The perpendicular reference is not an equilibrium.', math: String.raw`\begin{aligned}U(0^\circ) &= -p_e E\\U(90^\circ) &= 0\\U(180^\circ) &= +p_e E\end{aligned}` },
] },
],
},
];
export function getTestLesson(experiment: Experiment): TestLesson | undefined {
return testLessons.find(lesson => lesson.id === experiment.id);
}
|