diff options
Diffstat (limited to '')
| -rw-r--r-- | src/test4.ts | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/src/test4.ts b/src/test4.ts new file mode 100644 index 0000000..9bd32d8 --- /dev/null +++ b/src/test4.ts @@ -0,0 +1,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); +} |