Welcome to TiddlyWiki created by Jeremy Ruston; Copyright © 2004-2007 Jeremy Ruston, Copyright © 2007-2011 UnaMesa Association
//{{{
[
{
"pluginName": "$tw.VPM",
"pluginScripts": [
{
"main": "nodejs/$tw.util.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.util.min",
"description": "Plugin for general utilities.",
"required": false,
"toLoad": false,
"developing": true,
"deActivated": false
},
{
"main": "$tw.ve.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.min",
"description": "Plugin for view mode editing features in TiddlyWiki.",
"required": false,
"developing": true,
"toLoad": true
},
{
"main": "$tw.LaTex.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.LaTex.min",
"description": "Plugin for LaTex formula handling.<br>MUST have a real LaTex rendering engine, such as MathJax or KaTex, to work properly.",
"required": false,
"developing": true,
"toLoad": true
},
{
"main": "$tw.3D.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.3D.min",
"description": "Plugin for 3D graphing in TiddlyWiki. (Default: THREE.js.)",
"required": false,
"developing": true,
"toLoad": true
},
{
"main": "$tw.data.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.data.min",
"description": "Plugin for data processing in TiddlyWiki. (Default: D3.js.)",
"required": false,
"developing": true,
"toLoad": true
},
{
"main": "$tw.numeric.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.numeric.min",
"description": "Plugin for numeric calculatons.",
"required": false,
"toLoad": true,
"developing": true,
"deActivated": false
},
{
"main": "$tw.physics.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.physics.min",
"description": "Plugin for physics simulation.",
"required": false,
"toLoad": true,
"developing": true,
"deActivated": false
},
{
"name": "Parallel.js",
"main": "js/Parallel-transferable.js",
"fallback": "https://unpkg.com/paralleljs@1.0/lib/parallel.js",
"website": "https://parallel.js.org/",
"description": "The Parallel.js main source.",
"developing": true,
"required": false,
"toLoad": false
}
],
"debugging": false
},
{
"pluginName": "$tw.ve",
"pluginScripts": [
{
"main": "$tw.ve.core.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.core.min",
"description": "The core of $tw.ve.",
"developing": true,
"required": true,
"toLoad": true
},
{
"main": "$tw.ve.extra.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.extra.min",
"description": "The extended features of $tw.ve.",
"developing": true,
"required": false,
"toLoad": true
},
{
"main": "$tw.ve.table.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.table.min",
"description": "View mode editing for tables in $tw.ve.",
"developing": true,
"required": false,
"toLoad": true
},
{
"main": "$tw.ve.tcalc.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.tcalc.min",
"description": "Spreadsheet features in $tw.ve.",
"developing": true,
"required": false,
"toLoad": true
}
],
"debugging": false
},
{
"pluginName": "$tw.LaTex",
"pluginScripts": [
{
"name": "MathJax",
"main": "$tw.LaTex.MathJax.js",
"fallback": "https://twve.tiddlyspot.com/#$tw.LaTex.MathJax.min",
"description": "Use MathJax as the rendering engine.",
"developing": true,
"required": false,
"toLoad": true
},
{
"name": "KaTex",
"main": "$tw.LaTex.KaTex.js",
"fallback": "https://twve.tiddlyspot.com/#$tw.LaTex.KaTex.min",
"description": "Use KaTex as the rendering engine.",
"developing": true,
"required": false,
"toLoad": false
}
],
"debugging": false
},
{
"pluginName": "$tw.3D",
"pluginScripts": [
{
"name": "THREE.js",
"main": "<script type='module'>import * as THREE from 'three';$tw.threeD.THREE=THREE;</script>",
"description": "The THREE.js main source.",
"required": true,
"toLoad": true
},
{
"main": "<script type='module'>import {CSS3DRenderer, CSS3DObject} from 'three/addons/renderers/CSS3DRenderer.js';$tw.threeD.CSS3DRenderer=CSS3DRenderer;$tw.threeD.CSS3DObject=CSS3DObject;</script>",
"description": "The CSS 3D renderer.",
"required": false,
"toLoad": true
},
{
"main": "<script type='module'>import {TrackballControls} from 'three/addons/controls/TrackballControls.js';$tw.threeD.TrackballControls = TrackballControls;</script>",
"description": "The track ball control handler.",
"required": false,
"toLoad": true
},
{
"main": "js/controls/FlyControls.min.js",
"description": "The fly control handler.",
"required": false,
"toLoad": false
},
{
"main": "js/controls/MouseControls.min.js",
"description": "The mouse control handler.",
"required": false,
"toLoad": false
},
{
"main": "js/controls/DragControls.min.js",
"description": "The drag-and-drop handler.",
"required": false,
"toLoad": false
},
{
"main": "js/controls/VRControls.min.js",
"description": "The VR control handler.",
"required": false,
"toLoad": false
},
{
"main": "<script type='module'>import {CSS3DRenderer} from 'https://unpkg.com/three@0.161.0/examples/jsm//renderers/CSS3DRenderer.js';$tw.threeD.CSS3DRenderer = CSS3DRenderer;</script>",
"description": "The CSS 3D renderer.",
"required": false,
"toLoad": false
},
{
"main": "js/controls/TrackballControls.min.js",
"description": "The track ball control handler.",
"required": false,
"toLoad": false
}
],
"debugging": false
},
{
"pluginName": "$tw.data",
"pluginScripts": [
{
"name": "plotly.js",
"main": "https://cdn.plot.ly/plotly-2.31.1.min.js",
"fallback": "plotly.min.js",
"description": "The plotly.js library.",
"required": false,
"toLoad": false
},
{
"name": "Apache ECharts",
"main": "https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js",
"fallback": "echarts.min.js",
"description": "The Apache ECharts library.",
"required": false,
"toLoad": false
},
{
"name": "D3.js",
"main": "https://d3js.org/d3.v7.min.js",
"fallback": "d3.min.js",
"description": "The D3 main source.",
"required": true,
"toLoad": true
},
{
"main": "$tw.data.TypedArray.js",
"fallback": "https://twve.tiddlyspot.com/#$tw.data.TypedArray.min",
"description": "The typed array module of $tw.data.",
"developing": true,
"required": false,
"toLoad": false
}
],
"debugging": false
},
{
"pluginName": "$tw.numeric",
"pluginScripts": [
{
"main": "$tw.numeric.ODE.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.numeric.ODE.min",
"description": "The ODE solver of $tw.numeric.",
"developing": true,
"required": false,
"toLoad": false,
"deActivated": true
},
{
"main": "$tw.numeric.FFT.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.numeric.FFT.min",
"description": "The Fast Fourier Transform (FFT) module of $tw.numeric.",
"developing": true,
"required": false,
"toLoad": false,
"deActivated": true
},
{
"main": "$tw.numeric.parallel.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.numeric.parallel.min",
"description": "The parallel library of $tw.numeric.",
"developing": true,
"required": false,
"toLoad": false,
"deActivated": true
}
],
"debugging": false
},
{
"pluginName": "$tw.physics",
"pluginScripts": [
{
"main": "$tw.physics.electrodynamics.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.physics.electrodynamics.min",
"description": "The physics simulation codes for electrodynamics.",
"developing": true,
"required": false,
"toLoad": true
},
{
"main": "$tw.physics.quantum.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.physics.quantum.min",
"description": "The physics simulation codes for quantum.",
"developing": true,
"required": false,
"deActivated": true,
"toLoad": false
},
{
"main": "$tw.physics.statisticaldynamics.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.physics.statisticaldynamics.min",
"description": "The physics simulation codes for statistical dynamics.",
"developing": true,
"required": false,
"deActivated": true,
"toLoad": false
},
{
"main": "$tw.physics.thermodynamics.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.physics.thermodynamics.min",
"description": "The physics simulation codes for thermodynamics.",
"developing": true,
"required": false,
"deActivated": true,
"toLoad": false
}
],
"debugging": false
}
]
//}}}
//{{{
[
{
"pluginName": "$tw.ve.table",
"pluginScripts": [
{
"main": "$tw.ve.tablelarge.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.tablelarge.min",
"description": "Large table support in $tw.ve.",
"required": false,
"toLoad": false
},
{
"name": "TableSortingPlugin",
"main": "TableSortingPlugin.min.js",
"fallback": "",
"description": "Add table sorting feature in $tw.ve.",
"required": false,
"toLoad": false
},
{
"name": "SortableGridPlugin",
"main": "SortableGridPlugin.min.js",
"fallback": "",
"description": "Add table sorting feature in $tw.ve.",
"required": false,
"toLoad": false
}
],
"debugging": false
},
{
"pluginName": "$tw.ve.tcalc",
"pluginScripts": [
{
"name": "Date/Time Extension",
"main": "$tw.ve.tcalc.datetime.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.tcalc.datetime.min",
"description": "Date/Time functions extension of $tw.ve.tcalc.",
"developing": true,
"required": false,
"toLoad": true
},
{
"name": "Statistics Extension",
"main": "$tw.ve.tcalc.stats.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.tcalc.stats.min",
"description": "Statistics functions extension of $tw.ve.tcalc.",
"developing": true,
"required": false,
"toLoad": true
},
{
"name": "Bookkeeping Extension",
"main": "$tw.ve.tcalc.bkkp.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.tcalc.bkkp.min",
"description": "Daily life bookkeeping functions extension of $tw.ve.tcalc.",
"developing": true,
"required": false,
"toLoad": false
},
{
"name": "Financial Extension",
"main": "$tw.ve.tcalc.fin.js",
"fallback": "http://twve.tiddlyspot.com/#$tw.ve.tcalc.fin.min",
"description": "Financial functions extension of $tw.ve.tcalc.",
"developing": true,
"required": false,
"toLoad": false
}
],
"debugging": false
},
{
"pluginName": "$tw.LaTex.MathJax",
"pluginScripts": [
{
"name": "MathJax-3-CHTML",
"id": "MathJax-script",
"main": "https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js",
"description": "The MathJax rendering engine.",
"default": true,
"required": false,
"toLoad": false
},
{
"name": "MathJax-2",
"main": "https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.7/MathJax.js?config=TeX-MML-AM_CHTML",
"description": "The MathJax rendering engine.",
"required": false,
"toLoad": true
}
],
"debugging": false
}
]
//}}}
/***
!! Point Charge
***/
//{{{
let charge = sphere({
radius: 0.01,
color: 0xFFD700,
opacity: 1
});
let q = label({
text: '\\(q > 0\\)',
color: charge.getColorHex()
});
q.lookAt(scene.camera.position);
q.rotation.z = 135/180*Math.PI;
q.setPosition(0.08,0.08,0);
charge.total = 1.6e-10;
charge.density = charge.total/charge.volume();
//}}}
/***
!! Solid Sphere
***/
//{{{
let R = 0.5;
let charge = sphere({
radius: R,
color: 0xFFD700,
opacity: 0.4
});
let Q = label({
text: '\\(Q > 0\\)',
color: charge.getColorHex()
});
Q.lookAt(scene.camera.position);
Q.rotation.z = 135/180*Math.PI;
Q.setPosition(0.08,0.08,0);
charge.total = 1.6e-5;
charge.density = charge.total/charge.volume();
//}}}
/***
!! Current Loop
***/
//{{{
var R = 1e-1, H = 2*Math.PI*R, Rt = 1e-3;
var current = torus({
radius: R,
tube: Rt,
color: 0xFFD700,
opacity: 1
});
current.arrow = arrow({
radius: Rt,
center: vector(R*1.2,0,0),
axis: vector(0,R/2,0),
color: 0xFFD700,
opacity: 1
},'noadd');
current.label = label({
position: current.arrow.position.clone().multiplyScalar(0.35),
text: 'I',
size: '10pt',
color: '#ffffff'
});
current.add(current.arrow);
current.total = vector(0,1,0);
current.total.value = current.total.length();
current.density = current.total.clone().multiplyScalar(1/current.crossSection());
current.density.value = current.density.length();
//}}}
/***
!! current.tinyFieldAt \((\vec r[,dV[,\vec dB]])\)
<<<
Calculate a tiny magnetic field \(d\vec B\) at position \(\vec r\) generated by this current flowing through a tiny segment \(d\vec l\) = dV.dx[1] of this current loop, using the Biot-Savart law \[d\vec B = {\mu_0 \over 4\pi}{Id\vec l \times \hat r' \over r'^2},\] where \(d\vec l\) is the vector dV.dx[1], dV is the tiny volume representing the tiny segment of current (located at dV.center), \(\vec r' = \vec r -\) dV.center.
<<<
***/
//{{{
current.tinyFieldAt = function(r,dV,dB){
let dr = r.clone().sub(dV.center);
if(!dB) dB = $tw.threeD.vector3();
else dB.set(0,0,0);
if(dV){
dB.copy(dr).normalize().cross(dV.dx[1]).multiplyScalar(
-1e-7*current.total.value/dr.lengthSq()
);
}
return dB;
};
//}}}
/***
!! current.fieldAt \((\vec r[,\vec B[,\text{source\_iterator}]])\)
<<<
Calculate the magnetic field \(\vec B\) at position \(\vec r\) generated by this current loop, using the source_iterator (or current.iterator) to integrate \[\vec B = \int {\mu_0 \over 4\pi}{Id\vec l \times \hat r' \over r'^2},\] where \(d\vec l\) is the vector dV.dx[1], dV is the tiny volume of each tiny segment of the current loop, \(\vec r' = \vec r -\) dV.center.
<<<
***/
//{{{
current.fieldAt = function(r,B,source_iterator){
console.log('fieldAt',r);
if(!B) B = $tw.threeD.vector3();
else B.set(0,0,0);
if(source_iterator === undefined)
source_iterator = current.iterator;
if(source_iterator){
let dB = vector();
source_iterator.run(function(dV){
B.add(current.tinyFieldAt(r,dV,dB));
});
}
return B;
};
//}}}
/***
!! Current Solid Cylinder
***/
//{{{
let R = 0.1, H = R*20,
current = cylinder({
//pos: vector(1,0,0),
radius: R,
//length: H,
axis: vector(0,0,H),
color: 0xFFD700,
opacity: 0.5
});
current.arrow = arrow({
pos: vector(0,R*1.5,-H/40),
axis: vector(0,0,H/20),
color: 0xFFD700,
opacity: 0.5
},'noadd');
current.label = label({
pos: current.arrow.position,
text: 'I',
size: scene.defaultFontSize/scene.getRange(),
color: '#ffffff'
});
current.add(current.arrow);
current.total = vector(0,0,1);
current.density = current.total.clone().multiplyScalar (1/current.crossSection());
//}}}
/***
!! Current Straight Wire
***/
//{{{
var R = 1e-3, H = 2500*R;
var current = cylinder({
//pos: vector(1,0,0),
radius: R,
axis: vector(0,0,H),
color: 0xFFD700,
opacity: 1
});
current.arrow = arrow({
radius: R,
pos: vector(0,R*10,-H/40),
axis: vector(0,0,H/20),
color: 0xFFD700,
opacity: 1
},'noadd');
current.label = label({
pos: current.arrow.position,
text: 'I',
size: scene.defaultFontSize/scene.getRange(),
color: '#ffffff'
});
current.add(current.arrow);
current.total = vector(0,0,1e-3);
current.density = current.total.clone().multiplyScalar (1/current.crossSection());
//}}}
!! Field Control
''Field'' [ =chkEfield] \(\vec E\) / [ =chkBfield] \(\vec B\) / / / ''Shape:'' <html><input type="radio" id="radioCartesianShape" name="radioFieldShape" value="Cartesian"></html> Cartesian / <html><input type="radio" id="radioSphericalShape" name="radioFieldShape" value="Spherical"></html> Spherical / <html><input type="radio" id="radioCylindricalShape" name="radioFieldShape" value="Cylindrical"></html> Cylindrical
!! Normalization Control
[ =chkNormalizeLength] Normalize ''length'' (otherwise ''opacity'')
/***
!!! init()
***/
//{{{
let Vf = scalarField.create(), dVf = scalarField.create(), nV = 0;
scene.add(Vf).add(dVf);
chkShowIntegration.checked = false;
btnStart.click();
scene.initialized = () => {
Vf.clear();
dVf.clear();
nV = 0;
}
//}}}
/***
!!! fieldIteratorParameters
***/
//{{{
setFieldIterator(SphericalIterator.create({
center: charge.position,
rmin: charge.getRadius()*2,
rmax: charge.getRadius()*2,
color: 0x00ffff,
opacity: 0.7,
layers: 1,
ntheta: 30,
nphi: 60
}));
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let si = SphericalIterator.create({
rmin: 0,
rmax: charge.getRadius(),
layers: 20,
ntheta: 45,
nphi: 90
});
si.showSlicedPoints(false);
setSourceIterator(si);
//}}}
/***
!!! atFieldPoint\((d\tau)\)
***/
//{{{
let V = scalarField.pointField();
V.Vr = 0;
const atFieldPoint = dtau => {
dV.position.copy(dtau.center);
V.clear(); V.Vr = 0;
V.position.copy(dtau.center);
ndV = 0;
}
//}}}
/***
!!! atSourcePoint\((d\tau_s, d\tau_f,\) si)
***/
//{{{
let ndV = 0, dV = scalarField.pointField(), dr = vector();
dV.dVr = 0;
const atSourcePoint = (dtaus,dtauf,si) => {
dr.copy(dtauf.center).sub(dtaus.center);
dV.dVr = tinyEPotential(charge,dr,dtaus.volume);
dV.setField(dV.dVr/Vf.max);
V.setField(V.Vr+dV.dVr);
dVf.setField(ndV,dV);
dVf.showField(true,ndV,++ndV);
if(ndV > si.n2){
ndV = 0;
dVf.show(false);
Vf.setField(nV,V);
}
},
//}}}
/***
!!! iterateOverSource(dtau,si)
***/
//{{{
iterateOverSource = (dtau,si) => {
let t_int = performance.now();
V.Vr = $tw.physics.scalarFieldAt(charge,dtau.center,$tw.physics.tinyEPotential,si);
if(nV === 0){
Vf.setField(nV,V.setField(V.Vr));
Vf.max *= 3;
//Vf.normalize(Vf.max);
}else{
Vf.setField(nV,V.setField(V.Vr/Vf.max));
}
Vf.showField(true,nV,++nV);
//console.log('Integration time:',twve.round(performance.now()-t_int,3),'ms');
},
//}}}
/***
!!! startSteppedSourceIteration()
***/
//{{{
startSteppedSourceIteration = (dV,si) => {
// Start integrating over the source.
charge.visible = false;
si.showSlicedPoints();
},
//}}}
/***
!!! doneSteppedSourceIteration()
***/
//{{{
doneSteppedSourceIteration = () => {
// Done integrating over the source, go to
// next field point.
Vf.setField(nV,V);
Vf.showField(true,nV,++nV);
},
//}}}
/***
!!! cancelSteppedSourceIteration()
***/
//{{{
cancelSteppedSourceIteration = (dV,si) => {
// Canceled integrating over the source, finish the
// on going integration.
charge.visible = true;
si.showSlicedPoints(false);
if(ndV) iterateOverSource(dV,si);
}
//}}}
/***
!!! data recording
***/
//{{{
labelPlot[0].innerHTML = '\\(\\Phi_E(r)\\)';
dataPlot[0].setTitle('Electric Flux vs Distance')
.setYTitle('Φ//~~E~~// (volt m)').setXTitle('//r// (m)');
labelPlot[1].innerHTML = '\\(E(r)\\)';
dataPlot[1].setTitle('Field Strength vs Distance')
.setYTitle('//E// (volt/m)').setXTitle('//r// (m)');
chkShowIntegration.checked = false;
chkPlot0.checked = chkPlot1.checked = true;
txtFramePause.value = 0;
btnStart.click();
//}}}
/***
!!! fieldIteratorParameters
***/
//{{{
setFieldIterator(SphericalIterator.create({
center: charge.position,
rmin: charge.getRadius()*0.1,
rmax: charge.getRadius()*2,
color: 0x00ffff,
opacity: 0.7,
layers: 100,
thetamin: Math.PI/2,
ntheta: 1,
phimin: Math.PI/4,
nphi: 1
}));
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let si = SphericalIterator.create({
rmin: 0,
rmax: charge.getRadius(),
layers: 50,
ntheta: 30,
nphi: 60
});
si.showSlicedPoints(false);
setSourceIterator(si);
//}}}
/***
!!! iterateOverSource(dtau,si)
***/
//{{{
let E = vector(), dr = vector(), dA = vector(), dataY = [];
const iterateOverSource = (dtau,si) => {
let t_int = performance.now();
$tw.physics.vectorFieldAt(charge,dtau.center,E,$tw.physics.tinyEField,si);
dtau.frontFaceA(dA);
//console.log('Field integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
dataY[0] = E.length()*$tw.threeD.fourPI*dtau.center.lengthSq(); dataY[1] = E.length();
let r = dr.copy(dtau.center).sub(charge.position).length();
recordData(scene.currentTime(),r,dataY);
}
//}}}
/***
!!! init()
***/
//{{{
chkPlot0.checked = true;
let Vf = scalarField.create(), nV = 0;
scene.add(Vf);
btnStart.click();
scene.initialized = () => {
Vf.clear();
nV = 0;
}
//}}}
/***
!!! data recording
***/
//{{{
labelPlot[0].innerHTML = '\\(V(r)\\)';
dataPlot[0].setTitle('Electric Potential vs Distance')
.setYTitle('//V// (volt)').setXTitle('//r// (m)');
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
setFieldIterator(SphericalIterator.create({
center: charge.position,
rmin: 1,
rmax: 10,
layers: 100,
thetamin: Math.PI/2,
ntheta: 1,
phimin: Math.PI/4,
nphi: 1
}));
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let V = scalarField.pointField(), dataY = [];
V.Vr = 0; V.dr = vector();
const atFieldPoint = dVf => {
let t_int = performance.now();
V.position.copy(dVf.center);
V.dr.copy(dVf.center).sub(charge.position);
V.Vr = $tw.physics.scalarFieldAt(charge,V.dr,$tw.physics.tinyEPotential);
Vf.setField(nV,V.setField(V.Vr));
Vf.showField(true,nV,++nV);
//console.log('Calculation time:',$tw.ve.round(performance.now()-t_int,3),'ms');
dataY[0] = V.Vr;
recordData(scene.currentTime(),V.dr.length(),dataY);
//console.log('r=',V.dr.length(),'V=',V.Vr);
}
//}}}
/***
!!! init()
***/
//{{{
let Ef = vectorField.create(), nE = 0;
scene.add(Ef);
btnStart.click();
scene.initialized = () => {
Ef.clear();
nE = 0;
}
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
let fi = SphericalIterator.create({
center: charge.position,
rmin: 1,
rmax: 1,
color: 0x00ffff,
opacity: 0.7,
layers: 1,
ntheta: 20,
nphi: 40
});
fi.showSlicedPoints();
setFieldIterator(fi);
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let E = vectorField.pointField();
E.Er = vector(); E.dr = vector();
const atFieldPoint = dVf => {
let t_int = performance.now();
E.position.copy(dVf.center);
E.dr.copy(dVf.center).sub(charge.position);
$tw.physics.vectorFieldAt(charge,E.dr,E.Er,$tw.physics.tinyEField);
E.setField(E.Er.multiplyScalar(1e-1));
Ef.setField(nE,E);
Ef.showField(true,nE,++nE);
//console.log('Calculation time:',$tw.ve.round(performance.now()-t_int,3),'ms');
}
//}}}
/***
!!! init()
***/
//{{{
chkPlot0.checked = true;
let Ef = vectorField.create(), nE = 0;
scene.add(Ef);
btnStart.click();
scene.initialized = () => {
Ef.clear();
nE = 0;
}
//}}}
/***
!!! data recording
***/
//{{{
labelPlot[0].innerHTML = '\\(E(r)\\)';
dataPlot[0].setTitle('Electric Field Strength vs Distance')
.setYTitle('//E// (volt / m)').setXTitle('//r// (m)');
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
setFieldIterator(SphericalIterator.create({
center: charge.position,
rmin: 1,
rmax: 10,
layers: 100,
thetamin: Math.PI/2,
ntheta: 1,
phimin: Math.PI/4,
nphi: 1
}));
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let E = vectorField.pointField();
E.Er = vector(); E.dr = vector();
let dataY = [];
const atFieldPoint = dVf => {
let t_int = performance.now();
E.position.copy(dVf.center);
E.dr.copy(dVf.center).sub(charge.position);
$tw.physics.vectorFieldAt(charge,E.dr,E.Er,$tw.physics.tinyEField);
dataY[0] = E.Er.length();
E.setField(E.Er.multiplyScalar(1e-1));
Ef.setField(nE,E);
Ef.showField(true,nE,++nE);
//console.log('Calculation time:',$tw.ve.round(performance.now()-t_int,3),'ms');
recordData(scene.currentTime(),E.dr.length(),dataY);
}
//}}}
/***
!!! Initialization
***/
//{{{
scene.textBookView();
cylinder({
radius: 1,
length: 2,
opacity: 0.2
});
if(chkCylindricalComponents) chkCylindricalComponents.checked = true;
btnStart.click();
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setFieldIterator(CylindricalIterator.create({
rmin: 1,
rmax: 1,
Nr: 1,
phimin: 0,
phimax: Math.PI*2,
Nphi: 60,
zstart: -1,
zend: 1,
Nz: 20
}).showSlicedPoints());
//}}}
/***
!!! Initialization
***/
//{{{
scene.textBookView();
sphere({
radius: 1,
opacity: 0.2
});
if(typeof chkSphericalComponents !== 'undefined')
chkSphericalComponents.checked = true;
chkCyclic.checked = true;
btnStart.click();
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setFieldIterator(SphericalIterator.create({
rmin: 1,
rmax: 1,
Nr: 1,
thetamin: Math.PI/4,
thetamax: Math.PI/4,
Ntheta: 1,
phimin: 0,
phimax: Math.PI*2,
Nphi: 60
}).showSlicedPoints());
//}}}
/***
!!! Initialization
***/
//{{{
//scene.setRange(6);
scene.textBookView();
if(chkCartesianComponents) chkCartesianComponents.checked = true;
btnStart.click();
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setFieldIterator(CartesianIterator.create({
xstart: 0.5,
xend: 0.5,
ystart: -0.5,
yend: 0.5,
zstart: -0.5,
zend: 0.5,
Nx: 1,
Ny: 10,
Nz: 10
}).showSlicedPoints());
//}}}
/***
!!! init()
***/
//{{{
let Bf = vectorField.create(), nB = 0;
scene.add(Bf);
txtFramePause.value = 0;
chkAutoCPF.checked = true;
btnStart.click();
scene.initialized = () => {
Bf.clear();
nB = 0;
scene.camera.position.set(1,1,1).multiplyScalar(tinyMagnet.mu.axis.length()*1e3);
///*
tinyMagnet.visible = false;
arrow({
color: tinyMagnet.mu.getColor(),
axis: tinyMagnet.mu.getAxis().multiplyScalar(1/6)
}).shiftToCenter();
//*/
}
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
const fi = tinyMagnet.getRadius
? CylindricalIterator.create({
center: tinyMagnet.position,
rmin: tinyMagnet.getRadius()*1.5,
rmax: tinyMagnet.getRadius()*3,
Nr: 5,
Nphi: 10,
zmin: -tinyMagnet.getLength(),
zmax: tinyMagnet.getLength(),
Nz: 10,
color: 0x00ffff,
opacity: 0.7
})
: CartesianIterator.create({
center: tinyMagnet.position,
xmin: -tinyMagnet.getWidth()*1.5,
xmax: tinyMagnet.getWidth()*1.5,
Nx: 10,
ymin: -tinyMagnet.getHeight()*1.5,
ymax: tinyMagnet.getHeight()*1.5,
Ny: 10,
zmin: -tinyMagnet.getDepth()*0.5,
zmax: tinyMagnet.getDepth()*0.5,
Nz: 20,
color: 0x00ffff,
opacity: 0.7
});
setFieldIterator(fi);
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let B = vectorField.pointField();
B.Br = vector();
const atFieldPoint = dVf => {
let t_int = performance.now();
B.position.copy(dVf.center);
tinyMagnet.mu.fieldAt(dVf.center,B.Br);
B.setField(B.Br.multiplyScalar(1e8));
Bf.setField(nB,B);
Bf.showField(true,nB,++nB);
//console.log('B =',B,'Calculated in',$tw.ve.round(performance.now()-t_int,3),'ms');
},
//}}}
/***
!!! doneFieldIteration()
***/
//{{{
doneFieldIteration = () => {
Bf.normalize(Bf.max*2e4);
}
//}}}
/***
!!! init()
***/
//{{{
let Bf = vectorField.create(), dBf = vectorField.create(), nB = 0;
Bf.factor = 1e-3;
scene.add(Bf).add(dBf);
chkShowIntegration.checked = false;
txtFramePause.value = 0;
chkAutoCPF.checked = true;
btnStart.click();
scene.initialized = () => {
Bf.clear();
dBf.clear();
nB = 0;
scene.camera.position.set(1,1,1).multiplyScalar(10);
}
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
///*
let fi = CartesianIterator.create({
center: barMagnet.position,
axis: barMagnet.mu.axis,
xmin: -barMagnet.getWidth()/2,
xmax: barMagnet.getWidth()/2,
Nx: 4,
ymin: -barMagnet.getHeight()/2,
ymax: barMagnet.getHeight()/2,
Ny: 4,
zmin: -barMagnet.getDepth(),
zmax: barMagnet.getDepth(),
Nz: 40,
color: 0x00ffff,
opacity: 0.7
});
//*/
/*
let fi = CylindricalIterator.create({
center: barMagnet.position,
axis: barMagnet.mu.axis,
rmin: 0,
rmax: barMagnet.getWidth()*2,
Nr: 10,
thetamin: 0,
thetamax: 2*Math.PI,
Ntheta: 30,
zmin: -barMagnet.getDepth(),
zmax: barMagnet.getDepth(),
Nz: 11,
color: 0x00ffff,
opacity: 0.7
});
//*/
//console.log('fi=',fi);
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setSourceIterator(barMagnet.mu.iterator);
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let B = vectorField.pointField();
B.Br = vector();
const atFieldPoint = (dVf,dVs) => {
dB.position.copy(dVf.center);
B.clear(); B.Br.set(0,0,0);
B.position.copy(dVf.center);
ndB = 0;
},
//}}}
/***
!!! doneFieldIteration()
***/
//{{{
doneFieldIteration = () => {
Bf.normalize(Bf.max*800);
}
//}}}
/***
!!! atSourcePoint(dVs,dVf,si)
***/
//{{{
let ndB = 0, dB = vectorField.pointField();
dB.dBr = vector();
dB.color = 0xffff00; dB.opacity = 0.5;
const atSourcePoint = (dVs,dVf,si) => {
barMagnet.mu.setTinyVolume(dVs);
barMagnet.mu.fieldAt(dVf.center,dB.dBr,null);
dB.setField(dB.dBr.multiplyScalar(Bf.factor));
B.setField(B.Br.add(dB.dBr));
dBf.setField(ndB,dB);
dBf.showField(true,ndB,++ndB);
if(ndB > si.n2){
ndB = 0;
dBf.show(false);
Bf.setField(nB,B);
}
},
//}}}
/***
!!! iterateOverSource(dV,si)
***/
//{{{
iterateOverSource = (dV,si) => {
let t_int = performance.now();
barMagnet.mu.fieldAt(dV.center,B.Br,si);
if(nB === 0){
Bf.setField(nB,B.setField(B.Br.multiplyScalar(Bf.factor)));
}else{
Bf.setField(
nB,B.setField(B.Br.multiplyScalar(Bf.factor))
);
}
Bf.showField(true,nB,++nB);
//console.log('Integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
},
//}}}
/***
!!! startSteppedSourceIteration()
***/
//{{{
startSteppedSourceIteration = (dV,si) => {
// Start integrating over the source.
//barMagnet.visible = false;
//si.showSlicedPoints();
},
//}}}
/***
!!! doneSteppedSourceIteration()
***/
//{{{
doneSteppedSourceIteration = () => {
// Done integrating over the source, go to
// next field point.
Bf.setField(nB,B);
Bf.showField(true,nB,++nB);
},
//}}}
/***
!!! cancelSteppedSourceIteration()
***/
//{{{
cancelSteppedSourceIteration = (dV,si) => {
// Canceled integrating over the source, finish the
// on going integration.
barMagnet.visible = true;
si.showSlicedPoints(false);
if(ndB) iterateOverSource(dV,si);
}
//}}}
/***
!!! init()
***/
//{{{
let Bf = vectorField.create(), dBf = vectorField.create(), nB = 0;
Bf.factor = 1e-2;
scene.add(Bf).add(dBf);
chkShowIntegration.checked = false;
txtFramePause.value = 0;
chkAutoCPF.checked = true;
btnStart.click();
scene.initialized = () => {
Bf.clear();
dBf.clear();
nB = 0;
scene.camera.position.set(1,1,1).multiplyScalar(10);
}
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
///*
const fi = CylindricalIterator.create({
center: cylinderMagnet.position,
axis: cylinderMagnet.axis,
rmin: 0,
rmax: cylinderMagnet.getRadius()*1.5,
Nr: 10,
phimin: 0,
phimax: 2*Math.PI,
Nphi: 10,
zmin: -cylinderMagnet.getHeight()*1.5,
zmax: cylinderMagnet.getHeight()*1.5,
Nz: 10,
color: 0x00ffff,
opacity: 0.7,
});
//*/
/*
const fi = CartesianIterator.create({
center: cylinderMagnet.position,
axis: cylinderMagnet.axis,
xmin: -cylinderMagnet.getRadius()*2,
xmax: cylinderMagnet.getRadius()*2,
Nx: 10,
ymin: -cylinderMagnet.getRadius()*2,
ymax: cylinderMagnet.getRadius()*2,
Ny: 10,
zmin: -cylinderMagnet.getLength(),
zmax: cylinderMagnet.getLength(),
Nz: 10,
color: 0x00ffff,
opacity: 0.7
});
//*/
//console.log('fi=',fi);
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setSourceIterator(cylinderMagnet.mu.iterator);
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let B = vectorField.pointField();
B.Br = vector();
const atFieldPoint = (dVf,dVs) => {
dB.position.copy(dVf.center);
B.clear(); B.Br.set(0,0,0);
B.position.copy(dVf.center);
ndB = 0;
},
//}}}
/***
!!! doneFieldIteration()
***/
//{{{
doneFieldIteration = () => {
Bf.normalize(Bf.max*100);
}
//}}}
/***
!!! atSourcePoint(dVs,dVf,si)
***/
//{{{
let ndB = 0, dB = vectorField.pointField();
dB.dBr = vector();
dB.color = 0xffff00; dB.opacity = 0.5;
const atSourcePoint = (dVs,dVf,si) => {
cylinderMagnet.mu.setTinyVolume(dVs);
cylinderMagnet.mu.fieldAt(dVf.center,dB.dBr,null);
dB.setField(dB.dBr.multiplyScalar(Bf.factor));
B.setField(B.Br.add(dB.dBr));
dBf.setField(ndB,dB);
dBf.showField(true,ndB,++ndB);
if(ndB > si.n2){
ndB = 0;
dBf.show(false);
Bf.setField(nB,B);
}
},
//}}}
/***
!!! iterateOverSource(dV,si)
***/
//{{{
iterateOverSource = (dV,si) => {
let t_int = performance.now();
cylinderMagnet.mu.fieldAt(dV.center,B.Br,si);
if(nB === 0){
Bf.setField(nB,B.setField(B.Br.multiplyScalar(Bf.factor)));
}else{
Bf.setField(
nB,B.setField(B.Br.multiplyScalar(Bf.factor))
);
}
Bf.showField(true,nB,++nB);
//console.log('Integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
},
//}}}
/***
!!! startSteppedSourceIteration()
***/
//{{{
startSteppedSourceIteration = (dV,si) => {
// Start integrating over the source.
//cylinderMagnet.visible = false;
//si.showSlicedPoints();
},
//}}}
/***
!!! doneSteppedSourceIteration()
***/
//{{{
doneSteppedSourceIteration = () => {
// Done integrating over the source, go to
// next field point.
Bf.setField(nB,B);
Bf.showField(true,nB,++nB);
},
//}}}
/***
!!! cancelSteppedSourceIteration()
***/
//{{{
cancelSteppedSourceIteration = (dV,si) => {
// Canceled integrating over the source, finish the
// on going integration.
cylinderMagnet.visible = true;
si.showSlicedPoints(false);
if(ndB) iterateOverSource(dV,si);
}
//}}}
/***
!!! Initialization
***/
//{{{
scene.textBookView();
btnStart.click();
cylinder({
radius: 1,
length: 2,
opacity: 0.2
});
chkShowSteps.onchange = () => {
showSteppedIteration(chkShowSteps.checked);
}
chkShowIntegration.checked = true;
chkShowSteps.checked = true;
showSteppedIteration(true);
scene.initialized = () => {
chkShowSteps.onchange();
}
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setSourceIterator(CylindricalIterator.create({
radius: 1,
layers: 10,
length: 2,
nz: 20,
nphi: 40
}).showSlicedPoints());
//}}}
/***
!!! Initialization
***/
//{{{
scene.textBookView();
btnStart.click();
sphere({
radius: cartesian.getUnitLength(),
opacity: 0.2
});
chkShowSteps.onchange = () => {
showSteppedIteration(chkShowSteps.checked);
}
chkShowIntegration.checked = true;
chkShowSteps.checked = true;
showSteppedIteration(true);
scene.initialized = () => {
chkShowSteps.onchange();
}
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setSourceIterator(SphericalIterator.create({
radius: cartesian.getUnitLength(),
layers: 10,
ntheta: 30,
nphi: 60
}).showSlicedPoints());
//}}}
/***
!!! Initialization
***/
//{{{
scene.textBookView();
btnStart.click();
chkShowSteps.onchange = () => {
showSteppedIteration(chkShowSteps.checked);
}
box({
position: vector(0.5,0.5,0.5),
width: 1,
height: 1,
depth: 1,
opacity: 0.2
});
chkShowIntegration.checked = true;
chkShowSteps.checked = true;
showSteppedIteration(true);
scene.initialized = () => {
chkShowSteps.onchange();
}
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setSourceIterator(CartesianIterator.create({
radius: cartesian.getUnitLength(),
xstart: 0,
xend: 1,
ystart: 0,
yend: 1,
zstart: 0,
zend: 1,
Nx: 10,
Ny: 10,
Nz: 10
}).showSlicedPoints());
//}}}
/***
!!! Initialization
***/
//{{{
txtDAQRate.value = 200;
txtFramePause.value = 200;
chkShowSteps.onchange = () => {
showSteppedIteration(chkShowSteps.checked);
}
chkShowIntegration.checked = false;
chkShowSteps.checked = false;
scene.initialized = () => {
chkShowSteps.onchange();
}
labelPlot[0].innerHTML = 'Err(steps)';
dataPlot[0].setTitle('Err(steps)')
.setYTitle('Err (%)').setXTitle('steps');
activateDAQChannels(3);
attachDAQBuffer(0,0);
attachDAQBuffer(0,1);
attachDAQBuffer(0,2);
//}}}
/***
!!! fieldIterator
***/
//{{{
setFieldIterator(CylindricalIterator.create({
rmin: charge.getRadius(),
rmax: charge.getRadius()*10,
layers: 20,
nphi: 1,
zstart: 1,
zend: 1,
Nz: 1
}));
//}}}
/***
!!! sourceIterator
***/
//{{{
let H = 2;
setSourceIterator(CylindricalIterator.create({
radius: charge.getRadius(),
layers: 10,
ntheta: 45,
length: H,
Nz: 20
}));
//}}}
/***
!!! iterateOverSource(dVf,si)
***/
//{{{
const iterateOverSource = (dVf,si) => {
let t_int = performance.now(), varn = 0,
Vcalc = 0, Vintegral = 0, Vdx3 = 0, Nsteps = 0,
qmax = [charge.getRadius(),$tw.threeD.TWOPI,H/2],
step_ratio = 1.1, nsteps = 0,
Vexp = Math.PI*Math.pow(charge.getRadius(),2)*H;
si.setSteps(varn,si.getSteps(varn)*step_ratio).starts();
let dq3 = si.dq3();
console.log(
'steps['+varn+']=',si.getSteps(varn),'Vexp=',Vexp,
'\ndq['+varn+']=',si.__dq[varn],'/',qmax[varn],'=',$tw.ve.round(si.__dq[varn]/qmax[varn]*100,2)+'%'
);
si.run(function(dVs){
nsteps++;
Vcalc += dVs.volume;
Vintegral += si.__q[0]*dq3;
Vdx3 += dVs.dx3();
});
Nsteps = si.totalSteps();
console.log(
'q['+varn+'] ends at',si.__q[varn],'/',si.__end[varn],'/',qmax[varn],'=',
$tw.ve.round(si.__end[varn]/qmax[varn]*100,2)+'%',
Math.round((si.__end[varn]-qmax[varn])/si.__dq[varn]),'steps off.',
'\nIntegration time:',$tw.ve.round(performance.now()-t_int,3),'(ms).',
'in',nsteps,'steps, /',Nsteps,'=',$tw.ve.round(nsteps/Nsteps*100,2)+'%',(nsteps-Nsteps),'steps off.'
);
console.log('Vcal='+Vcalc+'('+$tw.ve.round((Vcalc-Vexp)/Vexp*100,2)+'%)');
console.log('Vint='+Vintegral+'('+$tw.ve.round((Vintegral-Vexp)/Vexp*100,2)+'%)');
console.log('Vdx3='+Vdx3+'('+$tw.ve.round((Vdx3-Vexp)/Vexp*100,2)+'%)');
recordData(scene.currentTime(),si.getSteps(varn),[
(Vcalc-Vexp)/Vexp*100,
(Vintegral-Vexp)/Vexp*100,
(Vdx3-Vexp)/Vexp*100
]);
}
//}}}
/***
!!! Initialization
***/
//{{{
txtDAQRate.value = 200;
txtFramePause.value = 200;
chkShowSteps.onchange = () => {
showSteppedIteration(chkShowSteps.checked);
}
chkShowIntegration.checked = false;
chkShowSteps.checked = false;
scene.initialized = () => {
chkShowSteps.onchange();
}
labelPlot[0].innerHTML = 'Err(steps)';
dataPlot[0].setTitle('Err(steps)')
.setYTitle('Err (%)').setXTitle('steps');
activateDAQChannels(3);
attachDAQBuffer(0,0);
attachDAQBuffer(0,1);
attachDAQBuffer(0,2);
//}}}
/***
!!! fieldIterator
***/
//{{{
setFieldIterator(SphericalIterator.create({
rmin: charge.getRadius(),
rmax: charge.getRadius()*10,
layers: 20,
ntheta: 1,
nphi: 1
}));
//}}}
/***
!!! sourceIterator
***/
//{{{
setSourceIterator(SphericalIterator.create({
radius: charge.getRadius(),
layers: 10,
ntheta: 45,
nphi: 90
}));
//}}}
/***
!!! iterateOverSource(dVf,si)
***/
//{{{
const iterateOverSource = (dVf,si) => {
let t_int = performance.now(), varn = 0,
Vcalc = 0, Vintegral = 0, Vdx3 = 0, Nsteps = 0,
qmax = [charge.getRadius(),Math.PI,$tw.threeD.TWOPI],
step_ratio = 1.1, nsteps = 0,
Vexp = (4/3)*Math.PI*Math.pow(charge.getRadius(),3);
si.setSteps(varn,si.getSteps(varn)*step_ratio).starts();
let dq3 = si.dq3();
console.log(
'steps['+varn+']=',si.getSteps(varn),'Vexp=',Vexp,
'\ndq['+varn+']=',si.__dq[varn],'/',qmax[varn],'=',$tw.ve.round(si.__dq[varn]/qmax[varn]*100,2)+'%'
);
si.run(function(dVs){
nsteps++;
Vcalc += dVs.volume;
Vintegral += Math.pow(si.__q[0],2)*Math.sin(si.__q[1])*dq3;
Vdx3 += dVs.dx3();
});
Nsteps = si.totalSteps();
console.log(
'q['+varn+'] ends at',si.__q[varn],'/',si.__end[varn],'/',qmax[varn],'=',
$tw.ve.round(si.__end[varn]/qmax[varn]*100,2)+'%',
Math.round((si.__end[varn]-qmax[varn])/si.__dq[varn]),'steps off.',
'\nIntegration time:',$tw.ve.round(performance.now()-t_int,3),'(ms).',
'in',nsteps,'steps, /',Nsteps,'=',$tw.ve.round(nsteps/Nsteps*100,2)+'%',(nsteps-Nsteps),'steps off.'
);
console.log('Vcal='+Vcalc+'('+$tw.ve.round((Vcalc-Vexp)/Vexp*100,2)+'%)');
console.log('Vint='+Vintegral+'('+$tw.ve.round((Vintegral-Vexp)/Vexp*100,2)+'%)');
console.log('Vdx3='+Vdx3+'('+$tw.ve.round((Vdx3-Vexp)/Vexp*100,2)+'%)');
recordData(scene.currentTime(),si.getSteps(varn),[
(Vcalc-Vexp)/Vexp*100,
(Vintegral-Vexp)/Vexp*100,
(Vdx3-Vexp)/Vexp*100
]);
}
//}}}
/***
!!! Initialization
***/
//{{{
txtDAQRate.value = 200;
txtFramePause.value = 200;
chkShowSteps.onchange = () => {
showSteppedIteration(chkShowSteps.checked);
}
chkShowIntegration.checked = false;
chkShowSteps.checked = false;
scene.initialized = () => {
chkShowSteps.onchange();
}
labelPlot[0].innerHTML = 'Err(steps)';
dataPlot[0].setTitle('Err(steps)')
.setYTitle('Err (%)').setXTitle('steps');
activateDAQChannels(3);
attachDAQBuffer(0,0);
attachDAQBuffer(0,1);
attachDAQBuffer(0,2);
//}}}
/***
!!! fieldIterator
***/
//{{{
setFieldIterator(CartesianIterator.create({
xstart: -1,
xend: 1,
Nx: 20,
ystart: 1,
yend: 1,
Ny: 1,
zstart: 1,
zend: 1,
Nz: 1
}));
//}}}
/***
!!! sourceIterator
***/
//{{{
let a = 2;
setSourceIterator(CartesianIterator.create({
xstart: -a/2,
xend: a/2,
Nx: 20,
ystart: -a/2,
yend: a/2,
Ny: 20,
zstart: -a/2,
zend: a/2,
Nz: 20
}));
//}}}
/***
!!! iterateOverSource(dVf,si)
***/
//{{{
const iterateOverSource = (dVf,si) => {
let t_int = performance.now(), varn = 0,
Vcalc = 0, Vintegral = 0, Vdx3 = 0, Nsteps = 0,
qmax = [a/2,a/2,a/2],
step_ratio = 1.1, nsteps = 0,
Vexp = Math.pow(a,3);
si.setSteps(varn,si.getSteps(varn)*step_ratio).starts();
let dq3 = si.dq3();
console.log(
'steps['+varn+']=',si.getSteps(varn),'Vexp=',Vexp,
'dq=',si.__dq,'dq3=',dq3,
'\ndq['+varn+']=',si.__dq[varn],'/',qmax[varn],'=',$tw.ve.round(si.__dq[varn]/qmax[varn]*100,2)+'%'
);
si.run(function(dVs){
nsteps++;
Vcalc += dVs.volume;
Vintegral += dq3;
Vdx3 += dVs.dx3();
});
Nsteps = si.totalSteps();
console.log(
'q['+varn+'] ends at',si.__q[varn],'/',si.__end[varn],'/',qmax[varn],'=',
$tw.ve.round(si.__end[varn]/qmax[varn]*100,2)+'%',
Math.round((si.__end[varn]-qmax[varn])/si.__dq[varn]),'steps off.',
'\nIntegration time:',$tw.ve.round(performance.now()-t_int,3),'(ms).',
'in',nsteps,'steps, /',Nsteps,'=',$tw.ve.round(nsteps/Nsteps*100,2)+'%',(nsteps-Nsteps),'steps off.'
);
console.log('Vcal='+Vcalc+'('+$tw.ve.round((Vcalc-Vexp)/Vexp*100,2)+'%)');
console.log('Vint='+Vintegral+'('+$tw.ve.round((Vintegral-Vexp)/Vexp*100,2)+'%)');
console.log('Vdx3='+Vdx3+'('+$tw.ve.round((Vdx3-Vexp)/Vexp*100,2)+'%)');
recordData(scene.currentTime(),si.getSteps(varn),[
(Vcalc-Vexp)/Vexp*100,
(Vintegral-Vexp)/Vexp*100,
(Vdx3-Vexp)/Vexp*100
]);
}
//}}}
/***
!!! Initialization
***/
//{{{
scene.textBookView();
scene.camera.position.multiplyScalar(1.5);
let L = 1.5, N = 3,
r0 = vector(L/2,L/2,L/2),
tmpV = vector(),
cartesian_volume = box({
position: vector(L/2,L/2,L/2),
width: L,
length: L,
height: L,
visible: false,
opacity: 0.2
}),
spherical_volume = sphere({
position: vector(L/2,L/2,L/2),
radius: L,
visible: false,
opacity: 0.2
}),
cylindrical_volume = cylinder({
position: vector(L/2,L/2,L/2),
radius: L,
length: L,
visible: false,
opacity: 0.2
}),
r = sphere({
position: vector(Math.random(),Math.random(),Math.random()).multiplyScalar(L/8).add(r0),
radius: 0.05,
color: 0xff0000,
opacity: 0.7
}),
rp = sphere({
radius: 0.05,
color: 0x00ff00,
opacity: 0.7
}),
arr_delta_r = arrow({
axis: tmpV.copy(r.position).sub(rp.position),
color: 0xffff00
});
chkCartesianComponents.checked = true;
chkSphericalComponents.checked = false;
chkCylindricalComponents.checked = false;
chkSpherical.checked = false;
chkCylindrical.checked = false;
scene.initialized = () => {
showSteppedIteration(true);
if(__boxs){
__boxs.show(true,true);
__boxs.cur_color = __boxs.getColor();
}
rate(1);
}
//}}}
/***
!!! scene.checkStatus
***/
//{{{
scene.checkStatus = () => {
if(chkCartesianComponents.checked){
cartesian_volume.visible = true;
spherical_volume.visible = false;
cylindrical_volume.visible = false;
setSourceIterator(cartesian_si);
}else if(chkSphericalComponents.checked){
cartesian_volume.visible = false;
spherical_volume.visible = true;
cylindrical_volume.visible = false;
setSourceIterator(spherical_si);
}else if(chkCylindricalComponents.checked){
cartesian_volume.visible = false;
spherical_volume.visible = false;
cylindrical_volume.visible = true;
setSourceIterator(cylindrical_si);
}else{
cartesian_volume.visible = false;
spherical_volume.visible = false;
cylindrical_volume.visible = false;
}
}
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let cartesian_si = CartesianIterator.create({
//radius: cartesian.getUnitLength(),
xstart: 0,
xend: L,
ystart: 0,
yend: L,
zstart: 0,
zend: L,
Nx: N,
Ny: N,
Nz: N
}),
spherical_si = SphericalIterator.create({
radius: L,
Nr: N,
thetamax: Math.PI/2,
Ntheta: N,
phimax: Math.PI/2,
Nphi: N,
start: true
}),
cylindrical_si = CylindricalIterator.create({
radius: L,
Nr: N,
thetamax: Math.PI/2,
Ntheta: N,
zmin: 0,
zmax: L,
Nz: N,
start: true
});
let dVs = cartesian_si.tinyVolume();
const sourceIterator = () => {
if(chkSphericalComponents.checked)
return spherical_si.showSlicedPoints();
if(chkCylindricalComponents.checked)
return cylindrical_si.showSlicedPoints();
return cartesian_si.showSlicedPoints();
}
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let dr = vector();
const atSourcePoint = dV => {
rp.position.copy(dV.position);
arr_delta_r.position.copy(rp.position);
arr_delta_r.setAxis(tmpV.copy(r.position).sub(rp.position));
if(!$tw.physics.displacement(r.position,dV,dr)){
console.log('dV',dV,'contains',r.position);
dVs.copy(dV);
__boxs.setColor(0xffffff);
}else{
__boxs.setColor(__boxs.cur_color);
}
}
//}}}
/***
!!! doneSteppedSourceIteration
***/
//{{{
let line_proj = [];
const doneSteppedSourceIteration = () => {
rp.position.copy(dVs.position);
arr_delta_r.position.copy(rp.position);
arr_delta_r.setAxis(tmpV.copy(r.position).sub(rp.position));
updateSourcePointStatus(dVs);
__boxs.calculateFaces(dVs);
__boxs.setColor(0xffffff);
let proj = vector();
for(let n=0; n<3; n++){
if(!line_proj[n]){
line_proj[n] = dashline({
//color: cartesian.axis_arrow[n].getColor(),
vertices: [
vector(), vector()
],
visible: false
});
}
proj.copy(dVs.dx[n]).normalize();
line_proj[n].setVertex(0,r.position)
.setVertex(1,proj.multiplyScalar(proj.dot(tmpV)).add(dVs.position));
}
}
//}}}
/***
!!! scene.idle
***/
//{{{
scene.idle = () => {
for(let n=0; n<3; n++)
line_proj[n].visible = true;
}
//}}}
/***
!!! init()
***/
//{{{
let Bf = vectorField.create(), nB = 0;
scene.add(Bf);
txtFramePause.value = 0;
chkAutoCPF.checked = true;
btnStart.click();
circle({
radius: wireloop.getRadius(),
color: 0xffff00,
opacity: 0.2
})
scene.initialized = () => {
scene.camera.position.multiplyScalar(wireloop.getRadius());
Bf.clear();
nB = 0;
chkCartesian.checked = false;
chkCartesianComponents.disabled = true;
tinyMagnet.mu.setCenter(tinyMagnet.position.set(0,0,0));
tinyMagnet.mu.calibrate(vector(0,0,tinyMagnet.getDepth()/2),0.5);
tinyMagnet.z0 = wireloop.getRadius();
tinyMagnet.position.z = -tinyMagnet.z0;
tinyMagnet.mu.setCenter(tinyMagnet.position);
tinyMagnet.v0 = -tinyMagnet.position.z/0.05;
tinyMagnet.velocity.z = tinyMagnet.v0;
}
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
const fi = wireloop.getRadius
? CylindricalIterator.create({
center: wireloop.position,
rmin: wireloop.getRadius()/1000,
rmax: wireloop.getRadius(),
Nr: 40,
Nphi: 60,
zmin: 0,
zmax: Rt/100,
Nz: 1,
color: 0x00ffff,
opacity: 0.7
})
: CartesianIterator.create({
center: wireloop.position,
xmin: -wireloop.getWidth()*1.5,
xmax: wireloop.getWidth()*1.5,
Nx: 10,
ymin: -wireloop.getHeight()*1.5,
ymax: wireloop.getHeight()*1.5,
Ny: 10,
zmin: -wireloop.getDepth()*0.5,
zmax: wireloop.getDepth()*0.5,
Nz: 20,
color: 0x00ffff,
opacity: 0.7
});
//console.log('fi=',fi);
setFieldIterator(fi);
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let B = vectorField.pointField();
B.Br = vector();
const atFieldPoint = dVf => {
let t_int = performance.now();
B.position.copy(dVf.center);
tinyMagnet.mu.fieldAt(dVf.center,B.Br);
B.setField(B.Br.multiplyScalar(1e-1),undefined,0.3);
Bf.setField(nB,B);
//console.log('B =',B,'Calculated in',$tw.ve.round(performance.now()-t_int,3),'ms');
}
//}}}
/***
!!! atInstance()
***/
//{{{
let inst_msg = [];
const atInstance = (simT,simdT) => {
if(tinyMagnet.position.z > tinyMagnet.z0){
tinyMagnet.position.z = -tinyMagnet.z0;
tinyMagnet.mu.setCenter(tinyMagnet.position);
}else if(typeof chkSlowMotion !== 'undefined' && chkSlowMotion.checked &&
Math.abs(tinyMagnet.position.z)<tinyMagnet.getDepth()*txtSlowWithin.value){
let ratio = +txtSlowRatio.value;
if(ratio) tinyMagnet.velocity.z = tinyMagnet.v0/ratio;
}else{
tinyMagnet.velocity.z = tinyMagnet.v0;
}
nB = 0;
fi.run(function(dV,n){
atFieldPoint(dV);
nB++;
});
Bf.showField(true,0,nB);
tinyMagnet.position.z += tinyMagnet.velocity.z*simdT;
tinyMagnet.mu.setCenter(tinyMagnet.position);
//inst_msg[0] = ' / r.z=';
//inst_msg[1] = $tw.ve.round(tinyMagnet.position.z,6);
//spanMsg.innerHTML = inst_msg.join('');
}
//}}}
/***
!!! data recording
***/
//{{{
labelPlot[0].innerHTML = '\\(\\oint \\vec B(\\vec r) \\cdot d\\vec l\\)';
dataPlot[0].setTitle("Ampere's Law with Distance")
.setYTitle('\\(\\oint \\vec B \\cdot d\\vec l\\)').setXTitle('//r// (m)');
chkShowIntegration.checked = false;
chkPlot0.checked = chkPlot1.checked = true;
txtFramePause.value = 0;
chkAutoCPF.checked = true;
btnStart.click();
scene.initialized = () => {
scene.camera.position.multiplyScalar(current.getRadius());
}
//}}}
/***
!!! fieldIteratorParameters
***/
//{{{
let fi = CylindricalIterator.create({
center: current.position,
rmin: current.getRadius()*0.01,
rmax: current.getRadius()*3,
Nr: 50,
phimin: 0,
Nphi: 60,
zmin: 0,
zmax: current.getLength()/1000,
Nz: 1,
color: 0x00ffff,
opacity: 0.5
}),
path = ring({
Rin: current.getRadius(),
Rout: current.getRadius()*1.05,
segments: fi.getSteps(1),
visible: false
});
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let si = CylindricalIterator.create({
rmax: current.getRadius(),
layers: 10,
Nphi: 60,
height: current.getHeight(),
Nz: 30
});
//si.showSlicedPoints(false);
setSourceIterator(si);
//}}}
/***
!!! iterateOverSource(dtau,si)
***/
//{{{
let B = vector(), dr = vector(), B_dl = 0,
dl = vector(), dataY = [];
const iterateOverSource = (dtau,si) => {
let t_int = performance.now();
$tw.physics.vectorFieldAt(current,dtau.center,B,$tw.physics.tinyBField,si);
dr.copy(dtau.center).sub(current.position);
dl.copy(scene.zaxis).cross(dr).normalize().multiplyScalar(fi.getCoordinate(0)*fi.getStepSize(1));
B_dl = B.dot(dl);
//console.log('Field integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
}
//}}}
/***
!! fi.startIteration
***/
//{{{
fi.startIteration = n => {
if(n===1){
//B_dl = 0;
path.visible = true;
path.setRadius(fi.getCoordinate(0));
}
}
//}}}
/***
!!! fi.endIteration
***/
//{{{
fi.endIteration = n => {
if(n===1){
dataY[0] = B_dl;
recordData(scene.currentTime(),fi.getCoordinate(0),dataY);
B_dl = 0;
}
}
//}}}
/***
!!! init()
***/
//{{{
let Bf = vectorField.create(), dBf = vectorField.create(), nB = 0;
scene.add(Bf).add(dBf);
Bf.factor = 2e5;
chkShowIntegration.checked = false;
txtFramePause.value = 200;
chkAutoCPF.checked = true;
btnStart.click();
scene.initialized = () => {
Bf.clear();
dBf.clear();
nB = 0;
}
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
let fi = CylindricalIterator.create({
center: current.position,
rmin: current.getRadius()*5,
rmax: current.getRadius()*5,
layers: 1,
Nphi: 20,
zstart: -current.getHeight()/3,
zend: current.getHeight()/3,
Nz: 20,
color: 0x00ffff,
opacity: 0.7
});
//fi.showSlicedPoints();
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
setSourceIterator(CylindricalIterator.create({
//rmin: current.getRadius(),
rmax: current.getRadius(),
layers: 30,
Nphi: 30,
height: current.getHeight(),
Nz: 100
}).showSlicedPoints(false));
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let B = vectorField.pointField();
B.Br = vector(); B.dr = vector();
const atFieldPoint = (dVf,dVs) => {
dB.position.copy(dVf.center);
B.clear(); B.Br.set(0,0,0);
B.position.copy(dVf.center);
ndB = 0;
}
//}}}
/***
!!! atSourcePoint(dVs,dVf,si)
***/
//{{{
let ndB = 0, dB = vectorField.pointField();
dB.dr = vector(); dB.dBr = vector();
dB.color = 0xffff00; dB.opacity = 0.5;
const atSourcePoint = (dVs,dVf,si) => {
dB.dr.copy(dVf.center).sub(dVs.center);
$tw.physics.tinyBField(current,dB.dr,dVs.volume,dB.dBr);
dB.setField(dB.dBr.multiplyScalar(Bf.factor));
B.setField(B.Br.add(dB.dBr));
dBf.setField(ndB,dB);
dBf.showField(true,ndB,++ndB);
if(ndB > si.n2){
ndB = 0;
dBf.show(false);
Bf.setField(nB,B);
}
},
//}}}
/***
!!! iterateOverSource(dV,si)
***/
//{{{
iterateOverSource = (dV,si) => {
let t_int = performance.now();
$tw.physics.vectorFieldAt(current,dV.center,B.Br,$tw.physics.tinyBField,si);
if(nB === 0){
Bf.setField(nB,B.setField(B.Br.multiplyScalar(Bf.factor)));
//Bf.max *= 10;
//Bf.normalize(Bf.max);
}else{
Bf.setField(
nB,B.setField(B.Br.multiplyScalar(Bf.factor))
);
}
Bf.showField(true,nB,++nB);
//console.log('Integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
},
//}}}
/***
!!! startSteppedSourceIteration()
***/
//{{{
startSteppedSourceIteration = (dV,si) => {
// Start integrating over the source.
//current.visible = false;
//si.showSlicedPoints();
},
//}}}
/***
!!! doneSteppedSourceIteration()
***/
//{{{
doneSteppedSourceIteration = () => {
// Done integrating over the source, go to
// next field point.
Bf.setField(nB,B);
Bf.showField(true,nB,++nB);
},
//}}}
/***
!!! cancelSteppedSourceIteration()
***/
//{{{
cancelSteppedSourceIteration = (dV,si) => {
// Canceled integrating over the source, finish the
// on going integration.
current.visible = true;
si.showSlicedPoints(false);
if(ndB) iterateOverSource(dV,si);
}
//}}}
/***
!!! init()
***/
//{{{
let Bf = vectorField.create(), dBf = vectorField.create(), nB = 0;
scene.add(Bf).add(dBf);
Bf.factor = 2e6;
chkShowIntegration.checked = false;
txtFramePause.value = 200;
chkAutoCPF.checked = true;
btnStart.click();
scene.initialized = () => {
Bf.clear();
dBf.clear();
nB = 0;
}
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
let fi = CylindricalIterator.create({
center: current.position,
rmin: current.getRadius()*50, //*5,
rmax: current.getRadius()*50, //*5,
layers: 1,
Nphi: 20,
zstart: -current.getHeight()/3,
zend: current.getHeight()/3,
Nz: 20,
color: 0x00ffff,
opacity: 0.7
});
//fi.showSlicedPoints();
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let si = CylindricalIterator.create({
//rmin: current.getRadius(),
rmax: current.getRadius(),
layers: 1, //30,
Nphi: 1, //30,
height: current.getHeight(),
Nz: 100
});
si.showSlicedPoints(false);
setSourceIterator(si);
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let B = vectorField.pointField();
B.Br = vector(); B.dr = vector();
const atFieldPoint = (dVf,dVs) => {
dB.position.copy(dVf.center);
B.clear(); B.Br.set(0,0,0);
B.position.copy(dVf.center);
ndB = 0;
}
//}}}
/***
!!! atSourcePoint(dVs,dVf,si)
***/
//{{{
let ndB = 0, dB = vectorField.pointField();
dB.dr = vector(); dB.dBr = vector();
dB.color = 0xffff00; dB.opacity = 0.5;
const atSourcePoint = (dVs,dVf,si) => {
dB.dr.copy(dVf.center).sub(dVs.center);
$tw.physics.tinyBField(current,dB.dr,dVs.volume,dB.dBr);
dB.setField(dB.dBr.multiplyScalar(Bf.factor));
B.setField(B.Br.add(dB.dBr));
dBf.setField(ndB,dB);
dBf.showField(true,ndB,++ndB);
if(ndB > si.n2){
ndB = 0;
dBf.show(false);
Bf.setField(nB,B);
}
},
//}}}
/***
!!! iterateOverSource(dV,si)
***/
//{{{
iterateOverSource = (dV,si) => {
let t_int = performance.now();
$tw.physics.vectorFieldAt(current,dV.center,B.Br,$tw.physics.tinyBField,si);
if(nB === 0){
Bf.setField(nB,B.setField(B.Br.multiplyScalar(Bf.factor)));
//Bf.max *= 10;
//Bf.normalize(Bf.max);
}else{
Bf.setField(
nB,B.setField(B.Br.multiplyScalar(Bf.factor))
);
}
Bf.showField(true,nB,++nB);
//console.log('Integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
},
//}}}
/***
!!! startSteppedSourceIteration()
***/
//{{{
startSteppedSourceIteration = (dV,si) => {
// Start integrating over the source.
current.visible = false;
si.showSlicedPoints();
},
//}}}
/***
!!! doneSteppedSourceIteration()
***/
//{{{
doneSteppedSourceIteration = () => {
// Done integrating over the source, go to
// next field point.
Bf.setField(nB,B);
Bf.showField(true,nB,++nB);
},
//}}}
/***
!!! cancelSteppedSourceIteration()
***/
//{{{
cancelSteppedSourceIteration = (dV,si) => {
// Canceled integrating over the source, finish the
// on going integration.
current.visible = true;
si.showSlicedPoints(false);
if(ndB) iterateOverSource(dV,si);
}
//}}}
/***
!!! init()
***/
//{{{
let Bf = vectorField.create(), dBf = vectorField.create(), nB = 0;
scene.add(Bf).add(dBf);
Bf.factor = 5e2;
chkShowIntegration.checked = false;
txtFramePause.value = 200;
chkAutoCPF.checked = true;
btnStart.click();
scene.initialized = () => {
Bf.clear();
dBf.clear();
nB = 0;
}
//}}}
/***
!!! fieldIteratorParameters()
***/
//{{{
let fi = CylindricalIterator.create({
center: current.position,
rmin: 1e-9,
rmax: current.getRadius()*2,
layers: 10,
Nphi: 30,
zstart: -current.getRadius(),
zend: current.getRadius(),
Nz: 20,
color: 0x00ffff,
opacity: 0.7
});
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let si = CylindricalIterator.create({
rmin: current.getRadius(),
rmax: current.getRadius(),
Nr: 1,
Nphi: 60,
zmin: 0,
zmax: 0,
Nz: 1
});
si.showSlicedPoints(false);
setSourceIterator(si);
//setSourceIterator(current.iterator);
//}}}
/***
!!! atFieldPoint(dVf)
***/
//{{{
let B = vectorField.pointField();
B.Br = vector(); B.dr = vector();
const atFieldPoint = (dVf,dVs) => {
dB.position.copy(dVf.center);
B.clear(); B.Br.set(0,0,0);
B.position.copy(dVf.center);
ndB = 0;
},
//}}}
/***
!!! doneFieldIteration()
***/
//{{{
doneFieldIteration = () => {
Bf.normalize(Bf.max*20);
};
//}}}
/***
!!! atSourcePoint(dVs,dVf,si)
***/
//{{{
let ndB = 0, dB = vectorField.pointField();
dB.dr = vector(); dB.dBr = vector();
dB.color = 0xffff00; dB.opacity = 0.5;
const atSourcePoint = (dVs,dVf,si) => {
dB.dr.copy(dVf.center);
if(current.tinyFieldAt){
current.tinyFieldAt(dB.dr,dVs,dB.dBr);
}else{
$tw.physics.tinyBField(current,dB.dr.sub(dVs.center),dVs.volume,dB.dBr);
}
dB.setField(dB.dBr.multiplyScalar(Bf.factor));
B.setField(B.Br.add(dB.dBr));
dBf.setField(ndB,dB);
dBf.showField(true,ndB,++ndB);
if(ndB > si.n2){
ndB = 0;
dBf.show(false);
Bf.setField(nB,B);
}
},
//}}}
/***
!!! iterateOverSource(dV,si)
***/
//{{{
iterateOverSource = (dV,si) => {
let t_int = performance.now();
if(current.fieldAt){
current.fieldAt(dV.center,B.Br,si);
}else{
$tw.physics.vectorFieldAt(current,dV.center,B.Br,$tw.physics.tinyBField,si);
}
if(nB === 0){
Bf.setField(nB,B.setField(B.Br.multiplyScalar(Bf.factor)));
}else{
Bf.setField(
nB,B.setField(B.Br.multiplyScalar(Bf.factor))
);
}
Bf.showField(true,nB,++nB);
//console.log('Integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
},
//}}}
/***
!!! startSteppedSourceIteration()
***/
//{{{
startSteppedSourceIteration = (dV,si) => {
// Start integrating over the source.
current.visible = false;
si.showSlicedPoints();
},
//}}}
/***
!!! doneSteppedSourceIteration()
***/
//{{{
doneSteppedSourceIteration = () => {
// Done integrating over the source, go to
// next field point.
Bf.setField(nB,B);
Bf.showField(true,nB,++nB);
},
//}}}
/***
!!! cancelSteppedSourceIteration()
***/
//{{{
cancelSteppedSourceIteration = (dV,si) => {
// Canceled integrating over the source, finish the
// on going integration.
current.visible = true;
si.showSlicedPoints(false);
if(ndB) iterateOverSource(dV,si);
}
//}}}
/***
!!! init()
***/
//{{{
let Ef = vectorField.create(), dEf = vectorField.create(), nE = 0;
scene.add(Ef).add(dEf);
chkShowIntegration.checked = false;
btnStart.click();
scene.initialized = () => {
Ef.clear();
dEf.clear();
nE = 0;
}
//}}}
/***
!!! fieldIteratorParameters
***/
//{{{
let fi = SphericalIterator.create({
center: charge.position,
rmin: charge.getRadius()*2,
rmax: charge.getRadius()*2,
color: 0x00ffff,
opacity: 0.7,
layers: 1,
ntheta: 20,
nphi: 40
}).showSlicedPoints();
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let si = SphericalIterator.create({
rmin: 0,
rmax: charge.getRadius(),
layers: 20,
ntheta: 30,
nphi: 60
}).showSlicedPoints(false);
setSourceIterator(si);
//}}}
/***
!!! atFieldPoint(dVf), atSourcePoint(dVs,dVf,si)
***/
//{{{
let E = vectorField.pointField();
E.Er = vector();
const atFieldPoint = dVf => {
dE.position.copy(dVf.center);
E.clear(); E.Er.set(0,0,0);
E.position.copy(dVf.center);
ndE = 0;
}
//}}}
//{{{
let ndE = 0, dE = vectorField.pointField(), dr = vector();
dE.dEr = vector(); dE.color = 0xffff00; dE.opacity = 0.5;
const atSourcePoint = (dVs,dVf,si) => {
dr.copy(dVf.center).sub(dVs.center);
$tw.physics.tinyEField(charge,dr,dVs.volume,dE.dEr)
dE.setField(dE.dEr.multiplyScalar(1/Ef.max));
E.setField(E.Er.add(dE.dEr));
dEf.setField(ndE,dE);
dEf.showField(true,ndE,++ndE);
if(ndE > si.n2){
ndE = 0;
dEf.show(false);
Ef.setField(nE,E);
}
},
//}}}
/***
!!! iterateOverSource(dV,si)
***/
//{{{
iterateOverSource = (dV,si) => {
let t_int = performance.now();
$tw.physics.vectorFieldAt(charge,dV.center,E.Er,$tw.physics.tinyEField,si);
if(nE === 0){
Ef.setField(nE,E.setField(E.Er));
Ef.max *= 5;
Ef.normalize(Ef.max);
}else{
Ef.setField(
nE,E.setField(E.Er.multiplyScalar(1/Ef.max))
);
}
Ef.showField(true,nE,++nE);
//console.log('Integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
},
//}}}
/***
!!! startSteppedSourceIteration()
***/
//{{{
startSteppedSourceIteration = (dV,si) => {
// Start integrating over the source.
charge.visible = false;
si.showSlicedPoints();
},
//}}}
/***
!!! doneSteppedSourceIteration()
***/
//{{{
doneSteppedSourceIteration = () => {
// Done integrating over the source, go to
// next field point.
Ef.setField(nE,E);
Ef.showField(true,nE,++nE);
},
//}}}
/***
!!! cancelSteppedSourceIteration()
***/
//{{{
cancelSteppedSourceIteration = (dV,si) => {
// Canceled integrating over the source, finish the
// on going integration.
charge.visible = true;
si.showSlicedPoints(false);
if(ndE) iterateOverSource(dV,si);
}
//}}}
/***
!!! data recording
***/
//{{{
labelPlot[0].innerHTML = '\\(V(r)\\)';
dataPlot[0].setTitle('Electric Potential vs Distance')
.setYTitle('//V// (volt)').setXTitle('//r// (m)');
labelPlot[1].innerHTML = '\\(E(r)\\)';
dataPlot[1].setTitle('Electric Field Strength vs Distance')
.setYTitle('//E// (volt / m)').setXTitle('//r// (m)');
chkShowIntegration.checked = false;
chkPlot0.checked = chkPlot1.checked = true;
txtFramePause.value = 0;
btnStart.click();
//}}}
/***
!!! fieldIteratorParameters
***/
//{{{
let fi = SphericalIterator.create({
center: charge.position,
rmin: charge.getRadius()*0.1,
rmax: charge.getRadius()*2,
color: 0x00ffff,
opacity: 0.7,
layers: 100,
thetamin: Math.PI/2,
ntheta: 1,
phimin: Math.PI/4,
nphi: 1
});
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let si = SphericalIterator.create({
rmin: 0,
rmax: charge.getRadius(),
layers: 50,
ntheta: 30,
nphi: 60
});
//si.showSlicedPoints(false);
setSourceIterator(si);
//}}}
/***
!!! init
***/
//{{{
let t_potential = $tw.threeD.stats.create(),
t_field = $tw.threeD.stats.create();
scene.initialized = () => {
t_potential.reset();
t_field.reset();
}
//}}}
/***
!!! iterateOverSource(dtau,si)
***/
//{{{
let E = vector(), dr = vector(), dataY = [];
const iterateOverSource = (dtau,si) => {
let t_int = performance.now();
let V = $tw.physics.scalarFieldAt(charge,dtau.center,$tw.physics.tinyEPotential,si);
t_potential.addInstantValue(performance.now()-t_int);
//console.log('Potential integration time:',$tw.ve.round(t_potential.getInstantValue(),3),'ms');
t_int = performance.now();
$tw.physics.vectorFieldAt(charge,dtau.center,E,$tw.physics.tinyEField,si);
t_field.addInstantValue(performance.now()-t_int);
//console.log('Field integration time:',$tw.ve.round(t_field.getInstantValue(),3),'ms');
dataY[0] = V; dataY[1] = E.length();
let r = dr.copy(dtau.center).sub(charge.position).length();
recordData(scene.currentTime(),r,dataY);
},
//}}}
/***
!!! iterationsCompleted()
***/
//{{{
compare = (d1,d2) => {
let rmsd = $tw.data.RMSD(d1,d2),
nrmsd = $tw.data.NRMSD(d1,d2),
rmsdirq = $tw.data.RMSDIQR(d1,d2);
console.log(
'RMSD:',rmsd,
'NRMSD:',($tw.ve.round(nrmsd*100,2)+'%'),
'RMSDIQR:',($tw.ve.round(rmsdirq*100,2)+'%')
);
},
iterationsCompleted = () => {
console.log(
'Average Integration Time - Potentail:',
$tw.ve.round(t_potential.getAverageValue(),3),'ms'
);
console.log(
'Average Integration Time - Field:',
$tw.ve.round(t_field.getAverageValue(),3),'ms'
);
let d = dataPlot[0].getDataSet(0);
//console.log(d);
d = d.clone();
d.differentiate(null,fi.__dq[0]).multiply(-1);
//console.log(d);
dataPlot[1].addDataSet(d).update();
compare(d,dataPlot[1].getDataSet(0));
d = dataPlot[1].getDataSet(0);
d = d.clone();
d.integrate(d.getValue(-1),-1,fi.__dq[0]);
//console.log(d);
dataPlot[0].addDataSet(d).update();
compare(d,dataPlot[0].getDataSet(0));
}
//}}}
/***
!!! Initialization
***/
//{{{
scene.textBookView();
//scene.setRange(2);
const R = cartesian.getUnitLength();
let labelrdl = label({
text: '\\(\\vec r_{dl}\\)',
pos: vector(R*0.5,0,0),
size: scene.defaultFontSize*0.3,
color: 0xffffff
}),
labelrdl_formula = label({
text: '\\(\\vec r_{dl} = R \\hat \\rho\\)',
pos: vector(-R/4,R,R/2),
size: scene.defaultFontSize*0.7,
color: 0xffffff
}),
dphi = circle({
radius: R*0.3,
color: 0x00ff00,
opacity: 0.3
}),
labeldphi = label({
text: '\\(d\\phi\\)',
size: scene.defaultFontSize*0.3,
color: 0x00ff00
}),
phi = circle({
radius: R*0.3,
opacity: 0.3,
color: 0xffff00
}),
labelphi = label({
text: '\\(\\phi\\)',
size: scene.defaultFontSize*0.3,
color: 0xffff00
}),
path = circle({
radius: R,
segments: 360,
opacity: 0.3
});
//}}}
/***
!!! fieldIteratorParameters
***/
//{{{
let fi = CylindricalIterator.create({
radius: R,
phistart: 0,
phiend: Math.PI*2,
zstart: 0,
zend: 0,
Nr: 1,
Nphi: 60,
Nz: 1
}).showSlicedPoints();
//dVf = fi.tinyVolume();
setFieldIterator(fi);
scene.initialized = () => {
if(__boxf) __boxf.showLabel(false);
rate(0.5);
}
//}}}
/***
!!! atFieldPoint
***/
//{{{
let dl = vector(),
rdl = vector(),
B = vector(),
rB = vector(),
arrB = arrow({
color: 0xffff00
}),
arrdl = arrow({
color: 0x00ffff
}),
labelB = label({
text: '\\(\\vec f(\\vec r)\\)',
size: scene.defaultFontSize*0.3,
color: 0xffff00
}),
labeldl = label({
text: '\\(d\\vec l\\)',
size: scene.defaultFontSize*0.3,
color: 0x00ffff
}),
labeldl_formula = label({
text: '\\(d\\vec l = Rd\\phi \\hat\\phi\\)',
size: scene.defaultFontSize*0.3,
pos: vector(-R/4,R,R/4),
color: 0x00ffff
});
const atFieldPoint = dV => {
let angle = fi.getCoordinate(1);
path.setThetaLength(angle);
dl.copy(scene.zaxis).cross(dV.dx[0]).normalize().multiplyScalar(R*fi.getStepSize(1));
arrdl.position.copy(
rdl.copy(
rB.copy(dV.position).add(dV.dx[0])
)
);
arrdl.setAxis(dl);
labeldl.setPosition(rdl.multiplyScalar(1.1));
labeldl.setDir(dl);
rdl.z = -R/5;
labeldl_formula.setPosition(rdl);
rdl.z = 0;
labeldl_formula.setDir(dl);
arrB.position.copy(rB);
arrB.setAxis(
B.set(Math.random(),Math.random(),Math.random()).normalize().multiplyScalar(rdl.length()*0.5)
);
labelB.setPosition(rB.add(B).multiplyScalar(1.1));
labelB.setDir(B);
labelrdl.setPosition(rdl.multiplyScalar(0.55));
labelrdl.setDir(dV.dx[0]);
rdl.z = R/5;
labelrdl_formula.setPosition(rdl);
rdl.z = 0;
labelrdl_formula.setDir(dV.dx[0]);
dphi.setThetaStart(angle);
dphi.setThetaLength(fi.getStepSize(1));
labeldphi.setPosition(rdl.multiplyScalar(0.3));
labeldphi.setDir(dV.dx[0]);
phi.setThetaLength(angle);
labelphi.setPosition(rdl.copy(dV.dx[0]).multiplyScalar(0.2).applyAxisAngle(scene.zaxis,-angle*0.5));
labelphi.setDir(rdl);
}
//}}}
/***
!!! scene.checkStatus
***/
//{{{
//scene.checkStatus = () => {
// labelrdl_formula.lookAt(scene.camera.position);
// labeldl_formula.lookAt(scene.camera.position);
//}
//}}}
/***
!!! data recording
***/
//{{{
labelPlot[0].innerHTML = '\\(B(r)\\)';
dataPlot[0].setTitle('Magnetic Field Strength vs Distance')
.setYTitle('//B// (T)').setXTitle('//r// (m)');
chkShowIntegration.checked = false;
chkPlot0.checked = chkPlot1.checked = true;
txtFramePause.value = 0;
chkAutoCPF.checked = true;
btnStart.click();
//}}}
/***
!!! fieldIteratorParameters
***/
//{{{
let fi = CylindricalIterator.create({
center: current.position,
rmin: current.getRadius()*0.1,
rmax: current.getRadius()*2,
color: 0x00ffff,
opacity: 0.7,
layers: 100,
phimin: Math.PI/4,
nphi: 1,
zmin: 0,
zmax: 0
});
setFieldIterator(fi);
//}}}
/***
!!! sourceIteratorParameters
***/
//{{{
let si = CylindricalIterator.create({
rmax: current.getRadius(),
layers: 50,
Nphi: 30,
height: current.getHeight(),
Nz: 100
});
//si.showSlicedPoints(false);
setSourceIterator(si);
//}}}
/***
!!! iterateOverSource(dtau,si)
***/
//{{{
let B = vector(), dr = vector(), dataY = [];
const iterateOverSource = (dtau,si) => {
let t_int = performance.now();
$tw.physics.vectorFieldAt(current,dtau.center,B,$tw.physics.tinyBField,si);
//console.log('Field integration time:',$tw.ve.round(performance.now()-t_int,3),'ms');
dataY[0] = B.length();
let r = dr.copy(dtau.center).sub(current.position).length();
recordData(scene.currentTime(),r,dataY);
}
//}}}
/***
!! Finite Bar Magnet
***/
//{{{
let barMagnet = box({
position: vector(1e-2,1e-2,0),
width: 1e-2,
height: 1e-2,
depth: 3e-2,
color: 0xFFFF00,
opacity: 0.5
});
barMagnet.mu = $tw.physics.magneticDipoleMoment({
position: barMagnet.position,
axis: vector(0,0,barMagnet.getDepth()),
//axis: vector(Math.random(),Math.random(),Math.random()),
volume: barMagnet.volume(),
color: 0xFFD700,
opacity: 1
});
//barMagnet.rotateWorld(barMagnet.mu.getAxis().cross(barMagnet.up).normalize(),-Math.PI/2);
barMagnet.mu.setMoment(barMagnet.mu.axis);
scene.add(barMagnet.mu.shiftToCenter());
sphere({
position: barMagnet.mu.getAxis().add(barMagnet.mu.position),
radius: barMagnet.getDepth()/20,
color: 0x000000,
opacity: 0.5
});
// Define source iterator
barMagnet.mu.iterator = CartesianIterator.create({
position: barMagnet.position,
axis: barMagnet.mu.axis,
xmin: -barMagnet.getWidth()/2,
xmax: barMagnet.getWidth()/2,
Nx: 20,
ymin: -barMagnet.getHeight()/2,
ymax: barMagnet.getHeight()/2,
Ny: 20,
zmin: -barMagnet.getDepth()/2,
zmax: barMagnet.getDepth()/2,
Nz: 40
});
// Set the magnetic field to be 0.5 T at the center of the top face.
barMagnet.mu.calibrate(barMagnet.mu.getAxis().add(barMagnet.mu.position),0.5);
console.log('barMagnet.mu',barMagnet.mu);
//}}}
/***
!! Finite Cylinder Magnet
***/
//{{{
let cylinderMagnet = cylinder({
position: vector(5e-2,3e-2,0),
axis: vector(3e-2,2e-2,4e-2),
radius: 1e-2,
color: 0xFFFF00,
opacity: 0.5
});
console.log('cylinder axis:',cylinderMagnet.axis);
cylinderMagnet.mu = $tw.physics.magneticDipoleMoment({
position: cylinderMagnet.position,
axis: cylinderMagnet.axis,
moment: cylinderMagnet.axis,
volume: cylinderMagnet.volume(),
color: 0xFFD700,
opacity: 1
});
scene.add(cylinderMagnet.mu.shiftToCenter());
sphere({
position: cylinderMagnet.mu.getAxis().add(cylinderMagnet.mu.position),
radius: cylinderMagnet.getRadius()/10,
color: 0x000000,
opacity: 0.5
});
// Define source iterator
cylinderMagnet.mu.iterator = CylindricalIterator.create({
position: cylinderMagnet.position,
axis: cylinderMagnet.axis,
rmin: 0,
rmax: cylinderMagnet.getRadius(),
Nr: 20,
phimin: 0,
phimax: 2*Math.PI,
Nphi: 60,
zmin: -cylinderMagnet.getHeight()/2,
zmax: cylinderMagnet.getHeight()/2,
Nz: 20
});
// Set the magnetic field to be 0.5 T at the center of the top face.
cylinderMagnet.mu.calibrate(cylinderMagnet.mu.getAxis().add(cylinderMagnet.mu.position),0.5);
//cylinderMagnet.mu.iterator.showSlicedPoints(true);
console.log('cylinderMagnet.mu',cylinderMagnet.mu);
//}}}
/***
!! Tiny Magnetic Dipole
***/
//{{{
let tinyMagnet = box({
width: 1e-4, // width 100 micron (x-direction)
height: 1e-4, // height 100 micron (y-direction)
depth: 1e-3, // depth 1000 micron (z-direction)
color: 0xFFFF00,
opacity: 0.5
});
$tw.threeD.physicalObject(tinyMagnet,{
mass: 0.01
});
// Assuming a moment of 1e6 electron spin moment (Bohr magneton).
// Source: https://en.wikipedia.org/wiki/Bohr_magneton
///*
tinyMagnet.mu = $tw.physics.magneticDipoleMoment({
color: 0xFFD700,
axis: vector(0,0,tinyMagnet.getDepth()),
moment: vector(0,0,1e6*$tw.physics.mu_B),
volume: tinyMagnet.volume(),
opacity: 1
});
//*/
///*
tinyMagnet.mu.dV = CartesianTinyVolume.create().setCoordinates(
[
-tinyMagnet.getWidth()/2,
-tinyMagnet.getHeight()/2,
-tinyMagnet.getDepth()/2
],
[
tinyMagnet.getWidth(),
tinyMagnet.getHeight(),
tinyMagnet.getDepth()
]
);
tinyMagnet.mu.dV.box = tinyMagnet.mu.dV.createBox()
.calculateFaces(tinyMagnet.mu.dV).show(true);
scene.add(tinyMagnet.mu.shiftToCenter());
console.log('tinyMagnet.mu',tinyMagnet.mu);
//*/
//}}}
/***
!! Tiny Magnetic Dipole
***/
//{{{
let tinyMagnet = cylinder({
radius: 5e-5, // radius 50 micron
length: 2e-4, // length 200 micron
color: 0xFFFF00,
opacity: 0.5
});
// Assuming a moment of 1e6 electron spin moment (Bohr magneton).
// Source: https://en.wikipedia.org/wiki/Bohr_magneton
tinyMagnet.mu = $tw.physics.magneticDipoleMoment({
color: 0xFFD700,
axis: vector(0,0,tinyMagnet.getLength()),
moment: vector(0,0,1e6*$tw.physics.mu_B),
volume: tinyMagnet.volume(),
opacity: 1
});
/*
tinyMagnet.mu.dV = CartesianTinyVolume.create().setCoordinates(
[
-tinyMagnet.getRadius(),
-tinyMagnet.getRadius(),
-tinyMagnet.getLength()/2
],
[
tinyMagnet.getRadius()*2,
tinyMagnet.getRadius()*2,
tinyMagnet.getLength()
]
);
tinyMagnet.mu.dV.box = tinyMagnet.mu.dV.createBox()
.calculateFaces(tinyMagnet.mu.dV).show(true);
//*/
scene.add(tinyMagnet.mu.shiftToCenter());
console.log('tinyMagnet.mu',tinyMagnet.mu);
//}}}
<!--{{{-->
<link rel="stylesheet" type="text/css" href="tw.qmo.css">
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"
}
}
</script>
<script type="text/javascript" src="$tw.plugins.min.js"></script>
<script type="text/javascript" src="$tw.VPM.js"></script>
<!--}}}-->
/***
''These codes are to solve @@color:red;1^^st^^ order differential equations@@ using the 4^^th^^ order ~Runge-Kutta method, for the following cases:''
# single particle 1D motion;
# single particle 3D motion;
# many particles 1D motion;
# many particles 3D motion.
***/
/***
!! Single Particle 1D Python
***/
/*{{{*/
def RK4(r,V,t,dt,v_now = None):
# Returns the next position or function value after time dt,
# using the 4th order Runge-Kutta algorithms.
# r: current position or function value
# V: Function v(r,t) shall return the velocity or first derivative at
# position r and time t.
# t: current time
# dt: time step
# v_now: current velocity or first derivative (optional).
r1 = r
v1 = v_now
if v1 is None: v1 = V(r1,t)
v2 = V(r+dt/2.0*v1,t+dt2)
v3 = V(r+dt/2.0*v2,t+dt3)
v4 = V(r+dt*v3,t+dt)
r += (v1+(v2+v3)*2.0+v4)*dt/6.0
v_now = V(r,t+dt)
return (r,v_now)
/*}}}*/
/***
!! Single Particle 3D Python
***/
/*{{{*/
def RK4Vector(r,V,t,dt,v_now = None):
# Returns the next position or function value after time dt,
# using the 4th order Runge-Kutta algorithms.
# r: current position or function value
# V: Function v(r,t) shall return the velocity or first derivative at
# position r and time t.
# t: current time
# dt: time step
# v_now: current velocity or first derivative (optional).
// Python knows what to do with vectors.
return RK4(r,V,t,dt,v_now)
/*}}}*/
/***
!! Many Particles 1D Python
***/
/*{{{*/
def RK4ListVector(r,v,A,t,dt,a_now = None):
# Returns into the original arrays the next r's and v's, after time dt
# has passed, using the 4th order Runge-Kutta algorithms.
# r: current positions, must be a vector array
# v: current velocities, must be a vector array
# A: function A(r,v,t) shall return the acceleration at position
# r, velocity v, and time t.
# t: current time
# dt: time step
# a_now: current acceleration (optional), must be a vector array
# if given.
N = len(r)
#rangeN = range(N)
r1 = r
v1 = v
a1 = a_now
if a1 is None: a1 = A(r1,v1,t)
rt = [None]*N
r2 = rt
v2 = [None]*N
dt2 = dt*0.5
for n in xrange(N):
r2[n] = r[n] + dt2*v1[n]
v2[n] = v[n] + dt2*a1[n]
a2 = A(r2,v2,t+dt2)
r3 = rt
v3 = [None]*N
for n in xrange(N):
r3[n] = r[n] + dt2*v2[n]
v3[n] = v[n] + dt2*a2[n]
a3 = A(r3,v3,t+dt3)
r4 = rt
v4 = [None]*N
for n in xrange(N):
r4[n] = r[n] + dt*v3[n]
v4[n] = v[n] + dt*a3[n]
a4 = A(r4,v4,t+dt)
dt /= 6.0
for n in xrange(N):
r[n] += (v1[n]+(v2[n]+v3[n])*2.0+v4[n])*dt
v[n] += (a1[n]+(a2[n]+a3[n])*2.0+a4[n])*dt
a_now = A(r,v,t+dt)
return (r,v,a_now)
/*}}}*/
/***
!! Many Particles 3D Python
***/
//{{{
def rk4va(y, f, t, dt):
// Returns the next y after time dt has passed, using the 4th
// order Runge-Kutta algorithms.
// y: current value for all the particles, must be a vector array.
// f: function f(y,t) shall return the derivatives of y's at time t,
// both the argument y and the return value of this function
// must be vector arrays.
// t: current time
// dt: time step
// Python knows what to do with vectors.
return rk4a(y, f, t, dt)
//}}}
/***
!! nextValue(r,v,a,t,dt,a_now)
***/
//{{{
def nextValue(r,v,a,t,dt,a_now):
typer = type(r)
if typer is list:
typer0 = type(r[0])
if typer0 is tuple:
return RK4ListTuple(r,v,a,t,dt,a_now)
elif typer0 is numpy.ndarray:
return RK4ListArray(r,v,a,t,dt,a_now)
elif typer0 is list:
return RK4ListArray(r,v,a,t,dt,a_now)
else:
return RK4ListVector(r,v,a,t,dt,a_now)
elif typer is numpy.ndarray:
return RK4ListArray(r,v,a,t,dt,a_now)
else:
return RK4(r,v,a,t,dt,a_now)
//}}}
/***
''These codes are to solve @@color:red;2^^nd^^ order differential equations@@ using the 4^^th^^ order ~Runge-Kutta method, for the following cases:''
# single particle 1D/3D motion;
# many particles 3D/1D motion.
!!! The Idea
The idea is shown in the figure below, @@which is captured from [[this video|https://youtu.be/smfX0Jt_f0I?t=325]]@@.
[img(60%,)[image/teaching/RK4 for 2ndODE.JPG]]
***/
/***
!! Single Particle 3D/1D Python
***/
/*{{{*/
def rk42(r, v, a, t, dt, a_cur):
# Returns a tuple containing the next r, next v, and the
# next a, using the 4th order Runge-Kutta algorithm.
# r: current position/distance
# v: current velocity/speed
# a: function a(r,v,t) shall return the acceleration at
# position r, velocity v, and time t
# t: current time
# dt: time step
# a_cur: (optional) current acceleration
r1 = r # current postion
v1 = v # current velocity
a1 = a_cur # current acceleration
if a1 == None: a1 = a(r1,v1,t,dt)
dt2 = dt*0.5 # first half step, using v1, a1
r2 = r+dt2*v1 # position at half step
v2 = v+dt2*a1 # velocity at half step
a2 = a(r2,v2,t+dt2) # acceleration at half step
r3 = r+dt2*v2 # position at half step
v3 = v+dt2*a2 # velocity at half step
a3 = a(r3,v3,t+dt2) # acceleration at half step
# using v3, a3 to calculate the next step
r4 = r+dt*v3 # position at next step
v4 = v+dt*a3 # velocity at next step
a4 = a(r4,v4,t+dt) # acceleration at the next step
# use a "some kind of average" of a1, a2, a3 and a4 to
# calculate the next v, and that of v1, v2, v3 and v4 to
# calculate the next r.
r += (v1+2*v2+2*v3+v4)/6*dt
v += (a1+2*a2+2*a3+a4)/6*dt
a_cur = a(r,v,t+dt)
# returns
# the next position
# the next velocity
# the next acceleration
return (r,v,a_cur)
/*}}}*/
/***
!! Many Particles 3D/1D Python
***/
/*{{{*/
def rk42a(r, v, a, t, dt, a_cur):
// Returns into the original arrays the next r's and v's at time t + dt,
// using the 4th order Runge-Kutta algorithms.
// r: current positions/distances, must be an array of vectors/scalars
// v: current velocities/speeds, must be an array of vectors/scalars
// a: function a(r,v,t) shall return the accelerations at positions r,
// velocities v, and time t, the arguments r, v and the return value
// of this function must all be arrays of scalars/vectors
// t: current time
// dt: time step
// a_cur: (optional) current accelerations
n=0
rangey = range(len(y))
y1 = y
yp1 = yp
k1 = a_cur
if k1 == None: k1 = f(y1,yp1,t) # current acceleration
dt2 = dt * 0.5
y2 = [0 for n in rangey]
yp2 = [0 for n in rangey]
for n in rangey:
y2[n] = y[n] + dt2*yp1[n]
yp2[n] = yp[n] + dt2*k1[n]
k2 = f(y2,yp2,t+dt2) # acceleration at half step
y3 = [0 for n in rangey]
yp3 = [0 for n in rangey]
for n in rangey:
y3[n] = y[n] + dt2*yp2[n]
yp3[n] = yp[n] + dt2*k2[n]
k3 = f(y3,yp3,t+dt2)
y4 = [0 for n in rangey]
yp4 = [0 for n in rangey]
for n in rangey:
y4[n] = y[n] + dt*yp3[n]
yp4[n] = yp[n] + dt*k3[n]
k4 = f(y4,yp4,t+dt)
for n in rangey:
y[n] = y[n] + (yp1[n]+(yp2[n]+yp3[n])*2+yp4[n])*dt/6
yp[n] = yp[n] + (k1[n]+(k2[n]+k3[n])*2+k4[n])*dt/6
/*}}}*/
-- 電荷不會動(靜電)、電荷等速動(靜磁、電磁感應)、電荷變速動(電磁波)
[[twD3CSS]]
/*{{{*/
.viewer th, .viewer thead td, .options th, .options thead td {
background-color: #c9c9c9;
color: black;
}
table.noborder, .noborder tr, .noborder th, .noborder td, .noborder thead td{
border:0;
}
#displayArea {position:absolute; left:-12.5em; width:80%;}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}
body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}
h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}
hr {height:1px;}
a {text-decoration:none;}
dt {font-weight:bold;}
ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}
.txtOptionInput {width:11em;}
#contentWrapper .chkOptionInput {border:0;}
.externalLink {text-decoration:underline;}
.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}
.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}
/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}
#mainMenu .tiddlyLinkExisting,
#mainMenu .tiddlyLinkNonExisting,
#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}
.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0 1em 1em; left:0px; top:0px;}
.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}
#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}
#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 0.3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}
.wizard {padding:0.1em 1em 0 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0; margin:0.4em 0 0.2em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0 0; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0;}
.wizardFooter .status {padding:0 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em;}
#messageArea {position:fixed; top:2em; right:0; margin:0.5em; padding:0.5em; z-index:2000; _position:absolute;}
.messageToolbar {display:block; text-align:right; padding:0.2em;}
#messageArea a {text-decoration:underline;}
.tiddlerPopupButton {padding:0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em; margin:0;}
.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}
.tabset {padding:1em 0 0 0.5em;}
.tab {margin:0 0 0 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}
#contentWrapper {display:block;}
#splashScreen {display:none;}
#displayArea {margin:1em 17em 0 14em;}
.toolbar {text-align:right; font-size:.9em;}
.tiddler {padding:1em 1em 0;}
.missing .viewer,.missing .title {font-style:italic;}
.title {font-size:1.6em; font-weight:bold;}
.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}
.tiddler .button {padding:0.2em 0.4em;}
.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}
.footer {font-size:.9em;}
.footer li {display:inline;}
.annotation {padding:0.5em; margin:0.5em;}
* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0 0.25em; padding:0 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}
.viewer table, table.twtable {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption,.twtable th, .twtable td, .twtable tr,.twtable caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}
.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}
.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}
.fieldsetFix {border:0; padding:0; margin:1px 0px;}
.sparkline {line-height:1em;}
.sparktick {outline:0;}
.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}
* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0; right:0;}
#backstageButton a {padding:0.1em 0.4em; margin:0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; width:90%; margin-left:3em; padding:1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em;}
#backstageCloak {display:none; z-index:20; position:absolute; width:100%; height:100px;}
.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/*{{{*/
@media print {
.header, .siteTitle, .siteSubtitle, #titleArea, .tagged, #mainMenu, #sidebar, #messageArea, .toolbar, #backstageButton, #backstageArea {display: none !important;}
.oddRow, evenRow {
background-color: #fff;
}
#displayArea {margin: 0; width: 100%;}
#tiddlerDisplay {margin: 0 0 0 13em; padding: 0; width: 120%;}
noscript {display:none;} /* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
}
/*}}}*/
chkHOTEnabled: true
chktw3DEnabled: true
chktwDataEnabled: true
chktwLaTexEnabled: true
chktwLaTexIncludeDollarSignsDisplay: false
chktwLaTexIncludeDollarSignsInline: true
chktwLaTexMathJaxAutoNumber: true
chktwLaTexPluginEnabled: true
chktwNumericDebug: false
chktwNumericEnabled: true
chktwNumericForceRadix2: false
chktwPhysicsEnabled: true
chktwVEnabled: true
chktwVPMAsync: false
chktwVPMEnabled: true
chktwVPMUseParallelJS: false
chktwVPMUseTransferables: false
chktwmathAutoNumber: false
chktwmathEnabled: true
chktwmathMathJaxAutoNumber: true
chktwmathUseMathJax: true
chktwmathUsekamath: false
chktwveCoreClickAway: true
chktwveCoreConfirmToDelete: true
chktwveCoreEditWrappers: true
chktwveCoreEnabled: true
chktwveCoreManualSave: true
chktwveCoreManualUpload: true
chktwveCorePreview: true
chktwveCoreShowFocus: true
chktwveExtraCountText: true
chktwveExtraCyclicNavi: false
chktwveExtraCyclickNavi: false
chktwveExtraIncludeSubs: true
chktwveExtraInline: true
chktwveExtraLocateChar: false
chktwveExtraMathAutoNumber: true
chktwveExtraNoClick: false
chktwveExtracyclicNavi: false
chktwveNumericDebug: false
chktwveNumericEnabled: true
chktwveNumericForceRadix2: false
chktwvePluginEnabled: true
chktwveTableEditAll: false
chktwveTableEnabled: true
chktwveTableIncludeCSS: false
chktwveTableLargeEnabled: true
chktwveTableMultiLine: true
chktwveTableTranspose: true
chktwveTcalcAllTables: false
chktwveTcalcAsync: false
chktwveTcalcColorNegativeNumbers: false
chktwveTcalcDebugMode: false
chktwveTcalcEnabled: true
chktwveTcalcInTextCalc: false
chktwveTcalcThousandSeparated: false
txttwveCoreMinEditWidth: 6
txttwveCorePreviewCaret: %7C
txttwveCorePreviewHeight: 15
txttwveExtraCountHow: word
txttwveExtraPreviewOpacity: 1.00
txttwveTableFixCols: 0
txttwveTableFixRows: 0
txttwveTableMaxHeight: 70000px
txttwveTableMaxWidth: 100%25
txttwveTableMinCellWidth: 2
txttwveTcalcDecimalMark: .
txttwveTcalcNegativeNumberColor: red
txttwveTcalcThousandSeparator: %2C
txttwveTcalcWorkFlow: TopDownLeftRight
|~ViewToolbar|closeTiddler closeOthers editTiddler > fields syncing permalink references jump|
|~EditToolbar|+saveTiddler -cancelTiddler deleteTiddler|
<!--{{{-->
<div class='toolbar' macro='toolbar [[ToolbarCommands::ViewToolbar]]'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
/***
!! Wire Loop
***/
//{{{
var R = 1.1e-2, H = 2*Math.PI*R, Rt = 1e-4;
var wireloop = torus({
radius: R,
tube: Rt,
radialSegments: 120,
color: 0xFFD700,
opacity: 1
});
wireloop.arrow = arrow({
radius: Rt,
center: vector(R*1.2,0,0),
axis: vector(0,R/2,0),
color: 0xFFD700,
visible: false,
opacity: 1
},'noadd');
wireloop.add(wireloop.arrow);
//}}}
/*{{{*/
.axis path,
.axis line {
fill: none;
stroke: black;
shape-rendering: crispEdges;
}
.axis text {
font-family: sans-serif;
font-size: 11px;
}
/*}}}*/
這個講義中我們將要練習''靜磁學裡【也是簡單】情況''的一種:@@color:red;一個【微小磁偶極 \(\vec m\)】【靜止時】@@在其周圍產生的【''磁場(magnetic field)'']。@@所謂的【偶極】就是【一個南極一個北極綁在一起】@@,''通常我們以偶極的中心為原點''。一個很小的磁偶極產生的磁場公式為\[\large{\begin{align*}\vec B (\vec r) &= {\mu_0 \over 4\pi}{8\pi \over 3}\vec m & \text{在磁偶極中心的位置}, \\ &={\mu_0 \over 4\pi}\left[(\vec m \cdot \hat r) \hat r - \vec m \over r^3\right] & \text{在其它任何位置}.\end{align*}}\] 我們通常會把這兩個公式寫在一起成為 \begin{equation}\Large{\boxed{\vec B(\vec r) = {\mu_0 \over 4\pi}\left[{(\vec m \cdot \hat r) \hat r - \vec m \over r^3}+{8\pi \over 3}\vec m\delta^3(\vec r)\right],}}\end{equation} 其中
* \(\large \vec B\) 就是我們要計算的磁場;
* \(\Large \vec r\) 是要計算磁場的位置(以''磁偶極的中心位置當原點'');
* \(\large \vec m\) 為磁偶極向量(稱為磁偶極矩),方向從南極到北極;
* \(\large \delta(\vec r)\) 是【狄拉克 \(\delta\) 函數】,它的函數值只有 0 和 1,\[\large\delta(\vec r) = \begin{cases}1 & \qquad \text{if }\vec r = 0, \\0 & \qquad \text{if }\vec r \neq 0.\end{cases}\] 有興趣的讀者可以參考[[維基百科狄拉克函數|https://zh.wikipedia.org/wiki/%E7%8B%84%E6%8B%89%E5%85%8B%CE%B4%E5%87%BD%E6%95%B0]] 或是英文版 [[Wikipedia Dirac Delta function|https://en.wikipedia.org/wiki/Dirac_delta_function]]。<br>
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 設計場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 畫出這個小磁鐵棒
tinyMagnet = box(
length = 1e-6, # 長度(x 方向)為 1 微米(1 micron)
height = 1e-6, # 高度(y 方向)為 1 微米(1 micron)
width = 1e-6, # 寬度(z 方向)為 1 微米(1 micron)
opacity=0.5
)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/5
xaxis = arrow(axis=vector(1,0,0)*R*30, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R*2)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*30, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R*2)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*30, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R*2)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 小磁鐵棒所帶的磁偶極矩(是個向量),假設在 +z 方向,大小為 1e6 個電子的自旋磁偶極矩
# 一個電子的自旋磁偶極矩稱為 波爾磁量子 Bohr magneton
# 波爾磁量子數值來源:https://en.wikipedia.org/wiki/Bohr_magneton
tinyMagnet.mu = vector(0, 0, 1e6*9.274009994e-24) # J/T (SI 單位制)
# 真空導磁律(SI 單位制)
mu0 = 4*pi*1e-7 # H/m or N/A^2, 來源:https://zh.wikipedia.org/wiki/%E7%A3%81%E5%AF%BC%E7%8E%87
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
# x 從 -5 倍磁鐵棒寬度的地方開始,到 +5 倍寬度的地方結束,間隔 1 個寬度
for x in arange(-tinyMagnet.width*5,tinyMagnet.width*5,tinyMagnet.width):
# y 從 -5 倍磁鐵棒高度的地方開始,到 +5 倍高度的地方結束,間隔 1 個高度
for y in arange(-tinyMagnet.height*5,tinyMagnet.height*5,tinyMagnet.height):
# z 從 -2 倍磁鐵棒深度的地方開始,到 +2 倍深度的地方結束,間隔 0.25 個深度
for z in arange(-tinyMagnet.depth*2,tinyMagnet.depth*2,tinyMagnet.depth/4):
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
r = vector(x,y,z) # 算出要計算磁場的位置向量
rn = r.norm() # 算出這個位置向量的單位向量
# 判斷位置 r 是否非常非常靠近小磁鐵本身的位置,如果是,
# 就用公式裡的第二項來計算,如果不是,就用第一項來計算磁場
if ????????????????? :
# r 這個位置在磁鐵的內部
# 用公式的第二項計算磁場
B = mu_0*2/3*tinyMagnet.mu
else:
# r 不在磁鐵內部,用公式的第一項計算磁場
B = mu0/(4*pi)*(tinyMagnet.mu.dot(rn)*rn - tinyMagnet.mu)/r.mag**3
arrow(pos=r,axis=B,shaftwidth=sw/3) # 畫一個箭頭代表磁場
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>||
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Magnet Tiny Bar]] [[JS Codes 磁偶極的磁場分布 -- 很小很小]]>>|
這個講義中我們將要練習''靜電學裡【次簡單】情況''的一種:@@color:red;一【群】聚集成【球狀】的電荷,在【靜止時】@@在其周圍產生的【''電位勢(electric potential)''],計算公式和單一個點電荷使用的基本上一樣,只是因為有【一群】電荷聚在一起,我們要用積分來計算:\[\Large{V(\vec r) = \int {1 \over 4\pi\epsilon} {\color{blue} \bf{dq} \over \color{blue}\Delta r}}\] 其中
* \(V\) 就是我們要計算的電位勢;
* \(\Large\vec r\) 是要計算電位勢的位置(以球狀電荷之中心當原點);
* \(\large \color{blue} \bf {dq}\) 為【@@color:blue;''一小塊體積''@@】裡面所帶的電量(可正可負);
* \(\large \Delta r\) 是從@@color:red;現在計算的那一個小塊@@開始到@@color:blue;計算電場的地方@@的距離
<<<
* 注意 \(\large\Delta r\) 【@@color:red;''不是''@@】從原點開始的向量,而是從【@@color:red;現在計算的那一個小塊@@】開始的。
* 因為電位勢公式 \[V = {1 \over 4\pi\epsilon_0}{q \over r}\] 裡面的 \(\large r\) 是從【點電荷】所在地開始的向量,而在這裡的計算中
## 我們把【現在計算的那一個小塊】當做一個點電荷來套用公式,所以
## \(\large \Delta r\) 是從【現在計算的那一個小塊】開始的距離。
<<<
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義球的半徑(可隨意調整)
R = 5
# 畫出一顆不太小的球代表一群聚成球狀的電荷分布
charge = sphere(radius=R, opacity=0.5)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/10
xaxis = arrow(axis=vector(1,0,0)*R*5, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*5, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*5, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 點電荷所帶的電荷,假設為 1e23 個質子的電荷
charge.q = 1.6e-19 * 1e23 # 庫倫
# 計算聚成球狀的電荷密度
charge.density = charge.q / (4/3)*pi*charge.radius**3
# 真空介電常數(SI 單位制)
epsilon = 8.854187817e-12
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
Vfield = points(radius=R/2) # 產生一個【空的】點集合,待會用來顯示計算過的位置
# radius 指定每個點的半徑
for theta in arange(0,180,180/20): # 天頂角從北極到南極,分成 20 步完成
theta = theta*pi/180 # 換成弧度
for phi in arange(0,360,360/40): # 方位角繞一整圈,分成 40 步完成
phi = phi*pi/180 # 換成弧度
r = R * 3 * vector( # 算出要計算電位勢的位置
sin(theta)*cos(phi), # x-分量
sin(theta)*sin(phi), # y-分量
cos(theta) # z-分量
)
# 對聚成球狀的一群電荷積分來計算電場
drp = charge.radius/50 # 將球的半徑分成許多小步計算,計算每一步的大小
dthetap = pi/30 # 將天頂角 thetap 分成許多小步計算,計算每一步的大小
dphip = pi*2/60 # 將方位角 phip 分成許多小步計算,計算每一步的大小
V = 0 # 電位勢先設定為 0,後面計算中會積分出來
for rp in arange(0,charge.radius,drp): # 積分開始,半徑從 0 到 charge.radius
for thetap in arange(0,pi,dthetap): # 天頂角從 0 到 pi(北極到南極)
for phip in arange(0,2*pi,dphip): # 方位角從 0 到 2*pi(繞一整圈)
# 每一小步對應一小塊的體積,裡面有電荷
r_dV = rp * vector( # 算出這一個小塊的位置
sin(thetap)*cos(phip),
sin(thetap)*sin(phip),
cos(thetap)
)
delta_r = r - r_dV # 計算從這一小塊開始到計算電場位置的向量
# 我們需要這個向量,因為底下要把這一小塊
# 當作點電荷,然後使用點電荷公式來計算電
# 場,而點電荷公式裡面的 r 是要從電荷所
# 在位置開始(不見得是原點開始)的向量。
# 算出這一小塊的體積(微積分公式)
dV = rp**2 * sin(thetap) * drp * dthetap * dphip
# 算出這一小塊裡面所含的電荷
dq = charge.density * dV
# 把這一小塊當成一個點電荷,套用點電荷公式計算小塊產生的微小電位勢
dV = 1/(4*pi*epsilon)*dq/delta_r.mag
# 加總到 V
V += dV
Vfield.append(pos=r) # 在計算的位置上放一個點,表示這個位置計算過了
# 並且以算出來的電位勢調整顏色深淺(或是透明度)
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Solid Sphere]] [[JS Codes 不動的電荷 -- 電位勢之二]]>>|
這個講義中我們要討論(真空中)電磁學四大定律之一的''高斯定律'' \[\large \oint_S \vec E \cdot d\vec A = {Q_\text{enc} \over \epsilon_0}.\] 這個定律的意義是:對一個「封閉的」曲面 \(S\) 進行「電通量 \(\Phi_E \equiv \int_\text{面積} \vec E \cdot d\vec A\)」的積分計算,其結果「正比於被這個封閉曲面包進去的電荷 \(Q_\text{enc}\)」,其中正比常數的分母 \(\epsilon_0\) 叫做【真空中的介電常數】或【真空的電容率】(參考[[維基百科真空電容率|https://zh.wikipedia.org/wiki/%E7%9C%9F%E7%A9%BA%E7%94%B5%E5%AE%B9%E7%8E%87]]),在 SI 單位制的數值為 \(\epsilon_0 = 8.854 187 817 ... \times 10^{-12} \text{ F}\cdot\text{m}^{-1}\)。
> @@向量 \(d\vec A\) 稱為【某個微小表面的面積向量】,其大小等於該表面的面積,方向則為該表面的法向量方向。@@
在這個講義裡我們要來練習【對球狀分布的一大群電荷,計算球型封閉曲面的電通量】,並將結果對【從電荷內部到外部之不同球型封閉曲面的半徑】做圖。
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義球的半徑(可隨意調整)
R = 5
# 畫出一顆不太小的球代表一群聚成球狀的電荷分布
charge = sphere(radius=R, opacity=0.5)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/10
xaxis = arrow(axis=vector(1,0,0)*R*5, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*5, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*5, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 點電荷所帶的電荷,假設為 1e23 個質子的電荷
charge.q = 1.6e-19 * 1e23 # 庫倫
# 計算聚成球狀的電荷密度
charge.density = charge.q / (4/3*pi*charge.radius**3)
# 真空介電常數(SI 單位制)
epsilon = 8.854187817e-12
F_r_g = graph(
title='Electric Flux vs Distance',
xtitle='<em>r</em> (m)',
ytitle='<em>Φ</em> (volt m)'
)
F_r = gcurve(graph=F_r_g,color=color.blue)
E_r_g = graph(
title='Electric Field Strength vs Distance',
xtitle='<em>r</em> (m)',
ytitle='<em>E</em> (volt / m)'
)
E_r = gcurve(graph=E_r_g,color=color.red)
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
theta = pi/2 # 計算電位勢/電場的位置之天頂角
phi = 0 # 計算電位勢/電場的位置之方位角
dphi = pi/30 # 每次計算改變方位角多少
for rf in arange(0,R*3,R/100): # 距離從 0 到 3 倍半徑,以半徑的 1/100 為步幅
r = rf * vector( # 算出要計算電位勢/電場的位置
sin(theta)*cos(phi), # x-分量
sin(theta)*sin(phi), # y-分量
cos(theta) # z-分量
)
phi += dphi # 下次計算位置的方位角
# 對聚成球狀的一群電荷積分來計算電場
drp = R/100 # 將球的半徑分成許多小步計算,計算每一步的大小
dthetap = pi/30 # 將天頂角 thetap 分成許多小步計算,計算每一步的大小
dphip = pi/30 # 將方位角 phip 分成許多小步計算,計算每一步的大小
F = 0 # 電通量先設定為 0,後面計算中會【積分】出來
E = vector(0,0,0) # 電場先設定為 0,後面計算中會積分出來
for rp in arange(0,charge.radius,drp): # 積分開始,半徑從 0 到 charge.radius
for thetap in arange(0,pi,dthetap): # 天頂角從 0 到 pi(北極到南極)
for phip in arange(0,2*pi,dphip): # 方位角從 0 到 2*pi(繞一整圈)
# 每一小步對應一小塊的體積,裡面有電荷
r_dV = rp * vector( # 算出這一個小塊的位置
sin(thetap)*cos(phip),
sin(thetap)*sin(phip),
cos(thetap)
)
delta_r = r - r_dV # 計算從這一小塊開始到計算電場位置的向量
# 我們需要這個向量,因為底下要把這一小塊
# 當作點電荷,然後使用點電荷公式來計算電
# 場,而點電荷公式裡面的 r 是要從電荷所
# 在位置開始(不見得是原點開始)的向量。
if ..................: # 計算電位勢/電場的位置如果正好在這一
continue # 小塊的裡面,不要算,跳過
# 請參考講義【積分計算的你儂我儂】寫出正確的程式碼
# 算出這一小塊的體積(微小但不是無限小體積公式,從無窮小體積公式積分得來)
dV = ((rp+drp)**3-rp**3)/3 * (cos(thetap)-cos(thetap+dthetap)) * dphip
# 算出這一小塊裡面所含的電荷
dq = charge.density * dV
# 把這一小塊當成一個點電荷,套用點電荷公式計算小塊產生的微小電場
dE = 1/(4*pi*epsilon)*dq/delta_r.mag2*delta_r.norm()
# 加總到 E
E += dE
# 電場計算完畢,計算電通量
# 原則上電通量的計算也應該要做積分,只是我們這個練習是球狀電荷,
# 直接把電場強度乘以球面積便是結果。如果不是球狀的,可能就得實際
# 做積分才行。
F = E.mag * 4*pi*rf**2
F_r.plot(rf,F) # 在 F-r 圖上畫一個點
E_r.plot(rf,E.mag) # 在 E-r 圖上畫一個點
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene width:"100%" [[Charge Solid Sphere]] [[JS Codes 不動的電荷 -- 高斯定律]]>>|
* [>img(20%,)[image/QRcode-wcy2.SimEM.jpg]] @@font-size:2em;這個講義的 URL:<br><br>http://faculty.ndhu.edu.tw/~wcy2/wcy2.SimEM.html@@
這份講義的目標是學會基本電磁學定律的計算,和[[前一份講義的主題「力學與運動」|http://faculty.ndhu.edu.tw/~wcy2/wcy2.SimForFun.html]]有所不同,然而計算的過程仍然可以按照同樣的「''建立場景」、「初始條件」、「細步計算''」這三個步驟來進行,只不過這裡的''「細步」''不像「力學與運動」裡面只有「時間」的細步,''這裡還可以包含「空間」的細步''。
* @@font-size:1.5em;color:red;如果__幾秒鐘後仍看不到__下面這條看起來顯示得不錯的公式,試著重新載入頁面。@@ \[\vec E = \int d\vec E = \int {1\over 4\pi\epsilon_0} {dq \over \Delta r^2} \hat {\Delta r}\]
* @@font-size:1.125em;按一下標題文字,可以展開隱藏內容,再按一下可以收起來。@@
!! 開始之前
|editable multilined|k
|width:4em;|width:20em;||
| ''開始之前'' |* @@font-size:1.3em;line-height:1.5em;對於數值模擬__完全沒經驗__的人,建議先把 ''[[基礎班|wcy2.SimForFun.html]]'' 學起來!@@||
|~|* ''初學者''或者''還不想用安裝版''的人,可以直接開始,網路版的 ~VPython:[[Web VPython|https://www.glowscript.org/]]<br>** 免安裝,上雲端,用自己的 Goolge 帳號登入就可以開始了!<br>** 本系列教案的程式碼__都有在 ~GlowScript 測試過(''測試版本為 ~GlowScript 2.8''),都可以執行__。<br>** @@color:red;注意:某些教案無法在 ~GlowScript 2.9 執行!@@<br>----<br>* ''有經驗者'',安裝才有全部的功能喔!到 [[這裡|https://vpython.org/]] 來安裝吧!<br>** ~VPython(http://vpython.org/)是 Python 語言的一個外掛<br>*** 它專門做 3D 電腦繪圖,功能夠強大,使用起來夠容易,是很實用的工具。|* __安裝版才能開更多外掛哦!__<br>* Python 的外掛太多、太好用了,進階使用者一定要用安裝版!|
!! 第一堂課
|editable multilined|k
|width:2em;|width:20em;|width:40em;|
| ''數學'' |* [[直角座標系]] -- ''最常用到''的座標系|* 直角座標系是我們最常用的座標系,因為它最簡單,也好用。|
|~|* [[球座標系]] -- 有''球形對稱''的時候使用<br>【球座標】!那是什麼?能吃嗎?|* 常用的直角座標系並【不見得】永遠好用,雖然原則上都可以使用。<br>* 一個''點電荷'',或是''聚成球狀的一群電荷'',使用''球形''座標反而比較方便哦!<br>@@想想看,我們在地球表面的位置通常是如何表示的(GPS)?是 \((x, y, z)\) 座標嗎?@@|
|>|>| @@font-size:1.5em;color:red;''開始之前,要先了解座標系哦!''@@ |
| ''第一堂課'' |不動的電荷 -- 靜電場之一:<br>* [[單個靜止電荷的電場分布]]<br>** ''最簡單''的狀況:<br>*** 一個點電荷<br>*** 靜止不動|【場】,物理學的重要基礎概念<br>----<br>庫倫定律 \[\large{\boxed{\vec E = {1 \over 4\pi\epsilon_0}{q \over r^2}\hat r}},\] 其中 \(r\) 是【從點電荷到計算電場位置的距離】,單位向量 \(\hat r\) 是【從點電荷到計算電場位置間連線的方向】。<br>> 單位向量就是【長度為 1 單位的向量】,主要作用在於指示方向。<br>* @@color:red;''課後練習''@@<br>## 這個程式執行的結果,應該會看到所有的箭頭落在球面上,且長度都一樣<br>*** 我們將這種狀況稱為【球狀對稱的分布】,''確認自己的結果符合球狀對稱性''。<br>## 多計算幾個不同半徑的球面,討論不同半徑球面上算出來的電場有什麼異同?|
|~|不動的電荷 -- 靜電場之二:<br>* [[單個靜止電荷的電場強度與距離之關係]]<br>** ''最簡單''的狀況:<br>*** 一個點電荷<br>*** 靜止不動|【場】,物理學的重要基礎概念<br>----<br>庫倫定律告訴我們電場強度和距離平方成反比, \[\large{\boxed{E \propto {1 \over r^2}}}\]<br>* @@color:red;''課後練習''@@<br>## 理論上這個關係應該是【平方反比】,檢查自己的結果,算出和平方反比之間的差異有多大。|
|~|不動的電荷 -- 靜電場之三<br>* [[單個靜止電荷的電位勢與距離之關係]]<br>** ''最簡單''的狀況:<br>*** 一個點電荷<br>*** 靜止不動|【場】,物理學的重要基礎概念<br>----<br>電位勢(electric potential)的大小和距離成反比, \[\large{\boxed{V = {1 \over 4\pi\epsilon_0}{q \over r} \propto {1 \over r}}}\]<br>* @@color:red;''課後練習''@@<br>## 理論上這個關係應該是【一次方反比】,檢查自己的結果,算出和一次方反比之間的差異有多大。|
!! 第二堂課
|editable multilined|k
|width:2em;|width:20em;|width:40em;|
| 數學 |* [[積分概念 -- 直角座標]]|# ''切割''成很多小塊<br># 每一小塊套用電磁公式計算<br># 加總所有小塊的計算結果|
|~|* [[積分概念 -- 球座標]]|# ''切割''成很多小塊<br># 每一小塊套用電磁公式計算<br># 加總所有小塊的計算結果|
|>|>| @@font-size:1.5em;color:red;''開始進行之前,要先了解【球座標】和【球座標積分】的概念哦!''@@ |
| ''第二堂課'' |不動的電荷 -- 靜電場之四<br>* [[群聚成球狀的靜止電荷之電場分布]]<br>** ''次簡單''的狀況:<br>*** 一堆點電荷聚成球狀<br>*** 靜止不動|【場】,物理學的重要基礎概念<br>----<br>當有很多電荷聚在一起的時候,我們會這樣做:<br># 在想像中將電荷聚在一起的區域切割成很多微小體積 \(d\tau\)<br>** 每個微小體積內應有微量電荷 \(dq = \rho_e d\tau\),其中 \(\rho_e\) 為【電荷密度】,也就是單位體積內的電荷;<br># 每一個微小體積內的微量電荷 \(dq\) 當做一個點電荷,套用庫倫定律計算 \(dq\) 產生的微小電場 \[d\vec E = {1 \over 4\pi\epsilon_0}{dq \over \Delta r^2}\hat{\Delta r};\]其中 \(\Delta r\) 是【從微量電荷到計算電場位置的距離】,單位向量 \(\hat r\) 是【從點電荷到計算電場位置間連線的方向】。<br>** 單位向量就是【長度為 1 單位的向量】,主要作用在於指示方向。<br># 將所有微小體積產生的微小電場全部加總起來(向量和)就是我們要的結果:\[\large{\boxed{\vec E = \int d\vec E = \int {1 \over 4\pi\epsilon_0} {dq \over \Delta r^2}\hat {\Delta r}}}\]<br>* @@color:red;''課後練習''@@<br>## 這個程式執行的結果,應該看起來和作業一【單一電荷】的結果幾乎一樣。<br>*** 參考作業一的課後練習,請確認自己的結果具有球狀對稱性。<br>## 根據公式,或者其他已知關於庫倫定律的結果,自行選擇一種情境進行驗證。例如:<br>*** 從某個教科書,或者從某個【可靠】的來源知道(''需明確標示來源''),電場的 OO 和 XX 成{{{_____}}}關係<br>**** 可驗證自己的結果中是否 OO 和 XX 的確呈現{{{_____}}}關係<br><<tiddler "注意事項##積分的小塊體積">>|
|~|不動的電荷 -- 靜電場之五<br>* [[群聚成球狀的靜止電荷的電場強度及電位勢與距離之關係]]<br>** 【電場】隨距離的關係是如何?<br>** 【電位勢】隨距離的關係是如何?|* 上一個作業只計算【外面】,這一個作業<br>** 要計算包含群聚成球狀分布的電荷的【裡面】和【外面】的電場以及電位勢,<br>** 並做出電場隨距離,以及電位勢隨距離的關係圖。<br>* @@color:red;''課後練習''@@<br>## 這個結果應該如下,請驗證自己的結果是否符合<br>*** 在電荷球的【外面】,電位勢與距離成反比,電場強度與距離平方成反比,也就是 \[V_\text{out} \propto {1 \over r}, \quad \quad E_\text{out} \propto {1 \over r^2}.\]<br>*** 在電荷球的【裡面】,電位勢與(距離平方的負數)成正比,電場強度與距離成正比,也就是 \[V_\text{in} \propto -r^2, \quad \quad E_\text{in} \propto r.\]<br>## (可選)根據定義,在這個情況下 \(E\) 和 \(V\) 會有這樣的關係:\[E = -{dV \over dr}, \quad \quad V = -\int E dr.\] 試著驗算自己的結果,看是否有滿足這樣的關係。<br>*** 數值微分與積分可以參考 [[Wikipedia Numerical differentiation|https://en.wikipedia.org/wiki/Numerical_differentiation]] 及 [[Wikipedia Numerical integration|https://en.wikipedia.org/wiki/Numerical_integration]]<br><<tiddler "注意事項##群聚體內部的積分">>|
|~|不動的電荷 -- 靜電場之六<br>* [[不動的電荷 -- 高斯定律]]<br>** ''最簡單''的狀況,電荷靜止不動|電磁學四大定律之一.0,對封閉曲面 \(S\) 計算通過此面的''電通量'':\[\large{\boxed{\Phi_{E} = \oint_S \vec E \cdot d\vec A = {Q_\text{enclosed} \over \epsilon_0}.}}\]<br>* @@color:red;''課後練習''@@ 高斯定律特性之定量驗證<br>## 通過封閉曲面 \(S\) 的電通量 \(\Phi_{E}\) 正比於【被封閉曲面包圍的電荷】。<br>## 在群聚的電荷球【裡面】,電通量與(距離的三次方)成正比,也就是 \(\large\Phi_{E,\text{in}} \propto r^3.\)<br>## 在群聚的電荷球【外面】,電通量與距離無關(根據第一個特性)。<br><<tiddler "注意事項##群聚體內部的積分">>|
!! 第三堂課
|editable multilined|k
|width:2em;|width:20em;|width:40em;|
| 數學 |* [[圓柱座標系]] -- 有''圓柱形對稱''的時候使用<br>【圓柱座標】!有比球座標好吃嗎?|* 常用的直角座標系並【不見得】永遠好用<br>* @@color:blue;直線電流@@用''圓柱形''座標會比較方便哦!|
|~|* [[積分概念 -- 圓柱座標]]|# ''切割''成很多小塊<br># 每一小塊套用電磁公式計算<br># 加總所有小塊的計算結果|
|>|>| @@font-size:1.5em;color:red;''開始進行之前,要先了解【圓柱座標】和【圓柱座標積分】的概念哦!''@@ |
| ''第三堂課'' |等速移動的電荷 -- 靜磁場之一<br>* [[等速移動的電荷 -- 細長直導線的磁場]]<br>** ''仍然簡單''的情況<br>*** 穩定電流|電生磁 -- ''細長直導線'' [[Michael Melloch 的演示|https://www.youtube.com/watch?v=caHXwJbkbQU&list=RDCMUC5ZsENSXOVzI0zHt4i2bZFw&index=2]]<br>電流 \(I\) 經過''一小段''電線(長度為 \(d\vec l'\))時,在這一小段電線周圍所產生的微小磁場可以經由<br>必歐 - 沙伐(~Biot-Savart)定律來計算:\[d\vec B(\vec r) = {\mu_0 I \over 4\pi} \color{blue}{\bf{d\vec l'} \over \Delta r^2} \color{blue} \times \hat {\Delta r}\] 若要計算''一整條''細長直導電線所產生的磁場,只需<br># 把一整條電線想像成【很多的小段電線】串聯組成,<br># 每一小段電線都套用必歐 - 沙伐定律計算微小磁場,<br># 把每一個微小磁場加總起來(向量相加)<br>也就是 \[\large\boxed{\vec B(\vec r) = \int_\text{沿著電線} d\vec B (\vec r) = \int_0^L {\mu_0 I \over 4\pi} \color{blue}{\bf{d\vec l'} \over \Delta r^2} \color{blue} \times \hat{\Delta r}}\] 其中 \(L\) 是導線的長度。這裡會是''一維空間''的積分。<br>* @@color:red;''課後練習''@@<br>## 電流經過細長直導線所產生的磁場,其電流和磁場的方向可以用所謂的【右手定則】來說明,<br>*** 也就是【大拇指方向順著電流,另外四指彎曲起來的方向就是磁場方向】,<br>*** 檢查自己的結果是否符合右手定則。<br>## 選幾個離電線更遠的地方畫看看,磁場有什麼樣的變化?<br>## 沿著垂直於導線的方向,作一張【磁場強度隨距離的變化】,<br>*** 應該會有 \(B \propto {1 \over r}\) 的關係,檢查自己的結果是否符合這個關係。|
|~|等速移動的電荷 -- 靜磁場之二<br>* [[等速移動的電荷 -- 粗長直導線的磁場]]<br>** ''仍然簡單''的情況<br>*** 穩定電流|電生磁 -- ''粗長直導線''<br>如果導線比較粗,就要計算必歐 - 沙伐(~Biot-Savart)定律的''三微空間''積分 \[\large{\boxed{\vec B(\vec r) = \int_\text{電線內部} d\vec B(\vec r) = \int\int\int {\mu_0 I \over 4\pi} \color{blue}{\bf{\vec J}d\tau \over \Delta r^2} \color{blue} \times \hat{\Delta r}}}\]<br>* @@color:red;''課後練習''@@<br>## 電流經過粗長直導線所產生的磁場,其電流和磁場的方向可以用所謂的【右手定則】來說明,<br>*** 也就是【大拇指方向順著電流,另外四指彎曲起來的方向就是磁場方向】,<br>*** 檢查自己的結果是否符合右手定則。<br>## 前面是在計算【導線中段】的結果,現在沿著導線長度的方向,計算超過導線長度地方的磁場<br>*** 比較看看和前面中段的結果有什麼異同?<br>|
|~|等速移動的電荷 -- 靜磁場之三<br>* [[長直導線的磁場隨距離的關係]]<br>** ''仍然簡單''的情況<br>*** 穩定電流|如果導線內的電流是均勻分布在其內部,計算導線【裡面】跟【外面】的磁場,畫出磁場隨著垂直距離的變化關係圖。<br>* @@color:red;''課後練習''@@<br>## 在計算導線內部的磁場時,<br>*** 我們一樣會碰到【計算磁場的位置正好在某一小塊的內部】這樣的情形,也一樣要避開,因為<br>#### 我們把每一小塊當作極小的一段電流,套用必歐 - 沙伐(Biot-Savart)定律的公式;且<br>#### 必歐 - 沙伐(Biot-Savart)定律只包含【小段電流以外的空間】,沒有包含小段電流裡面<br>*** ''如果沒避開就會得到不正確的結果''。<br>**** 妳/你應該已經發現,【簡單的】避開程式碼已經不管用了!<br>***** 我們需要正確的程式碼才好。正確的程式碼該如何寫?請參考[[積分計算的你儂我儂]]。<br>----<br>* @@color:blue;''延伸說明''@@<br>## 這個結果,如果寫得正確,應該如下列所述。(如果時間許可,確認一下自己的結果是否如此。)<br>*** 在導線的【外面】,磁場強度與距離成反比,也就是 \[B_\text{out} \propto {1 \over r}.\]<br>*** 在導線的【裡面】,磁場強度與距離成正比,也就是 \[B_\text{in} \propto r.\]|
|~|等速移動的電荷 -- 靜磁場之四<br>* [[等速移動的電荷 -- 安培定律]]<br>** ''仍然簡單''的情況<br>*** 穩定電流|電磁學四大定律之三.0<br>安培定律([[安培定律說明影片|https://drive.google.com/file/d/12l7bQvqA_h3fMk74wUzmv6BhlIT5AW1r/view?usp=sharing]]) \[\large{\boxed{\oint \vec B \cdot d\vec l = \mu_0 I_\text{enclosed}}}\]<br>* 安培定律是個【路徑積分】,不熟悉的同學可以參考講義 [[路徑積分 -- 以安培定律為例]]([[路徑積分說明影片|https://drive.google.com/file/d/10_lSVvg5ihl8PLtOOXHb7LHE0uPzgShW/view?usp=sharing]])<br>* @@color:red;''課後練習''@@<br>## 安培定律說 \[\oint \vec B \cdot d\vec l = \mu_0I_\text{enc},\] 也就是''路徑積分的結果正比於【穿過封閉路徑的電流】'',據此我們可知<br>### 對於半徑大過導線粗細(\(\rho \ge R\))的封閉路徑而言,<br>**** 整個導線的電流都已經穿過它,<br>**** 因此不管封閉路徑的半徑再怎麼增加,能夠穿過它的電流也不會更多,<br>**** 也就是這個積分的結果應為常數。<br>**** @@檢查自己的計算結果,封閉路徑的半徑大於導線半徑的時候,積分結果是否為常數?@@<br>### 而對於半徑小於導線(\(\rho < R\))的封閉路徑而言,<br>**** 只有被封閉路徑圈住的電流才能穿過它,其它部分的電流則不行,<br>**** 因此半徑越大就可以有越多的電流穿過它。<br>**** @@自己的結果顯示出什麼樣的關係?@@<br>----<br>* @@color:blue;''延伸說明''@@<br>## 從上面 ''1.a 的結果'',以''正圓形''的封閉路徑來計算的話,\[\oint \vec B \cdot d\vec l = \mu_0I_\text{enc} \quad \to \quad \oint_\text{正圓} B \hat\phi \cdot (\rho d\phi)\hat\phi = B\rho\oint_\text{正圓} d\phi = B\rho(2\pi) = \mu_0I,\] 可以推得''在導線的外部'' \[\boxed{B = {\mu_0 I \over 2\pi \rho} \qquad \to \qquad B \propto {1 \over \rho}.}\] 這個結果我們在<br>*** [[等速移動的電荷 -- 細長直導線的磁場]] 的課後練習,以及<br>*** [[長直導線的磁場隨距離的關係]]裡面應該都已經看到。<br>## 從上面 ''1.b 的結果'',同樣以''正圓形''封閉路徑來計算,\[\oint_\text{正圓} B \hat\phi \cdot (\rho d\phi)\hat\phi = B\rho(2\pi) = \mu_0I{\pi \rho^2 \over \pi R^2} = \mu_0I{\rho^2 \over R^2}.\] 由此我們推得''在導線的內部'' \[\boxed{B = {\mu_0I \over 2\pi}{\rho \over R^2} \qquad \to \qquad B \propto \rho.}\] 這個結果我們在[[長直導線的磁場隨距離的關係]]裡面也已經看到。|
!! 第四堂課
|editable multilined|k
|width:2em;|width:20em;|width:40em;|
| 數學 |* [[圓柱座標系]] -- 有''圓柱形對稱''的時候使用<br>【圓柱座標】!有比球座標好吃嗎?|* 常用的直角座標系並【不見得】永遠好用<br>* @@color:blue;直線電流@@用''圓柱形''座標會比較方便哦!|
|~|* [[積分概念 -- 圓柱座標]]|# ''切割''成很多小塊<br># 每一小塊套用電磁公式計算<br># 加總所有小塊的計算結果|
|>|>| @@font-size:1.5em;color:red;''開始進行之前,要先了解【圓柱座標】和【圓柱座標積分】的概念哦!''@@ |
||等速移動的電荷 -- 靜磁場之五<br>* [[等速移動的電荷 -- 繞圈細導線的磁場]]<br>** ''仍然簡單''的情況<br>*** 穩定電流|電生磁 -- ''繞圈細導線'' [[Michael Melloch 的演示|https://www.youtube.com/watch?v=bq6IhapfucE]]<br>如果導線繞成一個圓圈(半徑為 \(R\)),這時候的磁場計算和一條細長直導線是類似的,都是<br>【將導線切成許多小段,沿著導線將每個小段的計算加起來】,不同的只是導線繞成一圈而不是一條直線。<br>這時候的''每一小段都是圓弧'',因此長度可以寫成 \(dl = Rd\phi\),其中 \(\phi\) 就是一小段圓弧的張角。這樣一來積分會變成 \[\large\boxed{\vec B(\vec r) = \int_\text{沿著圓圈} d\vec B (\vec r) = \int_0^{2\pi} {\mu_0 I \over 4\pi} \color{blue}{\bf{Rd\phi} \over \Delta r^2} \hat\phi \times \hat{\Delta r}}\] 其中 ''\(\hat\phi\) 是沿著小段電線所在處的切線方向之單位向量''。<br><br>沿著 \(z\) 軸畫出磁場強度隨距離的關係圖,能夠說出它們之間的關係嗎?<br>* {{FrameSmallRight{[img(46%,)[image/teaching/Fig-Bfield-loop.jpg]][img(46%,)[image/teaching/Fig-Bfield-dipole.jpg]]左:繞圈導線中穩定電流產生的磁場。右:一個微小磁鐵產生的磁場,兩者具有相似性。<br>圖片來源:[[維基百科磁偶極矩|https://en.wikipedia.org/wiki/Magnetic_dipole#:~:text=A%20magnetic%20dipole%20is%20the,the%20analogy%20is%20not%20perfect.]]。}}} @@color:red;''課後練習''@@<br>## 一段繞圈導線中穩定電流產生的磁場,<br>*** 會和一個小磁鐵的磁場有點類似(如右圖),<br>*** 確認自己的結果和右圖有相似性。<br>## 從線圈中心出發,沿著線圈中心軸(\(z\)-軸)計算磁場強度隨距離 \(z\) 的關係<br>*** 距離 \(z\) 是從線圈的中心點開始<br>*** 結果是否符合 \[B = {\mu_0IR^2 \over (z^2+R^2)^{3/2}}\] 這樣的關係?|
| 第四堂課 |磁鐵中的磁場 -- 靜磁場之六<br>* [[一個很小很小磁偶極的磁場分布]]<br>** ''最簡單的磁鐵''|很小很小磁偶極 \(\vec m\) 在它週圍(真空)產生的磁場(參考[[維基百科 Magnetic Dipole|https://en.wikipedia.org/wiki/Magnetic_dipole]])為<br>* 若使用很小很小的線圈計算,\begin{equation}\large{\boxed{\vec B = {\mu_0 \over 4\pi}\left({3(\vec m \cdot \hat r)\hat r - \vec m \over r^3} + {8\pi \over 3}\vec m\delta(\vec r)\right)}}\end{equation}<br>* 若使用很小很小的磁鐵計算,\begin{equation}\large{\boxed{\vec H = {1 \over 4\pi}\left({3(\vec m \cdot \hat r)\hat r - \vec m \over r^3} - {4\pi \over 3}\vec m\delta(\vec r)\right)}}\end{equation}<br>其中 \(\vec r\) 都是從偶極的中心點開始的位置向量。<br><br>這裡我們看到 (1) 式計算的是 \(\vec B\),(2) 式計算的是 \(\vec H\),這兩個量之間的關聯是 \[\vec B = \mu_0(\vec H + \vec M)\] 其中 \(\vec M\) 是【單位體積內的磁偶極矩】,稱為【磁化強度】。<br>> 如果是''很小很小的磁鐵'',\(\vec M = \vec m \delta(\vec r)\),可以試著放入 (2) 式看看會得到什麼樣的 \(\vec B\)<br>> 和 (1) 式比較看看差別在哪裡。<br>>> 嚴格來講應該是 \(\vec H\) 叫做磁場,\(\vec B\) 叫做【磁通密度】(磁通量密度)<br>>> 不過人們經常不去區分兩者,都用【磁場】來稱呼。<br><br>* 我們可以很容易看出 (1)、(2) 兩式''都有【兩項】''<br>** @@第一項一模一樣(注意 \(\vec H\) 和 \(\vec B\) 之間的關係)@@<br>** @@差別僅在第二項@@<br>* 至於@@color:red;''計算時要選哪一個?''@@<br>## @@如果還不熟悉 \(\vec H\) 的概念,那就計算 (1) 式,將來熟悉了之後再說。@@<br>## 如果對於 \(\vec H\) 的概念可以掌握,就計算 (2) 式。<br>兩項之中<br>* ''第一項的意義是【磁偶極在它的週圍產生的磁場】'';<br>* ''而第二項則是【磁偶極在自己的位置產生的磁場】'',<br>其中 \(\delta(\vec r)\) 叫做__【狄拉克 \(\delta\) 函數】,它的值只有 0 和 1,在【自己的位置時】為 1,在其它任何位置時都為 0。__<br>(關於狄拉克函數的性質,可參考 [[維基百科狄拉克函數|https://zh.wikipedia.org/wiki/%E7%8B%84%E6%8B%89%E5%85%8B%CE%B4%E5%87%BD%E6%95%B0]] 或是英文版 [[Wikipedia Dirac Delta function|https://en.wikipedia.org/wiki/Dirac_delta_function]])<br>* @@color:red;''課後練習''@@<br>## 這個程式執行的結果<br>*** 應該和[[等速移動的電荷 -- 繞圈細導線的磁場]]的結果相似<br>*** 如果不是的話,檢查看看程式碼哪裡有錯喔!<br>## 從磁鐵中心出發,沿著磁鐵中心軸(\(z\)-軸)計算磁場強度隨距離 \(z\) 的關係<br>*** 和[[等速移動的電荷 -- 繞圈細導線的磁場]]裡面課後練習 (2) 的結果比較看看,有沒有相似的結果?<br>*** 注意距離 \(z\) 是從磁鐵的中心點開始|
|~|磁鐵中的磁場 -- 靜磁場之七<br>* [[日常大小磁偶極的磁場分布]]<br>** ''日常生活中可見的磁鐵''|很多很多很小很小磁偶極聚在一起,單位體積內的磁偶極矩為 \(\vec M\),則在它週圍(外部或者內部)產生的磁場為<br># 若以上面的 (1) 式計算,\begin{equation}\large{\boxed{\vec B = \int d\vec B = {\mu_0 \over 4\pi} \int \left[{3(\vec M \cdot \hat r)\hat r - \vec M \over r^3} + {8\pi \over 3}\vec M \delta(\vec r)\right]d\tau}}\end{equation}<br># 若以上面的 (2) 式計算,\begin{equation}\large{\boxed{\vec H = \int d\vec B = {1 \over 4\pi} \int \left[{3(\vec M \cdot \hat r)\hat r - \vec M \over r^3} - {4\pi \over 3}\vec M \delta(\vec r)\right]d\tau}}\end{equation} 且 \(\vec B = \mu_0(\vec H + \vec M)\)。<br>> 算出來的結果應該類似於影片中的狀況:[[Michael Melloch 的演示|https://www.youtube.com/watch?v=QaZ0h76X6d0&list=RDCMUC5ZsENSXOVzI0zHt4i2bZFw&index=3]]<br>* @@color:red;''課後練習''@@<br>## 在磁鐵的外部<br>*** 磁場方向大致上有【離開 N 極】以及【進入 S 極】的趨勢<br>*** 確認自己的結果符合這個預期。<br>## 利用[[等速移動的電荷 -- 繞圈細導線的磁場]]裡計算一個線圈的程式碼<br>*** 將好幾個線圈(比如說 50 個或 100 個)沿 \(z\)-軸【疊起來】成為一個【羅線管】<br>*** 計算這個螺線管周圍的磁場分布,和這次的磁鐵結果相比較,有什麼相似之處?有甚麼差異之處?|
|~|等速移動的電荷 -- 靜磁場之八<br>* [[磁場的高斯定律]]<br>** |電磁學四大定律之二.0<br>磁場的高斯定律 \[\large{\boxed{\oint \vec B \cdot d\vec A = ?}}\]|
!! 第五堂課
|editable multilined|k
|width:2em;|width:20em;|width:40em;|
| 數學 |* [[圓柱座標系]] -- 有''圓柱形對稱''的時候使用<br>【圓柱座標】!有比球座標好吃嗎?|* 常用的直角座標系並【不見得】永遠好用<br>* @@color:blue;直線電流@@用''圓柱形''座標會比較方便哦!|
|~|* [[積分概念 -- 圓柱座標]]|# ''切割''成很多小塊<br># 每一小塊套用電磁公式計算<br># 加總所有小塊的計算結果|
|>|>| @@font-size:1.5em;color:red;''開始進行之前,要先了解【圓柱座標】和【圓柱座標積分】的概念哦!''@@ |
| 第五堂課 |等速移動的磁鐵 -- ''變動''磁場之一<br>* [[等速移動的磁鐵 -- 法拉第定律]]<br>** 磁生電:變動的磁通量可以產生感應電流<br>** [[法拉第定律說明影片|https://drive.google.com/file/d/164TOFJKxRG62vUvXMAAkQECwvRwwHZUO/view?usp=sharing]]|電磁學四大定律之四.0<br>法拉第定律(@@磁生電:變動的磁通量可以產生感應電流@@)\[\large{\boxed{emf = -{d\Phi_{B} \over dt}}}\] //emf// 是「感應電動勢」<br><br>[[有趣的演示|https://www.youtube.com/watch?v=pMfNuP1Wozw&list=RDCMUC5ZsENSXOVzI0zHt4i2bZFw&index=4]]|
<<foldHeadings>>
這個講義中我們將要練習''靜電學裡【最簡單】情況''的一種:@@color:red;一個【點電荷】【靜止時】@@在其周圍產生的【''電位勢(electric potential)''】,計算公式為 \[\Large{V (\vec r) = {1 \over 4\pi\epsilon_0}{q \over r}} \quad \propto \quad {1 \over r},\] 其中
* \(\large V\) 就是我們要計算的電位勢;
* \(\Large \vec r\) 是要計算電位勢的位置(以''點電荷所在位置當原點'');
* \(\large q\) 為點電荷所帶的電量(可正可負);<br>
除了電位勢為純量而不是向量之外,電位勢隨著距離呈現的是【反比】走勢,也就是 \[V \propto {1 \over r},\] 這點也和__電場強度的平方反比走勢__有所不同。(要練習電場計算的話可以參考 [[靜止點電荷的電場分布]] 或者 [[靜止點電荷的電場強度與距離的關係]])
> ''電位勢只有大小沒有方向''(也就是所謂的【''純量''】)。
>> 在過去用手計算的年代,純量因為沒有方向,計算上比向量簡單許多。
>> 但現代電腦也會計算向量,因此就寫程式來說,計算向量跟計算純量的差別並不大。
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義小球的半徑(可隨意調整,看起來像個點電荷即可)
R = 1e-4
# 畫出一顆小球代表一個點電荷
charge = sphere(radius=R, opacity=0.5)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/5
xaxis = arrow(axis=vector(1,0,0)*R*30, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R*2)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*30, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R*2)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*30, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R*2)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 點電荷所帶的電荷,假設為 1 個質子的電荷
charge.q = 1.6e-19 # 庫倫
# 真空介電常數(SI 單位制)
epsilon = 8.854187817e-12
# 產生一個空的【曲線圖】,取名為 V_r(因為要畫 V vs r 的曲線圖)
V_r = gcurve(color=color.blue)
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
theta = pi/2 # 計算電場位置的天頂角
phi = pi/4 # 計算電場位置的方位角
for rf in arange(R,R*10,R*10/100): # 距離從點電荷表面到 數 倍半徑的地方
r = rf * vector( # 算出要計算電場的位置
sin(theta)*cos(phi), # x-分量
sin(theta)*sin(phi), # y-分量
cos(theta) # z-分量
)
V = 1/(4*pi*epsilon)*charge.q/r.mag # 套用公式計算電位勢
V_r.plot(rf,V) # 在 V_r 曲線圖上畫一個點
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">>|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Point]] [[JS Codes 單個靜止電荷的電位勢與距離之關係]]>>|
這個講義中我們將要練習''靜電學裡【最簡單】情況''的一種:@@color:red;一個【點電荷】【靜止時】@@在其周圍產生的【''電場(electric field)''],計算公式為【''庫倫定律''】\[\Large{\vec E (\vec r) = {1 \over 4\pi\epsilon_0}{q \over r^2}\hat r},\] 其中
* \(\large \vec E\) 就是我們要計算的電場;
* \(\Large \vec r\) 是要計算電場的位置(以''點電荷所在位置當原點'');
* \(\large q\) 為點電荷所帶的電量(可正可負);<br>
> ''電場有大小也有方向''(也就是所謂的【''向量''】),它的大小是由庫倫定律裡面 \[\Large {1 \over 4\pi\epsilon_0}{q \over r^2}\] 這部份來計算,而方向則是由最後的那個符號 \(\Large \hat r\) 來指出。注意那個符號的上面是【帽子(''hat'')\(\large\bf{\hat }\)】而不是箭頭\(\vec \),它叫做【向量 \(\Large \vec r\) 的''單位向量''】,其方向就是 \(\Large \vec r\) 的方向,長度是 @@color:red;1 單位@@,是個純粹拿來指方向的向量。
>> 長度是 @@color:red;1 單位@@的意思,就是說如果使用公尺為單位(如:MKS 或 SI 單位制),長度就是 1 公尺;但如果使用公分為單位(如:CGS 單位制),長度就是 1 公分。
>>> ''通常我們使用【標準單位制】,也就是 MKS 或 SI 單位制。''
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 設計場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義小球的半徑(可隨意調整,看起來像個點電荷即可)
R = 1e-4
# 畫出一顆小球代表一個點電荷
charge = sphere(radius=R, opacity=0.5)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/5
xaxis = arrow(axis=vector(1,0,0)*R*30, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R*2)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*30, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R*2)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*30, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R*2)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 點電荷所帶的電荷,假設為 1 個質子的電荷
charge.q = 1.6e-19 # 庫倫
# 真空介電常數(SI 單位制)
epsilon = 8.854187817e-12
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
for theta in arange(0,180,180/20): # 天頂角從北極到南極,分成 20 步完成
theta = theta*pi/180 # 換成弧度
for phi in arange(0,360,360/40): # 方位角繞一整圈,分成 40 步完成
phi = phi*pi/180 # 換成弧度
r = R * 15 * vector( # 算出要計算電場的位置
sin(theta)*cos(phi), # x-分量
sin(theta)*sin(phi), # y-分量
cos(theta) # z-分量
)
E = 1/(4*pi*epsilon)*charge.q/r.mag2*r.norm() # 套用公式計算電場
arrow(pos=r,axis=E*2e-1,shaftwidth=sw/3) # 畫一個箭頭代表電場
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
!! 課後練習
# 這個程式執行的結果,應該會看到所有的箭頭落在球面上,且長度都一樣(我們將這種狀況稱為【球狀對稱的分布】),如果不是的話,檢查看看程式碼哪裡有錯喔!
# 多計算幾個不同半徑的球面,看看不同半徑球面上算出來的電場有什麼樣的不同?
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">> / <<tw3DCommonPanel "Boost Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">>|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> (<<tw3DCommonPanel "Label CPS">>) <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Point]] [[JS Codes 單個靜止電荷的電場分布]]>>|
這個講義中我們仍在練習''靜電學裡【最簡單】情況''的一種:@@color:red;一個【點電荷】【靜止時】@@的【''電場(electric field)''],和[[前一個講義|靜止點電荷的電場分布]]不同的是,這裡我們要看的是【電場強度隨距離的關係】。電場強度的計算公式當然還是庫倫定律,\[\Large{E (\vec r) = {1 \over 4\pi\epsilon_0}{q \over r^2}} \quad \propto \quad {1 \over r^2},\] 其中
* \(\large E\) 就是我們要計算的電場強度;
* \(\Large \vec r\) 是要計算電場的位置(以''點電荷所在位置當原點'');
* \(\large q\) 為點電荷所帶的電量(可正可負);<br>
> 這個講義我們要將電場強度隨距離的變化關係做一個圖,計算正確的畫圖形應該具有【''平方反比''】走勢。
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 設計場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義小球的半徑(可隨意調整,看起來像個點電荷即可)
R = 1e-4
# 畫出一顆小球代表一個點電荷
charge = sphere(radius=R, opacity=0.5)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/5
xaxis = arrow(axis=vector(1,0,0)*R*30, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R*2)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*30, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R*2)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*30, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R*2)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 點電荷所帶的電荷,假設為 1 個質子的電荷
charge.q = 1.6e-19 # 庫倫
# 真空介電常數(SI 單位制)
epsilon = 8.854187817e-12
# 產生一個空的【曲線圖】,取名為 E_r(因為要畫 E vs r 的曲線圖)
E_r = gcurve(color=color.red)
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
theta = pi/2 # 計算電場位置的天頂角
phi = pi/4 # 計算電場位置的方位角
for rf in arange(R,R*10,R*10/100): # 距離從點電荷表面到 數 倍半徑的地方
r = rf * vector( # 算出要計算電場的位置
sin(theta)*cos(phi), # x-分量
sin(theta)*sin(phi), # y-分量
cos(theta) # z-分量
)
E = 1/(4*pi*epsilon)*charge.q/r.mag2*r.norm() # 套用公式計算電場
arrow(pos=r,axis=E*2e-1,shaftwidth=sw/3) # 畫一個箭頭代表電場
E_r.plot(rf,E.mag) # 在 E_r 曲線圖上畫一個點
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">>|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Point]] [[JS Codes 單個靜止電荷的電場強度與距離之關係]]>>|
! 針對二階微分方程的四階 ~Runge-Kutta 方法
對二階微分方程求解,我們按照 [[四階 Runge-Kutta 方法]] 裡面求解一階微分方程的過程,''同樣先定義出二階微分的函數''以及''初始條件'':\[\begin{equation}\ddot y = f(y, \dot y, t), \quad y(t_0) = y_0, \quad \dot y(t_0) = \dot y_0.\end{equation}\]
>注意上面這個二階微分 \(\ddot y\) 在一般情況會是 \(y\) 及 \(\dot y\) 的函數,對一個力學系統來說,通常我們能夠知道【受力】,而根據牛頓第二定律,知道受力就可以算出【加速度】,而加速度正是位置的二次微分,這樣我們就知道
>>對力學系統而言上面 (2) 式中的 \(y\) 就是位置 \(\vec r\),而
>> \(\dot y\) 就是速度 \(\vec v\),
>>\(\ddot y = f(y,\dot y,t)\) 算出來的就是加速度 \(\vec a\),而加速度會是位置和速度的函數。
>物理上什麼情況下加速度是位置的函數呢?舉一個簡單的例子:彈簧-質量系統,在此系統裡物體的受力為 \(-kx\),其中的 //x// 就是位置(相對於平衡點),也就是說【受力和位置有關】,或者說【受力是位置的函數】,而受力可以讓我們算出加速度,所以理所當然【加速度是位置的函數】。
>
>至於什麼情況下加速度會是速度的函數呢?只要受力是速度的函數就是了,比如說空氣阻力 \(\vec f = -{1 \over 2} \rho v^2 C_{D}A \hat v\) 就是一個典型的例子。
接著按照右圖(由 [[此影片|https://youtu.be/smfX0Jt_f0I?t=325]] 截出)的做法寫成程式碼:[>img(45%,)[image/teaching/RK4 for 2ndODE.JPG]]
對【單粒子一維運動】來說程式碼也不算複雜:<<slider 'rk42j' 'Runge-Kutta 2 JS##Single Particle 1D Javascript' 'Javascript'>>、<<slider 'rk42p' 'Runge-Kutta 2 Python##Single Particle 3D/1D Python' 'Python'>>。
!!!! 單粒子三維版本
當然處理三維運動的能力是必要的:<<slider 'rk42vj' 'Runge-Kutta 2 JS##Single Particle 3D Javascript' 'Javascript Vector'>>、<<slider 'rk42vp' 'Runge-Kutta 2 Python##Single Particle 3D/1D Python' 'Python Vector'>>。
!!!! 多粒子一維版本
實用上我們要處理多粒子的陣列版本:<<slider 'rk42aj' 'Runge-Kutta 2 JS##Many Particles 1D Javascript' 'Javascript Array(測試中)'>>、<<slider 'rk42ap' 'Runge-Kutta 2 Python##Many Particles 3D/1D Python' 'Python Array(未測試)'>>。
!!!! 多粒子三維版本
@@更貼近實際的話我們應該是需要多粒子的三維版本:<<slider 'rk42vaj' 'RK42 Codes JS##Many Particles 3D Javascript' 'Javascript Vector Array(測試中)'>>、<<slider 'rk42vap' 'RK42 Codes Python##Many Particles 3D/1D Python' 'Python Vector Array(未測試)'>>。@@
!! 參考文獻
# 維基百科 [[Runge-Kutta 網頁|https://en.wikipedia.org/wiki/Runge%E2%80%93Kutta_methods]]
# [[RK4 for 2nd order ODE|https://www.youtube.com/watch?v=smfX0Jt_f0I&feature=youtu.be&t=325]]
!! 常用座標系
<<tiddler "座標系說明##常用座標系">><<tiddler "座標系說明##曲線座標系">>
事實上,在討論電磁學的時候我們經常碰到具有【球狀對稱】或是【圓柱狀對稱】的情況,因此,了解這些座標系會讓這些計算方便很多!在這個講義裡我們要來學習【''圓柱座標系''】
!! 圓柱座標系
在具有【''圓柱形對稱性''】的情況下,使用圓柱形座標系會比直角座標系方便不少,這是我們學習圓柱座標系的主要理由。至於甚麼時候會有【圓柱形對稱性】?比如說一根圓柱,或者一條直線的情況,都是具有圓柱對稱性的。
在三度空間裡要標示一個位置,需要三個數字,比如說直角座標的 \((x, y, z)\) 便是,在使用圓柱座標的時候,這三個數字是 @@font-size:1.2em;color:blue;\((\rho, \phi, z)\)@@,其中
* \(\Large \rho\) 是【從圓柱''中心軸''到這個位置的''垂直距離''】
* \(\large\phi\) 是【從 ''//x//-軸''】''偏轉''到這個位置的''角度'',也就是【''方位角''】
* \(\Large z\) 就是直角座標系裡面的 \(\Large z\)
參考下方繪圖區,應該可以比較容易理解。
<<<
__如欲觀察座標軸的方向,可以勾選【Cylindrical】前面的方框,繪圖區內就會顯示出座標軸。__
> @@font-size:1.2em;line-height:1.6em;圓柱座標系的座標軸也是互相垂直的,只是三個座標軸的方向會隨著位置不同而有改變,不像直角座標系的三個軸方向永遠都是固定在一開始選好的方向。''勾選下方【Cylindrical】前面的方塊''的話,可以在動畫區看到圓柱座標系的三個座標軸的方向,如果讓動畫繼續進行,就可以看到這三個軸的方向隨著位置不同而改變。@@
>> 如果能夠幫助觀察的話,可以按【Stop】鍵停止動畫,或取消勾選【Components】前面的方框。
<<<
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cylindrical System Control">> / <<tw3DCommonPanel "Frame Control">>|
|>|<<tw3DScene [[JS Codes 圓柱座標系]]>>|
!! 常用座標系
科學與工程上常用的座標系有三種:
#【''直角''坐標系】- 大家最熟悉的座標系
#【''球''座標系】- 在''球狀對稱''的情況很好用
#【''圓柱''座標系】- 在''圓柱對稱''的情況很好用
!! 曲線座標系
一般來講,我們__不管碰到什麼情況都使用直角座標系來處理,原則上是可行的__,只是有時候用另外的座標系會比較方便,例如,當我們正在討論的@@系統本身具有''球狀對稱性''的時候,我們採用''球座標系''就會讓計算變得''很方便''@@;同理,如果系統具有''圓柱狀的對稱性'',則我們採用''圓柱座標系就會很方便''。
! 微分方程
__物理上的動力學過程經常都是以微分方程來表示的__,例如描述日常生活可見的運動過程之牛頓第二運動定律(Newton's Second Law of Motion) \[f = ma = m{d^2x \over dt^2} \quad \text{(1D)}, \quad or \quad \vec f = m\vec a = m{d^2\vec r \over dt^2} \quad \text{(3D)}.\] 就是許多人學到的第一條微分方程。又比如說描述真空中電磁場狀況的馬克斯威爾方程(Maxwell's Equations) \[\begin{aligned}\vec\nabla \cdot \vec E &= {\rho \over \epsilon_0} \\ \vec\nabla \times \vec E &= -{\partial \vec B \over \partial t} \\ \vec\nabla \cdot \vec B &= 0 \\ \vec\nabla \times \vec B &= \mu_0 \vec j + \mu_0\epsilon_0{\partial \vec E \over \partial t},\end{aligned}\] 是許多理工科系學生都要學會的微分方程。因為如此,我們在解物理問題的時候都是求解相關的微分方程,不論是以解析或是數值方法進行,解出微分方程就是解決了那一個物理問題。
物理上微分方程的變數通常是【位置 \(\vec r\)】或者【時間 \(t\)】,簡單起見我們以時間 \(t\) 為變數來說明。
! 數值方法求解 -- 一階微分方程
以數值方法解一階微分方程的想法其實很簡單,基本上就是
# 要先知道一階微分方程本身 \[{dy \over dt} = f(y,t),\] 其中 \(f(y,t)\) 這個函數的形式必須為已知的。
# 要先知道初始時間 \(t_0\) 的函數值 \(y_0\)。
# 從初始時間開始,一次做一小步(\(t_{n+1} = t_n + dt\))。
# 每一小步都用 \[y_{n+1} = y_n + \left({dy \over dt}\right)_{t=t_n}dt = y_n + f(y_n,t_n) dt\] 來估計下一步的值。
我們如果一步一步來看,從初始時間開始 \(t_0, y_0\) 為已知,那麼下一步的估計值就是 \[y_1 = y_0 + f(y_0, t_0)dt,\] 再下一步的估計值就是 \[y_2 = y_1 + f(y_1, t_1)dt.\] 這裡應該可以很快看出來,就只是【把現在的 \(y\) 與 \(t\) 代入一階微分的函數 \(f(y,t)\)】去計算出【現在的斜率】,然後用現在的值加上「斜率 × 時間間隔」來估計下一步的值。
!! 誤差
這個概念非常簡單而且直接,要寫出程式碼並不困難,問題在於【計算成本】的考量,每一小步的時間 \(dt\) ''不可能''無限小,這樣一來估計出來的下一步值跟實際應該有的值之間就會有所差異。
對每一小步來講,這個差異並不會很大,只要我們選擇的步伐 \(dt\) 仍然夠小就可以。但是數值計算會讓誤差持續累積,每一步的微小差異都會累積到下一步去,計算夠久之後誤差就可能大到離譜的程度!
所以__數值方法求解微分方程的過程中,如何''減少誤差累積''是至關重要的事情__。
仔細看上面的(1)式,不難發現整個過程的''重點就在於【計算出現在的斜率】'',也就是說,如何估計出一個「''能減少誤差累積的斜率''」,是數值計算的關鍵!
目前最普遍採用的方法,可能是「[[四階 Runge-Kutta 方法]]」,它不見得是誤差最小的方法,但應該是誤差夠小的實用方法中最簡單的一個。
Type the text for '拋體運動二--阻力大不大'
*假設由左到右排列共 \(N\) 個離散數值,\(f_n = f(x_n), \quad n=(0,1,2,\dots,n,n+1,\dots,N-1) \in N\),
*其變數 \(x_n\) 之間為等間隔 \(h\),也就是 \(x_{n+1} - x_n = h, \quad n = (0, \dots, N-1)\)。
!!一次微分
*數值微分一般是以差分計算來處理,主要是取泰勒展開式 \[f(x) = \sum_{n=0}^{\infty} {f^{(n)}(x_0) \over n!}(x-x_0)^n = f(x_0) + f^{(1)}(x_0) (x-x_0) + {f^{(2)}(x_0) \over 2!} (x-x_0)^2 + {f^{(3)}(x_0) \over 3!} (x-x_0)^3 + \cdots \tag{1}\] 的前 \(m\) 項做為近似,捨棄 \(m+1\) 以及之後的所有項,並以 \(O((x-x_0)^{m+1})\) 表示其誤差的數量級。
!!!!兩點差分
*右邊:\[\boxed{f_n^{(1)} \simeq {1 \over h}(f_{n+1}-f_n), \quad n < N-1, \quad \text{err} \sim O(h)} \tag{2}\]
**讓泰勒展開式 (1) 的 \(x = x_{n+1}, \quad x_0 = x_n, \quad x-x_0 = x_{n+1}-x_n = h\),我們可以很容易寫下 \[f_{n+1} = f_n + hf_n^{(1)} + {h^2 \over 2!}f_n^{(2)} + {h^3 \over 3!}f_n^{(3)} + {h^4 \over 4!}f_n^{(4)} + \cdots, \tag{2-1}\] 簡單移項就可看出 \[f_{n+1} - f_n = hf_n^{(1)} + O(h^2) \quad \to \quad {1 \over h}(f_{n+1}-f_n) = f_n^{(1)} + O(h)\]
*左邊:\[\boxed{f_n^{(1)} \simeq {1 \over h}(f_n-f_{n-1}), \quad n > 0, \quad \text{err} \sim O(h)} \tag{3}\]
**同上做法 \[f_{n-1} = f_n - hf_n^{(1)} + {h^2 \over 2!}f_n^{(2)}-{h^3 \over 3!}f_n^{(3)}+{h^4 \over 4!}f_n^{(4)}-\cdots, \tag{3-1}\] 同樣簡單移項便可得 \[f_{n-1} - f_n = -hf_n^{(1)} + O(h^2) \quad \to \quad {1 \over h}(f_n-f_{n-1}) = f_n^{(1)} + O(h)\]
!!!!三點差分
*右邊:\[\boxed{f_n^{(1)} \simeq {1 \over 2h}(-f_{n+2}+4f_{n+1}-3f_n), \quad n < N-2, \quad \text{err} \sim O(h^2)} \tag{4}\]
**這裡我們需要 \(f_{n+2}\):\[f_{n+2} = f_n + 2hf_n^{(1)} + {(2h)^2 \over 2!}f_n^{(2)} + {(2h)^3 \over 3!}f_n^{(3)} + {(2h)^4 \over 4!}f_n^{(4)} + \cdots, \tag{4-1}\] 將 (2-1) × 4 \(-\) (4-1) 以消去 \(h^2\) 項可得 \[4f_{n+1} - f_{n+2} = 3f_n + 2hf_n^{(1)} + O(h^3)\] 簡單移項便可得 \[-f_{n+2}+4f_{n+1}-3f_n = 2hf_n^{(1)} + O(h^3) \quad \to \quad {1 \over 2h}(-f_{n+2}+4f_{n+1}-3f_n) = f_n^{(1)}+ O(h^2)\]
*左邊:\[\boxed{f_n^{(1)} \simeq {1 \over 2h}(3f_n-4f_{n-1}+f_{n-2}), \quad n > 1, \quad \text{err} \sim O(h^2)} \tag{5}\]
**這裡我們需要 \(f_{n-2}\):\[f_{n-2} = f_n - 2hf_n^{(1)} + {(2h)^2 \over 2!}f_n^{(2)} - {(2h)^3 \over 3!}f_n^{(3)} + {(2h)^4 \over 4!}f_n^{(4)} - \cdots, \tag{5-1}\] 將 (5-1) \(-\) (3-1) × 4 以消去 \(h^2\) 項可得 \[f_{n-2} - 4f_{n-1} = -3f_n + 2hf_n^{(1)} + O(h^3)\] 簡單移項便可得 \[3f_n-4f_{n-1}+f_{n-2} = 2hf_n^{(1)} + O(h^3) \quad \to \quad {1 \over 2h}(3f_n-4f_{n-1}+f_{n-2}) = f_n^{(1)}+ O(h^2)\]
*中間:\[\boxed{f_n^{(1)} \simeq {1 \over 2h}(f_{n+1}-f_{n-1}), \quad 0 < n < N-1, \quad \text{err} \sim O(h^2)} \tag{6}\]
**將 (2-1) \(-\) (3-1) 以消去 \(h^2\) 項就得到 \[f_{n+1} - f_{n-1} = 2hf_n^{(1)} + O(h^3) \quad \to \quad {1 \over 2h}(f_{n+1} - f_{n-1}) = f_n^{(1)} + O(h^2)\]
!!!!四點差分
*右邊:\[\boxed{f_n^{(1)} \simeq {1 \over 4h}(-f_{n+3}+f_{n+2}+5f_{n+1}-5f_n), \quad n < N-3, \quad \text{err} \sim O(h^2)} \tag{7}\]
**這裡我們需要 \(f_{n+3}\):\[f_{n+3} = f_n + 3hf_n^{(1)} + {(3h)^2 \over 2!}f_n^{(2)} + {(3h)^3 \over 3!}f_n^{(3)} + {(3h)^4 \over 4!}f_n^{(4)} + \cdots, \tag{7-1}\] 將 (2-1) × 5 \(+\) (4-1) \(-\) (7-1) 以消去 \(h^2\) 項,可得 \[5f_{n+1} + f_{n+2} - f_{n+3} = 5f_n + 4hf_n^{(1)} + O(h^3)\] 簡單移項便可得 \[-f_{n+3}+f_{n+2}+5f_{n+1}-5f_n = 4hf_n^{(1)} + O(h^3) \quad \to \quad {1 \over 4h}(-f_{n+3}+f_{n+2}+5f_{n+1}-5f_n) = f_n^{(1)}+ O(h^2)\] 亦可將 (2-1) \(+\) (4-1) × 2 \(-\) (7-1) 以消去 \(h^2\) 項,可得 \[f_{n+1} + 2f_{n+2} - f_{n+3} = 2f_n + 2hf_n^{(1)} + O(h^3)\] 簡單移項便可得 \[-f_{n+3}+2f_{n+2}+f_{n+1}-2f_n = 2hf_n^{(1)} + O(h^3) \quad \to \quad \boxed{ {1 \over 2h}(-f_{n+3}+2f_{n+2}+f_{n+1}-2f_n) = f_n^{(1)}+ O(h^2)}\]
*左邊:\[\boxed{f_n^{(1)} \simeq {1 \over 4h}(5f_n-5f_{n-1}-f_{n-2}+f_{n-3}), \quad n > 2, \quad \text{err} \sim O(h^2)} \tag{8}\]
**這裡我們需要 \(f_{n-3}\):\[f_{n-3} = f_n - 3hf_n^{(1)} + {(3h)^2 \over 2!}f_n^{(2)} - {(3h)^3 \over 3!}f_n^{(3)} + {(3h)^4 \over 4!}f_n^{(4)} - \cdots, \tag{8-1}\] 將 (3-1) × 5 \(+\) (5-1) \(-\) (8-1) 以消去 \(h^2\) 項,可得 \[5f_{n-1} + f_{n-2} - f_{n-3} = 5f_n - 4hf_n^{(1)} + O(h^3)\] 簡單移項便可得 \[-f_{n-3}+f_{n-2}+5f_{n-1}-5f_n = -4hf_n^{(1)} + O(h^3) \quad \to \quad {1 \over 4h}(5f_n-5f_{n-1}-f_{n-2}+f_{n-3}) = f_n^{(1)}+ O(h^2)\] 亦可將 (3-1) \(+\) (5-1) × 2 \(-\) (8-1) 以消去 \(h^2\) 項,可得 \[f_{n-1} + 2f_{n-2} - f_{n-3} = 2f_n - 2hf_n^{(1)} + O(h^3)\] 簡單移項便可得 \[-2f_n+f_{n-1}+2f_{n-2}-f_{n-3} = -2hf_n^{(1)} + O(h^3) \quad \to \quad \boxed{ {1 \over 2h}(2f_n-f_{n-1}-2f_{n-2}+f_{n-3}) = f_n^{(1)}+ O(h^2)}\]
!!!!五點差分
*右邊:\[\boxed{f_n^{(1)} \simeq {1 \over 4h}(-f_{n+4} +f_{n+3} + f_{n+2} + 3f_{n+1} - 4f_n), \quad n < N-4, \quad \text{err} \sim O(h^2)} \tag{9}\]
**這裡需要 \(f_{n+4}\):\[f_{n+4} = f_n + 4hf_n^{(1)} + {(4h)^2 \over 2!}f_n^{(2)} + {(4h)^3 \over 3!}f_n^{(3)} + {(4h)^4 \over 4!}f_n^{(4)} + \cdots, \tag{9-1}\] 將 (2-1) × 3 \(+\) (4-1) \(+\) (7-1) \(-\) (9-1) 以消去 \(h^2\) 項,可得 \[3f_{n+1}+f_{n+2}+f_{n+3}-f_{n+4} = 4f_n + 4hf_n^{(1)} + O(h^3)\] 簡單移項便可得 \[-f_{n+4} +f_{n+3} + f_{n+2} + 3f_{n+1} - 4f_n = 4hf_n^{(1)} + O(h^3) \quad \to \quad {1 \over 4h}(-f_{n+4} +f_{n+3} + f_{n+2} + 3f_{n+1} - 4f_n) = f_n^{(1)} + O(h^2)\]
*左邊:\[\boxed{f_n^{(1)} \simeq {1 \over 4h}(4f_n - 3f_{n-1} - f_{n-2} - f_{n-3} + f_{n-4}), \quad n > 3, \quad \text{err} \sim O(h^2)}\]
**這裡需要 \(f_{n-4}\):\[f_{n-4} = f_n - 4hf_n^{(1)} + {(4h)^2 \over 2!}f_n^{(2)} - {(4h)^3 \over 3!}f_n^{(3)} + {(4h)^4 \over 4!}f_n^{(4)} - \cdots, \tag{10-1}\] 將 (3-1) × 3 \(+\) (5-1) \(+\) (8-1) \(-\) (10-1) 以消去 \(h^2\) 項,可得 \[3f_{n-1}+f_{n-2}+f_{n-3}-f_{n-4} = 4f_n - 4hf_n^{(1)} + O(h^3)\] 簡單移項便可得 \[-4f_n + 3f_{n-1} + f_{n-2} + f_{n-3} - f_{n-4} = -4hf_n^{(1)} + O(h^3) \quad \to \quad {1 \over 4h}(4f_n - 3f_{n-1} - f_{n-2} - f_{n-3} + f_{n-4}) = f_n^{(1)} + O(h^2)\]
*中間:\[\boxed{f_n^{(1)} \simeq {1 \over 12h}(-f_{n+2}+8f_{n+1}-8f_{n-1}+f_{n-2}), \quad 2 < n < N-2, \quad \text{err} \sim O(h^4)} \tag{11}\]
**(2-1) 減去 (3-1) 以消去 \(h^2\) 並保留到 \(h^3\) 項就得到 \[f_{n+1}-f_{n-1} = 2hf_n^{(1)} + {2h^3 \over 3!}f_n^{(3)} + O((2h)^5) \tag{11-1}\]
**(4-1) 減去 (5-1) 以消去 \(h^2\) 並保留到 \(h^3\) 項就得到 \[f_{n+2}-f_{n-2} = 2(2h)f_n^{(1)} + {2(2h)^3 \over 3!}f_n^{(3)} + O((2h)^5) \tag{11-2}\]
**再將 (11-1) × 8 \(-\) (11-2) 以消去 \(h^3\) 項:\[8(f_{n+1}-f_{n-1}) - (f_{n+2}-f_{n-2}) = 12hf_n^{(1)} + O((2h)^5)\] 整理一下即可得 \[-f_{n+2} + 8f_{n+1} - 8f_{n-1} + f_{n-2} = 12hf_n^{(1)} + O((2h)^5) \quad \to \quad {1 \over 12h}(-f_{n+2} + 8f_{n+1} - 8f_{n-1} + f_{n-2}) = f_n^{(1)} + O(h^4)\]
!!二次微分
*二次微分可以先做一次微分之後再微分,
*也可以直接用泰勒展開式從原來的數據點直接計算出來,如下所示。
!!!!三點差分
*右邊:\[\boxed{f_n^{(2)} \simeq {1 \over h^2}(f_{n+2}-2f_{n+1}+f_n), \quad n < N-2, \quad \text{err} \sim O(h^2)} \tag{10}\]
**將 (4-1) \(-\) (2-1) × 2 以消去 \(h\) 並保留到 \(h^2\) 項即可得 \[f_{n+2}-2f_{n+1} = -f_n + h^2f_n^{(2)} + O(h^3) \quad \to \quad {1 \over h^2}(f_{n+2}-2f_{n+1}+f_n) = f_n^{(2)} + O(h^2)\]
*左邊:\[\boxed{f_n^{(2)} \simeq {1 \over h^2}(f_n-2f_{n-1}+f_{n-2}), \quad n > 1, \quad \text{err} \sim O(h^2)} \tag{11}\]
**將 (5-1) \(-\) (3-1) × 2 以消去 \(h\) 並保留到 \(h^2\) 項即可得 \[f_{n-2}-2f_{n-1} = -f_n + h^2f_n^{(2)} + O(h^3) \quad \to \quad {1 \over h^2}(f_n-2f_{n-1}+f_{n-2}) = f_n^{(2)} + O(h^2)\]
*中間:\[\boxed{f_n^{(2)} \simeq {1 \over h^2}(f_{n+1}-2f_n+f_{n-1}), \quad 0 < n < N-1, \quad \text{err} \sim O(h^2)} \tag{12}\]
**將 (2-1) \(+\) (3-1) 以消去 \(h\) 並保留到 \(h^2\) 項即可得 \[f_{n+1}+f_{n-1} = 2f_n + h^2f_n^{(2)} + O(h^4) \quad \to \quad {1 \over h^2}(f_{n+1}-2f_n+f_{n-1}) = f_n^{(2)} + O(h^2)\]
!!!!五點差分
*右邊:\[\boxed{f_n^{(2)} \simeq {1 \over 2h^2}(f_{n+4}-f_{n+3}-f_{n+2}+f_{n+1}), \quad n < N-4, \quad \text{err} \sim O(h)}\]
**將 ((2-1) \(+\) (9-1)) \(-\) ((4-1) \(+\) (7-1)) 以消去 \(h\) 項,可得 \[(f_{n+1}+f_{n+4}) - (f_{n+2}+f_{n+3}) = 2h^2f_n^{(2)} + O(h^3) \quad \to \quad {1 \over 2h^2}(f_{n+4}-f_{n+3}-f_{n+2}+f_{n+1}) = f_n^{(2)}+O(h)\]
*左邊:\[\boxed{f_n^{(2)} \simeq {1 \over 2h^2}(f_{n-1}-f_{n-2}-f_{n-3}+f_{n-4}), \quad n > 3, \quad \text{err} \sim O(h)}\]
**將 ((3-1) \(+\) (10-1)) \(-\) ((5-1) \(+\) (8-1)) 以消去 \(h\) 項,可得 \[(f_{n-1}+f_{n-4}) - (f_{n-2}+f_{n-3}) = 2h^2f_n^{(2)} + O(h^3) \quad \to \quad {1 \over 2h^2}(f_{n-1}-f_{n-2}-f_{n-3}+f_{n-4}) = f_n^{(2)}+O(h)\]
*中間:\[\boxed{f_n^{(2)} \simeq {1 \over 12h^2}(-f_{n+2}+16f_{n+1}-30f_n+16f_{n-1}-f_{n-2}), \quad 1 < n < N-2, \quad \text{err} \sim O(h^4)} \tag{15}\]
**將 16 × ((2-1) \(+\) (3-1)) \(-\) ((4-1) \(+\) (5-1)) 以消去 \(h, h^3, h^4, h^5\) 等項,可得 \[16(f_{n+1}+f_{n-1}) - (f_{n+2}+f_{n-2}) = 30f_n + 12h^2f_n^{(2)} + O(h^6) \quad \to \quad {1 \over 12h^2}(-f_{n+2}+16f_{n+1}-30f_n+16f_{n-1}-f_{n-2}) = f_n^{(2)}+O(h^4)\]
!!Ref
*[[Five-point stencil|https://en.wikipedia.org/wiki/Five-point_stencil]]
*[[Savitzky-Golay filter|https://en.wikipedia.org/wiki/Savitzky%E2%80%93Golay_filter]] for smoothing and differentiation
<<foldHeadings>>
!! 中間值計算
數值積分公式都只給出【整個小區間】積分的結果,小區間裡面的結果並沒有,如果需要將整個積分出來的函數畫出來的話,能夠有每個小區間中間的結果也許比較好(真的嗎?),我們可以利用各個方法的內插公式把這些算出來。
!!!! Simpson's rule
\[\left({n^3 \over 6} - {3n^2 \over 4} + n\right)f_1 +
\left({n^3 \over 3}+n^2\right)f_2 + \left({n^3 \over 6}-{n^2 \over 4}\right)f_3\] 當 \(n=2\)(積分整個小區間),上式變成 \[\left({8 \over 6} - {12 \over 4} + 2\right)f_1 +
\left({8 \over 3}+4\right)f_2 + \left({8 \over 6}-{4 \over 4}\right)f_3 = \boxed{ {1 \over 3}(f_1 + 4 f_2 + f_3)}\] 當 \(n=1\)(積分到小區間中點),上式變成 \[\left({1 \over 6} - {3 \over 4} + 1\right)f_1 +
\left({1 \over 3}+1\right)f_2 + \left({1 \over 6}-{1 \over 4}\right)f_3 = \boxed{ {1 \over 3}\left({5 \over 4}f_1 + 4 f_2 + {-1 \over 4}f_3\right)}\]
----
!! 參考文獻
* [[Wiki|https://en.wikipedia.org/wiki/Newton%E2%80%93Cotes_formulas]]
* [[Wolframe|https://mathworld.wolfram.com/Newton-CotesFormulas.html]] -- up to 11-point rules.
* [[eFunda -- Newton-Cotes Formulas|https://www.efunda.com/math/num_integration/num_int_newton.cfm]]
* [[Newton-Cotes Formulas at MSU|https://archive.lib.msu.edu/crcmath/math/math/n/n080.htm]]
* [[Dr. Bolhoff, Cockrell School of Engineering|http://www.cs.utexas.edu/users/kincaid/PGE310/Ch11.pdf]]
* [[Stable Newton-Cotes Formula|http://www.holoborodko.com/pavel/numerical-methods/numerical-integration/stable-newton-cotes-formulas/]]
物理的積分公式裡面經常包含【一小塊的體機】,例如計算一群電荷聚在一起所產生的電場 \[\vec E(\vec r) = \int {1 \over 4\pi\epsilon_0}{\rho d\tau \over r^2}\hat r\] 時,裡面的 \(d\tau\) 便是【一小塊的體積】。通常我們會直接拿微積分的公式來計算:\[d\tau = (r \sin\theta d\phi) (r d\theta) dr = r^2 \sin\theta d\phi d\theta dr \qquad (\text{Spherical}) \tag{1}\] \[d\tau = (\rho d\phi) d\rho dz \qquad (\text{Cylindrical}) \tag{2}\] 然而微積分的公式得在小塊體積為「無窮小」的情況下才會得到正確的結果,但是在數值計算中我們經常無法將體積切到【無窮小塊】,也就是我們的小塊通常是有限大小,這時候使用這些公式會產生一定程度的誤差。有限大小的時候,體積公式如果改成【對小體積積分之後的結果】,會比較準確,細節如下。
首先我們看''球座標'',無窮小塊的體積公式為 (1) 式,將它積分一個很小的範圍 \[(r, \theta, \phi) \quad \to \quad (r+\Delta r, \theta+\Delta\theta, \phi+\Delta\phi),\] 其結果為 \begin{align*}\int_r^{r+\Delta r}\int_\theta^{\theta+\Delta\theta}\int_\phi^{\phi+\Delta\phi}(r\sin\theta d\phi)(rd\theta)dr &= \left(\int_r^{r+\Delta r}r^2dr\right)\left(\int_\theta^{\theta+\Delta\theta}\sin\theta d\theta\right) \left(\int_\phi^{\phi+\Delta\phi}d\phi\right) \\ &= \left(\int_r^{r+\Delta r}r^2dr\right)\left(\int_\theta^{\theta+\Delta\theta}\sin\theta d\theta\right) \left(\left[\phi\right]_\phi^{\phi+\Delta\phi}\right) \\ &= \left(\int_r^{r+\Delta r}r^2 dr\right)\left( \left[-\cos\theta\right]_\theta^{\theta+\Delta\theta}\right)\Delta\phi \\ &= \left[r^3 \over 3\right]_r^{r+\Delta r}(\cos\theta - \cos(\theta+\Delta\theta))\Delta\phi \\ \\ &= \boxed{\left({(r+\Delta r)^3 \over 3} - {r^3 \over 3}\right)(\cos\theta - \cos(\theta+\Delta\theta))\Delta\phi.}\end{align*}
接著我們看''圓柱座標'',無窮小塊的體積公式為 (2) 式,將它積分一個很小的範圍 \[(\rho, \phi, z) \quad \to \quad (\rho+\Delta\rho, \phi+\Delta\phi, z+dz),\] 其結果為 \begin{aligned}\int_z^{z+\Delta z}\int_\rho^{\rho+\Delta \rho}\int_\phi^{\phi+\Delta\phi}(\rho d\phi)d\rho dz &= \left(\int_\rho^{\rho+\Delta\rho} \rho d\rho\right)\left(\int_\phi^{\phi+\Delta\phi}d\phi\right)\left(\int_z^{z+\Delta z}dz\right) \\ &= \left(\int_\rho^{\rho+\Delta\rho} \rho d\rho\right)\left(\left[\phi\right]_\phi^{\phi+\Delta\phi}\right)\left([z]_z^{z+\Delta z}\right) \\ &= \left[\rho^2 \over 2\right]_\rho^{\rho+\Delta\rho} \Delta\phi \Delta z \\ \\ &= \boxed{\left({(\rho+\Delta \rho)^2 \over 2} - {\rho^2 \over 2}\right)\Delta\phi \Delta z.}\end{aligned}
!!! Finite Volume Spherical
\[\large d\tau_\text{finite} = {1\over 3}\left((r+\Delta r)^3 - r^3\right)(\cos\theta - \cos(\theta+\Delta\theta))\Delta\phi, \qquad (\text{Spherical})\]
!!! Finite Volume Cylindrical
\[\large d\tau_\text{finite} = {1 \over 2}\left((\rho+\Delta\rho)^2-\rho^2\right)\Delta\phi \Delta z \qquad (\text{Cylindrical})\]
* 在【設定場景】的倒數第二行,以及【初始條件】的中間,都有出現 {{{for n in range(len(ball)):}}} 這樣一行,這個 {{{for ...... }}} 開頭的指令,叫做 {{{for 迴圈}}}。
** 【迴圈】是告訴 Python(其他電腦語言也一樣)要做【重複的事情】,什麼重複的事情?就是迴圈指令下方【縮排進去的事情】。
*** 以【設計場景】的程式碼來看,迴圈指令在倒數第二行,之後只有一行縮排進去,也就是說,那最後一行就是迴圈要重複做的事情。
*** 以【初始條件】的程式碼來看,迴圈指令之後有好幾行縮排進去,那幾行都是要重複做的事情。
** 常見的迴圈指令有 {{{for}}} 以及 {{{while}}},一般稱為 {{{for 迴圈}}} 以及 {{{while 迴圈}}}。上面的 {{{for n in range(len(ball)):}}} 就是一個 {{{for 迴圈}}},而在[[拋體運動一]]的【細步計算】裡面,我們已經看到過 {{{while 迴圈}}} 了。
** 這個迴圈會重複幾次呢?那得看要重複做的事情是什麼。現在這個例子裡,我們要做的事情是【設定每顆球的初始條件】,所以很自然【{{{ball}}} 這個串列裡面有幾顆球,這個迴圈就該重複幾次】。上面的 {{{for n in range(len(ball)):}}} 便是以 {{{len(ball)}}}(串列裡有幾顆球)做為迴圈的重複次數。
** ''迴圈指令之後必須接著一個冒號'',表示下一行開始就是要重複做的事情。這個冒號是語法規定,沒有什麼理由的。
** 迴圈內要重複做的事情,都要【縮排】,上面的 {{{for ... :}}} 下面幾行都有內縮。這也只是語法規定,不必解釋的。__各個語言有自己的語法規定,不一定和 Python 一樣。__
** 縮排可以使用【Tab】或是【空白】,但同一段只能使用一種,不能混用。
** 縮排要縮到多裡面,隨意,但同一段必須一致。上面的迴圈內是使用【Tab】內縮【一次】。
** ''縮排結束就代表要重複做的事情結束''。上面的 {{{# 初始條件設定完成 ......}}} 這一行和迴圈指令 {{{for ... :}}} 是對齊的,表示這一行開始縮排結束,也就是迴圈裡要重複做的事情到此之前已經結束。
* 在【初始條件】的第三行,{{{def}}} 就是【定義,英文 define】,定義一個【函數/指令】。任何電腦語言都可以自訂函數/指令,用法不一定相同,在 Python 就是用 {{{def}}} 這個關鍵字。
** 任何一個自訂函數/指令,都要有名字,跟在 {{{def}}} 後面的文字,就是自訂函數/指令的名字。上面的 {{{def init():}}} 就是定義一個叫做 {{{init}}} 的函數/指令。''名字後面一定要跟著一對小括弧才行。''
** 函數/指令可以接受參數,就放在名字後面的小括弧裡。例如 {{{sin(x)}}} 這個函數,{{{sin}}} 是它的名字,小括弧裡的 {{{x}}} 就是它的參數。上面的 {{{init()}}} 括弧裡面沒有東西,表示我們定義的這個 {{{init}}} 【不】需要任何參數。
** ''小括弧後面必須接著一個冒號'',表示下一行開始就是函數/指令要做的事情。這個冒號也是語法規定,沒有什麼理由的。__各個語言有自己的語法規定,不一定和 Python 一樣。__
** 函數/指令要做的事情,都要【縮排】,上面的 {{{def init():}}} 下面幾行都有內縮,表示這幾行就是函數/指令要做的事情。
** 縮排的規則和迴圈內的縮排是一樣的。
* @@color:blue;光是定義函數/指令並不會產生結果,必須【叫用】那個函數/指令才會產生結果。@@
** 上面最後一行的 {{{init()}}} 就是在【叫用】 {{{init}}} 這個函數/指令,讓它實際執行定義在裡面的程式碼來產生結果。
*** 定義函數/指令就好像寫一段食譜,光是寫食譜並不會真的產生一道菜,必須使用食譜進行烹調才會真的產生一道菜。
這個講義中我們將要練習''靜磁學裡【也是簡單】情況''的一種:@@color:red;一個【日常大小磁偶極 \(\vec m\)】【靜止時】@@在其【內部】以及【周圍】產生的【''磁場(magnetic field)'']。@@所謂的【日常大小磁偶極】就是【常見的磁鐵】@@,''通常我們以磁鐵的中心為原點''。一個日常大小的磁偶極,可以將其視為【很多很多很小很小的磁偶極聚在一起】,因此其磁場的計算便是【將這些很小磁偶極產生的磁場加總起來】,具體公式如下:\[\large{\boxed{\vec B = \int d\vec B = {\mu_0 \over 4\pi} \int \left[{(\vec M \cdot \hat r)\hat r - \vec M \over r^3} + {8\pi \over 3}\vec M \delta(\vec r)\right]d\tau}}\] 其中
* \(\large \vec B\) 就是我們要計算的磁場;
* \(\Large \vec r\) 是要計算磁場的位置(以''磁偶極的中心位置當原點'');
* \(\large \vec M\) 為【單位體積的磁偶極矩】;
* \(\large d\tau\) 為一個很小的體積;
* \(\large \delta(\vec r)\) 是【狄拉克 \(\delta\) 函數】,它的函數值只有 0 和 1,\[\large\delta(\vec r) = \begin{cases}1 & \qquad \text{if }\vec r = 0, \\0 & \qquad \text{if }\vec r \neq 0.\end{cases}\] 有興趣的讀者可以參考[[維基百科狄拉克函數|https://zh.wikipedia.org/wiki/%E7%8B%84%E6%8B%89%E5%85%8B%CE%B4%E5%87%BD%E6%95%B0]] 或是英文版 [[Wikipedia Dirac Delta function|https://en.wikipedia.org/wiki/Dirac_delta_function]]。<br>
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 設計場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 畫出這個日常大小的磁鐵棒
barMagnet = box(
width = 1e-2, # 寬度(x 方向)為 1cm
height = 1e-2, # 高度(y 方向)為 1cm
depth = 3e-2, # 深度(z 方向)為 3cm
opacity=0.5
)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/5
xaxis = arrow(axis=vector(1,0,0)*R*30, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R*2)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*30, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R*2)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*30, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R*2)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 磁鐵棒所帶的總磁偶極矩(是個向量),假設在 +z 方向,大小約為 3e19 個電子的自旋磁偶極矩
# 電子自旋磁矩數值來源:https://zh.wikipedia.org/wiki/%E9%9B%BB%E5%AD%90%E7%A3%81%E5%81%B6%E6%A5%B5%E7%9F%A9
barMagnet.mu = vector(0, 0, 3e19*9.284764620e-24) # J/T (SI 單位制)
# 單位體積裡的磁偶極矩 = 總磁偶極矩 / 總體機(也是個向量)
barMagnet.M = barMagnet.mu / (barMagnet.width*barMagnet.height*barMagnet.depth)
# 真空導磁律(SI 單位制)
mu0 = 4*pi*1e-7 # NA^-2, 來源:https://zh.wikipedia.org/wiki/%E7%A3%81%E5%AF%BC%E7%8E%87
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
# x 從 -5 倍磁鐵棒寬度的地方開始,到 +5 倍寬度的地方結束,間隔 0.25 個寬度
for x in arange(-barMagnet.width*5,barMagnet.width*5,barMagnet.width/4):
# y 從 -5 倍磁鐵棒高度的地方開始,到 +5 倍高度的地方結束,間隔 0.25 個高度
for y in arange(-barMagnet.height*5,barMagnet.height*5,barMagnet.height/4):
# z 從 -2 倍磁鐵棒深度的地方開始,到 +2 倍深度的地方結束,間隔 0.25 個深度
for z in arange(-barMagnet.depth*2,barMagnet.depth*2,barMagnet.depth/4):
r = vector(x,y,z) # 算出要計算磁場的位置向量
rn = r.norm() # 算出這個位置向量的單位向量
B = vector() # 先產生一個值為 0 的磁場向量,
# 下面的積分會將磁場累加在這個向量
# 積分整個磁鐵棒來計算 r 這個位置的磁場
# x 軸切割成 10 份(確認程式正確之後,可自由調整,切越細計算就越準,但時間就越長)
dxp = barMagnet.width/10
for xp in arange(-barMagnet.width/2,barMagnet.width/2,dxp):
# y 軸切割成 10 份(確認程式正確之後,可自由調整)
dyp = barMagnet.height/10
for yp in arange(-barMagnet.height/2,barMagnet.height/2,dyp):
# z 軸切割成 10 份(確認程式正確之後,可自由調整)
dzp = barMagnet.depth/10
for zp in arange(-barMagnet.depth/2,barMagnet.depth/2,dzp):
rp = vector(xp, yp, zp) # 每一小塊磁鐵的位置向量
rpn = rp.norm() # 小塊磁鐵位置向量的單位向量
dtau = dxp*dyp*dzp # 小塊磁鐵的體積
# 判斷 r 是否正好在這個小塊【裡面】,如果是,
# 就要用公式裡的第二項,如果不是,則用第一項來
# 計算小塊磁鐵產生的一點點磁場
dr = r - rp
drn = dr.nowm()
if (dr.x*xp > 0 and abs(dr.x) < dxp): # x 距離在小塊的寬度之內
if(dr.y*yp > 0 and abs(dr.y) < dyp): # y 距離也在小塊的高度之內
if(dr.z*zp > 0 and abs(dr.z) < dzp): # z 距離也在小塊的深度之內
# r 應該是在小塊體積之內,用公式的第二項來計算
dB = mu_0*2/3*barMagnet.M*dtau
B += dB
continue # 繼續往下一小塊計算,跳過下面的程式碼
# r 不在小塊體積裡面,用公式的第一項計算磁場
dB = mu0/(4*pi)*(tinyMagnet.M.dot(drn)*drn - tinyMagnet.M)*dtau/dr.mag**3
# 這一小塊的磁場加到總磁場
B += dB
# 一小塊的計算結束,繼續往下一小塊計算
# 磁鐵的積分結束(注意:縮排要退出到和磁體積分開始的那一行對齊,表示積分結束後要執行下面這些程式碼)
arrow(pos=r,axis=B,shaftwidth=sw/3) # 畫一個箭頭代表磁場
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|[ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Magnet Finite Bar]] [[JS Codes 磁偶極的磁場分布 -- 日常大小]]>>|
這個講義中我們將要練習''靜磁學裡【也是簡單】情況''的一種:@@color:red;一個【日常大小磁偶極 \(\vec m\)】【靜止時】@@在其【內部】以及【周圍】產生的【''磁場(magnetic field)'']。@@所謂的【日常大小磁偶極】就是【常見的磁鐵】@@,''通常我們以磁鐵的中心為原點''。一個日常大小的磁偶極,可以將其視為【很多很多很小很小的磁偶極聚在一起】,因此其磁場的計算便是【將這些很小磁偶極產生的磁場加總起來】,具體公式如下:\[\large{\boxed{\vec B = \int d\vec B = {\mu_0 \over 4\pi} \int \left[{(\vec M \cdot \hat r)\hat r - \vec M \over r^3} + {8\pi \over 3}\vec M \delta(\vec r)\right]d\tau}}\] 其中
* \(\large \vec B\) 就是我們要計算的磁場;
* \(\Large \vec r\) 是要計算磁場的位置(以''磁偶極的中心位置當原點'');
* \(\large \vec M\) 為【單位體積的磁偶極矩】;
* \(\large d\tau\) 為一個很小的體積;
* \(\large \delta(\vec r)\) 是【狄拉克 \(\delta\) 函數】,它的函數值只有 0 和 1,\[\large\delta(\vec r) = \left\{\begin{align*} &1 &\qquad \text{if } \vec r = 0,\\ &0 &\qquad \text{if } \vec r \neq 0.\end{align*}\right.\] 有興趣的讀者可以參考[[維基百科狄拉克函數|https://zh.wikipedia.org/wiki/%E7%8B%84%E6%8B%89%E5%85%8B%CE%B4%E5%87%BD%E6%95%B0]] 或是英文版 [[Wikipedia Dirac Delta function|https://en.wikipedia.org/wiki/Dirac_delta_function]]。<br>
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 設計場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 畫出這個日常大小的磁鐵棒
barMagnet = box(
width = 1e-2, # 寬度(x 方向)為 1cm
height = 1e-2, # 高度(y 方向)為 1cm
depth = 3e-2, # 深度(z 方向)為 3cm
opacity=0.5
)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/5
xaxis = arrow(axis=vector(1,0,0)*R*30, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R*2)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*30, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R*2)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*30, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R*2)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 磁鐵棒所帶的總磁偶極矩(是個向量),假設在 +z 方向,大小約為 3e19 個電子的自旋磁偶極矩
# 電子自旋磁矩數值來源:https://zh.wikipedia.org/wiki/%E9%9B%BB%E5%AD%90%E7%A3%81%E5%81%B6%E6%A5%B5%E7%9F%A9
barMagnet.mu = vector(0, 0, 3e19*9.284764620e-24) # J/T (SI 單位制)
# 單位體積裡的磁偶極矩 = 總磁偶極矩 / 總體機(也是個向量)
barMagnet.M = barMagnet.mu / (barMagnet.width*barMagnet.height*barMagnet.depth)
# 真空導磁律(SI 單位制)
mu0 = 4*pi*1e-7 # NA^-2, 來源:https://zh.wikipedia.org/wiki/%E7%A3%81%E5%AF%BC%E7%8E%87
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
# x 從 -5 倍磁鐵棒寬度的地方開始,到 +5 倍寬度的地方結束,間隔 0.25 個寬度
for x in arange(-barMagnet.width*5,barMagnet.width*5,barMagnet.width/4):
# y 從 -5 倍磁鐵棒高度的地方開始,到 +5 倍高度的地方結束,間隔 0.25 個高度
for y in arange(-barMagnet.height*5,barMagnet.height*5,barMagnet.height/4):
# z 從 -2 倍磁鐵棒深度的地方開始,到 +2 倍深度的地方結束,間隔 0.25 個深度
for z in arange(-barMagnet.depth*2,barMagnet.depth*2,barMagnet.depth/4):
r = vector(x,y,z) # 算出要計算磁場的位置向量
rn = r.norm() # 算出這個位置向量的單位向量
B = vector() # 先產生一個值為 0 的磁場向量,
# 下面的積分會將磁場累加在這個向量
# 積分整個磁鐵棒來計算 r 這個位置的磁場
# x 軸切割成 10 份(確認程式正確之後,可自由調整,切越細計算就越準,但時間就越長)
dxp = barMagnet.width/10
for xp in arange(-barMagnet.width/2,barMagnet.width/2,dxp):
# y 軸切割成 10 份(確認程式正確之後,可自由調整)
dyp = barMagnet.height/10
for yp in arange(-barMagnet.height/2,barMagnet.height/2,dyp):
# z 軸切割成 10 份(確認程式正確之後,可自由調整)
dzp = barMagnet.depth/10
for zp in arange(-barMagnet.depth/2,barMagnet.depth/2,dzp):
rp = vector(xp, yp, zp) # 每一小塊磁鐵的位置向量
rpn = rp.norm() # 小塊磁鐵位置向量的單位向量
dtau = dxp*dyp*dzp # 小塊磁鐵的體積
# 判斷 r 是否正好在這個小塊【裡面】,如果是,
# 就要用公式裡的第二項,如果不是,則用第一項來
# 計算小塊磁鐵產生的一點點磁場
dr = r - rp
if (dr.x*xp > 0 and abs(dr.x) < dxp): # x 距離在小塊的寬度之內
if(dr.y*yp > 0 and abs(dr.y) < dyp): # y 距離也在小塊的高度之內
if(dr.z*zp > 0 and abs(dr.z) < dzp): # z 距離也在小塊的深度之內
# r 應該是在小塊體積之內,用公式的第二項來計算
dB = 8*pi/3*barMagnet.M*dtau
B += dB
continue # 繼續往下一小塊計算,跳過下面的程式碼
# r 不在小塊體積裡面
dB = mu0/(4*pi)*(tinyMagnet.M.dot(rpn)*rpn - tinyMagnet.M)*dtau/rp.mag**3
B += dB
# 一小塊的計算結束,繼續往下一小塊計算
# 磁鐵的積分結束(注意:縮排要退出到和磁體積分開始的那一行對齊,表示積分結束後要執行下面這些程式碼)
arrow(pos=r,axis=B,shaftwidth=sw/3) # 畫一個箭頭代表磁場
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
!! 課後練習
# 這個程式執行的結果,應該 xxxx,如果不是的話,檢查看看程式碼哪裡有錯喔!
#
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Cylindrical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Magnet Finite Cylinder]] [[Field Iterators]] [[JS Codes 磁偶極的磁場分布 -- 日常大小 -- 圓柱]]>>|
sudo raspi-config
go to the advanced options menu
go to GL driver
Choose Enable(如果看到三個選項,選第一個)
Choose OK
It will prompt you to reboot, say Yes
!! 積分的小塊體積
* @@color:red;background-color:yellow;注意事項@@
## 積分的概念是把一個物體切成很多很多的小塊,然後
*** 把每一小塊當作一個點,
*** 套用最基本的公式計算一小塊的結果,
*** 再把每一小塊的結果加總起來。
## 積分過程中通常需要計算【一小塊的體積】
*** 在微積分的公式裡一小塊的體積就是套用【長 × 寬 × 高】的概念。例如:
**** 直角座標下一小塊體積就是 \(d\tau = (dx)(dy)(dz)\)
***** 其中 \(dx\) 就是一小塊沿著 \(\hat x\)-軸方向的邊長,
***** \(dy\) 就是一小塊沿著 \(\hat y\)-軸方向的邊長,
***** \(dz\) 就是一小塊沿著 \(\hat z\)-軸方向的邊長。
***** 這三個邊長就是這一小塊的【長】【寬】【高】。
**** __哪一邊是長、哪一邊是寬、高,並沒有關係,算出來的體積是一樣的。__
*** 球座標下積分的小塊體積公式為 \(d\tau = (dr)(rd\theta)(r\sin\theta d\phi)\),其中 \(r d\theta\) 及 \(r\sin\theta d\phi\) 是一小段圓弧。
*** 圓柱座標下積分的小塊體積公式為 \(d\tau = (d\rho)(\rho d\phi)(dz)\),其中 \(\rho d\phi\) 是一小段圓弧。
## 對於直角座標,這樣的計算永遠都成立,因為三個邊都是直線。
*** 但對於''球座標''或''圓柱座標''的小塊來說,
**** ''因為有''一個或兩個邊是''圓弧形''的,''這個計算就只有在【無窮小塊】的時候才會成立''。
## @@但是數值計算不可能將物體切成無窮小塊,因為那樣會切出無窮多塊,就得花費無窮長的時間做計算。@@
## 不是無窮小塊的時候應該如何正確計算小塊的體積?可以參考[[數值積分裡面的小塊體積]]裡面的說明。
!! 群聚體內部的積分
* @@color:red;background-color:yellow;注意事項@@
## 在電荷球的內部計算電場或電位勢的時候,會出現【計算的位置剛好在某一小塊的內部】這種情況,
*** 這個時候【要另外處理這個小塊】,理由是
#### 我們把每一小塊當作點電荷,套用點電荷的公式;且
#### 點電荷的公式只包含【點電荷以外的空間】,沒有包含點電荷裡面(因為點電荷根本沒有裡面!)。
*** 如果''沒有特別處理就會得到不正確的結果''。
## 最簡單的處理方式就是【避開不算】
*** 簡單版的避開程式碼也很好寫(如範例中的),但很可能不夠正確。
*** 要寫出較準確的程式碼需要清楚的向量運算概念,
**** 如果還沒有建立清楚的向量概念,可以先用簡單的程式碼,然後【儘可能切得很小塊】
***** 切得越小塊計算越準確,代價是計算時間就拉得越長。
## 如果已經熟悉向量運算,就參考[[積分計算的你儂我儂]]試看看寫一段較準確的程式碼來避開這種情況吧!
*** 除了避開不算之外,當然還有別的處理方式,例如
****【單獨把這一小塊切成多個更小塊】,
***** 這樣做還是會有一個更小塊包含到計算的位置,這個更小塊也是得特別處理,
****** 只是比起原先的小塊要小很多,準確度自然就高很多。
*** 進階的處理方法可以等到更加熟悉程式語言的時候再來思考與學習,
**** 現在先把最簡單的處理方法練習起來吧!
!! 常用座標系
<<tiddler "座標系說明##常用座標系">><<tiddler "座標系說明##曲線座標系">>
事實上,在討論電磁學的時候我們經常碰到具有【球狀對稱】或是【圓柱狀對稱】的情況,因此,了解這些座標系會讓這些計算方便很多!在這個講義裡我們要來學習【''球座標系''】
!! 球座標系
在具有【''球形對稱性''】的情況下,使用球形座標系會比直角座標系方便不少,這是我們學習球座標系的主要理由。至於甚麼時候會有【球形對稱性】?比如說一顆球,它所具有的對稱性就稱為「球對稱性」;或者一個點,它基本上就是把一顆球縮到很小很小,所以也具有球對稱性。
在三度空間裡要標示一個位置,需要三個數字,比如說直角座標的 \((x, y, z)\) 便是,而在使用球座標的時候,這三個數字是 @@font-size:1.2em;color:blue;\((r, \theta, \phi)\)@@,其中
* \(\Large r\) 是【從''原點''到這個位置的''距離''】
* \(\large\theta\) 是【從 ''//z//-軸''】''傾斜''到這個位置的''角度'',也稱為【''天頂角''】
* \(\large\phi\) 是【從 ''//x//-軸''】''偏轉''到這個位置的''角度'',也稱為【''方位角''】
<<<
* 如果用地球表面的位置來說明,那麼
**【天頂角】就是【從北極傾斜下來】的角度,和【緯度(從赤道上來的角度)】正好互為補角,而
**【方位角】可以正好是【經度】,假如我們把 \(x\)-軸對到東經 0 度(本初子午線)的話。
* @@font-size:1.2em;line-height:1.6em;球座標系的座標軸也是互相垂直的,只是三個座標軸的方向會隨著位置不同而有改變,不像直角座標系的三個軸方向永遠都是固定在一開始選好的方向。@@
** ''勾選下方【Spherical】前面的方塊''的話,可以在動畫區看到球座標系的三個座標軸的方向,如果讓動畫繼續進行,就可以看到這三個軸的方向隨著位置不同而改變。
<<<
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Spherical System Control">> / <<tw3DCommonPanel "Frame Control">>|
|>|<<tw3DScene [[JS Codes 球座標系]]>>|
!! 常用座標系
<<tiddler "座標系說明##常用座標系">>
這些座標系之中,【直角座標系】應該是大家第一個學到,也應該是多數人最熟悉一個座標系。生活上會遇到的力學問題,很大一部分是使用直角座標系就可以解決的,這裡我們稍微複習一下這個座標系。
在三度空間裡要標示一個位置,需要三個數字,在直角座標就是我們熟悉的 \((x, y, z)\) 分量,它們其實就是這個位置分別在 ''\(x\)-軸''、 ''\(y\)-軸'',以及 ''\(z\)-軸'' 上【''影子的位置''】。
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">> / <<tw3DCommonPanel "Frame Control">>|
|>|<<tw3DScene [[JS Codes 直角座標系]]>>|
!! 概念說明
所謂【積分】,簡單來說就是下列【''三步驟''】:
# 在腦海裡把物體切成【很多很多】【很小很小】的小塊;
# 每一小塊當做一個【點】,套用【點】的計算公式;
# 所有的小塊都算過,把結果【加總起來】,便是積分的結果。
! 圓柱座標積分之概念展示
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Air Drag">>|
|<<tw3DCommonPanel "Frame Control">> / [ =chkShowSteps] Show steps|<<tw3DCommonPanel "Cylindrical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene height:'30em' [[JS Codes 積分概念 -- 圓柱座標]]>>|
!! 概念說明
所謂【積分】,簡單來說就是下列【''三步驟''】:
# 在腦海裡把物體切成【很多很多】【很小很小】的小塊;
# 每一小塊當做一個【點】,套用【點】的計算公式;
# 所有的小塊都算過,把結果【加總起來】,便是積分的結果。
!! 球座標積分之概念展示
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Air Drag">>|
|<<tw3DCommonPanel "Frame Control">> / [ =chkShowSteps] Show steps|<<tw3DCommonPanel "Spherical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene width:'45em' height:'28em' [[JS Codes 積分概念 -- 球座標]]>>|
!! 概念說明
所謂【積分】,簡單來說就是下列【''三步驟''】:
# 在腦海裡把物體切成【很多很多】【很小很小】的小塊;
# 每一小塊當做一個【點】,套用【點】的計算公式;
# 所有的小塊都算過,把結果【加總起來】,便是積分的結果。
!! 直角座標積分之概念展示
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Air Drag">>|
|<<tw3DCommonPanel "Frame Control">> / [ =chkShowSteps] Show steps|<<tw3DCommonPanel "Cartesian System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene width:'45em' height:'28em' [[JS Codes 積分概念 -- 直角座標]]>>|
這裡我們要計算球的體積來確認數值積分的準確度,已知球的體積為:\[\large V = \int d\tau = \int_0^H \int_0^R\int_0^{2\pi} (\rho d\phi) d\rho dZ = \pi R^2 H \tag{1}\] 其中
* \(V\) 就是我們要計算的球體積;
* \(d\tau\) 是一個很小的體積;
* \(R\) 是球的半徑。
這裡要測試的主要是【小塊體積 \(d\tau\) 的計算】。微積分裡面這個小塊是【無窮小】,因此其體積用方形體公式【長 × 寬 × 高】,也就是 (1) 式裡面的 \[d\tau = (\rho d\phi) d\rho dz \tag{2}\] 來計算,誤差是趨近於 0 的。但是在數值計算中,這個小體積「不可能」是無窮小,因此若還是使用 (2) 式來計算,肯定有相當程度的誤差。事實上,一個不是無窮小的小塊體積應該是將 (1) 式對小塊體積的範圍做積分,其結果為 <<tiddler "數值積分裡面的小塊體積##Finite Volume Cylindrical">> 計算細節可參考 [[數值積分裡面的小塊體積]]。
|noborder|k
|<<tw3DCommonPanel "Flow Control">>|<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">> / [ =chkShowSteps] Show steps|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Solid Sphere]] [[Field Iterators]] [[JS Codes 積分測試 -- 圓柱座標]]>>|
這裡我們要計算球的體積來確認數值積分的準確度,已知球的體積為:\[\large V = \int d\tau = \int_0^R\int_0^\pi\int_0^{2\pi} (r\sin\theta d\phi) (rd\theta) dr = {4 \over 3}\pi R^3 \tag{1}\] 其中
* \(V\) 就是我們要計算的球體積;
* \(d\tau\) 是一個很小的體積;
* \(R\) 是球的半徑。
這裡要測試的主要是【小塊體積 \(d\tau\) 的計算】。微積分裡面這個小塊是【無窮小】,因此其體積用方形體公式【長 × 寬 × 高】,也就是 (1) 式裡面的 \[d\tau = (r\sin\theta d\phi) (rd\theta) dr \tag{2}\] 來計算,誤差是趨近於 0 的。但是在數值計算中,這個小體積「不可能」是無窮小,因此若還是使用 (2) 式來計算,肯定有相當程度的誤差。事實上,一個不是無窮小的小塊體積應該是將 (1) 式對小塊體積的範圍做積分,其結果為 <<tiddler "數值積分裡面的小塊體積##Finite Volume Spherical">> 計算細節可參考 [[數值積分裡面的小塊體積]]。
|noborder|k
|<<tw3DCommonPanel "Flow Control">>|<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">> / [ =chkShowSteps] Show steps|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Solid Sphere]] [[Field Iterators]] [[JS Codes 積分測試 -- 球座標]]>>|
這裡我們要計算球的體積來確認數值積分的準確度,已知球的體積為:\[\large V = \int d\tau = \int_0^H \int_0^R\int_0^{2\pi} (\rho d\phi) d\rho dZ = \pi R^2 H \tag{1}\] 其中
* \(V\) 就是我們要計算的球體積;
* \(d\tau\) 是一個很小的體積;
* \(R\) 是球的半徑。
這裡要測試的主要是【小塊體積 \(d\tau\) 的計算】。微積分裡面這個小塊是【無窮小】,因此其體積用方形體公式【長 × 寬 × 高】,也就是 (1) 式裡面的 \[d\tau = (\rho d\phi) d\rho dz \tag{2}\] 來計算,誤差是趨近於 0 的。但是在數值計算中,這個小體積「不可能」是無窮小,因此若還是使用 (2) 式來計算,肯定有相當程度的誤差。事實上,一個不是無窮小的小塊體積應該是將 (1) 式對小塊體積的範圍做積分,其結果為 <<tiddler "數值積分裡面的小塊體積##Finite Volume Cylindrical">> 計算細節可參考 [[數值積分裡面的小塊體積]]。
|noborder|k
|<<tw3DCommonPanel "Flow Control">>|<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">> / [ =chkShowSteps] Show steps|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Solid Sphere]] [[Field Iterators]] [[JS Codes 積分測試 -- 直角座標]]>>|
> 這個講義的說明影片:[[積分計算的你儂我儂說明影片|https://drive.google.com/file/d/13QcN3gycmLrVKGFms3kP2_DdgSoynCcQ/view?usp=sharing]]
! 積分計算時該如何避開在小塊內部的情況
我們在計算[[群聚成球狀的靜止電荷的電場強度及電位勢與距離之關係]]以及[[長直導線的磁場隨距離的關係]]的時候,都有碰到【''計算電/磁場的位置正好在某個小塊的內部''】這種情況,而且我們已經知道這種情況應該要避開,也就是【要跳過這一小塊不要算】的。
在前兩個講義的程式碼中,我們只用了一個非常簡化的想法來避開這種情況:
* 如果@@color:red;計算電場/磁場的位置 \(\vec r\)(圖一中紅點)@@和小塊的位置 \(\vec r'\) 之間的距離小於小塊的最大邊長,就當做是在小塊裡面。
{{FrameHalfRight{
|width:410px;<<tw3DCommonPanel "Cartesian System Control">> / <<tw3DCommonPanel "Boost Control">>|
|<<tw3DCommonPanel "Spherical System Control">> / <<tw3DCommonPanel "Cylindrical System Control">>|
|<<tw3DScene [[JS Codes 積分計算的你儂我儂]]>>|
@@圖一:@@動畫展示積分過程中,有機會出現【@@color:red;background-color:white;計算電/磁場的位置(紅點)@@正好在某個小塊體積之內】的情形(小塊體積變成灰色)。<br><br>把畫面拉近一些,再旋轉畫面找一個看得比較清楚的視角,可以較容易看出文中公式 (1) 和 (2) 所描述的情形。<br><html><ul><li>拉近畫面:雙指在觸控螢幕上滑開、滑鼠滾輪滾動、雙指在觸控板前後滑動。</li><li>旋轉畫面:單指在螢幕上滑動、按住滑鼠左鍵移動、按住左鍵單指在觸控板移動。</li></ul></html>}}}
<<<
{{{
# r 是計算電場/磁場的位置
# rp 是現在這個小塊的位置
delta_r = r - rp
if delta_r.mag < drp: # drp 是小塊在 r 方向的邊長
continue
}}}
<<<
''@@font-size:1.2em;這個過度簡化的想法很容易寫,但其結果可想而知不會正確!@@''
<<<
因為
* 即使不在小塊的內部,也有可能因靠得夠近而被誤判,或者
* 即使已經在小塊內部,但距離卻大於最大邊長而被誤判。
<<<
那麼我們該如何正確的避開這種情況呢?
我們就從【確定有這種情況】來看看到底這種情況有什麼特性,了解清楚之後就可以寫出正確的程式碼。
當我們確定有【計算電場/磁場的位置就在現在這個小塊裡面】的情況時,可以從圖一中看出(''可能需要拉近或旋轉一下圖一的畫面''):
# 從 綠點 \(\vec r\ '\)(小塊體積的一個角落)到 @@color:red;紅點 \(\vec r\) (計算電/磁場的位置)@@的向量 \[\Delta\vec r = \vec r - \vec r\ ' \qquad \text{(圖一黃色箭頭)}\]和小塊體積的三個邊長向量(__可拉近或旋轉圖一的畫面看得較清楚__) \[d\vec x_1, d\vec x_2, d\vec x_3 \quad \text{(從綠點出發,沿著三個邊長的紅、綠、淡藍三個向量)}\] 夾角都小於 90°,也就是說【\(\Delta \vec r\) 和三個邊長向量的內積都要 > 0】,寫成代數就是 \begin{equation}\Delta \vec r \cdot d\vec x_1 > 0, \quad \text{and} \quad \Delta \vec r \cdot d\vec x_2 > 0, \quad \text{and} \quad \Delta \vec r \cdot d\vec x_3 > 0\end{equation}
# \(\Delta \vec r\) 在小塊體積的三個邊上的投影長度都會小於那個邊長,也就是 \begin{equation}\Delta \vec r \cdot d\vec x_1 < dx_1 dx_1, \quad \text{and} \quad \Delta \vec r \cdot d\vec x_2 < dx_2 dx_2, \quad \text{and} \quad \Delta \vec r \cdot d\vec x_3 < dx_3 dx_3.\end{equation}
把 (1)、(2) 兩個式子合併起來,我們就可以得到【當''@@color:red;計算電/磁場的位置 \(\vec r\)@@ 正好位於某個小塊體積之內''】的條件為 \[\large{\boxed{\begin{align*}0 \quad < \quad \Delta \vec r \cdot d\vec x_1 \quad < \quad dx_1^2, \qquad \text{and} \\ 0 \quad < \quad \Delta \vec r \cdot d\vec x_2 \quad < \quad dx_2^2, \qquad \text{and} \\ 0 \quad < \quad \Delta \vec r \cdot d\vec x_3 \quad < \quad dx_3^2. \qquad\qquad \end{align*}}}\]
<<<
底下是相對應的通用型 Python 程式碼
{{{
# delta_r, dx_1, dx_2, dx_3 都【必須】是【向量】,且已經事先計算出來
if 0 < delta_r.dot(dx_1) and delta_r.dot(dx_1) < dx_1.mag2:
# 第一個邊符合條件,測試第二個邊
if 0 < delta_r.dot(dx_2) and delta_r.dot(dx_2) < dx_2.mag2:
# 第二個邊也符合條件,測試第三個邊
if 0 < delta_r.dot(dx_3) and delta_r.dot(dx_3) < dx_3.mag2:
# 第三個邊也符合條件,表示計算場的位置【是】包含在這一小塊體積之內
# 可能的處理方式有
# 1. 不要算這一小塊
# 2. 將這一小塊切得更細(只切這一小塊)
# 現在我們先採取簡單的做法,也就是 1. 不要算這一小塊
continue
# 計算場的位置【不是】包含在現在這一小塊體積之內,正常計算
# 注意: 按照定義,計算電場/電位勢的時候,delta_r 應該是【從小塊中心】出發到
# 計算電場/電位勢位置的向量,所以應該要把小塊中心 r_center 計算出來
# 然後再算出符合定義的 delta_r
# 提示: 參考上面的 3D 圖,或者自己在紙上畫一個小塊,觀察
# 小塊位置 + 三個邊的向量,也就是 r_dV + dx_1 + dx_2 + dx_3,
# 會到小塊的哪裡?
......
}}}
<<<
>> @@font-size:1.2em;color:red;//注意: 一般而言,電腦程式語言並【不】認識 \(0 < a < b\) 這樣的寫法,通常是得把它寫成兩個比較式:\[0 < a \text{ and } a < b\]//@@
<<<
* 如果是【[[直角座標系]]】,\(\large d\vec x_1, \quad d\vec x_2, \quad d\vec x_3 \qquad \to \qquad dx\ \hat x, \quad dy\ \hat y, \quad dz\ \hat z\);<br><br>
* 如果是【[[圓柱座標系]]】,\(\large d\vec x_1, d\vec x_2, d\vec x_3 \qquad \to \qquad d\rho\ \hat \rho, \quad \rho d\phi\ \hat \phi, \quad dz\ \hat z \qquad \qquad \large\boxed{\bf{\hat\phi = \hat z \times \hat \rho}}\);<br><br>
* 如果是 【[[球座標系]]】,\(\large d\vec x_1, d\vec x_2, d\vec x_3 \qquad \to \qquad dr\ \hat r, \quad rd\theta\ \hat \theta, \quad r\sin\theta d\phi\ \hat \phi \qquad \large\boxed{\bf{\hat\phi = \hat z \times \hat r \qquad \hat \theta = \hat \phi \times \hat r}}\)。
<<<
{{Title{
法拉第定律
}}}
> 這個講義的說明影片:[[法拉第定律說明影片|https://drive.google.com/file/d/164TOFJKxRG62vUvXMAAkQECwvRwwHZUO/view?usp=sharing]]
!! 現象
* [[法拉第定律|https://zh.wikipedia.org/wiki/%E6%B3%95%E6%8B%89%E7%AC%AC%E7%94%B5%E7%A3%81%E6%84%9F%E5%BA%94%E5%AE%9A%E5%BE%8B]]^^[1]^^是由英國物理學家[[麥可‧法拉第|https://zh.wikipedia.org/wiki/%E9%BA%A5%E5%8F%AF%C2%B7%E6%B3%95%E6%8B%89%E7%AC%AC]]^^[2]^^在經過數年的研究之後於 1831 年所提出,主要談的是【磁生電】的現象:當一個磁鐵朝向(或者遠離)一個線圈移動(線圈【沒有】接上電源),在線圈上會產生感應電流。
* 磁鐵移動速度越快,感應電流越大;線圈的圈數越多,感應電流也越大。
* 如果反過來把磁鐵固定不動而讓線圈(【沒有】接上電源)朝向(或遠離)磁鐵移動,也會產生同樣的效果。
* [[PhET|https://phet.colorado.edu/zh_TW/]] 網頁上有一個 [[法拉第定律的互動模擬|https://phet.colorado.edu/sims/html/faradays-law/latest/faradays-law_zh_TW.html]],可以用滑鼠抓取磁鐵移動,讓磁鐵通過線圈中間即可看到燈泡會有亮的時候。
!! 原理
法拉第定律可以寫成 \begin{equation}\epsilon = -{d\Phi_{B} \over dt} = -{d \over dt}\int_\text{線圈圍起來的面積} \vec B \cdot d\vec A,\end{equation} 其意義為:
# 磁通量 \(\Phi_{B}\) 若隨時間有所變化,則會在線圈上產生【感應電壓】(也稱【感應電動勢】) \(\epsilon\);
# ''感應電壓的大小等於''【磁通量的變化率】(\(d\Phi_{B} / dt\));
# 感應電壓會在線圈引起感應電流,其方向為【能夠彌補磁通量變化】的方向(式(1) 的【負號】就是這個意思)。
** 例如:假如磁鐵和線圈互相靠近,通過線圈圍起來的面積的【磁通量就會增加】,那麼感應電流的方向就是【讓磁通量減少】的方向。
*** 反過來如果磁鐵和線圈互相遠離,則【磁通量會減少】,那麼感應電流的方向就是【讓磁通量增加】的方向。
! 設計場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 畫出一個小磁鐵棒
# 畫出一個線圈
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/5
xaxis = arrow(axis=vector(1,0,0)*R*30, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R*2)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*30, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R*2)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*30, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R*2)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 小磁鐵棒所帶的磁偶極矩(是個向量)
# 請自行了解一般強力磁鐵的磁偶極矩(或者磁場)的大小
# 小磁鐵的初始位置
# 小磁鐵的初始速度(自行決定要靠近或是遠離線圈)
# 線圈相關的條件(提示:感應電壓會引起感應電流,電壓和電流滿足 ... 定律)
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
# 磁鐵移動(可以的話應盡量採用榮格-庫塔方法來計算運動,短時間無法做到的話,則採取最簡單的等速運動公式)
# 計算【通過線圈圍起來的面積】的磁通量(用箭頭表示磁場大小與方向,如果磁場很小,可以把箭頭長度拉長)
# 計算磁通量隨時間的變化率(需要做數值微分,請自行找出適合自己使用的方法)
# 紀錄感應電壓
# 計算感應電流(想想看,有電壓,如何算電流,以前學過的)
//}}}
!! 課後練習
# 劃出【感應電壓隨時間】以及【感應電流隨時間】的數據圖,確認有符合【感應電流產生的磁場傾向於彌補磁通量的改變】。
|noborder|k
|width:45%;<<tw3DCommonPanel Flow Control>>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel LabelCPS>> / [X=chkSlowMotion] Slow when z < L * <html><input type="number" title="Slow Motion." id="txtSlowWithin" min="1" max="10" step="1" value="2" style="width:35px"></html> \(\large v = v_0\) / <html><input type="number" title="Slow Motion Ratio." id="txtSlowRatio" min="1" max="50" step="1" value="20" style="width:35px"></html>|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Magnet Tiny Bar]] [[Wire Loop]] [[JS Codes 等速移動的磁鐵 -- 法拉第定律]]>>|
!! 參考文獻
# [[維基百科法拉第定律|https://zh.wikipedia.org/wiki/%E6%B3%95%E6%8B%89%E7%AC%AC%E7%94%B5%E7%A3%81%E6%84%9F%E5%BA%94%E5%AE%9A%E5%BE%8B]]
# [[維基百科麥可‧法拉第|https://zh.wikipedia.org/wiki/%E9%BA%A5%E5%8F%AF%C2%B7%E6%B3%95%E6%8B%89%E7%AC%AC]]
> 這個講義的說明影片:[[安培定律說明影片|https://drive.google.com/file/d/12l7bQvqA_h3fMk74wUzmv6BhlIT5AW1r/view?usp=sharing]]
> 這個計算在數學上稱為【路徑積分】,不熟悉的同學可以參考講義 [[路徑積分 -- 以安培定律為例]]
這個講義中我們要討論(真空中)電磁學四大定律之一的''安培定律'' \[\large{\boxed{\oint \vec B \cdot d\vec l = \mu_0 I_\text{enc}}},\] 其中
* \(\large \color{blue} \bf {dl'}\) 為封閉路徑其中@@color:blue;''一小段的【長度】''@@;
* \(I_\text{enc}\) 是''穿過封閉路徑所圍起來區域的電流'';
這個定律的意義是:對一個「封閉的」路徑 \(l\) 進行「磁場的路徑積分 \(\int \vec B \cdot d\vec l\)」計算,其結果「正比於穿過這個封閉路徑的電流 \(I_\text{enc}\)」,其中正比常數 \(\mu_0\) 叫做【真空中的磁導率】(參考[[維基百科磁導率|https://zh.wikipedia.org/wiki/%E7%A3%81%E5%AF%BC%E7%8E%87]]),在 SI 單位制的數值為 \(\mu_0 = 4\pi \times 10^{-7} \text{ N}\cdot\text{A}^{-2}。\)
在這個講義裡我們要來練習對【流著穩定電流的長直導線,計算磁場在@@color:red;圓形@@封閉路徑的積分】,並將計算結果對【從導縣內部到外部之不同封閉路徑的半徑】做圖。因為是__長直導線__,我們選擇__圓柱座標__ \((\rho, \phi, z)\),並且選擇封閉路徑就是''繞圓柱側面一圈的圓形路徑''。如此一來導線附近的磁場方向和封閉路徑的方向就會一致,都是沿著圓形路徑的切線方向,也就是圓柱座標裡的 \(\hat\phi\) 方向。換句話說 \[\vec B = B\hat\phi, \qquad d\vec l = (\rho d\phi)\hat\phi,\] 其中 \(\rho\) 是封閉路徑的半徑。''注意圓周上任何兩點的切線方向都不一樣,也就是 \(\hat\phi\) 方向在圓周上的每一個點都不會一樣,所以在每一個計算的位置都要先把 \(\hat \phi\) 這個向量計算出來''。這個計算並不困難,只需利用【切線方向平行於 \(z\)-軸和半徑方向的外積】這個關係即可,\[\large \hat\phi = \hat z \times \hat\rho,\] 其中 \(z\)-軸是一開始就選好固定的,而 \(\hat\rho\) 就是小段路徑所在位置的水平面投影(也就是它的 \(x\)-分量以及 \(y\)-分量組成的向量),只要小段路徑的位置算出來,\(\hat\rho\) 就跟著算出來,而 \(\hat\phi\) 自然也就可以算出來了。
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義一條【粗】的長直導線
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 電流大小
I = # 安培,自己選擇一個合理的電流值
# 電流密度(單位面積的電流)
J = wire.axis.norm() * I / (pi * R**2)
# 真空磁導率(或導磁率,SI 單位制)
mu_0 = 4 * pi * 1e-7 # N / A^2
# 產生一個空的數據圖(準備畫 路徑積分結果 對 路徑半徑 的數據圖)
BL_vs_R =
//}}}
! 細步計算
//{{{
BL = 0 # 路徑積分的結果,先設為 0
# 計算磁場的路徑積分之迴圈,沿著圓形封閉路徑上多個位置做計算
r = vector( # 算出要計算 磁場 的位置
?, # x-分量
?, # y-分量
? # z-分量
)
dl = # 一小段路徑的向量
B = vector(0,0,0) # 磁場先設定為 0,後面計算中會積分出來
# 切割電線(做積分)
drp = R / 20 # 沿著圓柱半徑切成多個小段
dphip = 2*pi / 60 # 沿著角度切成多個小角度
dzp = L / 50 # 沿著圓柱軸長切成多個小段
# 積分迴圈,細導線只需要一個迴圈,粗導線就需要三個
# 計算這一小塊電線的體積(微小但不是無限小體積公式,從上面公式積分得來)
r_dV = vector( # 算出這一小塊電線的位置
?, # x-分量
?, # y-分量
? # z-分量
)
delta_r = r - r_dV # 計算從這一小塊電線開始到計算電場位置的向量
# 我們需要這個向量,因為底下要利用比歐-沙伐
# 公式計算一小塊電流產生的磁場,而比歐-沙伐
# 公式裡面的 r 是要從一小塊電流所在位置開始
# (不見得是原點開始)的向量。
# 利用比歐-沙伐公式計算這一小塊電線產生的微小磁場
# 加總到 B
B += dB
arrow(pos=r,axis=B*1e4,shaftwidth=sw/3) # 畫一個箭頭代表磁場
# 計算路徑積分
BL += B.dot(dl)
# 在數據圖上畫一個點
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Cylindrical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Current Solid Cylinder]] [[JS Codes 等速移動的電荷 -- 安培定律]]>>|
!! 參考文獻
# 維基百科 [[安培環路定律|https://zh.wikipedia.org/wiki/%E5%AE%89%E5%9F%B9%E7%8E%AF%E8%B7%AF%E5%AE%9A%E5%BE%8B]]
這個講義中我們將要練習''電磁學裡【也還算簡單】情況''的一種:@@color:red;在一條【粗】長直導線裡面等速移動的電荷(穩定電流),@@在其周圍產生的【''磁場(magnetic field)''],具體的做法為跟 [[等速移動的電荷 -- 細長直導線的磁場]] 是一樣的:\[\vec B(\vec r) = \int_\text{整條導線} d\vec B(\vec r)\] 只是現在變成''粗''導線,所以對導線的積分要從【切成很多的小線段】改成【切成很多的''小塊''】,具體的做法是:
# 將粗長直導線切成很多很多的''小塊'',
# 每一個小塊套用【''比歐-沙伐定律''】計算磁場,
# 將每一個小塊的磁場(向量)加起來 \[\Large{\vec B(\vec r) = \int_\text{整條導線內部} d\vec B(\vec r) = \int_\text{整條導線內部} {\mu_0 \over 4\pi} d\tau'{\color{blue} \bf{\vec j \times \hat { \Delta r}} \over \color{blue}\Delta r^2},}\]
其中
* \(\vec B\) 就是我們要計算的磁場;
* \(\Large\vec r\) 是要計算磁場的位置(以電流中心點當原點);
* \(\vec j\) 是''電流密度'',定義為【通過單位面積的電流】,其大小為 \(I / A\)(A 為導線的截面積),方向為電流的方向;
* \(\large \color{blue} \bf {d\tau'}\) 為【@@color:blue;''一小塊''@@】的體積;
* \(\large \Delta \vec r\) 是從@@color:red;現在計算的那一小塊電線@@開始到@@color:blue;計算磁場的地方@@的向量
<<<
* 注意 \(\large\Delta \vec r\) 【@@color:red;''不是''@@】從原點開始的向量,而是從【@@color:red;現在計算的那一小塊電線@@】開始的。
<<<
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義電線的半徑及長度(可隨意調整)
R = 0.05 # 電線半徑
L = 2 # 電線長度
# 畫出一條細圓柱代表一條細直電線
wire = cylinder(pos=vector(0,0,-L/2), radius=R, axis=vector(0,0,L), opacity=0.5)
# 畫出一個箭頭代表電流方向
sw = R/10
arrI = arrow(axis=vector(0,0,L/5), shaftwidth=sw) # 箭頭長度是電線的 1/5
arrI.pos = arrI.pos - arrI.axis/2 # 把箭頭移到畫面中央
arrI.pos.y += R*1.5 # 箭頭稍微離開電線一些
text( # 箭頭的中央放一個文字
text = 'I', # 文字內容
pos = arrI.pos+arrI.axis/2, # 文字位置
height = R, # 文字高度
font = 'serif' # 設定字型
)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 電流大小
I = 50 # 安培
# 電流密度(單位面積的電流)
J = wire.axis.norm() * I / (pi * R**2)
# 真空磁導率(或導磁率,SI 單位制)
mu_0 = 4 * pi * 1e-7 # N / A^2
//}}}
! 細步計算
//{{{
for z in arange(-L/4,L/4,L/20): # z 從 -L/4 到 L/4,共計算 20 個位置
for phi in arange(0,2*pi,2*pi/20): # 方位角繞一整圈,共計算 20 個位置
r = vector( # 算出要計算 磁場 的位置
R * 1.25 * cos(phi), # 在電線半徑 1.25 倍的地方(電線外面不遠處)
R * 1.25 * sin(phi),
z
)
B = vector(0,0,0) # 磁場先設定為 0,後面計算中會積分出來
# 切割電線(做積分)
drp = R / 20 # 沿著圓柱半徑切成多個小段
dphip = 2*pi / 60 # 沿著角度切成多個小角度
dzp = L / 50 # 沿著圓柱軸長切成多個小段
for rp in arange(0,R,drp): # 積分開始 rp 從 0 到 R
for phip in arange(0,2*pi,dphip): # phip 從 0 到 2pi(繞一圈)
for zp in arange(-L/2,L/2,dzp): # zp 從 -L/2 到 L/2
# 每一小塊電線體積為 dV,面有電流 JdV 流過
# 計算這一小塊電線的體積(微積分公式,無限小體積,長 x 寬 x 高)
#dV = drp * (rp*dphip) * dzp
# 計算這一小塊電線的體積(微小但不是無限小體積公式,從上面公式積分得來)
dV = ((rp+drp)**2 - rp**2)/2 * dphip * dzp
r_dV = vector( # 算出這一小塊電線的位置
rp * cos(phip),
rp * sin(phip),
zp
)
delta_r = r - r_dV # 計算從這一小塊電線開始到計算電場位置的向量
# 我們需要這個向量,因為底下要利用比歐-沙伐
# 公式計算一小塊電流產生的磁場,而比歐-沙伐
# 公式裡面的 r 是要從一小塊電流所在位置開始
# (不見得是原點開始)的向量。
# 根據定義,delta_r 要從小塊的中心開始,
# 試著參考前面的作業將小塊的中心計算出來,
# 然後把 delta_r 改成從小塊中心開始
# 利用比歐-沙伐公式計算這一小塊電線產生的微小磁場
dB = mu_0/(4*pi) * dV * J.cross(delta_r) / delta_r.mag**3
# 加總到 B
B += dB
arrow(pos=r,axis=B*1e4,shaftwidth=sw/3) # 畫一個箭頭代表磁場
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">> / <<tw3DCommonPanel "Boost Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Cylindrical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Current Solid Cylinder]] [[JS Codes 等速移動的電荷 -- 粗長直導線的磁場]]>>|
!! 參考文獻
# 維基百科 [[比歐-沙伐定律|https://zh.wikipedia.org/wiki/%E6%AF%95%E5%A5%A5-%E8%90%A8%E4%BC%90%E5%B0%94%E5%AE%9A%E5%BE%8B]]
這個講義中我們將要練習''電磁學裡【還算簡單】情況''的一種:@@color:red;在一條細長直導線裡面等速移動的電荷(穩定電流),@@在其周圍產生的【''磁場(magnetic field)''],具體做法是
# 將細長直導線切成很多很多,很小很小的線段,
# 每一個小線段套用【''比歐-沙伐定律''】計算磁場,\[d\vec B(\vec r) = {\mu_0 I \over 4\pi} {\color{blue} \bf{d\vec l'} \over \color{blue}\Delta r^2} \color{blue} \times \hat { \Delta r}\]
# 將每一個小線段的磁場(向量)加起來 \[\Large{\vec B(\vec r) = \int_\text{整條導線} d\vec B(\vec r) = \int_\text{整條導線} {\mu_0 I \over 4\pi} {\color{blue} \bf{d\vec l'} \over \color{blue}\Delta r^2} \color{blue} \times \hat { \Delta r},}\]
其中
* \(\vec B\) 就是我們要計算的磁場;
* \(\Large\vec r\) 是要計算磁場的位置(以電流中心點當原點);
* \(I\) 是電流的大小;
* \(\large \color{blue} \bf {d\vec l'}\) 為【@@color:blue;''一小段電線''@@】的長度向量,這個向量的大小就是小段電線的長度,方向就是電電流在這個小段的流動方向;
* \(\large \Delta \vec r\) 是從@@color:red;現在計算的那一小段電線@@開始到@@color:blue;計算磁場的地方@@的向量
<<<
* 注意 \(\large\Delta \vec r\) 【@@color:red;''不是''@@】從原點開始的向量,而是從【@@color:red;現在計算的那一小段電線@@】開始的。
<<<
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義電線的半徑及長度(可隨意調整)
R = 0.005 # 電線半徑
L = 2 # 電線長度
# 畫出一條細圓柱代表一條細直電線
wire = cylinder(pos=vector(0,0,-L/2), radius=R, axis=vector(0,0,L), opacity=0.5)
# 畫出一個箭頭代表電流方向
sw = R
arrI = arrow(axis=vector(0,0,L/5), shaftwidth=sw) # 箭頭長度是電線的 1/5
arrI.pos = arrI.pos - arrI.axis/2 # 把箭頭移到畫面中央
arrI.pos.y += R*20 # 箭頭稍微離開電線一些
text( # 箭頭的中央放一個文字
text = 'I', # 文字內容
pos = arrI.pos+arrI.axis/2, # 文字位置
height = R*10, # 文字高度
font = 'serif' # 設定字型
)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 電流大小
I = 1 # 安培
# 真空磁導率(或導磁率,SI 單位制)
mu_0 = 4 * pi * 1e-7 # N / A^2
//}}}
! 細步計算
//{{{
for z in arange(-L/4,L/4,L/20): # z 從 -L/4 到 L/4,共計算 20 個位置
for phi in arange(0,2*pi,2*pi/20): # 方位角繞一整圈,共計算 20 個位置
r = vector( # 算出要計算 磁場 的位置
R * 10 * cos(phi), # 在電線半徑 10 倍遠的地方(不算很遠,因為電線很細)
R * 10 * sin(phi),
z
)
B = vector(0,0,0) # 磁場先設定為 0,後面計算中會積分出來
# 切割電線(做積分)
dzp = L / 50 # 沿著電線切成多個小段
for zp in arange(-L/2,L/2,dzp): # 積分開始,zp 從 -L/2 到 L/2
# 每一小段電線長度為 dl,在這個程式裡面也就是 dzp,裡面有電流 I 流過
# 產生這一小段電線的向量
dl = vector(0,0,dzp)
r_dl = vector( # 算出這一小段電線的位置
0,
0,
zp
)
delta_r = r - r_dl # 計算從這一小段電線開始到計算電場位置的向量
# 我們需要這個向量,因為底下要利用比歐-沙伐
# 公式計算一小段電流產生的磁場,而比歐-沙伐
# 公式裡面的 r 是要從一小段電流所在位置開始
# (不見得是原點開始)的向量。
# 利用比歐-沙伐公式計算這一小段電線產生的微小磁場
dB = mu_0/(4*pi) * I * dl.cross(delta_r) / delta_r.mag**3
# 加總到 B
B += dB
arrow(pos=r,axis=B*1e4,shaftwidth=sw/3) # 畫一個箭頭代表磁場
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Cylindrical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Current Wire]] [[JS Codes 等速移動的電荷 -- 細長直導線的磁場]]>>|
!! 參考文獻
# 維基百科 [[比歐-沙伐定律|https://zh.wikipedia.org/wiki/%E6%AF%95%E5%A5%A5-%E8%90%A8%E4%BC%90%E5%B0%94%E5%AE%9A%E5%BE%8B]]
這個講義中我們將要練習''電磁學裡【也還算簡單】情況''的一種:@@color:red;在一條【繞圈】細導線裡面等速移動的電荷(穩定電流),@@在其周圍產生的【''磁場(magnetic field)''],具體的做法為跟 [[等速移動的電荷 -- 細長直導線的磁場]] 是一樣的:\[\vec B(\vec r) = \int_\text{整條導線} d\vec B(\vec r)\] 只是現在''把直線彎曲成繞一圈'',對導線的積分仍舊是【切成很多的小線段】,只是這些小線段都是【''圓弧上的一小段''】,具體的做法是:
# 將繞圈細直導線切成很多很多的''小段圓弧'',
# 每一個小段套用【''比歐-沙伐定律''】計算磁場,
# 將每一個小段的磁場(向量)加起來 \[\Large{\vec B(\vec r) = \int_\text{整個圓周} {\mu_0 \over 4\pi} {\color{blue} \bf{Id\vec l' \times \hat { \Delta r}} \over \color{blue}\Delta r^2},= {\mu_0 I\over 4\pi} \int_0^{2\pi} {\color{blue} \bf{Rd\phi} \over \color{blue}\Delta r^2} \color{blue}{\hat\phi \times \hat{\Delta r}},}\]
其中
* \(\vec B\) 就是我們要計算的磁場;
* \(\Large\vec r\) 是要計算磁場的位置(以線圈中心點為原點);
* \(I\) 是''電流大小'';
* \(R\) 是線圈的半徑;
* \(\large \color{blue} \bf{dl' = Rd\phi}\) 為@@color:blue;''一小段圓弧的【長度】''@@;
* \(\large \color{blue} \bf{\hat\phi}\) 是@@color:blue;''一小段圓弧的【方向】''@@;
* \(\large \Delta \vec r\) 是從@@color:red;現在計算的那一小段圓弧電線@@開始到@@color:blue;計算磁場的地方@@的向量
<<<
* 注意 \(\large\Delta \vec r\) 【@@color:red;''不是''@@】從原點開始的向量,而是從【@@color:red;現在計算的那一小段圓弧電線@@】開始的。
<<<
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義一個圓形線圈
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 電流大小
I = 1 # 安培
# 真空磁導率(或導磁率,SI 單位制)
mu_0 = 4 * pi * 1e-7 # N / A^2
//}}}
! 細步計算
//{{{
# 計算磁場位置的迴圈,可能需要不只一個
r = vector( # 算出要計算 磁場 的位置
?, # x-分量
?, # y-分量
? # z-分量
)
B = vector(0,0,0) # 磁場先設定為 0,後面計算中會積分出來
# 切割磁鐵(做積分)
# 積分迴圈,細導線只需要一個迴圈,粗導線就需要三個
r_dl = vector( # 算出這一小段電線的【位置】
?, # x-分量
?, # y-分量
? # z-分量
)
dl = ? # 算出這一小段電線的【方向】
# 自己徒手畫個圖看看,這個方向應該指向何方?
# 想想看,怎麼利用已知的向量來計算出這個向量?
delta_r = r - r_dl # 計算從這一小段電線開始到計算電場位置的向量
# 我們需要這個向量,因為底下要利用比歐-沙伐
# 公式計算一小段電流產生的磁場,而比歐-沙伐
# 公式裡面的 r 是要從一小段電流所在位置開始
# (不見得是原點開始)的向量。
# 利用比歐-沙伐公式計算這一小段電線產生的微小磁場
dB = mu_0/(4*pi) * I * dl.cross(delta_r) / delta_r.mag**3
# 加總到 B
B += dB
arrow(pos=r,axis=B*1e4,shaftwidth=sw/3) # 畫一個箭頭代表磁場
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Cylindrical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Current Loop]] [[JS Codes 等速移動的電荷 -- 繞圈細導線的磁場]]>>|
!! 參考文獻
# 維基百科 [[比歐-沙伐定律|https://zh.wikipedia.org/wiki/%E6%AF%95%E5%A5%A5-%E8%90%A8%E4%BC%90%E5%B0%94%E5%AE%9A%E5%BE%8B]]
這個講義中我們將要練習''靜電學裡【次簡單】情況''的一種:@@color:red;一【群】聚集成【球狀】的電荷,在【靜止時】@@在其周圍產生的【''電場(electric field)''],計算公式主要仍然為【''庫倫定律''】,只是因為有【一群】電荷聚在一起,我們要用積分來計算\[\Large{\vec E(\vec r) = \int {1 \over 4\pi\epsilon} {\color{blue}{\bf{dq} \over \color{blue}\Delta r^2}} \hat{\Delta r}}\] 其中
* \(\vec E\) 就是我們要計算的電場;
* \(\Large\vec r\) 是要計算電場的位置(以球狀電荷之中心當原點);
* \(\large \color{blue} \bf {dq}\) 為【@@color:blue;''一小塊體積''@@】裡面所帶的電量(可正可負);
* \(\large \Delta \vec r\) 是從@@color:red;現在計算的那一個小塊@@開始到@@color:blue;計算電場的地方@@的向量
<<<
* 注意 \(\large\Delta \vec r\) 【@@color:red;''不是''@@】從原點開始的向量,而是從【@@color:red;現在計算的那一個小塊@@】開始的。
* 因為庫倫定律 \[\vec E = {1 \over 4\pi\epsilon_0}{q \over r^2}\hat r\] 裡面的 \(\large\vec r\) 是從【點電荷】所在地開始的向量,而在這裡的計算中
## 我們把【現在計算的那一個小塊】當做一個點電荷來套用庫倫定律,所以
## \(\large \Delta \vec r\) 是從【現在計算的那一個小塊】開始的向量。
<<<
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義球的半徑(可隨意調整)
R = 5
# 畫出一顆不太小的球代表一群聚成球狀的電荷分布
charge = sphere(radius=R, opacity=0.5)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/10
xaxis = arrow(axis=vector(1,0,0)*R*5, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*5, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*5, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 點電荷所帶的電荷,假設為 1e23 個質子的電荷
charge.q = 1.6e-19 * 1e23 # 庫倫
# 計算聚成球狀的電荷密度
charge.density = charge.q / (4/3)*pi*charge.radius**3
# 真空介電常數(SI 單位制)
epsilon = 8.854187817e-12
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
for theta in arange(0,180,180/20): # 天頂角從北極到南極,分成 20 步完成
theta = theta*pi/180 # 換成弧度
for phi in arange(0,360,360/40): # 方位角繞一整圈,分成 40 步完成
phi = phi*pi/180 # 換成弧度
r = R * 3 * vector( # 算出要計算電場的位置
sin(theta)*cos(phi), # x-分量
sin(theta)*sin(phi), # y-分量
cos(theta) # z-分量
)
# 對聚成球狀的一群電荷積分來計算電場
drp = charge.radius/50 # 將球的半徑分成許多小步計算,計算每一步的大小
dthetap = pi/30 # 將天頂角 thetap 分成許多小步計算,計算每一步的大小
dphip = pi*2/60 # 將方位角 phip 分成許多小步計算,計算每一步的大小
E = vector(0,0,0) # 電場先設定為 0,後面計算中會積分出來
for rp in arange(0,charge.radius,drp): # 積分開始,半徑從 0 到 charge.radius
for thetap in arange(0,pi,dthetap): # 天頂角從 0 到 pi(北極到南極)
for phip in arange(0,2*pi,dphip): # 方位角從 0 到 2*pi(繞一整圈)
# 每一小步對應一小塊的體積,裡面有電荷
r_dV = rp * vector( # 算出這一個小塊的位置
sin(thetap)*cos(phip),
sin(thetap)*sin(phip),
cos(thetap)
)
delta_r = r - r_dV # 計算從這一小塊開始到計算電場位置的向量
# 我們需要這個向量,因為底下要把這一小塊
# 當作點電荷,然後使用點電荷公式來計算電
# 場,而點電荷公式裡面的 r 是要從電荷所
# 在位置開始(不見得是原點開始)的向量。
# 算出這一小塊的體積(微積分公式,無限小體積,長 x 寬 x 高)
dV = drp * (rp*dthetap) * (rp*sin(thetap)* dphip)
# 算出這一小塊裡面所含的電荷
dq = charge.density * dV
# 把這一小塊當成一個點電荷,套用點電荷公式計算小塊產生的微小電場
dE = 1/(4*pi*epsilon) * dq / delta_r.mag2 * delta_r.norm()
# 加總到 E
E += dE
arrow(pos=r,axis=E*3e-12,shaftwidth=sw/3) # 畫一個箭頭代表電場,乘上一個比例讓箭頭看起來大小合適
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Solid Sphere]] [[JS Codes 群聚成球狀的靜止電荷之電場分布]]>>|
這個講義中我們將要觀察一群電荷產生的''電位勢'' \[\large{V(\vec r) = \int {1 \over 4\pi\epsilon} {\color{blue}{\bf{dq} \over \Delta r}}}\] 以及''靜電場'' \[\large{\vec E(\vec r) = \int {1 \over 4\pi\epsilon} \color{blue} { {\bf{dq} \over \Delta r^2}\ \hat \Delta r}}\] 隨距離變化的關係,並了解在一群電荷【裡面】和【外面】的差異。@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義球的半徑(可隨意調整)
R = 5
# 畫出一顆不太小的球代表一群聚成球狀的電荷分布
charge = sphere(radius=R, opacity=0.5)
# 畫一個箭頭代表 x 軸,並加上一個文字 X
# 箭頭長度可在 axis=某個向量 隨意調整
# 箭頭寬度可在 shaftwidth=某個數值 任意調整,自己調整看看,找出喜歡的比例
sw = R/10
xaxis = arrow(axis=vector(1,0,0)*R*5, color=color.red, shaftwidth=sw)
text(text="X", pos=xaxis.axis, color=xaxis.color, height=R)
# 畫一個箭頭代表 y 軸,並加上一個文字 Y
yaxis = arrow(axis=vector(0,1,0)*R*5, color=color.green, shaftwidth=sw)
text(text="Y", pos=yaxis.axis, color=yaxis.color, height=R)
# 畫一個箭頭代表 z 軸,並加上一個文字 Z
zaxis = arrow(axis=vector(0,0,1)*R*5, color=color.cyan, shaftwidth=sw)
text(text="Z", pos=zaxis.axis, color=zaxis.color, height=R)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 點電荷所帶的電荷,假設為 1e23 個質子的電荷
charge.q = 1.6e-19 * 1e23 # 庫倫
# 計算聚成球狀的電荷密度
charge.density = charge.q / (4/3*pi*charge.radius**3)
# 真空介電常數(SI 單位制)
epsilon = 8.854187817e-12
# 產生一個新畫布,用來畫 V_r 圖,取名為 V_r_g
V_r_g = graph(
title = 'Electric Potential vs Distance', # 畫布標題
xtitle = '<em>r</em> (m)', # x-軸標題
ytitle = '<em>V</em> (volt)' # y-軸標題
)
# 產生一個空的【曲線圖】,取名為 V_r(因為要畫 V vs r 的曲線圖)
V_r = gcurve(
graph = V_r_g, # 指定畫布為 V_r_g
color = color.blue
)
# 產生一個新畫布,用來畫 E_r 圖,取名為 E_r_g
E_r_g = graph(
title = 'Electric Field Strength vs Distance', # 畫布標題
xtitle = '<em>r</em> (m)', # x-軸標題
ytitle = '<em>E</em> (volt / m)' # y-軸標題
)
# 產生一個空的【曲線圖】,取名為 E_r(因為要畫 E vs r 的曲線圖)
E_r = gcurve(
graph = E_r_g, # 指定畫布為 E_r_g
color = color.red
)
//}}}
! 細步計算
//{{{
'''
---------------------------------------------------------------------------------------------------------
細步計算
---------------------------------------------------------------------------------------------------------
'''
theta = pi/2 # 計算電位勢/電場的位置之天頂角
phi = 0 # 計算電位勢/電場的位置之方位角
dphi = pi/30 # 每次計算改變方位角多少
for rf in arange(R*3/100,R*3,R/100): # 距離從接近 0 到 3 倍半徑,以半徑的 1/100 為步幅
# 第一個計算點【不要】太靠近 0,可能會算出一個很大的電場
# 造成圖形無法顯示出結果
r = rf * vector( # 算出要計算電位勢/電場的位置
sin(theta)*cos(phi), # x-分量
sin(theta)*sin(phi), # y-分量
cos(theta) # z-分量
)
phi += dphi # 下次計算位置的方位角
# 對聚成球狀的一群電荷積分來計算電場
drp = R/30 # 將球的半徑分成許多小步計算,計算每一步的大小
dthetap = pi/30 # 將天頂角 thetap 分成許多小步計算,計算每一步的大小
dphip = pi/30 # 將方位角 phip 分成許多小步計算,計算每一步的大小
V = 0 # 電位勢先設定為 0,後面計算中會積分出來
E = vector(0,0,0) # 電場先設定為 0,後面計算中會積分出來
for rp in arange(0,charge.radius,drp): # 積分開始,半徑從 0 到 charge.radius
for thetap in arange(0,pi,dthetap): # 天頂角從 0 到 pi(北極到南極)
for phip in arange(0,2*pi,dphip): # 方位角從 0 到 2*pi(繞一整圈)
# 每一小步對應一小塊的體積,裡面有電荷
r_dV = rp * vector( # 算出這一個小塊的位置
sin(thetap)*cos(phip),
sin(thetap)*sin(phip),
cos(thetap)
)
delta_r = r - r_dV # 計算從這一小塊開始到計算電場位置的向量
# 我們需要這個向量,因為底下要把這一小塊
# 當作點電荷,然後使用點電荷公式來計算電
# 場,而點電荷公式裡面的 r 是要從電荷所
# 在位置開始(不見得是原點開始)的向量。
if delta_r.mag < drp : # 計算電位勢/電場的位置如果正好在這一
continue # 小塊的裡面,不要算,跳過
# 算出這一小塊的體積(微積分公式,無窮小體積,長 x 寬 x 高)
#dV = rp * (rp*dthetap) * (rp*sin(thetap)*dphip)
# 算出這一小塊的體積(微小但不是無限小體積公式,從上面公式積分得來)
dV = ((rp+drp)**3-rp**3)/3 * (cos(thetap)-cos(thetap+dthetap)) * dphip
# 算出這一小塊裡面所含的電荷
dq = charge.density * dV
# 把這一小塊當成一個點電荷,套用點電荷公式計算小塊產生的微小電位勢
dV = 1/(4*pi*epsilon)*dq/delta_r.mag
# 加總到 V
V += dV
# 把這一小塊當成一個點電荷,套用點電荷公式計算小塊產生的微小電場
dE = 1/(4*pi*epsilon)*dq/delta_r.mag2*delta_r.norm()
# 加總到 E
E += dE
V_r.plot(rf,V) # 在 V-r 圖上畫一個點
E_r.plot(rf,E.mag) # 在 E-r 圖上畫一個點
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Spherical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Charge Solid Sphere]] [[JS Codes 群聚成球狀的靜止電荷的電場強度及電位勢與距離之關係]]>>|
https://en.wikipedia.org/wiki/IEEE_754
{{MOSTTitle{
路徑積分 -- 以安培定律為例
}}}
> 這個講義的說明影片:[[路徑積分說明影片|https://drive.google.com/file/d/10_lSVvg5ihl8PLtOOXHb7LHE0uPzgShW/view?usp=sharing]]
{{MOSTSection{
!! 路徑積分是什麼?
}}}
{{MOSTParagraph{
{{FrameHalfRight{
<<tw3DScene [[JS Codes 路徑積分-基本概念]]>>圖一:路徑積分的基本概念。動畫中的''自選路徑為圓形(半徑為 $R$),自定的方向為逆時針方向'',將路徑切成很多小段,每一小段用一個@@background-color:cyan;向量 \(d\vec l\) (青色)@@來代表。
由於我們選擇的路徑是圓形,所以每一小段都是一段圓弧,而圓弧長度是【圓半徑 × 圓弧張角】,所以''每一小段長度 $dl = R d\phi$。''
每一小段 \(d\vec l\) 的方向就是該小段所在位置''圓弧的切線方向'',這個方向''在圓柱座標系下就是【\(\hat \phi\) 軸】的方向。從上圖中應該不難看出 \(\bf{\hat \phi}\) 可以用 \(\bf{\hat z}\) 和 \(\bf{\hat \rho}\) 的外積算出來。''
@@background-color:yellow;向量函數(黃色)@@,在物理學裡面可能是電場、磁場,或者是重力場等【可以用向量】來描述的物理量。通常物理上的向量函數會有一些規律,不會亂七八糟,動畫中的@@background-color:yellow;向量函數@@看起來很亂,只是想表達【這可以是任何向量函數】的意思。}}} 所謂路徑積分,就是【沿著一條自選的路徑,方向自定,計算一個向量函數沿著路徑的投影,累加起來】這樣的計算,用數學式子來寫的話,就是 \[\int_\text{自選路徑} \vec f(\vec r) \cdot d\vec l,\] 其中 \(\vec f(\vec r)\) 就是那個向量函數,\(d\vec l\) 就是【代表一小段路徑的向量】。
> @@在計算安培定律的時候,磁場 \(\vec B(\vec r)\) 就是那個向量函數。@@
}}}
{{MOSTSubSection{
!!! 路徑積分的步驟
}}}
{{MOSTSubParagraph{
根據前面所述,路徑積分的步驟可細分為:
# 選擇一個路徑;
# 選定一個沿路徑前進的方向;
# 將路徑切割成很多小段,每一個小段用一個向量 \(d\vec l\) 來代表,這個向量【長度要等於小段路徑長】,【方向要沿著前進方向】;
# 每一個小段計算 \(\vec f(\vec r) \cdot d\vec l\),並把所有小段的結果加起來。
}}}
{{MOSTSubSection{
!!! 以安培定律為例
}}}
{{MOSTSubParagraph{
我們用安培定律來說明如何做這個路徑積分。安培定律用白話來講的話是
> 磁場的封閉路徑積分結果 等於 常數 \(\mu_0\) 乘上【被封閉路徑圍起來的電流】
寫成數學式子的話是 \[\oint \vec B(\vec r) \cdot d\vec l = \mu_0 I_\text{enc},\] 其中 \(\oint\) 的意思是【封閉路徑積分】,常數 \(\mu_0 \sim 1.2566370614...×10^{-6}\text{ H}\cdot\text{m}^{-1}\) 是【[[真空中的磁導率|https://zh.wikipedia.org/wiki/%E7%9C%9F%E7%A9%BA%E7%A3%81%E5%AF%BC%E7%8E%87]]】,\(I_\text{enc}\) 是【被封閉路徑圍起來的電流】。
}}}
{{MOSTSubParagraph{
我們來按照上面的四個步驟逐一加以說明。
# 選擇一個路徑
** 安培定律要【封閉路徑】,我們就要找一個封閉路徑來算。在【只有一條直電線】這種簡單的情況下,電線產生的磁場是【繞著電線轉圈】的,所以我們的封閉路徑也要【繞電線一圈】。
** 路徑積分的形狀可以隨意,但是我們通常要選【最簡單】或是【最好算】的形狀。
** 繞電線一圈最簡單的形狀應該是【圓形】,所以我們選擇一個【''繞電線一圈半徑為 \(R\) 的圓形''】做為計算安培定律的封閉路徑。
# 選定一個沿路徑前進的方向
** 對於一個圓形路徑我們可以【順時針】或是【逆時針】方向來做路徑積分。
** 因為數學上我們定義【逆時針】方向的角度為正,所以如果沒有特別需求,''通常我們會從 \(x\)-軸開始,沿著逆時針方向做路徑積分''。
# 將路徑切割成很多小段,每一個小段用一個向量 \(d\vec l\) 來代表,這個向量【長度要等於小段路徑長】,【方向要沿著前進方向】
** 圓形路徑的切割只需要【切割角度】即可,如果我們用圓柱座標,這個角度就是 \(\phi\),從 \(0\) 開始到 \(2\pi\) 結束。
** 假設將圓形路徑切割成 \(N\) 段圓弧,則''每一小段圓弧的張角為 \(d\phi = 2\pi / N\),長度為 \(\bf{dl = Rd\phi}\)''。
*** 至於要切割多少段,就看計算結果夠不夠準以及電腦夠不夠快,
*** 通常還在測試程式碼階段的時候不要切太細,等到確定程式碼正確之後,就可以切很細讓電腦去跑久一點以得到更準確的結果。
** 每一小段的前進方向,就是該段圓弧的切線方向,也就是''圓柱座標的 \(\bf{\hat \phi}\)-軸方向''。
** [[圓柱座標系]]的 ''\(\bf{\hat\phi}\)-軸方向可以依照下列方式計算出來'':
*** 算出現在這個小段的位置 \(\vec r_{dl} = (R\cos\phi, R\sin\phi, 0)\),以及它的單位向量 \(\hat \rho = \vec r_{dl} / r_{dl}\);
*** 將兩個單位向量 \(\hat z\) 和 \(\hat \rho\) 做 外積就可以算出 \(\hat \phi\) 這個單位向量。
**** 至於應該是 \(\hat z \times \hat \rho\) 還是 \(\hat \rho \times \hat z\),應該可以自己從上面圖一裡面看出來。
# 每一個小段計算 \(\vec f(\vec r) \cdot d\vec l\),並把所有小段的結果加起來
** 在安培定律的計算中,這個向量函數 \(\vec f(\vec r)\) 就是磁場 \(\vec B(\vec r)\),磁場要另外積分計算出來。
*** 這裡我們專注在路徑積分,就不細談磁場的積分。
** 把所有小段都算完,結果全部加起來,就是【磁場路徑積分】的結果。
}}}
這個講義中我們將沿著和導線垂直方向,計算一根粗長直導線所產生的磁場 \[\large{\vec B(\vec r) = \int {\mu_0 \over 4\pi} d\tau'{\color{blue} \bf{\vec j \times \hat { \Delta r}} \over \color{blue}\Delta r^2}}\] 的''強度和 \(\vec r\) 到導線的@@垂直距離@@ \(\rho\) 之間的關係, 以及在導線的【@@內部@@】和【@@外部@@】有什麼不同。''
@@color:red;font-size:1.5em;底下的標題列按一下可以顯示隱藏內容@@
! 建立場景
//{{{
GlowScript 2.9 VPython
# 使用 GlowScript 的話,上面這行會自動產生在第一行,不能刪除喔!
'''
---------------------------------------------------------------------------------------------------------
設計場景
---------------------------------------------------------------------------------------------------------
'''
# 定義電線的半徑及長度(可隨意調整)
R = 0.05 # 電線半徑
L = 2 # 電線長度
# 畫出一條細圓柱代表一條細直電線
wire = cylinder(pos=vector(0,0,-L/2), radius=R, axis=vector(0,0,L), opacity=0.5)
# 畫出一個箭頭代表電流方向
sw = R/10
arrI = arrow(axis=vector(0,0,L/5), shaftwidth=sw) # 箭頭長度是電線的 1/5
arrI.pos = arrI.pos - arrI.axis/2 # 把箭頭移到畫面中央
arrI.pos.y += R*1.5 # 箭頭稍微離開電線一些
text( # 箭頭的中央放一個文字
text = 'I', # 文字內容
pos = arrI.pos+arrI.axis/2, # 文字位置
height = R, # 文字高度
font = 'serif' # 設定字型
)
//}}}
! 初始條件
//{{{
'''
---------------------------------------------------------------------------------------------------------
初始條件
---------------------------------------------------------------------------------------------------------
'''
# 電流大小
I = 50 # 安培
# 電流密度(單位面積的電流)
J = wire.axis.norm() * I / (pi * R**2)
# 真空磁導率(或導磁率,SI 單位制)
mu_0 = 4 * pi * 1e-7 # N / A^2
# 產生一個新畫布,用來畫 B_r 圖,取名為 B_r_g
B_r_g = graph(
title = 'Magnetic Field Strength vs Distance', # 畫布標題
xtitle = '<em>r</em> (m)', # x-軸標題
ytitle = '<em>B</em> (T)' # y-軸標題
)
# 產生一個空的【曲線圖】,取名為 B_r(因為要畫 B vs r 的曲線圖)
B_r = gcurve(
graph = B_r_g, # 指定畫布為 B_r_g
color = color.blue
)
//}}}
! 細步計算
//{{{
for d in arange(0,2*R,2*R/200): # 距離 d 從 0 到 2R,共計算 200 個位置
r = vector( # 算出要計算 磁場 的位置
d, # 沿著 x-軸(垂直於導線長軸的方向)
0,
0
)
B = vector(0,0,0) # 磁場先設定為 0,後面計算中會積分出來
# 切割電線(做積分)
drp = R / 20 # 沿著圓柱半徑切成多個小段
dphip = 2*pi / 60 # 沿著角度切成多個小角度
dzp = L / 80 # 沿著圓柱軸長切成多個小段
for rp in arange(0,R,drp): # 積分開始 rp 從 0 到 R
for phip in arange(0,2*pi,dphip): # phip 從 0 到 2pi(繞一圈)
for zp in arange(-L/2,L/2,dzp): # zp 從 -L/2 到 L/2
# 每一小塊電線體積為 dV,面有電流 JdV 流過
# 計算這一小塊電線的體積(微積分公式,無限小體積,長 x 寬 x 高)
#dV = drp * (rp*dphip) * dzp
# 計算這一小塊電線的體積(微小但不是無限小體積公式,從上面公式積分得來)
dV = ((rp+drp)**2 - rp**2)/2 * dphip * dzp
r_dV = vector( # 算出這一小塊電線的位置
rp * cos(phip),
rp * sin(phip),
zp
)
delta_r = r - r_dV # 計算從這一小塊電線開始到計算電場位置的向量
# 我們需要這個向量,因為底下要利用比歐-沙伐
# 公式計算一小塊電流產生的磁場,而比歐-沙伐
# 公式裡面的 r 是要從一小塊電流所在位置開始
# (不見得是原點開始)的向量。
# 避開包含計算磁場位置的小塊
# 參考前面的作業將此段程式碼寫出
# (注意現在是圓柱座標不是球座標)
# 根據定義,delta_r 要從【小塊的中心點】開始
# 參考前面的作業將程式碼寫出
# 利用比歐-沙伐公式計算這一小塊電線產生的微小磁場
dB = mu_0/(4*pi) * dV * J.cross(delta_r) / delta_r.mag**3
# 加總到 B
B += dB
B_r.plot(d,B.mag) # 在 B_r 曲線圖上畫一個點
rate(100) # 更新畫面,裡面的數字是【希望】電腦可以每秒更新
# 這麼多次,電腦夠快就做得到,不夠快也不會出錯
# 調整這個數字可以調整動畫的速度
//}}}
<<foldHeadings>>
|noborder|k
|width:45%;<<tw3DCommonPanel "Flow Control">>|width:45%;<<tw3DCommonPanel "Label Statistics">>|
|<<tw3DCommonPanel "Simulation Time Control">>|<<tw3DCommonPanel "Cartesian System Control">>|
|<<tw3DCommonPanel "Frame Control">> / <<tw3DCommonPanel "View Control">>|<<tw3DCommonPanel "Cylindrical System Control">> / [ =chkShowIntegration] Show Integration|
|<<tw3DCommonPanel "Plot0 Control">> / <<tw3DCommonPanel "DAQ Control">> / <<tw3DCommonPanel "Gravity Control">><br><<twDataPlot id:dataPlot0>>|<<tw3DCommonPanel "Plot1 Control">> / <<tw3DCommonPanel "Message">><br><<twDataPlot id:dataPlot1>>|
|>|<<tw3DScene [[Current Solid Cylinder]] [[JS Codes 長直導線的磁場隨距離的關係]]>>|