-
Notifications
You must be signed in to change notification settings - Fork 0
/
local-search.xml
648 lines (311 loc) · 380 KB
/
local-search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>numpy积累</title>
<link href="/2024/01/19/numpy/"/>
<url>/2024/01/19/numpy/</url>
<content type="html"><![CDATA[<p>这篇文章主要解决的问题是,Numpy 提供了许多线性代数的工具,但是我因为线性代数学的不好,因此总是不会用。</p><span id="more"></span><h1 id="基本公式-of-linalg"><a href="#基本公式-of-linalg" class="headerlink" title="基本公式 of linalg"></a>基本公式 of linalg</h1><h2 id="numpy-linalg-svd"><a href="#numpy-linalg-svd" class="headerlink" title="numpy.linalg.svd"></a>numpy.linalg.svd</h2><p>函数定义:</p><figure class="highlight python"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><pre><code class="hljs python">linalg.svd(a, full_matrices=<span class="hljs-literal">True</span>, compute_uv=<span class="hljs-literal">True</span>, hermitian=<span class="hljs-literal">False</span>)<br></code></pre></td></tr></table></figure><p>Singular Value Decomposition.</p><p>When _a_ is a 2D array, and <code>full_matrices=False</code>, then it is factorized as <code>u @ np.diag(s) @ vh = (u * s) @ vh</code>, where _u_ and the Hermitian transpose of _vh_ are 2D arrays with orthonormal columns and _s_ is a 1D array of _a_’s singular values. When _a_ is higher-dimensional, SVD is applied in stacked mode as explained below.</p><p><a href="https://numpy.org/doc/stable/reference/generated/numpy.linalg.svd.html">numpy.linalg.svd — NumPy v1.24 Manual</a></p><p>SVD 的作用是将 2D 矩阵进行分解。对于高维的矩阵,之后再研究。矩阵 $A$,可以写成 SVD 分解形式:$A=USV^H$,其中 $A=a,U=u,S=np.diag(s), V^H=vh$,其中 $s$ 是矩阵 $A$ 的所有奇异值 $\sigma_i$,有 $\sigma_i=\sqrt{\lambda_i}$,$vh$ 的行是 $A^HA$ 的特征向量,$u$ 的列是 $AA^H$ 的特征向量,而且 $u,vh$ 都是酉矩阵,转置相乘为单位矩阵。这里的上标的意思是转置。</p><p><a href="https://zhuanlan.zhihu.com/p/135396870">特征值分解,奇异值分解(SVD) - 知乎</a></p><p>注意得到的特征向量都不一定是 $A$ 的。因此 DLT 算法中:</p><p><a href="https://imgse.com/i/pFDLehR"><img src="https://s21.ax1x.com/2024/03/05/pFDLehR.png" alt="pFDLehR.png"></a></p><p>我们想求的是 $A^\top A$ 的特征向量,然后就有 $h^\top A^\top Ah=\sigma_i h^\top h=\sigma_i |h|^2 = \sigma_i$,也就是说要使得特征值最小,那不就取最小特征值的特征向量,也就是 $vh[-1]$。</p><p>如果 <code>full_matrices=True</code>,则三个返回值的维度为 <code>mxm, min(m,n), nxn</code>,这时候想要重建原本的矩阵,需要将中间的矩阵还原:</p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs python">u, s, vh = np.linalg.svd(a, full_matrices=<span class="hljs-literal">True</span>)<br>u.shape, s.shape, vh.shape <span class="hljs-comment"># ((9, 9), (6,), (6, 6))</span><br>np.allclose(a, np.dot(u[:, :<span class="hljs-number">6</span>] * s, vh)) <span class="hljs-comment"># True</span><br>smat = np.zeros((<span class="hljs-number">9</span>, <span class="hljs-number">6</span>), dtype=<span class="hljs-built_in">complex</span>)<br>smat[:<span class="hljs-number">6</span>, :<span class="hljs-number">6</span>] = np.diag(s)<br>np.allclose(a, np.dot(u, np.dot(smat, vh)))<span class="hljs-comment"># True</span><br></code></pre></td></tr></table></figure><p>如果使用 <code>full_matrices=False</code>,则可以直接相乘。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs python">u, s, vh = np.linalg.svd(a, full_matrices=<span class="hljs-literal">False</span>)<br>u.shape, s.shape, vh.shape <span class="hljs-comment"># ((9, 6), (6,), (6, 6))</span><br>np.allclose(a, np.dot(u * s, vh)) <span class="hljs-comment"># True</span><br>smat = np.diag(s)<br>np.allclose(a, np.dot(u, np.dot(smat, vh))) <span class="hljs-comment"># True</span><br></code></pre></td></tr></table></figure></p><h2 id="numpy-linalg-pinv"><a href="#numpy-linalg-pinv" class="headerlink" title="numpy.linalg.pinv"></a>numpy.linalg.pinv</h2><p><a href="https://numpy.org/doc/stable/reference/generated/numpy.linalg.pinv.html">numpy.linalg.pinv — NumPy v1.24 Manual</a><br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">linalg.pinv(a, rcond=<span class="hljs-number">1e-15</span>, hermitian=<span class="hljs-literal">False</span>)<br></code></pre></td></tr></table></figure><br>计算矩阵的伪逆。伪逆是一个没有学过的概念,参考 <a href="https://en.wikipedia.org/wiki/Moore%E2%80%93Penrose_inverse">Moore–Penrose inverse - Wikipedia</a>。只需要记住最简单的定义:</p><p>对于一个有解的方程 $Ax=b$,伪逆可以给出一个矩阵 $A^+$,使得一个解 $\bar{x}=A^+b$ 成立。<br>事实上,如果对 $A$ 进行分解,$A=Q_1\Sigma Q_2^\top$,可以认为 $A^+=Q_2\Sigma^+Q_1^\top$,其中 $\Sigma^+$ 是 $\Sigma$ 的各特征值的倒数。</p><p>因此,可以用这个函数进行问题的求解,比如 Photometric Stereo 问题:</p><p><a href="https://imgse.com/i/pFDLn91"><img src="https://s21.ax1x.com/2024/03/05/pFDLn91.png" alt="pFDLn91.png"></a></p><p>求解出来 $\tilde{n}$ 即可。</p><h2 id="numpy-linalg-norm"><a href="#numpy-linalg-norm" class="headerlink" title="numpy.linalg.norm"></a>numpy.linalg.norm</h2><p><a href="https://numpy.org/doc/stable/reference/generated/numpy.linalg.norm.html">numpy.linalg.norm — NumPy v1.24 Manual</a><br>作用是对选中的轴进行归一化,得到范数,返回值是结果。不是原地变化。<br><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs python">linalg.norm(x, <span class="hljs-built_in">ord</span>=<span class="hljs-literal">None</span>, axis=<span class="hljs-literal">None</span>, keepdims=<span class="hljs-literal">False</span>)<br></code></pre></td></tr></table></figure></p><p>如果不选择 axis,则对所有的元素求范数。<br>ord 的作用如下:<br>For values of <code>ord < 1</code>, the result is, strictly speaking, not a mathematical ‘norm’, but it may still be useful for various numerical purposes.<br>The following norms can be calculated:</p><div class="table-container"><table><thead><tr><th style="text-align:center">ord</th><th style="text-align:center">norm for matrices</th><th style="text-align:center">norm for vectors</th></tr></thead><tbody><tr><td style="text-align:center">None</td><td style="text-align:center">Frobenius norm</td><td style="text-align:center">2-norm</td></tr><tr><td style="text-align:center"><code>fro</code></td><td style="text-align:center">Frobenius norm</td><td style="text-align:center">–</td></tr><tr><td style="text-align:center"><code>nuc</code></td><td style="text-align:center">nuclear norm</td><td style="text-align:center">–</td></tr><tr><td style="text-align:center">inf</td><td style="text-align:center">max(sum(abs(x), axis=1))</td><td style="text-align:center">max(abs(x))</td></tr><tr><td style="text-align:center">-inf</td><td style="text-align:center">min(sum(abs(x), axis=1))</td><td style="text-align:center">min(abs(x))</td></tr><tr><td style="text-align:center">0</td><td style="text-align:center">–</td><td style="text-align:center">sum(x != 0)</td></tr><tr><td style="text-align:center">1</td><td style="text-align:center">max(sum(abs(x), axis=0))</td><td style="text-align:center">as below</td></tr><tr><td style="text-align:center">-1</td><td style="text-align:center">min(sum(abs(x), axis=0))</td><td style="text-align:center">as below</td></tr><tr><td style="text-align:center">2</td><td style="text-align:center">2-norm (largest sing. value)</td><td style="text-align:center">as below</td></tr><tr><td style="text-align:center">-2</td><td style="text-align:center">smallest singular value</td><td style="text-align:center">as below</td></tr><tr><td style="text-align:center">other</td><td style="text-align:center">–</td><td style="text-align:center">sum(abs(x)<strong>ord) </strong>(1./ord)</td></tr></tbody></table></div><p>The Frobenius norm is given by:</p><script type="math/tex; mode=display">\newcommand{\d}{\mathrm{d}}\newcommand{\bs}[1]{\boldsymbol{ #1}}||A||_F=[\sum_{i,j}\text{abs}(a_{i,j})^2]^{1/2}</script><p>The nuclear norm is the sum of the singular values.<br>Both the Frobenius and nuclear norm orders are only defined for matrices and raise a ValueError when <code>x.ndim != 2</code>.</p>]]></content>
<categories>
<category>计算机知识</category>
<category>数学</category>
</categories>
<tags>
<tag>编程</tag>
</tags>
</entry>
<entry>
<title>2024已来</title>
<link href="/2024/01/01/update/"/>
<url>/2024/01/01/update/</url>
<content type="html"><![CDATA[<p>新年快乐!</p><span id="more"></span><p>2023有点慵懒了。基本上都在摸鱼和上网冲浪,跟导师进行了科研,学了一些计算机技术。不过似乎除了积累经验也没什么建树。希望2024能有所不同。本科毕业了,继续读研究生。好好学习努力工作。</p>]]></content>
</entry>
<entry>
<title>blender实用技巧和典型案例</title>
<link href="/2023/12/05/blender/"/>
<url>/2023/12/05/blender/</url>
<content type="html"><![CDATA[<p>Blender学习中的记录。不定期更新。</p><span id="more"></span><h1 id="基本建模技巧"><a href="#基本建模技巧" class="headerlink" title="基本建模技巧"></a>基本建模技巧</h1><h2 id="Tips"><a href="#Tips" class="headerlink" title="Tips"></a>Tips</h2><p>大部分的指令不能通过 <code>ESC</code> 退出,即使 ESC 了也会起作用,比如:</p><ul><li>环切的时候,esc 表示在中间环切。</li><li>extrude 的时候,esc 表示创建新边,但是不挤出。这时候进行缩放会发现是原地缩放。</li><li>Shift+C,让 3D 游标回到世界中心。</li><li>ctrl+A,选择应用所有的变换。变换进行了之后,会在变换界面显示出来。如果使用阵列等命令,会在变换之前的基础上进行操作。所以为了防止原形毕露,需要应用变换,使得新的样式变成基本的样式。</li><li>H 隐藏选中的物体。Alt+H 取消全部隐藏。</li><li>F 可以连接选中的 primitives。点和线都可以。</li></ul><h2 id="开口封口"><a href="#开口封口" class="headerlink" title="开口封口"></a>开口封口</h2><p>内容较为简单,直接叙述。<br>在选中需要封口的一个环形的边之后,使用快捷键 <code>F</code> 就可以封口。</p><p><a href="https://imgse.com/i/pFDGbNT"><img src="https://s11.ax1x.com/2024/03/05/pFDGbNT.png" alt="pFDGbNT.png"></a></p><p><a href="https://imgse.com/i/pFDGOCF"><img src="https://s11.ax1x.com/2024/03/05/pFDGOCF.png" alt="pFDGOCF.png"></a></p><p>如果直接按 <code>F</code> 的时候,产生的是黑色的面,证明你选择边的顺序不对,生成了重叠的面。去掉部分的边,然后多次按 <code>F</code> 也能达到最佳的效果。</p><h2 id="快速选中循环边"><a href="#快速选中循环边" class="headerlink" title="快速选中循环边"></a>快速选中循环边</h2><p>使用 <code>Option/Alt + LMB</code> 可以快速选中一条边的循环边。</p><h2 id="平面开圆"><a href="#平面开圆" class="headerlink" title="平面开圆"></a>平面开圆</h2><p>首先通过调整吸附模式,通过拖动 3D 游标让它吸附到你需要的地方的中心点(圆心)。</p><p><a href="https://imgse.com/i/pFDGjgJ"><img src="https://s11.ax1x.com/2024/03/05/pFDGjgJ.png" alt="pFDGjgJ.png"></a></p><p>删掉中间的面。</p><p><a href="https://imgse.com/i/pFDGzuR"><img src="https://s11.ax1x.com/2024/03/05/pFDGzuR.png" alt="pFDGzuR.png"></a></p><p>然后在中间 <code>shift+A</code>,添加一个圆。调整使之符合要求。</p><p><a href="https://imgse.com/i/pFDJpHx"><img src="https://s11.ax1x.com/2024/03/05/pFDJpHx.png" alt="pFDJpHx.png"></a></p><p>选中两条循环边之后,右键合并循环边。注意边是有顺序的,如果顺序不对,会发现中间被填上了。这样是错误的。</p><p><a href="https://imgse.com/i/pFDJPUK"><img src="https://s11.ax1x.com/2024/03/05/pFDJPUK.png" alt="pFDJPUK.png"></a></p><p>然后 extrude 即可。任务完成。</p><h2 id="旋转阵列"><a href="#旋转阵列" class="headerlink" title="旋转阵列"></a>旋转阵列</h2><p>两种方法,第一种是使用编辑模式下的 Spin 工具,在 3D 游标处展开旋转轴。而且可以自动 merge。</p><p><a href="https://imgse.com/i/pFDcmsP"><img src="https://s21.ax1x.com/2024/03/05/pFDcmsP.png" alt="pFDcmsP.png"></a></p><p>第二种办法是使用阵列修改器。好处是可以实时查看。坏处是操作繁琐。<br>在进行阵列修改之前,先在需要的原点处设置一个空物体,然后将空物体设置成阵列修改的依据,对空物体进行操作即可。</p><p><a href="https://imgse.com/i/pFDcnqf"><img src="https://s21.ax1x.com/2024/03/05/pFDcnqf.png" alt="pFDcnqf.png"></a></p><p>两种办法都会出现的问题是,物体的 origin 可能和 3D 游标不是你想象的那样和谐。需要在 Object 模式下,右键重设 Origin。</p><p><a href="https://imgse.com/i/pFDcKZ8"><img src="https://s21.ax1x.com/2024/03/05/pFDcKZ8.png" alt="pFDcKZ8.png"></a></p><h2 id="Shift-S"><a href="#Shift-S" class="headerlink" title="Shift+S"></a>Shift+S</h2><p>Shift+S 可以调出 cursor 的移动面板,方便的选择 Cursor 的位置。特别地,可以让 Cursor 移动到面的中心,不用像之前一样手动划分了。</p><p><a href="https://imgse.com/i/pFDcMdS"><img src="https://s21.ax1x.com/2024/03/05/pFDcMdS.png" alt="pFDcMdS.png"></a></p><h2 id="模拟小键盘"><a href="#模拟小键盘" class="headerlink" title="模拟小键盘"></a>模拟小键盘</h2><p>在没有小键盘的情况下,参考手册 <a href="https://docs.blender.org/manual/en/latest/editors/preferences/input.html">Input — Blender Manual</a> 可以调节出来模拟小键盘的功能。通常不使用。</p><h2 id="间隔选中"><a href="#间隔选中" class="headerlink" title="间隔选中"></a>间隔选中</h2><p>菜单里面,select->checker deselect 可以隔一个取消选中一个。</p><h2 id="合并点到中心"><a href="#合并点到中心" class="headerlink" title="合并点到中心"></a>合并点到中心</h2><p><a href="https://imgse.com/i/pFDc1iQ"><img src="https://s21.ax1x.com/2024/03/05/pFDc1iQ.png" alt="pFDc1iQ.png"></a></p><p>这种情况属于 “ 合并 “,使用快捷键 m 调出合并菜单,合并到中心即可。</p><p><a href="https://imgse.com/i/pFDc3Gj"><img src="https://s21.ax1x.com/2024/03/05/pFDc3Gj.png" alt="pFDc3Gj.png"></a></p><h2 id="平滑着色"><a href="#平滑着色" class="headerlink" title="平滑着色"></a>平滑着色</h2><p>右键可以进行平滑着色。</p><p><a href="https://imgse.com/i/pFDcYMq"><img src="https://s21.ax1x.com/2024/03/05/pFDcYMq.png" alt="pFDcYMq.png"></a></p><p>如果着色不对,说明法向量没有正确的计算,需要在侧变量手动勾选法向的自动平滑。</p><p><a href="https://imgse.com/i/pFDcts0"><img src="https://s21.ax1x.com/2024/03/05/pFDcts0.png" alt="pFDcts0.png"></a></p><h2 id="点的基本操作"><a href="#点的基本操作" class="headerlink" title="点的基本操作"></a>点的基本操作</h2><p><a href="https://www.bilibili.com/video/BV1To4y1G7SV">【5分钟Blender小技巧】-编辑点_哔哩哔哩_bilibili</a><br>这个视频教了很多。</p><h3 id="点的移动"><a href="#点的移动" class="headerlink" title="点的移动"></a>点的移动</h3><p>GG,按照边移动。<br> ctrl+shift+B,能够对点倒角。ctrl+B,只能对边倒角。<br> J 连接两个点。</p><h3 id="横切面"><a href="#横切面" class="headerlink" title="横切面"></a>横切面</h3><p>在一条边上选中若干个点,按 V 可以切开</p><p><a href="https://imgse.com/i/pFDLPXT"><img src="https://s21.ax1x.com/2024/03/05/pFDLPXT.png" alt="pFDLPXT.png"></a></p><p>按 alt+V 可以切开的同时在中间连接面。</p><p><a href="https://imgse.com/i/pFDLFnU"><img src="https://s21.ax1x.com/2024/03/05/pFDLFnU.png" alt="pFDLFnU.png"></a></p><h3 id="点的平滑"><a href="#点的平滑" class="headerlink" title="点的平滑"></a>点的平滑</h3><p>选中多个点,然后右键,选择平滑点</p><p><a href="https://imgse.com/i/pFDLA74"><img src="https://s21.ax1x.com/2024/03/05/pFDLA74.png" alt="pFDLA74.png"></a></p><p>然后可以 shift+R 重复这一操作直到满足要求。</p><h3 id="点的对齐"><a href="#点的对齐" class="headerlink" title="点的对齐"></a>点的对齐</h3><p>点吸附模式下,即使仅在一个轴上运动,也能进行对齐。</p><p>如果有多个点需要对齐,可以考虑使用缩放模式的缩放功能。原理是这样的:</p><blockquote><p>选中多个点,让它们在某一个轴上缩放,这时候如果缩放倍数为 0,那么它们在这个轴上的距离就都是零了,也就意味着在同一条直线上。</p></blockquote><p>这时候就相当于对齐了。好妙的思路。</p><h3 id="顶点组"><a href="#顶点组" class="headerlink" title="顶点组"></a>顶点组</h3><p>ctrl+G,定义新的顶点组。可以用来快速选择,在顶点组界面进行 select 就直接选中了。<br>还有其他功能,刷参数之类的。</p><p><a href="https://imgse.com/i/pFDLVAJ"><img src="https://s21.ax1x.com/2024/03/05/pFDLVAJ.png" alt="pFDLVAJ.png"></a></p><h3 id="球化点"><a href="#球化点" class="headerlink" title="球化点"></a>球化点</h3><p>alt+shift+S,可以让选中的所有点球化分布。</p><p><a href="https://imgse.com/i/pFDLZN9"><img src="https://s21.ax1x.com/2024/03/05/pFDLZN9.png" alt="pFDLZN9.png"></a></p><h1 id="基本操作误解"><a href="#基本操作误解" class="headerlink" title="基本操作误解"></a>基本操作误解</h1><h2 id="挤出选区-Extrude"><a href="#挤出选区-Extrude" class="headerlink" title="挤出选区 Extrude"></a>挤出选区 Extrude</h2><p>挤出 Extrude 有五种不同的操作,即</p><ul><li>Extrude Region</li><li>Extrude Manifold</li><li>Extrude Along Normals</li><li>Extrude Individuals</li><li>Extrude to Cursor<br>具体细节参考 <a href="https://docs.blender.org/manual/en/latest/modeling/meshes/editing/mesh/extrude.html">Extrude — Blender Manual</a>,这里给出大致的理解:</li><li>挤出选择的区域</li><li>挤出选择的区域,并且作为 Manifold 处理,冲突的边和面都会被转化,使之符合 Manifold 定义。</li><li>各选区按照自己的法线方向挤出,而不是一个统一的方向。</li><li>各选区挤出之后,各自获得单独的中心点,因此之后按照中心点操作的时候,各面是独立的。也就是说,相接触的边不会被合并成一条边。</li><li>直接挤出到鼠标点击的位置。</li></ul>]]></content>
<categories>
<category>经验分享</category>
</categories>
<tags>
<tag>经验分享</tag>
<tag>建模</tag>
</tags>
</entry>
<entry>
<title>路过图床的一点小知识</title>
<link href="/2023/10/01/tc/"/>
<url>/2023/10/01/tc/</url>
<content type="html"><![CDATA[<p>首先,十分建议注册账号。如果图片访问量不高的话,路过图床会将图片存储在压缩空间中,这时候再去访问图片就会发现看不见了。需要登录账号告诉图床这个图片还有用。</p><p>其次,可以先上传图片,然后再登录账号。路过很聪明,会直接将你上传的图片和之后登录的账号挂钩。</p><p>路过图床只能在国内使用!如果将来出国,需要要换方案。</p>]]></content>
</entry>
<entry>
<title>OpenGL一点错误理解</title>
<link href="/2023/08/23/opengl/"/>
<url>/2023/08/23/opengl/</url>
<content type="html"><![CDATA[<p>OpenGL的一些记录。</p><span id="more"></span><h2 id="小章节"><a href="#小章节" class="headerlink" title="小章节"></a>小章节</h2><p>内容来自 <a href="https://blog.csdn.net/cd_yourheart/article/details/122375438">OpenGL:动态修改VBO/EBO_六月的翅膀的博客-CSDN博客</a>。<br>主要的错误有:</p><ul><li>VAO 和 VBO 的理解错误。</li><li>VAO 中的 stride 理解错误。</li><li>面上节点顺序剔除问题。</li></ul><h3 id="VAO"><a href="#VAO" class="headerlink" title="VAO"></a>VAO</h3><p>第一个问题可以用 <a href="https://learnopengl-cn.github.io/01%20Getting%20started/04%20Hello%20Triangle/#_10">你好,三角形 - LearnOpenGL CN</a> 的讲解解释:</p><blockquote><p>顶点数组对象 (Vertex Array Object, VAO) 可以像顶点缓冲对象那样被绑定,任何随后的顶点属性调用都会储存在这个 VAO 中。这样的好处就是,当配置顶点属性指针时,你只需要将那些调用执行一次,之后再绘制物体的时候只需要绑定相应的 VAO 就行了。这使在不同顶点数据和属性配置之间切换变得非常简单,只需要绑定不同的 VAO 就行了。刚刚设置的所有状态都将存储在 VAO 中</p></blockquote><p>注意这里说的是顶点属性调用。一个顶点数组对象会储存以下这些内容:</p><ul><li><code>glEnableVertexAttribArray</code> 和 <code>glDisableVertexAttribArray</code> 的调用。</li><li>通过 <code>glVertexAttribPointer</code> 设置的顶点属性配置。</li><li>通过 <code>glVertexAttribPointer</code> 调用与顶点属性关联的顶点缓冲对象。</li></ul><p><a href="https://imgse.com/i/pFD87fe"><img src="https://s11.ax1x.com/2024/03/05/pFD87fe.png" alt="pFD87fe.png"></a></p><p>也就是说,VAO 和 VBO 是相对独立的。所以修改 VBO 的数据的时候,不用考虑 VAO 的问题。<br>其实对于 EBO,VAO 也会进行记录,但是记录的方式不同。<code>glDrawElements</code> 函数从当前绑定到 <code>GL_ELEMENT_ARRAY_BUFFER</code> 目标的 EBO 中获取其索引。这意味着我们每次想要使用索引渲染对象时都必须绑定相应的 EBO,这又有点麻烦。碰巧顶点数组对象也跟踪元素缓冲区对象绑定。在绑定 VAO 时,绑定的<strong>最后一个元素缓冲区对象</strong>存储为 VAO 的元素缓冲区对象。然后,绑定到 VAO 也会自动绑定该 EBO。</p><p><a href="https://imgse.com/i/pFD8bSH"><img src="https://s11.ax1x.com/2024/03/05/pFD8bSH.png" alt="pFD8bSH.png"></a></p><p>也就是说,VAO 记录的是最后一个绑定的 <code>GL_ELEMENT_ARRAY_BUFFER</code>,所以在 VAO 解绑之前,不能解绑 EBO。而 VAO 记录的 VBO 都是指针,解不解绑是无所谓的,所以无需紧张。</p><h3 id="Stride"><a href="#Stride" class="headerlink" title="Stride"></a>Stride</h3><p>第二个问题也是看书就得知的。<br><code>glVertexAttribPointer</code> 函数的参数非常多,所以我会逐一介绍它们:</p><ul><li>第一个参数指定我们要配置的顶点属性。还记得我们在顶点着色器中使用 <code>layout(location = 0)</code> 定义了 position 顶点属性的位置值 (Location) 吗?它可以把顶点属性的位置值设置为 <code>0</code>。因为我们希望把数据传递到这一个顶点属性中,所以这里我们传入 <code>0</code>。</li><li>第二个参数指定顶点属性的大小。顶点属性是一个 <code>vec3</code>,它由 3 个值组成,所以大小是 3。</li><li>第三个参数指定数据的类型,这里是 <code>GL_FLOAT</code>(GLSL 中 <code>vec*</code> 都是由浮点数值组成的)。</li><li>下个参数定义我们是否希望数据被标准化 (Normalize)。如果我们设置为 <code>GL_TRUE</code>,所有数据都会被映射到 0(对于有符号型 signed 数据是 -1)到 1 之间。我们把它设置为 <code>GL_FALSE</code>。</li><li>第五个参数叫做步长 (Stride),它告诉我们在连续的顶点属性组之间的间隔。由于下个组位置数据在 3 个 <code>float</code> 之后,我们把步长设置为 <code>3 * sizeof(float)</code>。要注意的是由于我们知道这个数组是紧密排列的(在两个顶点属性之间没有空隙)我们也可以设置为 0 来让 OpenGL 决定具体步长是多少(只有当数值是紧密排列时才可用)。一旦我们有更多的顶点属性,我们就必须更小心地定义每个顶点属性之间的间隔,我们在后面会看到更多的例子(译注: 这个参数的意思简单说就是从这个属性第二次出现的地方到整个数组 0 位置之间有多少字节)。</li><li>最后一个参数的类型是 <code>void*</code>,所以需要我们进行这个奇怪的强制类型转换。它表示位置数据在缓冲中起始位置的偏移量 (Offset)。由于位置数据在数组的开头,所以这里是 0。我们会在后面详细解释这个参数。<br>这个问题就很简单了,填零的时候是自动计算的,而不是说紧密排布。</li></ul><h3 id="正向剔除"><a href="#正向剔除" class="headerlink" title="正向剔除"></a>正向剔除</h3><p>这个也是看书就能得到的事情。OpenGL 提供剔除的功能,可以自行设置。这也要求点是按照逆时针的顺序排布,不能乱序。</p><h3 id="Program-的-uniform-设置"><a href="#Program-的-uniform-设置" class="headerlink" title="Program 的 uniform 设置"></a>Program 的 uniform 设置</h3><p>要想设置 program 的变量,必须首先 bind 这个程序。debug 用时一小时。<br><figure class="highlight cpp"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><pre><code class="hljs cpp">program-><span class="hljs-built_in">bind</span>();<br>f-><span class="hljs-built_in">glDrawArrays</span>(GL_POINTS, <span class="hljs-number">0</span>, nbr);<br></code></pre></td></tr></table></figure></p><p>解决方案:以后动手之前,必须整理好学习资料。出现问题,第一时间查看手册。</p>]]></content>
<categories>
<category>计算机知识</category>
<category>OpenGL</category>
</categories>
<tags>
<tag>编程</tag>
</tags>
</entry>
<entry>
<title>conda和pip的简单记录</title>
<link href="/2023/05/05/conda/"/>
<url>/2023/05/05/conda/</url>
<content type="html"><![CDATA[<p>一些经验记录。</p><span id="more"></span><h2 id="BUG"><a href="#BUG" class="headerlink" title="BUG"></a>BUG</h2><h3 id="HTTP-000-CONNECTION-FAILED"><a href="#HTTP-000-CONNECTION-FAILED" class="headerlink" title="HTTP 000 CONNECTION FAILED"></a>HTTP 000 CONNECTION FAILED</h3><p><a href="https://zhuanlan.zhihu.com/p/641402545#:~:text=%E8%A7%A3%E5%86%B3%E5%8A%9E%E6%B3%95%EF%BC%9A%E5%8F%AA%E9%9C%80%E8%A6%81%E4%B8%80%E5%8F%A5%E5%91%BD%E4%BB%A4%EF%BC%9Aconda%20config%20--set,ssl_verify%20no%20%E6%B5%8B%E8%AF%95%E6%88%90%E5%8A%9F%20%EF%BC%81">CondaHTTPError: HTTP 000 CONNECTION FAILED for url 解决办法 - 知乎</a></p><p>这种情况多出现于使用国内镜像的情况。使用如下命令即可。<br><figure class="highlight bash"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><pre><code class="hljs bash">conda config --<span class="hljs-built_in">set</span> ssl_verify no<br></code></pre></td></tr></table></figure></p><h2 id="安装-PyTorch-cuda"><a href="#安装-PyTorch-cuda" class="headerlink" title="安装 PyTorch-cuda"></a>安装 PyTorch-cuda</h2><p>在一些特殊情况下,使用官方命令安装 pytorch 的时候,会默认安装 CPU 版本。总不能重新配环境吧(倒也不是不行)。</p><p>第一种解决办法,去掉 <code>-c torch</code></p><figure class="highlight sh"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs sh">conda install pytorch torchvision torchaudio pytorch-cuda=11.7 -c nvidia<br></code></pre></td></tr></table></figure><p>第二种方法,<a href="https://blog.csdn.net/HuangJM3/article/details/123685177">安装GPU版本的pytorch(解决pytorch安装时默认安装CPU版本的问题)保姆级教程_3EoIPrime的博客-CSDN博客</a>,如果发现了 cpuonly,删掉它。</p><h2 id="技巧"><a href="#技巧" class="headerlink" title="技巧"></a>技巧</h2><h3 id="pip-更新所有的包"><a href="#pip-更新所有的包" class="headerlink" title="pip 更新所有的包"></a>pip 更新所有的包</h3><p>需要使用一个包 <code>pip-review</code>,使用 pip 安装即可。输入如下命令:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs bash">pip install pip-review<br>pip-review --<span class="hljs-built_in">local</span> --auto<br></code></pre></td></tr></table></figure><br>就可以进行全部更新了。</p>]]></content>
<categories>
<category>经验分享</category>
</categories>
<tags>
<tag>经验分享</tag>
<tag>编程</tag>
</tags>
</entry>
<entry>
<title>网站部署新策略:Firebase!</title>
<link href="/2023/04/06/website/"/>
<url>/2023/04/06/website/</url>
<content type="html"><![CDATA[<p>Firebase是由谷歌提供的轻量级后端服务器,面向个人用户提供了十分有用的控制台和各种后端服务,而且是免费的。使用Firebase部署个人网站,相较于GitPages有更好的效果。</p><span id="more"></span><h2 id="基本动作"><a href="#基本动作" class="headerlink" title="基本动作"></a>基本动作</h2><p>在初次进入Firebase之后,如果使用的是Google Chrome浏览器,会自动登录上谷歌账号。<br>然后需要根据引导,创建自己的第一个项目。</p><p><a href="https://imgse.com/i/ppI1A91"><img src="https://s1.ax1x.com/2023/04/06/ppI1A91.png" alt="ppI1A91.png"></a></p><p>一个项目是一套完整的后端系统。后端不仅仅是由网页组成的。为了部署我们的网页,我们需要添加Host功能。这里提供了<a href="https://firebase.google.com/docs/hosting/quickstart?authuser=0&hl=zh">官方文档</a>,里面分了如下三个步骤:</p><ul><li>安装 Firebase CLI</li><li>初始化项目</li><li>部署到网站</li></ul><h3 id="安装相关工具和设置"><a href="#安装相关工具和设置" class="headerlink" title="安装相关工具和设置"></a>安装相关工具和设置</h3><p>需要在你想要部署的本地文件夹中安装相关的库,同时还要在你的系统下安装工具:<br><figure class="highlight bash"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><pre><code class="hljs bash">npm install firebase<br>npm install -g firebase-tools<br></code></pre></td></tr></table></figure></p><p>然后需要在文件内登录你的账号,便于部署:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">firebase login<br></code></pre></td></tr></table></figure><br>这里会弹出一个网页,登录谷歌账号然后回来即可。</p><h3 id="初始化项目"><a href="#初始化项目" class="headerlink" title="初始化项目"></a>初始化项目</h3><p>可以先将你的文件放在<code>public</code>文件夹下面,也可以之后放置。使用如下命令进行初始化:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">firebase init<br></code></pre></td></tr></table></figure><br>初始化过程中,会让你选择项目和目的,目的选中<code>Host</code>的较长的那个选项,这个选项全文我忘记了,大意是部署网站,可选择地部署Github Actions。本次实践不需要Actions。</p><p>然后会提供许多选项,按照你自己的需求选择即可。我选择了一个<code>不覆盖index.html</code>,因为我已经有写好了的文件。当然这个选项我其实没有看仔细就选上了。</p><h3 id="部署到网站"><a href="#部署到网站" class="headerlink" title="部署到网站"></a>部署到网站</h3><p>直接<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">firebase deploy<br></code></pre></td></tr></table></figure><br>就会自动部署到你的站点上。会提示你部署的网址,在浏览器中打开就可以查看了。</p><h2 id="使用自定义域名"><a href="#使用自定义域名" class="headerlink" title="使用自定义域名"></a>使用自定义域名</h2><p>如果完成了上面的步骤,在你的项目控制台中,会出现Hosting的功能。</p><p><a href="https://imgse.com/i/ppI1Jjf"><img src="https://s1.ax1x.com/2023/04/06/ppI1Jjf.md.png" alt="ppI1Jjf.md.png"></a></p><p>添加你的网域(域名)即可。<a href="https://firebase.google.com/docs/hosting/custom-domain?hl=zh&authuser=0">官方文档</a>中给出了详细的步骤,来自定义域名。</p><p>最简单的步骤如下:</p><ul><li>选中Firebase里面的<code>添加自定义域名</code>,填写信息。</li><li>在Firebase上生成TXT身份验证信息,然后在域名网站中添加相应的DNS条目。可以一次为<code>www</code>和裸域名同时添加。</li><li>等待DNS修改生效,这时Firebase通过身份验证。</li><li>在Firebase中获取要求添加的DNS条目,添加。等待DNS修改生效。</li><li>DNS修改生效,这时网站可以正常访问,但是没有SSL证书。</li><li>再过一段时间,SSL证书下发,网站可以HTTPS访问。</li></ul><p>具体步骤,文档写的十分详细,可以参考。</p><h2 id="补充资料"><a href="#补充资料" class="headerlink" title="补充资料"></a>补充资料</h2><p><a href="https://zhuanlan.zhihu.com/p/86961133">namesilo相关事项</a></p>]]></content>
<categories>
<category>博客</category>
</categories>
<tags>
<tag>博客</tag>
<tag>互联网</tag>
</tags>
</entry>
<entry>
<title>QtOpenGL使用方法</title>
<link href="/2023/03/10/QtOpenGL/"/>
<url>/2023/03/10/QtOpenGL/</url>
<content type="html"><![CDATA[<p>这里介绍如何在Qt里面使用OpenGL功能。代码在macOS 13 M1 平台上测试通过。<br><span id="more"></span></p><h1 id="基本架构"><a href="#基本架构" class="headerlink" title="基本架构"></a>基本架构</h1><p>在Qt 6中使用OpenGL,需要知道Qt接管了OpenGL的什么功能。在普通的OpenGL程序中,有GLFW和GLAD两部分对OpenGL进行了功能加强,前者提供了窗口管理版本管理等功能,后者负责从系统中获得OpenGL函数地址。在Qt中,前者的窗口管理功能由Qt本身替代,而版本管理和其他属性设置,由<code>QSurfaceFormat</code>管理。这个名字里面没有出现OpenGL,很是惬意。而GLAD则不用理睬,Qt也处理好了这一方面。</p><p>在初次学习中,犯的最大的错误是忽视了SurfaceFormat的介绍。因此首先讲解SurfaceFormat是什么。</p><p><a href="https://doc.qt.io/qt-6/qsurfaceformat.html">QSurfaceFormat Class | Qt GUI 6.4.2</a>,是Qt对于各种Surface提供的配置文件。其中的函数<code>QSurfaceFormat::setDefaultFormat</code>则是为所有Surface设置配置文件。Surface不是只有OpenGL的,而是可以有多种type,比如:</p><div class="table-container"><table><thead><tr><th>Constant</th><th>Value</th><th>Description</th></tr></thead><tbody><tr><td><code>QSurface::RasterSurface</code></td><td><code>0</code></td><td>The surface is is composed of pixels and can be rendered to using a software rasterizer like Qt’s raster paint engine.</td></tr><tr><td><code>QSurface::OpenGLSurface</code></td><td><code>1</code></td><td>The surface is an OpenGL compatible surface and can be used in conjunction with <a href="https://doc.qt.io/qt-6/qopenglcontext.html">QOpenGLContext</a>.</td></tr><tr><td><code>QSurface::RasterGLSurface</code></td><td><code>2</code></td><td>The surface can be rendered to using a software rasterizer, and also supports OpenGL. This surface type is intended for internal Qt use, and requires the use of private API.</td></tr><tr><td><code>QSurface::OpenVGSurface</code></td><td><code>3</code></td><td>The surface is an OpenVG compatible surface and can be used in conjunction with OpenVG contexts.</td></tr><tr><td><code>QSurface::VulkanSurface</code></td><td><code>4</code></td><td>The surface is a Vulkan compatible surface and can be used in conjunction with the Vulkan graphics API.</td></tr><tr><td><code>QSurface::MetalSurface</code></td><td><code>5</code></td><td>The surface is a Metal compatible surface and can be used in conjunction with Apple’s Metal graphics API. This surface type is only supported on macOS and iOS.</td></tr><tr><td><code>QSurface::Direct3DSurface</code></td><td><code>6</code></td><td>The surface is a Direct 3D 11 and 12 compatible surface and can be used in conjunction with the DXGI and Direct3D APIs. This surface type is only supported on Windows.</td></tr></tbody></table></div><p>而QSurfaceFormat与其说是QSurface的配置,不如说是为了OpenGL专用的设置。因为其中大部分设置都是专属于OpenGL的。</p><p>初次学习时犯下的一个重要错误是,没有仔细阅读文档中的注意事项。比如:</p><ol><li>QOpenGLWidget allows using different OpenGL versions and profiles when the platform supports it. Just set the requested format via <a href="https://doc.qt.io/qt-6/qopenglwidget.html#setFormat">setFormat</a>(). Keep in mind however that having multiple QOpenGLWidget instances in the same window requires that they all use the same format, or at least formats that do not make the contexts non-sharable. To overcome this issue, prefer using <a href="https://doc.qt.io/qt-6/qsurfaceformat.html#setDefaultFormat">QSurfaceFormat::setDefaultFormat</a>() instead of <a href="https://doc.qt.io/qt-6/qopenglwidget.html#setFormat">setFormat</a>().</li><li>Calling <a href="https://doc.qt.io/qt-6/qsurfaceformat.html#setDefaultFormat">QSurfaceFormat::setDefaultFormat</a>() before constructing the <a href="https://doc.qt.io/qt-6/qapplication.html">QApplication</a> instance is mandatory on some platforms (for example, macOS) when an OpenGL core profile context is requested. This is to ensure that resource sharing between contexts stays functional as all internal contexts are created using the correct version and profile.</li></ol><p>这两个提醒,正好对应了我在常见错误部分所写的两个我犯下的错误。后面会详细叙述。</p><h1 id="动手绘制三角形"><a href="#动手绘制三角形" class="headerlink" title="动手绘制三角形"></a>动手绘制三角形</h1><h2 id="Promote-UI"><a href="#Promote-UI" class="headerlink" title="Promote UI"></a>Promote UI</h2><p>第一步是完成UI设计。在Qt Creator里面设置UI文件,按照喜好安排即可。注意其中需要添加一个QOpenGLWidget的组件,然后在组件右键,选择<code>Promote to</code>将其提升为自己的类。</p><p><a href="https://imgse.com/i/ppnOMQI"><img src="https://s1.ax1x.com/2023/03/10/ppnOMQI.png" alt="ppnOMQI.png"></a><br><a href="https://imgse.com/i/ppnOlOP"><img src="https://s1.ax1x.com/2023/03/10/ppnOlOP.png" alt="ppnOlOP.png"></a><br>创建完成之后,就需要在给出的头文件里面实现自己的<code>myGLWidget</code>。</p><h2 id="GLWidget"><a href="#GLWidget" class="headerlink" title="GLWidget"></a>GLWidget</h2><p>首先需要一大堆头文件。<br><figure class="highlight cpp"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></div></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QOpenGLWidget></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QOpenGLFunctions></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QOpenGLContext></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QOpenGLShader></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QOpenGLShaderProgram></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QOpenGLVertexArrayObject></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QOpenGLBuffer></span></span><br></code></pre></td></tr></table></figure></p><p>然后和往常一样,我们需要实现最简单的Shader。这里直接使用字符串。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-type">static</span> <span class="hljs-type">const</span> <span class="hljs-type">char</span> *vertexShaderSource = <span class="hljs-string">"#version 400 core\n"</span><br> <span class="hljs-string">"layout (location = 0) in vec3 aPos;\n"</span><br> <span class="hljs-string">"void main()\n"</span><br> <span class="hljs-string">"{\n"</span><br> <span class="hljs-string">" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"</span><br> <span class="hljs-string">"}\0"</span>;<br><span class="hljs-type">static</span> <span class="hljs-type">const</span> <span class="hljs-type">char</span> *fragmentShaderSource = <span class="hljs-string">"#version 400 core\n"</span><br> <span class="hljs-string">"out vec4 FragColor;\n"</span><br> <span class="hljs-string">"void main()\n"</span><br> <span class="hljs-string">"{\n"</span><br> <span class="hljs-string">" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"</span><br> <span class="hljs-string">"}\n\0"</span>;<br></code></pre></td></tr></table></figure></p><p>然后需要实现类的基本结构,最重要的部分有三个,<code>initializeGL, resizeGL, paintGL</code>。其中第一位是OpenGL的资源准备,第二位是在窗口发生缩放时,OpenGL的应对方式,第三位是渲染的过程。</p><p>这里使用OpenGL的核心模式,我们需要实现VAO,VBO,shader和program。QtOpenGL提供了相应的管理方法。具体使用方式基本一致,需要注意的是VAO和VBO提供了<code>bind()</code>函数,可以自动绑定到当前上下文中。当然如果你愿意,也可以使用VBO中的<code>bufferId</code>函数得到OpenGL的ID。不过VAO不提供这一手段。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-keyword">class</span> <span class="hljs-title class_">myGLWidget</span> : <span class="hljs-keyword">public</span> QOpenGLWidget<br>{<br> Q_OBJECT<br><span class="hljs-keyword">public</span>:<br> <span class="hljs-built_in">myGLWidget</span>(QWidget *parent = <span class="hljs-literal">nullptr</span>): <span class="hljs-built_in">QOpenGLWidget</span>(parent) {}<br><br> QOpenGLShader *vert_shader, *frag_shader;<br> QOpenGLShaderProgram *program;<br> QOpenGLVertexArrayObject m_vao;<br> QOpenGLBuffer m_vbo;<br><span class="hljs-keyword">protected</span>:<br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">initializeGL</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-comment">// Set up the rendering context, load shaders and other resources, etc.:</span><br> QOpenGLFunctions *f = QOpenGLContext::<span class="hljs-built_in">currentContext</span>()-><span class="hljs-built_in">functions</span>();<br> f-><span class="hljs-built_in">glClearColor</span>(<span class="hljs-number">1.0f</span>, <span class="hljs-number">1.0f</span>, <span class="hljs-number">1.0f</span>, <span class="hljs-number">1.0f</span>);<br> vert_shader = <span class="hljs-keyword">new</span> <span class="hljs-built_in">QOpenGLShader</span>(QOpenGLShader::Vertex, <span class="hljs-keyword">this</span>);<br> vert_shader-><span class="hljs-built_in">compileSourceCode</span>(vertexShaderSource);<br> frag_shader = <span class="hljs-keyword">new</span> <span class="hljs-built_in">QOpenGLShader</span>(QOpenGLShader::Fragment, <span class="hljs-keyword">this</span>);<br> frag_shader-><span class="hljs-built_in">compileSourceCode</span>(fragmentShaderSource);<br> program = <span class="hljs-keyword">new</span> <span class="hljs-built_in">QOpenGLShaderProgram</span>(<span class="hljs-keyword">this</span>);<br> program-><span class="hljs-built_in">addShader</span>(vert_shader);<br> program-><span class="hljs-built_in">addShader</span>(frag_shader);<br> program-><span class="hljs-built_in">link</span>();<br> m_vao.<span class="hljs-built_in">create</span>();<br> <span class="hljs-keyword">if</span> (m_vao.<span class="hljs-built_in">isCreated</span>())<br> m_vao.<span class="hljs-built_in">bind</span>();<br><br> m_vbo.<span class="hljs-built_in">create</span>();<br> m_vbo.<span class="hljs-built_in">bind</span>();<br> <span class="hljs-type">float</span> vertices[] = {<br> <span class="hljs-number">-0.5f</span>, <span class="hljs-number">-0.5f</span>, <span class="hljs-number">0.0f</span>, <span class="hljs-comment">// left</span><br> <span class="hljs-number">0.5f</span>, <span class="hljs-number">-0.5f</span>, <span class="hljs-number">0.0f</span>, <span class="hljs-comment">// right</span><br> <span class="hljs-number">0.0f</span>, <span class="hljs-number">0.5f</span>, <span class="hljs-number">0.0f</span> <span class="hljs-comment">// top</span><br> };<br> f-><span class="hljs-built_in">glBufferData</span>(GL_ARRAY_BUFFER, <span class="hljs-built_in">sizeof</span>(vertices), vertices, GL_STATIC_DRAW);<br> f-><span class="hljs-built_in">glVertexAttribPointer</span>(<span class="hljs-number">0</span>, <span class="hljs-number">3</span>, GL_FLOAT, GL_FALSE, <span class="hljs-number">3</span> * <span class="hljs-built_in">sizeof</span>(<span class="hljs-type">float</span>), (<span class="hljs-type">void</span>*)<span class="hljs-number">0</span>);<br> f-><span class="hljs-built_in">glEnableVertexAttribArray</span>(<span class="hljs-number">0</span>);<br><span class="hljs-comment">// f->glBindBuffer(GL_ARRAY_BUFFER, 0);</span><br><span class="hljs-comment">// f->glBindVertexArray(0);</span><br> }<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">resizeGL</span><span class="hljs-params">(<span class="hljs-type">int</span> w, <span class="hljs-type">int</span> h)</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-comment">// Update projection matrix and other size related settings:</span><br><span class="hljs-comment">// m_projection.setToIdentity();</span><br><span class="hljs-comment">// m_projection.perspective(45.0f, w / float(h), 0.01f, 100.0f);</span><br><span class="hljs-comment">// ...</span><br> }<br><br> <span class="hljs-function"><span class="hljs-type">void</span> <span class="hljs-title">paintGL</span><span class="hljs-params">()</span> <span class="hljs-keyword">override</span></span><br><span class="hljs-function"> </span>{<br> <span class="hljs-comment">// Draw the scene:</span><br> QOpenGLFunctions *f = QOpenGLContext::<span class="hljs-built_in">currentContext</span>()-><span class="hljs-built_in">functions</span>();<br> f-><span class="hljs-built_in">glClear</span>(GL_COLOR_BUFFER_BIT);<br> program-><span class="hljs-built_in">bind</span>();<br> m_vao.<span class="hljs-built_in">bind</span>();<br> f-><span class="hljs-built_in">glDrawArrays</span>(GL_TRIANGLES, <span class="hljs-number">0</span>, <span class="hljs-number">3</span>);<br> program-><span class="hljs-built_in">release</span>();<br> }<br><br>};<br></code></pre></td></tr></table></figure></p><p>从代码中可以看到,基本使用方法和普通的OpenGL相似,只是将<code>glBindBuffer</code>之类换成了更直接的<code>bind()</code>。</p><p>需要注意的是,要想使用OpenGL函数,必须使用<code>QOpenGLFunctions</code>提供的接口。照搬上面的语句即可。</p><p>QOpenGL没有对OpenGL进行全盘迁移。因为全盘迁移之后,它其实就变成了<a href="https://doc.qt.io/qt-6/qt3d-index.html">Qt 3D 6.4.2</a>。</p><h2 id="调用"><a href="#调用" class="headerlink" title="调用"></a>调用</h2><p>因为我们使用的是promote方式进行实现的,所以不用做什么动作就可以启用了。但是默认的version其实是OpenGL2.0,部分平台不支持。所以我们需要在窗口创建之前,完成这一设置。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs cpp">QSurfaceFormat format;<br>format.<span class="hljs-built_in">setDepthBufferSize</span>(<span class="hljs-number">24</span>);<br>format.<span class="hljs-built_in">setStencilBufferSize</span>(<span class="hljs-number">8</span>);<br>format.<span class="hljs-built_in">setVersion</span>(<span class="hljs-number">3</span>, <span class="hljs-number">3</span>);<br>format.<span class="hljs-built_in">setProfile</span>(QSurfaceFormat::CoreProfile);<br>QSurfaceFormat::<span class="hljs-built_in">setDefaultFormat</span>(format);<br>MainWindow w;<br>w.<span class="hljs-built_in">show</span>();<br></code></pre></td></tr></table></figure><h2 id="效果"><a href="#效果" class="headerlink" title="效果"></a>效果</h2><p>预期效果如下:<br><a href="https://imgse.com/i/ppnOQyt"><img src="https://s1.ax1x.com/2023/03/10/ppnOQyt.png" alt="ppnOQyt.png"></a></p><h1 id="常见错误"><a href="#常见错误" class="headerlink" title="常见错误"></a>常见错误</h1><h2 id="SurfaceFormat"><a href="#SurfaceFormat" class="headerlink" title="SurfaceFormat"></a>SurfaceFormat</h2><p>需要在main函数里面设置<code>SurfaceFormat</code>,否则会报错<code>openglcontext: Could not create NSOpenGLContext with shared context</code>。这是因为多个Surface必须使用相同的Format,所以如果只设置一个的话,就会发生配置不同的冲突。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string">"mainwindow.h"</span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QApplication></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><QSurfaceFormat></span></span><br><span class="hljs-function"><span class="hljs-type">int</span> <span class="hljs-title">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc, <span class="hljs-type">char</span> *argv[])</span></span><br><span class="hljs-function"></span>{<br> <span class="hljs-function">QApplication <span class="hljs-title">a</span><span class="hljs-params">(argc, argv)</span></span>;<br> QSurfaceFormat format;<br> format.<span class="hljs-built_in">setDepthBufferSize</span>(<span class="hljs-number">24</span>);<br> format.<span class="hljs-built_in">setStencilBufferSize</span>(<span class="hljs-number">8</span>);<br> format.<span class="hljs-built_in">setVersion</span>(<span class="hljs-number">3</span>, <span class="hljs-number">3</span>);<br> format.<span class="hljs-built_in">setProfile</span>(QSurfaceFormat::CoreProfile);<br> QSurfaceFormat::<span class="hljs-built_in">setDefaultFormat</span>(format);<br> MainWindow w;<br> w.<span class="hljs-built_in">show</span>();<br> <span class="hljs-keyword">return</span> a.<span class="hljs-built_in">exec</span>();<br>}<br></code></pre></td></tr></table></figure></p><h2 id="Version-not-supported"><a href="#Version-not-supported" class="headerlink" title="Version not supported"></a>Version not supported</h2><p>这种情况依然发生在SurfaceFormat的问题上。如果在设置<code>DefaultFormat</code>之前创建了<code>QWindow</code>,那么默认surface不会起作用。因此,无法看到预期的效果。<br>所以,需要将顺序进行调整。<br><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp">QSurfaceFormat::<span class="hljs-built_in">setDefaultFormat</span>(format);<br>MainWindow w;<br>w.<span class="hljs-built_in">show</span>();<br></code></pre></td></tr></table></figure></p>]]></content>
<categories>
<category>计算机知识</category>
<category>qt</category>
</categories>
<tags>
<tag>编程</tag>
</tags>
</entry>
<entry>
<title>简单理解Qt项目的CMakeLists.txt</title>
<link href="/2022/08/10/qt-cmake/"/>
<url>/2022/08/10/qt-cmake/</url>
<content type="html"><![CDATA[<p>本文简单研究了Qt生成的默认的CMakeLists.txt。理解之后便可以较为合理地设计自己的Qt程序。<br><span id="more"></span></p><p>Qt的典型<code>CMakeLists.txt</code>的逐段解析如下:</p><figure class="highlight bash"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br></pre></div></td><td class="code"><pre><code class="hljs bash"><span class="hljs-comment"># CMake的最低版本号为3.5</span><br>cmake_minimum_required(VERSION 3.5)<br><br><span class="hljs-comment"># project名称是"untitled",版本号是0.1,编译语言是C++</span><br>project(untitled VERSION 0.1 LANGUAGES CXX)<br><br><span class="hljs-comment"># 将当前目录添加到include之内</span><br><span class="hljs-built_in">set</span>(CMAKE_INCLUDE_CURRENT_DIR ON)<br><br><span class="hljs-comment"># 自动编译.ui文件,只有添加了Qt组件才能起作用</span><br><span class="hljs-built_in">set</span>(CMAKE_AUTOUIC ON)、<br><span class="hljs-comment"># 自动进行MOC,只有添加了Qt组件才能起作用</span><br><span class="hljs-built_in">set</span>(CMAKE_AUTOMOC ON)<br><span class="hljs-comment"># 自动解析RCC资源文件,只有添加了Qt组件才能起作用</span><br><span class="hljs-built_in">set</span>(CMAKE_AUTORCC ON)<br><br><span class="hljs-comment"># 使用C++17标准</span><br><span class="hljs-built_in">set</span>(CMAKE_CXX_STANDARD 17)<br><span class="hljs-comment"># 确保预先提供C++版本是必要的,否则编译时可能忽略前文对C++17的要求</span><br><span class="hljs-built_in">set</span>(CMAKE_CXX_STANDARD_REQUIRED ON)<br><br><span class="hljs-comment"># 导入QT Widgets包,找Qt6或者Qt5的包均可</span><br>find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)<br><span class="hljs-comment"># 根据找到的Qt版本,再次导入Widgets</span><br>find_package(Qt<span class="hljs-variable">${QT_VERSION_MAJOR}</span> REQUIRED COMPONENTS Widgets)<br><br><span class="hljs-comment"># 设置需要编译的源文件,.ui文件使用AUTOUIC处理。</span><br><span class="hljs-built_in">set</span>(PROJECT_SOURCES<br> main.cpp<br> mainwindow.cpp<br> mainwindow.h<br> mainwindow.ui<br>)<br><br><span class="hljs-comment"># 针对Qt6和Qt5的不同处理</span><br><span class="hljs-keyword">if</span>(<span class="hljs-variable">${QT_VERSION_MAJOR}</span> GREATER_EQUAL 6)<br> <span class="hljs-comment"># 如果是Qt6,会引入更多的特性,正文中有所解释</span><br> qt_add_executable(untitled<br> MANUAL_FINALIZATION<br> <span class="hljs-variable">${PROJECT_SOURCES}</span><br> )<br><span class="hljs-comment"># Define target properties for Android with Qt 6 as:</span><br><span class="hljs-comment"># set_property(TARGET untitled APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR</span><br><span class="hljs-comment"># ${CMAKE_CURRENT_SOURCE_DIR}/android)</span><br><span class="hljs-comment"># For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation</span><br><span class="hljs-keyword">else</span>()<br> <span class="hljs-comment"># 如果是Qt5,则按照一般处理</span><br> <span class="hljs-keyword">if</span>(ANDROID)<br> add_library(untitled SHARED<br> <span class="hljs-variable">${PROJECT_SOURCES}</span><br> )<br><span class="hljs-comment"># Define properties for Android with Qt 5 after find_package() calls as:</span><br><span class="hljs-comment"># set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")</span><br> <span class="hljs-keyword">else</span>()<br> add_executable(untitled<br> <span class="hljs-variable">${PROJECT_SOURCES}</span><br> )<br> endif()<br>endif()<br><br><span class="hljs-comment"># 链接Widgets到输出文件上</span><br><span class="hljs-comment"># 默认动态链接,如果需要静态链接,需要指定链接库的后缀.lib</span><br>target_link_libraries(untitled PRIVATE Qt<span class="hljs-variable">${QT_VERSION_MAJOR}</span>::Widgets)<br><br><span class="hljs-comment"># 设置目标的一些属性</span><br>set_target_properties(untitled PROPERTIES<br> MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com<br> MACOSX_BUNDLE_BUNDLE_VERSION <span class="hljs-variable">${PROJECT_VERSION}</span><br> MACOSX_BUNDLE_SHORT_VERSION_STRING <span class="hljs-variable">${PROJECT_VERSION_MAJOR}</span>.<span class="hljs-variable">${PROJECT_VERSION_MINOR}</span><br> MACOSX_BUNDLE TRUE<br> WIN32_EXECUTABLE TRUE<br>)<br><br><span class="hljs-comment"># Qt6 的特性</span><br><span class="hljs-keyword">if</span>(QT_VERSION_MAJOR EQUAL 6)<br> qt_finalize_executable(untitled)<br>endif()<br></code></pre></td></tr></table></figure><h2 id="Qt6带来的变化"><a href="#Qt6带来的变化" class="headerlink" title="Qt6带来的变化"></a>Qt6带来的变化</h2><p>文中体现出来的变化主要在于<code>qt_add_executable</code>和<code>qt_finalize_target</code>.</p><p><code>qt_add_executable</code>的工作是为目标平台构建一个适当的目标、将目标链接到<code>Qt::Core</code>库和处理CMake目标构建完成后的结束动作(finalization)。</p><p><code>qt_finalize_target</code>是和上一个指令配合使用的,如果定义了<code>MANUAL_FINALIZATION</code>,需要在合适的地方手动进行结束动作。</p><p>其中为了多平台,<code>qt_add_executable</code>主要的区别在于:</p><ul><li>Android平台上,只创建<code>MODULE</code>库,忽略任何 <code>WIN32</code> 或 <code>MACOSX_BUNDLE</code>选项,接受Android的特性选项。</li><li>其他平台上,创建一个可执行目标。</li></ul><p><code>qt_finalize_target</code>的主要区别在于:</p><ul><li>Android,创建一个部署环境,创建APK打包。</li><li>WASM,创建<code>${target}.html,qtloader.js,qtlogo.svg</code>文件。</li><li>iOS,补全没有设置的属性,比如<code>XCODE_ATTRIBUTE_DEVELOPMENT_TEAM</code>,<code>MACOSX_BUNDLE_GUI_IDENTIFIER</code>之类的。</li></ul><p>当然这里的简单介绍跟没说一样。自己进行相应的程序构建之后才能理解为什么需要新的特性。</p><p>几个值得一看的文档如下。</p><p><a href="https://runebook.dev/zh-CN/docs/qt/qt-add-executable">qt_add_executable</a></p><p><a href="https://runebook.dev/zh-CN/docs/qt/qt-finalize-target#qt6-finalize-target">qt_finalize_target</a></p><p><a href="https://doc.qt.io/qt-6/qt-add-executable.html">qt_add_executable</a></p><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>关于三个AUTO工具其实也有很多学问,可以参考文章如下。</p><p><a href="https://cmake.org/cmake/help/latest/prop_tgt/AUTOUIC.html">AUTOUIC - CMake 3.24.0 Documentation</a></p><p><a href="https://cmake.org/cmake/help/latest/prop_tgt/AUTOMOC.html">AUTOMOC - CMake 3.24.0 Documentation</a></p><p><a href="https://cmake.org/cmake/help/latest/prop_tgt/AUTORCC.html">AUTORCC - CMake 3.24.0 Documentation</a></p>]]></content>
<categories>
<category>计算机知识</category>
<category>Qt</category>
</categories>
<tags>
<tag>编程</tag>
</tags>
</entry>
<entry>
<title>IOCCC-科学计算器代码解析</title>
<link href="/2022/07/14/IOCCC-ar1/"/>
<url>/2022/07/14/IOCCC-ar1/</url>
<content type="html"><![CDATA[<p>本文是对IOCCC赛事中来自Qiming Hou老师的科学计算器的简单代码解析。该代码来自赛事IOCCC 20th,Hou老师获得奖项Best self documenting。<br><span id="more"></span></p><h2 id="事先声明"><a href="#事先声明" class="headerlink" title="事先声明"></a>事先声明</h2><p>由于本人能力欠缺,本代码仍在继续解析中,因此如果分析出现了偏差,请及时联系本人更正。</p><h2 id="代码概览"><a href="#代码概览" class="headerlink" title="代码概览"></a>代码概览</h2><p>源代码如下。<br><figure class="highlight c"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></div></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><math.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> clear 1;<span class="hljs-keyword">if</span>(c>=11){c=0;sscanf(_,<span class="hljs-string">"%lf%c"</span>,&r,&c);while(*++_-c);}\</span><br><span class="hljs-meta"> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(argc>=4&&!main(4-(*_++==<span class="hljs-string">'('</span>),argv))_++;g:c+=</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> puts(d,e) return 0;}{double a;int b;char c=(argc<4?d)&15;\</span><br><span class="hljs-meta"> b=(*_%__LINE__+7)%9*(3*e>>c&1);c+=</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> I(d) (r);<span class="hljs-keyword">if</span>(argc<4&&*#d==*_){a=r;r=usage?r*a:r+a;goto g;}c=c</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> return <span class="hljs-keyword">if</span>(argc==2)printf(<span class="hljs-string">"%f\n"</span>,r);return argc>=4+</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> usage main(4-__LINE__/26,argv)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> calculator *_*(int)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> l (r);r=--b?r:</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> _ argv[1]</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> x</span><br><br><span class="hljs-type">double</span> r;<br><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc,<span class="hljs-type">char</span>** argv)</span>{<br> <span class="hljs-keyword">if</span>(argc<<span class="hljs-number">2</span>){<br> <span class="hljs-built_in">puts</span>(<br> usage: calculator <span class="hljs-number">11</span>/<span class="hljs-number">26</span>+<span class="hljs-number">222</span>/<span class="hljs-number">31</span><br> +~~~~~~~~~~~~~~~~~~~~~~~~calculator-\<br> ! <span class="hljs-number">7.584</span>,<span class="hljs-number">367</span> )<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+<br> ! clear ! <span class="hljs-number">0</span> ||l -x l <span class="hljs-built_in">tan</span> <span class="hljs-title function_">I</span> <span class="hljs-params">(/)</span> |<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+<br> ! 1 | 2 | 3 ||l 1/x l <span class="hljs-built_in">cos</span> <span class="hljs-title function_">I</span> <span class="hljs-params">(*)</span> |<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+<br> ! 4 | 5 | 6 ||l <span class="hljs-built_in">exp</span> l <span class="hljs-built_in">sqrt</span> <span class="hljs-title function_">I</span> <span class="hljs-params">(+)</span> |<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+<br> ! 7 | 8 | 9 ||l <span class="hljs-built_in">sin</span> l <span class="hljs-built_in">log</span> <span class="hljs-title function_">I</span> <span class="hljs-params">(-)</span> |<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~<span class="hljs-params">(<span class="hljs-number">0</span></span><br><span class="hljs-params"> )</span>;<br> }<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure></p><p>可以看到,这里在<code>main</code>函数中绘制了一个十分形象的计算器,而且它是可以编译通过的!这么神奇的现象是由前面的宏定义实现的。抛开这些不谈,我们先来看一下运行结果。</p><p>赛事官方提供了如下的<code>makefile</code>。<br><figure class="highlight makefile"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br></pre></td><td class="code"><pre><code class="hljs makefile"><span class="hljs-comment">#!/usr/bin/env make</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># 2011 makefile</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># Copyright (C) 2011, Landon Curt Noll, Simon Cooper, and Leonid A. Broukhis.</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># Creative Commons Attribution-ShareAlike 3.0 Unported License.</span><br><span class="hljs-comment"># See: http://creativecommons.org/licenses/by-sa/3.0/</span><br><br><br><span class="hljs-comment">################</span><br><span class="hljs-comment"># tool locations</span><br><span class="hljs-comment">################</span><br><span class="hljs-comment">#</span><br>SHELL= /bin/bash<br>CP= cp<br>CPP= cpp<br>GUNZIP= gunzip<br>LD= ld<br>MAKE= make<br>RM= rm<br>SED= sed<br>TAR= tar<br>TRUE= true<br><br><span class="hljs-comment"># optimization</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># Most compiles will safely use -O2. Some can use only -O1 or -O.</span><br><span class="hljs-comment"># A few compilers have broken optimizers or this entry make break</span><br><span class="hljs-comment"># under those buggy optimizers and thus you may not want anything.</span><br><span class="hljs-comment">#</span><br>OPT= -O2<br><br><span class="hljs-comment"># bitness</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># Some entries require 32-bitness,</span><br><span class="hljs-comment"># other entries require 64-bitess.</span><br><span class="hljs-comment"># By default we assume nothing.</span><br><span class="hljs-comment">#</span><br>ARCH=<br><br><span class="hljs-comment"># default flags for ANSI C compilation</span><br><span class="hljs-comment">#</span><br>CFLAGS= -Wall -W -ansi -pedantic ${ARCH} ${OPT} -lm<br><br><span class="hljs-comment"># ANSI compiler</span><br><span class="hljs-comment">#</span><br><span class="hljs-comment"># Set CC to the name of your ANSI compiler.</span><br><span class="hljs-comment">#</span><br>CC= cc<br><br><br><span class="hljs-comment">##############################</span><br><span class="hljs-comment"># Special flags for this entry</span><br><span class="hljs-comment">##############################</span><br><span class="hljs-comment">#</span><br>ENTRY= hou<br>DATA=<br><br><br><span class="hljs-comment">#################</span><br><span class="hljs-comment"># build the entry</span><br><span class="hljs-comment">#################</span><br><span class="hljs-comment">#</span><br><span class="hljs-section">all: ${ENTRY} ${DATA}</span><br>@${TRUE}<br><br><span class="hljs-section">${ENTRY}: ${ENTRY}.c</span><br>${CC} ${CFLAGS} ${ENTRY}.c -o ${ENTRY}<br><br><span class="hljs-comment"># alternative executable</span><br><span class="hljs-comment">#</span><br><span class="hljs-section">alt:</span><br>@${TRUE}<br><br><br><span class="hljs-comment">###############</span><br><span class="hljs-comment"># utility rules</span><br><span class="hljs-comment">###############</span><br><span class="hljs-comment">#</span><br><span class="hljs-section">everything: all alt</span><br><br><span class="hljs-section">clean:</span><br>${RM} -f ${ENTRY}.o<br><br><span class="hljs-section">clobber: clean</span><br>${RM} -f ${ENTRY}<br><br><span class="hljs-section">nuke: clobber</span><br>@echo gnab gib!<br><br><span class="hljs-section">install:</span><br>@echo <span class="hljs-string">"Surely you're joking Mr. Feynman!"</span><br><br><span class="hljs-comment"># backwards compatibility</span><br><span class="hljs-comment">#</span><br><span class="hljs-section">build: all</span><br><br><br><span class="hljs-comment">##################</span><br><span class="hljs-comment"># 133t hacker rulz</span><br><span class="hljs-comment">##################</span><br><span class="hljs-comment">#</span><br><span class="hljs-section">love:</span><br>@echo 'not war?'<br><br><span class="hljs-section">haste:</span><br><span class="hljs-variable">$(MAKE)</span> waste<br><br><span class="hljs-section">waste:</span><br>@echo 'waste'<br><br><span class="hljs-section">easter_egg:</span><br>@echo you expected to mis-understand this $${RANDOM} magic<br>@echo chongo '<was here>' <span class="hljs-string">"/\\oo/\\"</span><br>@echo Readers shall not be disallowed from being unable to partly misunderstand this final echo.<br>@${TRUE}<br></code></pre></td></tr></table></figure></p><p>简单阅读可以知道,直接运行<code>make</code>得到的结果和<code>gcc hou.c -o hou</code>类似,仅仅是编译选项有所不同。</p><p>对于得到的二进制文件<code>hou</code>,有如下运行结果。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ ./hou 11/26+222/31<br>7.584367<br>$ ./hou <span class="hljs-string">'log((21701-19937)-(23209-21701))/log(2)'</span><br>8.000000<br>$ ./hou <span class="hljs-string">'sin(1.5708)+0.04321+log(sqrt(exp(1*1*1)))+(1+2*3)-0.4-0.6+(4+6)*(2-1+2*3)-tan(0.785398)+2*10/3*6*sqrt(16/2/2)*10+10000-1000'</span><br>9876.543210<br></code></pre></td></tr></table></figure><p>这里体现出了题目科学计算器的功能了,调用这个看起来很像计算器的程序可以进行科学计算。它是如何实现的呢?</p><h2 id="宏展开"><a href="#宏展开" class="headerlink" title="宏展开"></a>宏展开</h2><p>第一步是要抛开宏的伪装,看清楚代码的真实逻辑。</p><p>使用如下指令可以获得宏展开后的代码结果。<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs bash">$ gcc -E hou.c > hou-expanded.c<br></code></pre></td></tr></table></figure><br>对新的文件进行部分整理,得到如下结果。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><math.h></span></span><br><span class="hljs-type">double</span> r;<br><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc,<span class="hljs-type">char</span>** argv)</span>{<br> <span class="hljs-keyword">if</span>(argc<<span class="hljs-number">2</span>){<br> <span class="hljs-keyword">if</span>(argc==<span class="hljs-number">2</span>)<span class="hljs-built_in">printf</span>(<span class="hljs-string">"%f\n"</span>,r);<span class="hljs-keyword">return</span> argc>=<span class="hljs-number">4</span>+ <span class="hljs-number">0</span>;}{<span class="hljs-type">double</span> a;<span class="hljs-type">int</span> b;<span class="hljs-type">char</span> c=(argc<<span class="hljs-number">4</span>?main(<span class="hljs-number">4</span><span class="hljs-number">-19</span>/<span class="hljs-number">26</span>,argv): *argv[<span class="hljs-number">1</span>]*(<span class="hljs-type">int</span>) <span class="hljs-number">11</span>/<span class="hljs-number">26</span>+<span class="hljs-number">222</span>/<span class="hljs-number">31</span> +~~~~~~~~~~~~~~~~~~~~~~~~*argv[<span class="hljs-number">1</span>]*(<span class="hljs-type">int</span>)- ! <span class="hljs-number">7.584</span>)&<span class="hljs-number">15</span>; b=(*argv[<span class="hljs-number">1</span>]%<span class="hljs-number">21</span> +<span class="hljs-number">7</span>)%<span class="hljs-number">9</span>*(<span class="hljs-number">3</span>*<span class="hljs-number">367</span>>>c&<span class="hljs-number">1</span>);c+=<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+<br> ! <span class="hljs-number">1</span>;<span class="hljs-keyword">if</span>(c>=<span class="hljs-number">11</span>){c=<span class="hljs-number">0</span>;<span class="hljs-built_in">sscanf</span>(argv[<span class="hljs-number">1</span>],<span class="hljs-string">"%lf%c"</span>,&r,&c);<span class="hljs-keyword">while</span>(*++argv[<span class="hljs-number">1</span>]-c);} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(argc>=<span class="hljs-number">4</span>&&!main(<span class="hljs-number">4</span>-(*argv[<span class="hljs-number">1</span>]++==<span class="hljs-string">'('</span>),argv))argv[<span class="hljs-number">1</span>]++;g:c+= ! <span class="hljs-number">0</span> ||(r);r=--b?r: - (r);r=--b?r: <span class="hljs-built_in">tan</span> (r);<span class="hljs-keyword">if</span>(argc<<span class="hljs-number">4</span>&&*<span class="hljs-string">"/"</span>==*argv[<span class="hljs-number">1</span>]){a=r;r=main(<span class="hljs-number">4</span><span class="hljs-number">-23</span>/<span class="hljs-number">26</span>,argv)?r*a:r+a;<span class="hljs-keyword">goto</span> g;}c=c |<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+<br> ! <span class="hljs-number">1</span> | <span class="hljs-number">2</span> | <span class="hljs-number">3</span> ||(r);r=--b?r: <span class="hljs-number">1</span>/ (r);r=--b?r: <span class="hljs-built_in">cos</span> (r);<span class="hljs-keyword">if</span>(argc<<span class="hljs-number">4</span>&&*<span class="hljs-string">"*"</span>==*argv[<span class="hljs-number">1</span>]){a=r;r=main(<span class="hljs-number">4</span><span class="hljs-number">-25</span>/<span class="hljs-number">26</span>,argv)?r*a:r+a;<span class="hljs-keyword">goto</span> g;}c=c |<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+<br> ! <span class="hljs-number">4</span> | <span class="hljs-number">5</span> | <span class="hljs-number">6</span> ||(r);r=--b?r: <span class="hljs-built_in">exp</span> (r);r=--b?r: <span class="hljs-built_in">sqrt</span> (r);<span class="hljs-keyword">if</span>(argc<<span class="hljs-number">4</span>&&*<span class="hljs-string">"+"</span>==*argv[<span class="hljs-number">1</span>]){a=r;r=main(<span class="hljs-number">4</span><span class="hljs-number">-27</span>/<span class="hljs-number">26</span>,argv)?r*a:r+a;<span class="hljs-keyword">goto</span> g;}c=c |<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~+<br> ! <span class="hljs-number">7</span> | <span class="hljs-number">8</span> | <span class="hljs-number">9</span> ||(r);r=--b?r: <span class="hljs-built_in">sin</span> (r);r=--b?r: <span class="hljs-built_in">log</span> (r);<span class="hljs-keyword">if</span>(argc<<span class="hljs-number">4</span>&&*<span class="hljs-string">"-"</span>==*argv[<span class="hljs-number">1</span>]){a=r;r=main(<span class="hljs-number">4</span><span class="hljs-number">-29</span>/<span class="hljs-number">26</span>,argv)?r*a:r+a;<span class="hljs-keyword">goto</span> g;}c=c |<br> +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(<span class="hljs-number">0</span><br> );<br> }<br> <span class="hljs-keyword">if</span>(argc==<span class="hljs-number">2</span>)<span class="hljs-built_in">printf</span>(<span class="hljs-string">"%f\n"</span>,r);<span class="hljs-keyword">return</span> argc>=<span class="hljs-number">4</span>+ <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><p>直接编译这个文件依然可以得到想要的结果。</p><p>然后注意如下事实:</p><ol><li><code>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~</code>的结果是0。这需要在类型转换下才能成立,否则会编译报错。</li><li>针对<code>argc</code>的大小进行分析,去除不需要的代码。</li></ol><p>我们可以将代码整理成为<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><stdio.h></span></span><br><span class="hljs-meta">#<span class="hljs-keyword">include</span> <span class="hljs-string"><math.h></span></span><br><span class="hljs-type">double</span> r;<br><span class="hljs-type">int</span> depth = <span class="hljs-number">0</span>;<br><span class="hljs-type">int</span> <span class="hljs-title function_">main</span><span class="hljs-params">(<span class="hljs-type">int</span> argc,<span class="hljs-type">char</span>** argv)</span>{<br> ++depth;<br> <span class="hljs-keyword">if</span>(argc<<span class="hljs-number">2</span>){ --depth; <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>; }<br> <span class="hljs-keyword">if</span> (argc <= <span class="hljs-number">3</span>)<br> {<br> <span class="hljs-type">double</span> a=<span class="hljs-number">0</span>;<span class="hljs-type">int</span> b;<br> <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> jj = <span class="hljs-number">0</span>; jj < depth; ++jj) <span class="hljs-built_in">putchar</span>(<span class="hljs-string">' '</span>);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Enter with argc=%d, argv[1]=%s\n"</span>, argc, argv[<span class="hljs-number">1</span>]);<br> <span class="hljs-type">char</span> c=<span class="hljs-number">1</span>;<br> b=<span class="hljs-number">0</span>;<br> <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> jj = <span class="hljs-number">0</span>; jj < depth; ++jj) <span class="hljs-built_in">putchar</span>(<span class="hljs-string">' '</span>);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Now a=%f, b=%d, c=%d, r=%f\n"</span> ,a, b, c, r);<br> main(<span class="hljs-number">4</span>, argv);<br> g1:c+= <span class="hljs-number">1</span>;<br> <span class="hljs-keyword">if</span>(*<span class="hljs-string">"/"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">4</span>, argv);<br> r=r*a;<br> <span class="hljs-keyword">goto</span> g1;<br> }<br> <span class="hljs-keyword">if</span>(*<span class="hljs-string">"*"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">4</span>, argv);<br> r=r*a;<br> <span class="hljs-keyword">goto</span> g1;<br> }<br> <span class="hljs-keyword">if</span>(*<span class="hljs-string">"+"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">3</span>, argv);<br> r=r+a;<br> <span class="hljs-keyword">goto</span> g1;<br> }<br> <span class="hljs-keyword">if</span>(*<span class="hljs-string">"-"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">3</span>, argv);<br> r=r+a;<br> <span class="hljs-keyword">goto</span> g1;<br> }<br> <span class="hljs-keyword">if</span>(argc==<span class="hljs-number">2</span>)<span class="hljs-built_in">printf</span>(<span class="hljs-string">"%f\n"</span>,r);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"End with a=%f, b=%d, c=%d, r=%f, ret=%d\n"</span> ,a, b, c, r, <span class="hljs-number">0</span>);<br> --depth;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br> }<br><br> <span class="hljs-keyword">if</span> (argc == <span class="hljs-number">4</span>)<br> {<br> <span class="hljs-type">double</span> a=<span class="hljs-number">0</span>;<span class="hljs-type">int</span> b;<br> <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> jj = <span class="hljs-number">0</span>; jj < depth; ++jj) <span class="hljs-built_in">putchar</span>(<span class="hljs-string">' '</span>);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Enter with argc=%d, argv[1]=%s\n"</span>, argc, argv[<span class="hljs-number">1</span>]);<br> <span class="hljs-type">char</span> c=(*argv[<span class="hljs-number">1</span>]*(<span class="hljs-type">int</span>) <span class="hljs-number">11</span>/<span class="hljs-number">26</span>+<span class="hljs-number">7</span>)&<span class="hljs-number">15</span>; <span class="hljs-comment">// number:>=11, else < 11</span><br> b=(*argv[<span class="hljs-number">1</span>]%<span class="hljs-number">21</span> +<span class="hljs-number">7</span>)%<span class="hljs-number">9</span>*(<span class="hljs-number">3</span>*<span class="hljs-number">367</span>>>c&<span class="hljs-number">1</span>); <span class="hljs-comment">// number:0, else, hash</span><br> <span class="hljs-keyword">for</span>(<span class="hljs-type">int</span> jj = <span class="hljs-number">0</span>; jj < depth; ++jj) <span class="hljs-built_in">putchar</span>(<span class="hljs-string">' '</span>);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Now a=%f, b=%d, c=%d, r=%f\n"</span> ,a, b, c, r);<br> <span class="hljs-keyword">if</span>(c>=<span class="hljs-number">11</span>){ <span class="hljs-comment">// number</span><br> c=<span class="hljs-number">0</span>;<br> <span class="hljs-built_in">sscanf</span>(argv[<span class="hljs-number">1</span>],<span class="hljs-string">"%lf%c"</span>,&r,&c); <span class="hljs-comment">// read number and operator, x+</span><br> <span class="hljs-keyword">while</span>(*++argv[<span class="hljs-number">1</span>]-c);<br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(!main(<span class="hljs-number">4</span>-(*argv[<span class="hljs-number">1</span>]++==<span class="hljs-string">'('</span>),argv)) <span class="hljs-comment">// is operator or (</span><br> argv[<span class="hljs-number">1</span>]++;<br> r=--b?r: - (r);<br> r=--b?r: <span class="hljs-built_in">tan</span> (r);<br> <br> r=--b?r: <span class="hljs-number">1</span>/ (r);<br> r=--b?r: <span class="hljs-built_in">cos</span> (r);<br> <br> r=--b?r: <span class="hljs-built_in">exp</span> (r);<br> r=--b?r: <span class="hljs-built_in">sqrt</span> (r);<br> <br> r=--b?r: <span class="hljs-built_in">sin</span> (r);<br> r=--b?r: <span class="hljs-built_in">log</span> (r);<br> <br> <span class="hljs-keyword">if</span>(argc==<span class="hljs-number">2</span>)<span class="hljs-built_in">printf</span>(<span class="hljs-string">"%f\n"</span>,r);<br> <span class="hljs-built_in">printf</span>(<span class="hljs-string">"End with a=%f, b=%d, c=%d, r=%f, ret=%d\n"</span> ,a, b, c, r, <span class="hljs-number">1</span>);<br> --depth;<br> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;<br> }<br>}<br></code></pre></td></tr></table></figure></p><h2 id="基本介绍"><a href="#基本介绍" class="headerlink" title="基本介绍"></a>基本介绍</h2><p>这里添加了相当数量的调试代码。总之这时候代码的主要逻辑就清晰明了了。可以看出,这里的表达式解析算法基本上符合表达式的BNF形式。</p><p>作者将表达式分为两类,分别代表了<code>exp_additive</code>加法表达式和<code>exp_multiplicative</code>乘法表达式。然后利用了如下关系。<br><figure class="highlight xl"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs xl"><span class="hljs-function"><span class="hljs-title">exp_additive</span> -></span> exp_multiplicative ( <span class="hljs-string">"+"</span>|<span class="hljs-string">"-"</span> ) exp_multiplicative<br><span class="hljs-function"><span class="hljs-title">exp_multiplicative</span> -></span> exp_cast ( <span class="hljs-string">"*"</span>|<span class="hljs-string">"/"</span>|<span class="hljs-string">"%"</span> ) exp_cast<br></code></pre></td></tr></table></figure></p><p>其中<code>exp_cast</code>为类型转换表达式。本计算器不支持这一功能,可以认为是单纯的数值。</p><p>在这一基础上,作者还将<code>exp_multiplicative</code>添加了一元运算符的支持。这体现在<code>main(4, argv)</code>函数中对于<code>r</code>的一系列函数操作。使得计算器和编译器不同,可以跳过一元函数调用直接解析表达式。</p><h2 id="详细分析"><a href="#详细分析" class="headerlink" title="详细分析"></a>详细分析</h2><h3 id="argc是什么"><a href="#argc是什么" class="headerlink" title="argc是什么"></a><code>argc</code>是什么</h3><p><code>argc</code>是用来判断当前处理表达式的类型的标志量。</p><div class="table-container"><table><thead><tr><th><code>argc</code></th><th>含义</th></tr></thead><tbody><tr><td>2</td><td>当前处理<code>exp_additive</code>,处理完成后结果保存在<code>r</code>,并输出</td></tr><tr><td>3</td><td>当前处理<code>exp_additive</code>,处理完成后结果保存在<code>r</code></td></tr><tr><td>4</td><td>当前处理<code>exp_multiplicative</code>,处理完成后结果保存在<code>r</code></td></tr></tbody></table></div><h3 id="表达式解析的基本结构"><a href="#表达式解析的基本结构" class="headerlink" title="表达式解析的基本结构"></a>表达式解析的基本结构</h3><p>参阅相关材料,并且对照本文代码,得到如下的解析结构。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">void</span> <span class="hljs-title function_">exp_additive</span><span class="hljs-params">()</span>{<br> <span class="hljs-type">char</span> op;<br> exp_multiplicative();<br> <span class="hljs-keyword">while</span>(<br> (op = OPERATOR( <span class="hljs-string">'+'</span> )) ||<br> (op = OPERATOR( <span class="hljs-string">'-'</span> )) ){<br> get_token();<br> exp_multiplicative();<br> ...<br> }<br> }<br><br> <span class="hljs-type">void</span> <span class="hljs-title function_">exp_multiplicative</span><span class="hljs-params">()</span>{<br> <span class="hljs-type">char</span> op;<br> exp_cast();<br> <span class="hljs-keyword">while</span>(<br> (op = OPERATOR( <span class="hljs-string">'*'</span> )) ||<br> (op = OPERATOR( <span class="hljs-string">'/'</span> )) ||<br> (op = OPERATOR( <span class="hljs-string">'%'</span> )) ){<br> get_token();<br> exp_cast();<br> ...<br> }<br> }<br></code></pre></td></tr></table></figure><p>本文代码基本符合。</p><h3 id="标志量a-b-c的含义"><a href="#标志量a-b-c的含义" class="headerlink" title="标志量a,b,c的含义"></a>标志量a,b,c的含义</h3><p>标志量<code>a</code>主要作用是暂存全局运算结果<code>r</code>,在计算得到新的<code>r</code>之后需要和先前的值合并,得到正确的计算值。比如<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-keyword">if</span>(*<span class="hljs-string">"/"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">4</span>, argv); <span class="hljs-comment">// 更新r的值,为新表达式的值。</span><br> r=r*a; <span class="hljs-comment">// 因为使用了*/,所以需要进行乘法运算。</span><br> <span class="hljs-comment">// 没有使用除法的原因是,在main(4,argv)中将/解析成了一个一元运算符。</span><br> <span class="hljs-keyword">goto</span> g1;<br>}<br></code></pre></td></tr></table></figure><br><code>b</code>,<code>c</code>的作用是使用两个hash表判断当前的字符是数字还是字母或者运算符。<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-comment">/*</span><br><span class="hljs-comment">char ASCII c</span><br><span class="hljs-comment">0 48 11</span><br><span class="hljs-comment">1 49 11</span><br><span class="hljs-comment">2 50 12</span><br><span class="hljs-comment">3 51 12</span><br><span class="hljs-comment">4 52 13</span><br><span class="hljs-comment">5 53 13</span><br><span class="hljs-comment">6 54 14</span><br><span class="hljs-comment">7 55 14</span><br><span class="hljs-comment">8 56 15</span><br><span class="hljs-comment">9 57 15</span><br><span class="hljs-comment">( 40 7</span><br><span class="hljs-comment">) 41 8</span><br><span class="hljs-comment">* 42 8</span><br><span class="hljs-comment">+ 43 9</span><br><span class="hljs-comment">- 45 10</span><br><span class="hljs-comment">/ 47 10</span><br><span class="hljs-comment">*/</span><br><span class="hljs-comment">/*</span><br><span class="hljs-comment">if c >= 11, that is number, b = 0;</span><br><span class="hljs-comment">else</span><br><span class="hljs-comment">char ASCII b</span><br><span class="hljs-comment">( 40 8</span><br><span class="hljs-comment">) 41 0</span><br><span class="hljs-comment">* 42 7</span><br><span class="hljs-comment">+ 43 8</span><br><span class="hljs-comment">- 45 1</span><br><span class="hljs-comment">a 97 2</span><br><span class="hljs-comment">/ 47 3</span><br><span class="hljs-comment">o 111 4</span><br><span class="hljs-comment">p 112 5</span><br><span class="hljs-comment">q 113 6</span><br><span class="hljs-comment">i 105 7</span><br><span class="hljs-comment">g 103 8</span><br><span class="hljs-comment">*/</span><br></code></pre></td></tr></table></figure></p><p>在<code>b</code>的解析式中使用了一个magic number<code>(3*367>>c&1)</code>,作用是进一步限定了代码的范围,让不合适的字母的非零<code>b</code>值归零。具体作用举例如下。<br><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-built_in">sin</span>-> s i n<br>s -> <span class="hljs-number">8</span>*<span class="hljs-number">0</span> -> <span class="hljs-number">0</span><br>i -> <span class="hljs-number">7</span><br>n -> <span class="hljs-number">3</span>*<span class="hljs-number">0</span> -> <span class="hljs-number">0</span><br></code></pre></td></tr></table></figure></p><p>所以<code>sin</code>的关键字符是<code>i</code>,而<code>s</code>的作用被设为<code>0</code>,防止和<code>cos</code>解析混淆。</p><h3 id="main函数的返回值"><a href="#main函数的返回值" class="headerlink" title="main函数的返回值"></a><code>main</code>函数的返回值</h3><p>简单而言,<code>main(3,argv)</code>的返回值为<code>0</code>,<code>main(4,argv)</code>的返回值为<code>1</code>。</p><p>这是为了在某些时候简化代码。</p><h3 id="第一部分的解析"><a href="#第一部分的解析" class="headerlink" title="第一部分的解析"></a>第一部分的解析</h3><p><code>main(3,argv)</code>对应<code>exp_additive</code>的解析。</p><p>我们暂时去掉调试代码。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-keyword">if</span> (argc <= <span class="hljs-number">3</span>)<br>{<br> <span class="hljs-type">double</span> a=<span class="hljs-number">0</span>;<span class="hljs-type">int</span> b;<br> <span class="hljs-type">char</span> c=<span class="hljs-number">1</span>;<br> b=<span class="hljs-number">0</span>;<br> main(<span class="hljs-number">4</span>, argv); <span class="hljs-comment">// 解析exp_multiplicative</span><br>g1:c+= <span class="hljs-number">1</span>;<br><span class="hljs-comment">// 以下对应符号解析exp_additive</span><br><span class="hljs-comment">// 使用goto相当于代码范式中的while循环</span><br> <span class="hljs-keyword">if</span>(*<span class="hljs-string">"/"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">4</span>, argv); <span class="hljs-comment">// 需要一个exp_multiplicative</span><br> r=r*a;<br> <span class="hljs-keyword">goto</span> g1;<br> }<br> <span class="hljs-keyword">if</span>(*<span class="hljs-string">"*"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">4</span>, argv); <span class="hljs-comment">// 需要一个exp_multiplicative</span><br> r=r*a;<br> <span class="hljs-keyword">goto</span> g1;<br> }<br> <span class="hljs-keyword">if</span>(*<span class="hljs-string">"+"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">3</span>, argv); <span class="hljs-comment">// 需要继续解析exp_additive</span><br> r=r+a;<br> <span class="hljs-keyword">goto</span> g1;<br> }<br> <span class="hljs-keyword">if</span>(*<span class="hljs-string">"-"</span>==*argv[<span class="hljs-number">1</span>]){<br> a=r;<br> main(<span class="hljs-number">3</span>, argv); <span class="hljs-comment">// 需要继续解析exp_additive</span><br> r=r+a;<br> <span class="hljs-keyword">goto</span> g1;<br> }<br> <span class="hljs-comment">// 上文中解析新表达式的时候没有自增argv[1],</span><br> <span class="hljs-comment">// 是为了将当前的符号作为一元运算符处理,</span><br> <span class="hljs-comment">// 以便简化/-的解析难度。</span><br> <span class="hljs-keyword">if</span>(argc==<span class="hljs-number">2</span>)<span class="hljs-built_in">printf</span>(<span class="hljs-string">"%f\n"</span>,r);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;<br>}<br></code></pre></td></tr></table></figure><h3 id="第二部分的解析"><a href="#第二部分的解析" class="headerlink" title="第二部分的解析"></a>第二部分的解析</h3><p><code>main(4,argv)</code>对应<code>exp_multiplicative</code>的解析。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><code class="hljs c"> <span class="hljs-keyword">if</span> (argc == <span class="hljs-number">4</span>) {<br> <span class="hljs-type">double</span> a=<span class="hljs-number">0</span>;<span class="hljs-type">int</span> b;<br> <span class="hljs-type">char</span> c=(*argv[<span class="hljs-number">1</span>]*(<span class="hljs-type">int</span>) <span class="hljs-number">11</span>/<span class="hljs-number">26</span>+<span class="hljs-number">7</span>)&<span class="hljs-number">15</span>; <span class="hljs-comment">// number:>=11, else < 11</span><br> b=(*argv[<span class="hljs-number">1</span>]%<span class="hljs-number">21</span> +<span class="hljs-number">7</span>)%<span class="hljs-number">9</span>*(<span class="hljs-number">3</span>*<span class="hljs-number">367</span>>>c&<span class="hljs-number">1</span>); <span class="hljs-comment">// number:0, else, hash</span><br> <span class="hljs-keyword">if</span>(c>=<span class="hljs-number">11</span>){ <span class="hljs-comment">// 当前解析的是数字</span><br> c=<span class="hljs-number">0</span>;<br> <span class="hljs-built_in">sscanf</span>(argv[<span class="hljs-number">1</span>],<span class="hljs-string">"%lf%c"</span>,&r,&c); <span class="hljs-comment">// 读取数字和运算符</span><br> <span class="hljs-keyword">while</span>(*++argv[<span class="hljs-number">1</span>]-c); <span class="hljs-comment">// 前移到运算符的位置</span><br> } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(!main(<span class="hljs-number">4</span>-(*argv[<span class="hljs-number">1</span>]++==<span class="hljs-string">'('</span>),argv))<br> <span class="hljs-comment">// 如果运算符是(,需要解析一个exp_additive</span><br> <span class="hljs-comment">// 否则,将剩下的部分继续作为exp_multiplicative解析</span><br> <span class="hljs-comment">// 而且需要注意,main(4,argv)只能解析一元运算符</span><br> argv[<span class="hljs-number">1</span>]++;<br> <span class="hljs-comment">// 如果运算符是'(',需要跳过配套的')'。使用main的返回值简化代码</span><br><br> <span class="hljs-comment">// 下面是根据b的值判断一元运算符的类型,并且作用上去。</span><br> r=--b?r: - (r);<br> r=--b?r: <span class="hljs-built_in">tan</span> (r);<br> <br> r=--b?r: <span class="hljs-number">1</span>/ (r);<br> r=--b?r: <span class="hljs-built_in">cos</span> (r);<br> <br> r=--b?r: <span class="hljs-built_in">exp</span> (r);<br> r=--b?r: <span class="hljs-built_in">sqrt</span> (r);<br> <br> r=--b?r: <span class="hljs-built_in">sin</span> (r);<br> r=--b?r: <span class="hljs-built_in">log</span> (r);<br> <span class="hljs-keyword">return</span> <span class="hljs-number">1</span>;<br> }<br>}<br></code></pre></td></tr></table></figure><h2 id="代码混淆"><a href="#代码混淆" class="headerlink" title="代码混淆"></a>代码混淆</h2><p>代码混淆的重点在于头部的语句。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-meta">#<span class="hljs-keyword">define</span> clear 1;<span class="hljs-keyword">if</span>(c>=11){c=0;sscanf(_,<span class="hljs-string">"%lf%c"</span>,&r,&c);while(*++_-c);}\</span><br><span class="hljs-meta"> <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span>(argc>=4&&!main(4-(*_++==<span class="hljs-string">'('</span>),argv))_++;g:c+=</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> puts(d,e) return 0;}{double a;int b;char c=(argc<4?d)&15;\</span><br><span class="hljs-meta"> b=(*_%__LINE__+7)%9*(3*e>>c&1);c+=</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> I(d) (r);<span class="hljs-keyword">if</span>(argc<4&&*#d==*_){a=r;r=usage?r*a:r+a;goto g;}c=c</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> return <span class="hljs-keyword">if</span>(argc==2)printf(<span class="hljs-string">"%f\n"</span>,r);return argc>=4+</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> usage main(4-__LINE__/26,argv)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> calculator *_*(int)</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> l (r);r=--b?r:</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> _ argv[1]</span><br><span class="hljs-meta">#<span class="hljs-keyword">define</span> x</span><br></code></pre></td></tr></table></figure><ol><li><code>argv[1]</code>是经常使用的值。<code>#define _ argv[1]</code> 进行一步混淆。</li><li><code>main(3,argv)</code>还是<code>main(4,argv)</code>,使用行号<code>4-__LINE__/26</code>判断。</li><li>一元运算符的运算需要大量格式相似的语句,使用<code>#define l (r);=__b?r:</code>可以和表格内容结合直接生成。表格中有多余的<code>x</code>,使用<code>#define x</code>直接清除。</li><li>二元运算符的循环解析,就是那个<code>goto</code>和后面的语句,使用一个<code>#define I(d)</code>简化。</li><li>返回值需要针对<code>argc</code>的不同而不同,直接使用一个<code>#define return</code>语句完成了三种情况的展开,很精妙。</li><li><code>#define puts(d,e)</code>将函数的头部定义体现了出来。注意这里的<code>d</code>是从<code>usage</code>到<code>7.584</code>的全部部分,<code>e</code>是简单的<code>367</code>。</li><li>代码中的magic number都很好的充当了hash函数的构造,而且magic number本身也是符合数学规律的,很精妙。</li><li><code>clear</code>的作用是判断hash函数的结果,转向进一步的处理。</li><li>代码中充斥着的<code>+</code> <code>~~~~</code> <code>!</code>在展开形式中充当了各表达式的构成部分。同时还可以把计算器的数字部分转化为不影响表达式的部分。比如<code>! 1 | 2 | 3 || ...</code></li><li><code>calculator</code>也是表达式的一部分,提供了强制类型转换。</li></ol><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>至此本份代码的解析基本完成。展开后的代码也可以得到正确的结果,分析部分也基本符合表达式的BNF定义。如果想要进一步得到代码构造的内在逻辑,就不得不更加深入的学习相关领域的知识。今天的分析就到此为止了。</p>]]></content>
<categories>
<category>算法</category>
</categories>
<tags>
<tag>编程</tag>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>SCR,TRIAC,Photo TRIAC-四两拨千斤的光耦隔离电路</title>
<link href="/2022/05/17/TRIAC/"/>
<url>/2022/05/17/TRIAC/</url>
<content type="html"><![CDATA[<p>在先前的一次电子设计中,我使用到了一种利用双向可控硅(TRIAC)控制市电通断的方法。经过一段时间的资料收集,我发现关于这方面的中文资料比较少。这里记录了我的学习结果。</p><span id="more"></span><h2 id="产生问题的电路图"><a href="#产生问题的电路图" class="headerlink" title="产生问题的电路图"></a>产生问题的电路图</h2><p><a href="https://imgtu.com/i/OIKu8A"><img src="https://s1.ax1x.com/2022/05/17/OIKu8A.png" alt="OIKu8A.png"></a></p><p>图中是一个比较典型的MOC3041芯片的应用电路。前一路的光电TRIAC控制了后端的功率TRIAC的G端,从而实现了小电流控制大功率的目的。我们可以看到电路中有许多外加电阻电容和MOS管。它们的作用是什么?为什么TRIAC可以实现控制电流的通断?本文章将一一解答。</p><h2 id="资料现象"><a href="#资料现象" class="headerlink" title="资料现象"></a>资料现象</h2><p>目前可以查到的中文资料基本上集中于可控硅的性质,而较少有涉及到可控硅的内部结构问题。不过还是有几篇文章值得阅读的。同时在英文互联网上我也找到了一些资料,将这些东西整理起来就可以对这些问题进行更加合理的解释了。</p><h2 id="可控硅"><a href="#可控硅" class="headerlink" title="可控硅"></a>可控硅</h2><p>可控硅,英文名Silicon Controlled Rectifier, 也即SCR,硅可控整流器,是一种大功率电器元件,又名晶闸管。在控制系统中,通常用于使用小功率控件控制大功率设备。</p><p>通常使用的可控硅分为<strong>单向可控硅</strong>和<strong>双向可控硅</strong>,而双向可控硅通常称为三端双相可控硅,又名TRIAC,即TRIad AC semiconductor switch。如名字所提示,单向可控硅可以控制单向电流的通断,通常用于直流电的控制或者交流电的整流设备。双向可控硅可以控制双向电流的通断,可以用于控制大功率交流电机。</p><h2 id="单向可控硅"><a href="#单向可控硅" class="headerlink" title="单向可控硅"></a>单向可控硅</h2><h3 id="基本结构"><a href="#基本结构" class="headerlink" title="基本结构"></a>基本结构</h3><p><a href="https://imgtu.com/i/OItZLj"><img src="https://s1.ax1x.com/2022/05/17/OItZLj.png" alt="OItZLj.png"></a></p><p>图中便是典型的单向可控硅的电路符号和半导体层面上的结构示意图。可以靠但单向可控硅由四层不同掺杂的半导体层组成。其中形成了三个PN结,从上到下分别是J1,J2,J3。该半导体器件引出了三个电极,分别将最外层的P型半导体作为元件的A极,将最外层的N型半导体作为元件的K极,将内层的P型半导体作为元件的G极。这样做有如下的理由。</p><h3 id="等效电路"><a href="#等效电路" class="headerlink" title="等效电路"></a>等效电路</h3><p><a href="https://imgtu.com/i/OXctAJ"><img src="https://s1.ax1x.com/2022/05/21/OXctAJ.png" alt="OXctAJ.png"></a></p><p>可以将可控硅的内层半导体分开来等效观察。我们发现左右两个三层半导体结构正好组成了PNP和NPN三极管,它们的等效电路如右图所示。</p><h3 id="电路分析"><a href="#电路分析" class="headerlink" title="电路分析"></a>电路分析</h3><p>预设K点为零电位,我们可以对这个电路进行分析。首先在G端口输入正的变化,经由Q2管的B-C进行放大,再由Q1管的B-C放大,可以发现这是一个正反馈过程。</p><p><a href="https://imgtu.com/i/OX2ZJs"><img src="https://s1.ax1x.com/2022/05/21/OX2ZJs.png" alt="OX2ZJs.png"></a></p><p>添加上需要的负载$R_{Load}$和必要的电压偏置$V_{GK}, V_{AK}$,我们得到了这样的电路图。</p><p>在$V_{GK}$等于零的时候,Q2管处于截止状态。回路中没有电流经过,Q1也处于截止状态。在Q1的BE管上没有压降,$V_{AK}$的电压全部加在Q2管的CE端口。</p><p>当电压$V_{GK}$逐渐抬升的时候,电流$I_{G}$逐渐提高,经过Q2放大得到的电流$I_{C2}$也在提高。回路电流逐渐增加,且呈正反馈趋势。</p><p>在正反馈的作用下,当$V_{GK}$和$I_{G}$提高到某一个值之后,两个三极管将趋于饱和状态。这时等效电路如下。</p><p><a href="https://imgtu.com/i/OXWsxI"><img src="https://s1.ax1x.com/2022/05/21/OXWsxI.png" alt="OXWsxI.png"></a></p><p>我们将所需要的$V_{GK}$和$I_{G}$分别称作<strong>门极触发电压</strong>$V_{GT}$(Gate Trigget Voltage)和<strong>门极触发电流</strong>$I_{GT}$(Gate Trigget Voltage)。前者通常是一个PN结的导通压降。</p><p>这时候由于深度正反馈,即使将$V_{GK}$撤离,两个三极管仍然保持着饱和状态。这时候回路几乎完全导通。</p><p>因此我们推导出了单向可控硅的基本性质,即</p><ul><li>通常情况下处于高阻态状态。</li><li>在GK极施加一定的电压和电流后,AK端口导通,导通压降很小。</li><li>当AK端口导通后,如果AK电流大于<strong>维持电流</strong>$I_H$(Holding current),即使撤离触发电压$V_{GK}$,AK端口仍然保持导通状态。</li></ul><p>我们还可以思考一个问题,如果栅极获得的是反向偏置会怎样?事实上,栅极反向偏置的时候,三极管工作在反向放大状态,即倒置状态。但是值得注意的是,这时候电路中并不存在正向的电流回路,也就是说SCR依旧处于截止状态。那么怎么才能在反向偏置的时候仍然能够正常导通?这时候就要研究双向可控硅的工作原理了。</p><h2 id="双向可控硅"><a href="#双向可控硅" class="headerlink" title="双向可控硅"></a>双向可控硅</h2><p><a href="https://imgtu.com/i/OvV5jg"><img src="https://s1.ax1x.com/2022/05/21/OvV5jg.png" alt="OvV5jg.png"></a></p><p>双向可控硅的符号和单向可控硅的符号相比,可以看成两个单向可控硅的反向连接。这也揭示了双向可控硅TRIAC的重要特点:可以双向导通。</p><p>但是这样的近似并不能很好的解释双向可控硅的工作原理。在半导体层面的解释上,我们将看到T1和T2两个电极并不是完全对称的,因此这里将G极直接引出的做法,实际上是忽略了G极的不同而进行的近似。</p><!-- [![Ovmw90.png](https://s1.ax1x.com/2022/05/21/Ovmw90.png)](https://imgtu.com/i/Ovmw90) --><p><a href="https://imgtu.com/i/OvnG26"><img src="https://s1.ax1x.com/2022/05/21/OvnG26.png" alt="OvnG26.png"></a></p><p>这就是TRIAC的半导体构成。可以看出来,从T1到T2和T2到T1,分别构成了PNPN的四层半导体结构,这便是上文研究过了的单向可控硅。但是看到栅极G,和T1-T2构成的可控硅进行了连接的地方并不是上文讨论的内层P型半导体层。我们很快就来探讨这里面的问题。</p><h3 id="工作环境"><a href="#工作环境" class="headerlink" title="工作环境"></a>工作环境</h3><p>这里需要注意的是,我们讨论施加在G上的信号,是相对于T1极而言的。这一点在半导体层面的讨论时将很有帮助。</p><p>通常TRIAC有四种工作模式,如下</p><ul><li>T2电势高于T1,同时栅极施加正电压。</li><li>T2电势高于T1,同时栅极施加负电压。</li><li>T2电势低于T1,同时栅极施加正电压。</li><li>T2电势低于T1,同时栅极施加负电压。</li></ul><p>这里就发现,只要栅极不是悬空的或者和T1直接相连的(低阻抗相连的),TRIAC都可以进行双向导通。</p><p>但是不同的模式下,TRIAC对栅极电流的敏感程度不同。通常栅极偏置和T2-T1偏置反相时,对电流的敏感程度低一些,而偏置同相的时候,会表现出较高的敏感度,也就更容易激发。其中的原因将在下面进行解释。</p><h3 id="模式一,T2正偏,栅极正向电流"><a href="#模式一,T2正偏,栅极正向电流" class="headerlink" title="模式一,T2正偏,栅极正向电流"></a>模式一,T2正偏,栅极正向电流</h3><p>当栅极电势高于T1极时,栅极电流从G流向T1,经过了P2层和N2层。在这时,P2层将会被充满N2释放出来的电子,这些电子将会在T2和T1的偏置电场作用下流向P2-N1这个PN结区域。我们将这个PN结称为J2结。</p><p>电子达到PN结区域后将在内电场的作用下顺利穿过PN结达到N1区域。同时会有更多空穴为了维持电荷平衡从而从P1区向N1区流动。这个中和的部分发生在N1区。同时会有空穴来到J2结,顺利穿过J2结来到P2区,提高了P2区的电势,从而促进了更多电子通过P2-N2结区达到T1电极。</p><p>总结而言,首先产生了电流N4-P2-N2。在电流进行的过程中产生了附加的电荷移动,使得内电流N1-P2产生,激发了可控硅P1-N1-P2-N2。</p><p>由于工艺设计,流经的电流P1-N1-P2-N2可以很大,导通内阻也很低,满足大多数驱动的要求。</p><h3 id="模式二,T2正偏,栅极反向电流"><a href="#模式二,T2正偏,栅极反向电流" class="headerlink" title="模式二,T2正偏,栅极反向电流"></a>模式二,T2正偏,栅极反向电流</h3><p>从结构图图中可以看出来,G和T1极有着些许对称性。当栅极反偏的时候,首先产生的是电流N2-P2-P4。经过相同的原理,产生了电流P1-N1-P2-N4。</p><p>正如前文所说,在电流P1-N1-P2-N4的作用下,空穴来到P2区,使得PN结P2-N2得到了逐渐提高的正向偏置。因此电流P1-N1-P2-N2也被建立了起来。</p><p>由于工艺设计,电子和空穴更加容易通过N2区进行传导。因此在P2区的电流产生了从P1-N1-P2-N4到P1-N1-P2-N2的转变。因此SCR P1-N1-P2-N2导通。</p><p>总结而言,首先激发了电流P1-N1-P2-N4,使得SCR P1-N1-P2-N2获得了正向偏置,从而引发了SCR的激活,使得电流得以导通。</p><h3 id="模式三,T2反偏,栅极正向电流"><a href="#模式三,T2反偏,栅极正向电流" class="headerlink" title="模式三,T2反偏,栅极正向电流"></a>模式三,T2反偏,栅极正向电流</h3><p>这种情况下,外加电流促进了P2层电势的提高,使得PN结P2-N2得到进一步正偏。因此N2层向P2层发射电子,后者则会有部分被PN结P2-N1捕获,在N1形成负电荷区域。</p><p>与此同时,P2层也在发射空穴达到N1区域。空穴在P1-N1内电场的作用下达到P1区域,在P1区域形成了正电荷区域,吸引N3的电子向P1区域扩散。</p><p>这部分电子自然也会有部分到达P2N1PN结,从而在N1区域吸引更多的空穴穿过P2N1PN结到达N1区域。</p><p>这些奇怪的进程将持续进行,直到SCR P2-N1-P1-N3被导通,从而自然地进行电荷转移。</p><p>当TRIAC被导通的时候,显然,栅极的状态不再那么敏感,可以撤离栅极电势,而导通状态不会改变。</p><p>这时候我们注意到在模式二和模式三中,在N2层上都出现了方向不同的两种电流。相对于模式一而言,这种反向电流使得电势变化相互抵消,相当于负反馈过程。因此要想达到预期的触发电压,需要施加更多的栅极电流。因此我们得出的结论是,模式二和模式三,有着较低的电流敏感度。</p><h3 id="模式四,T2反偏,栅极反向电流"><a href="#模式四,T2反偏,栅极反向电流" class="headerlink" title="模式四,T2反偏,栅极反向电流"></a>模式四,T2反偏,栅极反向电流</h3><p>模式四和模式三有所对称性。这次是由N4层向P2层注入电子,将P2-N4深度正偏。同样地,N4发射的电子被P2N1结捕获,促进了P1N1电流的形成。</p><p>这时SCR P2N1P1N3得到了足够的激励而被启动。这个过程可以看作是正反馈过程,其中电流的增加促进了PN结P2N1的进一步正偏,提高了通过的电流。</p><h3 id="V-I特性"><a href="#V-I特性" class="headerlink" title="V-I特性"></a>V-I特性</h3><p>事实上从微观层面没有无法逾越的鸿沟。即使TRIAC处于截止状态,依然会有少量的漏电流的存在。因此,如果T2-T1进行足够大的偏置,也是可以将TRIAC直接导通,而不需要考虑栅极情况的。这个最大的电压被称为<strong>击穿电压</strong>(Breakover voltage)。查阅相关资料后可以得到如下的V-I特性曲线。</p><p><img src="https://www.electronicshub.org/wp-content/uploads/2015/05/71.jpg" alt="electronicshub.org/triac"></p><p>因此可以得到,在TRIAC已经导通,而且栅极激励已经移除的情况下,将TRIAC截止的几种方法:</p><ul><li>中断T2T1之间的电压,使之短路或断路。</li><li>改变T2T1的电压极性(交流电自然满足)。</li><li>将T2T1之间的电流降低到维持电流以下。</li></ul><p>所以在交流电控制时,栅极激励的有无可以直接控制电流的通断。</p><h3 id="三极管视角下的反向栅极电流"><a href="#三极管视角下的反向栅极电流" class="headerlink" title="三极管视角下的反向栅极电流"></a>三极管视角下的反向栅极电流</h3><p>之前我们在介绍反向栅极电流的时候,提到了它的主要工作原理是利用电流改变电势从而引起主要SCR的触发。在这个思路上我们可以画出等效的三极管电路图。</p><p><a href="https://imgtu.com/i/OvHwiq"><img src="https://s1.ax1x.com/2022/05/22/OvHwiq.png" alt="OvHwiq.png"></a></p><p>当栅极出现反向电流的时候,事实上是导通了Q3这个三极管,从而给其中的等效电容充电。当电容充电到一定程度时,可以使Q2达到放大模式,从而触发了中间部分的SCR。</p><p>这其实就是前文中对”电势上升”的解释。半导体器件工作在不同状态时可以给出不同的模型,在分析的时候需要灵活变通。</p><h2 id="光耦可控硅"><a href="#光耦可控硅" class="headerlink" title="光耦可控硅"></a>光耦可控硅</h2><p>前文的TRIAC需要一定的电压电流才能触发。通常我们使用的控制元件,如MCU、PLC、FPGA等器件无法直接满足这样的触发条件。另一方面我们需要做到前后端隔离,尽可能减少处理器的损坏,同时保证操作员的安全。</p><p>在这样的目的支持下,使用其他的方式来获得TRIAC的栅极触发条件便成为了研究的目的。在半导体行业十分著名的隔离方法便是光电隔离。经过一定工艺处理,半导体器件可以获得足够的光敏感性,从而达到光触发的目的。</p><p><a href="https://imgtu.com/i/OvbN6O"><img src="https://s1.ax1x.com/2022/05/22/OvbN6O.png" alt="OvbN6O.png"></a></p><p>这是前文的电路图中出现过的MOC30系列的光耦可控硅的原理图。可以注意到其中有一个发光二极管、一个<code>CIRCUIT</code>和一个讨论过了的TRIAC。这里的TRIAC经过了特殊设计,需要在紫外线和栅极的共同作用下才能导通。</p><p>工作原理也是十分简单,只要发光二极管导通,发出紫外线使TRIAC被激活,等到<code>CIRCUIT</code>部分发出信号即可完成导通。</p><p><code>CIRCUIT</code>部分其实值得更多的讨论。光耦可控硅的主要分类就是在这里进行的。主要的两种触发方式是零点触发和随机相位触发。</p><p><strong>零点触发</strong>,Zero-Cross,ZC,是指只有在二次侧交流电达到零点的时候才能导通TRIAC。这样做是考虑到了负载电路的电感效应和高电压的特性。在电压为零时,导通后,通常电流会处于一个比较低的水平,甚至可能是没有电流。这样做对负载电路的影响最小,也不会产生电火花等危险情况。</p><p><strong>随机相位触发</strong>,Random-Phase,RP,是指允许在二次侧交流电在任意相位的时候触发TRIAC。通常用于工作条件温和的交流电外设,如灯具调光器、温度控制器和小型马达。随机相位触发允许在交流电的任何一个相位触发,因此输出的电压波形通常为缺角的正弦波,存在高次谐波。</p><h2 id="综合电路分析"><a href="#综合电路分析" class="headerlink" title="综合电路分析"></a>综合电路分析</h2><p><a href="https://imgtu.com/i/OIKu8A"><img src="https://s1.ax1x.com/2022/05/17/OIKu8A.png" alt="OIKu8A.png"></a></p><p>终于,我们回到了这个电路。现在我们可以对它进行分析了。</p><p>先从一次侧开始讨论。我们知道,要想导通二极管,需要给出一定的压降和电流通道。为了保护MCU的端口,我们添加了NMOS作为电流通路,防止电流灌入MCU中。其中R19和R22作为限流电阻存在,防止电流过大损坏器件。</p><p>在二次侧,我们看到了熟悉的TRIAC。其中让我们费解的是R18和R23这两个2512的电阻,和后端的一个RC电路。</p><p>RC电路的出现是为了减少负载的电抗效应将TRIAC误触发。考虑感性负载,电流落后于电压。电流变为零时,TRIAC应当正常截止。但是这时候电压不为零,直接施加在了TRIAC两端。如果这个电压超过一定额度,就会使TRIAC内部的结间电荷没有能够及时释放,从而无法进入截止状态。添加的RC电路正是提供了容性回路,使得电压迅速释放。</p><p>但是考虑感性不是那么大的负载,在TRIAC截止的时候,RC电路会保持一定的压降,反而可能触发TRIAC,违背了我们的意愿。所以通常RC电路的C会选择较小值,如电路图中为10nF的薄膜电容。</p><p>RC电路能不能去除呢?其实RC电路还有另一种作用,那就是过电压吸收。因为负载的电抗效应,在适当的条件下,负载电压可能出现一定的过冲。这时候RC电路就可以吸收一部分电荷,从而减缓电压的上升,实现TRIAC的过压保护。</p><p>R18可以在极端情况下对光耦TRIAC进行保护。假设在二次侧电压峰值处光耦被导通,光耦最大峰值驱动电流为1A,则</p><script type="math/tex; mode=display">R_{18} = \frac{V_{Peak}}{I_{Peak}} = \frac{220\sqrt{2}}{1} \approx 311 \mathrm{\Omega}</script><p>电路中使用的电阻是360$\mathrm{\Omega}$,也算是一个比较合格的保护电路。</p><p>同时注意到TRIAC栅极事实上存在着电容效应。如果光耦TRIAC截止,同时电路中不存在R23的话,栅极将处于浮空状态,电感效应会使得栅极处于随机触发的状态,这不符合我们的预期效果。</p><p>所以R23被添加在电路中,在光耦TRIAC截止的时候将栅极拉低。</p><p>回过头来,我们发现光耦TRIAC导通的时候,这个电阻依然存在,而且会分走栅极的电流。这时候就需要理论计算来得到合适的阻值了。</p><p>假设TRIAC需要$I_{GT},V_{GT}$才能正常触发导通,在R18上经过的电流为</p><script type="math/tex; mode=display">I_{R18} = I_{GT} + I_{R23} = I_{GT} + \frac{V_{GT}}{R_{23}}</script><p>在电阻R18上的压降变成了</p><script type="math/tex; mode=display">V_{R18} = \left(I_{GT} + \frac{V_{GT}}{R_{23}}\right)R_{18}</script><p>假设T2T1电压为$V_T$,光耦TRIAC的导通压降为$V_{TM}$,考虑回路就有电压关系</p><script type="math/tex; mode=display">V_T = V_{R18} + V_{TM} + V_{GT}</script><p>根据光耦TRIAC的数据手册和功率TRIAC的数据手册提供的导通压降和触发电压电流大小即可确定合适的R23电阻值。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文参考了多种参考资料,从零开始讨论了SCR、TRIAC、Photo TRIAC的基本性质,目的是对一个常见的交流电控制电路进行分析。</p><p>本文写作时间紧迫,如若发现其中的分析错误、逻辑错误或者笔误,欢迎邮件联系讨论。本人文化水平不高,出现错误请予以谅解,本人会认真听从意见并更正。</p><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p>正文的单向可控硅的原理介绍参考了<a href="https://www.cnblogs.com/sunshine-jackie/p/8137469.html">可控硅工作原理及参数详解</a>。这是一篇十分详细的文章,学过模电的同学就可以从学到不少东西。</p><p>正文中的双向可控硅的原理介绍参考了文章<a href="https://www.electronicshub.org/triac/">ElectronicsHub TRIAC</a>。这是一篇不错的科普读物。</p><p>Everlight公司提供的光电TRIAC的资料,提供了更加详细的特性解释。<a href="https://www.everlight.com/wp-content/uploads/2021/10/Photo-TRIAC%E7%9A%84%E7%89%B9%E6%80%A7%E8%88%87%E6%87%89%E7%94%A8%E4%BB%8B%E7%B4%B9_Ver1.0%E7%B9%81.pdf">Photo TRIAC的特性與應用介紹</a></p><p>光耦可控硅的资料也来自MOC30系列的datasheet,我不记得在哪里下载了。搜索MOC3041就可以找到。</p><p>同时也少不了一个国内致力于可控硅方向的网站提供的文档,<a href="http://www.KKG.com.cn">对双向可控硅内部电路的探讨</a>。该文档可以在网站内搜索标题得到下载地址。</p>]]></content>
<categories>
<category>电子设计</category>
</categories>
<tags>
<tag>电子设计</tag>
</tags>
</entry>
<entry>
<title>步进电机-相数、拍数和步距角的相关计算</title>
<link href="/2022/05/02/stepmotor/"/>
<url>/2022/05/02/stepmotor/</url>
<content type="html"><![CDATA[<p>这里梳理步进电机的相关计算问题。</p><span id="more"></span><h2 id="基本概念"><a href="#基本概念" class="headerlink" title="基本概念"></a>基本概念</h2><p>本课程中主要强调了的是磁阻式步进电机。磁阻式步进电机的力矩来源于磁路使磁阻最小的能力。下面是一个四相步进电机的图例。</p><p><a href="https://imgtu.com/i/OFF76J"><img src="https://s1.ax1x.com/2022/05/02/OFF76J.png" alt="OFF76J.png"></a></p><p>步进电机分为定子和转子两大部分。定子主要需要注意的是磁极。对于$p$相步进电机,通常定子中有$2p$个绕组,也就是$2p$个磁极。也就是说,绕组数等于磁极数。每一相有两个绕组,位于直径的两端。</p><p>磁极表面有均匀分布的小齿。转子上也均匀分布着小齿。但是二者数目不是一一对应的。</p><p><a href="https://imgtu.com/i/OFAEr9"><img src="https://s1.ax1x.com/2022/05/02/OFAEr9.png" alt="OFAEr9.png"></a></p><p><strong>齿距角</strong>的定义是相邻两齿中心线的夹角,设$Z_r$位转子齿数,有齿距角$\theta_t$</p><script type="math/tex; mode=display">\theta _t = \frac{360^{o}}{Z_r}</script><p>对于转子齿数的规定是,要求转子转动一半时(即转子从同一相的一个磁极转到了同一相的另一个磁极),定子和转子的齿数相差1。换用课本上的话说,就是</p><blockquote><p>相邻磁极下的定子转子齿之间错开转子齿距角的$\frac{1}{m}$倍。</p></blockquote><p>注意到$m=p$,所以上面两种定义是相同的。写成数学语言便是</p><script type="math/tex; mode=display">\frac{Z_r}{2p} = K \pm \frac{1}{m}</script><script type="math/tex; mode=display">Z_r = 2pK \pm 2</script><p>因此每一个极距下的转子齿数不是整数。这里正负号通常使转子齿数多一点,即正号。</p><h2 id="拍数和步距角"><a href="#拍数和步距角" class="headerlink" title="拍数和步距角"></a>拍数和步距角</h2><p>步进电机的控制通常为一个周期$N$个通电状态。在一个周期中,步进电机各绕组的不同通电状态的数量成为<strong>拍数</strong>。</p><p>根据同步电动机的相关知识,每个通电周期之后,步进电机的定子磁场将旋转半周。相应的转子和定子之间的小齿也将在半周内进行同步。因为上面规定了转子和定子齿数的关系,所以<strong>每个通电周期转子转过一个齿距角</strong>。</p><p><strong>步距角</strong>的定义是,改变一次通电状态,转过的角度。假设一个通电周期有$N$拍,那么步距角$\theta_b$</p><script type="math/tex; mode=display">\theta_b = \frac{\theta_t}{N} = \frac{360^{o}}{Z_rN}</script><h2 id="常见的通电模式"><a href="#常见的通电模式" class="headerlink" title="常见的通电模式"></a>常见的通电模式</h2><p>以四相步进电机为例。常见的通电模式为四相单四拍、四相双四拍、四相八拍。</p><p>四相单四拍的通电规律为</p><script type="math/tex; mode=display">A \rightarrow B \rightarrow C \rightarrow D \rightarrow \dots</script><p>四相双四拍的通电规律为</p><script type="math/tex; mode=display">AB \rightarrow BC \rightarrow CD \rightarrow DA \rightarrow \dots</script><p>四相八拍的通电规律为</p><script type="math/tex; mode=display">A\rightarrow AB \rightarrow B\rightarrow BC \rightarrow C\rightarrow CD \rightarrow D\rightarrow DA \rightarrow \dots</script><p>其中有拍数和相数的关系</p><script type="math/tex; mode=display">N=km</script><p>$k$的值为1时,称其为单拍制,为2时,称其为双拍制。可以看到,四相单四拍和四相双四拍均为单拍制,而四相八拍为双拍制。</p><p>单拍制下,步距角为$\displaystyle \frac{1}{m}$的齿距角,双拍制下步距角为$\displaystyle \frac{1}{2m}$的齿距角。</p><h2 id="引入电角度"><a href="#引入电角度" class="headerlink" title="引入电角度"></a>引入电角度</h2><p>和之前的电机不同,步进电机中电角度等于转子齿数乘以机械角度,即</p><script type="math/tex; mode=display">\theta _e = Z_r\theta</script><p>那么齿距角应该是</p><script type="math/tex; mode=display">\theta_{te} = \frac{360^{o}}{Z_r}Z_r = 2\pi \mathrm{rad}</script><p>步距角自然是</p><script type="math/tex; mode=display">\theta_{be} = \frac{2\pi}{N}</script><h2 id="研究力矩"><a href="#研究力矩" class="headerlink" title="研究力矩"></a>研究力矩</h2><p>转矩是失调角的周期函数,周期为转子的一个齿距角,即$2\pi$rad电角。</p><p>单相通电的时候,静态力矩的基波分量为</p><script type="math/tex; mode=display">T = -T_m\sin(\theta_e - \theta_{e0})</script><p><a href="https://imgtu.com/i/OFZAKg"><img src="https://s1.ax1x.com/2022/05/02/OFZAKg.png" alt="OFZAKg.png"></a></p><p>这时的力矩是否为稳定平衡?图中标识了稳定平衡点,这里取了$\theta_{e0}=0$。总之齿正好对齐的时候最稳定。</p><p>多相通电的时候,就需要考虑不同相之间的电角差距了。</p><p>电角的差距应该和步距角相同,那么在$m$相步进电机$n$相同时通电时,静态转矩应该为</p><script type="math/tex; mode=display">\begin{aligned}T &= \sum_{i}^{n}T_i \\&= T_m\sum_{i=1}^{n}\sin(\theta_e - (i-1)\theta_{be})\\&= -T_m\frac{\sin\dfrac{n\theta_{be}}{2}}{\sin\dfrac{\theta_{be}}{2}}\sin(\theta_e-\frac{n-1}{2}\theta_{be}) \\\end{aligned}</script><p>单拍制下,步距角有公式</p><script type="math/tex; mode=display">\theta_{be} = \frac{2\pi}{m}</script><p>所以最大静转矩为</p><script type="math/tex; mode=display">\frac{T_{m(n)}}{T_m} = \frac{\sin{\dfrac{n\pi}{m}}}{\sin\dfrac{\pi}{m}}</script><h2 id="启动转矩"><a href="#启动转矩" class="headerlink" title="启动转矩"></a>启动转矩</h2><p>接下来考虑启动转矩。</p><p><a href="https://imgtu.com/i/OFe1Yt"><img src="https://s1.ax1x.com/2022/05/02/OFe1Yt.png" alt="OFe1Yt.png"></a></p><p>正常启动需要让<strong>相邻通电状态的合成转矩大于负载转矩</strong>。这是因为在正常的通电切换时,不同的通电状态是合成的正弦波,因此力矩最小值通常在切换时取得。</p><p>计算启动力矩,需要先得到步距角$\theta_{be}$,因为相邻的磁极的相位差即为步距角。</p><p>如果是单相通电,如四相单四拍,那么要考虑的是$\sin(\theta_e)$和$\sin(\theta_e - \theta_{be})$的交点,即</p><script type="math/tex; mode=display">T_{start1} = T_m\sin(\dfrac{\pi}{2} + \dfrac{\theta_{be}}{2})</script><p>其中$\dfrac{\pi}{2}$是因为取最高点后面的第一个交点,二分之一的步距角是两个三角函数的交点距离最高点的相位差。</p><p>如果是双相通电,如四相双四拍,那么就要考虑两项通电时候的合成磁场。</p><script type="math/tex; mode=display">T_{AB} = -T_m(\sin(\theta_e) + \sin(\theta_e - \theta_{be}))</script><script type="math/tex; mode=display">T_{BC} = -T_m(\sin(\theta_e - \theta_{be}) + \sin(\theta_e - 2\theta_{be}))</script><p>为了取交点,让$T_{AB}=T_{BC}$,得到</p><script type="math/tex; mode=display">\sin(\theta_e) = \sin(\theta_e - 2\theta_{be})</script><p>通常让$\theta_e$在$[0,\pi]$区间中,得到$\theta_e = \pi$</p><p>那么将该数值带进$T_{AB}$得到$T_m$,即为启动转矩。</p><p>如果是四相八拍,这时候注意步距角发生了变化,但是计算的步距角依然采取的是单拍的步距角。同样是进行合成</p><script type="math/tex; mode=display">T_{A} = -T_m\sin(\theta_e)</script><script type="math/tex; mode=display">T_{AB} = -T_m(\sin(\theta_e) + \sin(\theta_e - \theta_{be}))</script><!-- $$T_{ABC} = -T_m(\sin(\theta_e) + \sin(\theta_e - \theta_{be}) + \sin(\theta_e - 2\theta_{be}))$$ --><p>令它们相等得到$\sin(\theta_e - \theta_{be}) = 0$,可以取$\theta_e = \dfrac{\pi}{2}$,得到起动转矩为$T_m$。</p><p>这里问题是步距角为什么取的是单拍的步距角?很简单,因为磁极的物理结构要求的偏差为$\dfrac{2\pi}{m}$,正好是单拍的步距角。所以这里的步距角其实是磁极的相位差,数值上等于单拍步距角而已。这个数值的来历是$\dfrac{2\pi}{m} \times m = 2\pi$,即经过$m$个磁极后相角相差$2\pi$,也就是相差一个齿!这正是上文的要求。</p><p>对于五相步进电机,上面求得的电角度分别是$0.7\pi$,$0.9\pi$,$0.8\pi$,求得到的转矩分别为$0.81T_m$,$1.30T_m$,$1.54T_m$。</p><h2 id="感想"><a href="#感想" class="headerlink" title="感想"></a>感想</h2><p>步进电机的原理很简单,但是计算题想要算对算好还是需要扣细节的。</p><h2 id="题外话"><a href="#题外话" class="headerlink" title="题外话"></a>题外话</h2><p>我写这篇笔记是因为我上课没听,而同时把这些角度全部搞混了,所以写不来作业题。很惭愧,上课摸鱼了造成这个悲剧…</p><p>如果以后接着上课摸鱼,恐怕需要摸出来许许多多的课程笔记…</p><p>还有其他的知识点我没有写,因为作业里没有。遇到了再整理。</p><h2 id="图片来源"><a href="#图片来源" class="headerlink" title="图片来源"></a>图片来源</h2><p>本文图片来自《自动控制元件及线路》,系本课程课本。如有侵权我会及时删除。</p>]]></content>
<categories>
<category>电机</category>
</categories>
<tags>
<tag>课内复习</tag>
<tag>电子设计</tag>
<tag>电机</tag>
</tags>
</entry>
<entry>
<title>在网页上使用TikZ!</title>
<link href="/2022/04/30/TikzInWeb/"/>
<url>/2022/04/30/TikzInWeb/</url>
<content type="html"><![CDATA[<p>TikZ是LaTeX users极为热爱的绘图工具。基于LaTeX,编程化的排版语言,TikZ在诸多图形绘制中相比传统的计算机绘制方法有较大优势。这里介绍几种网页中绘制图形的方法。</p><span id="more"></span><h2 id="直接截图"><a href="#直接截图" class="headerlink" title="直接截图"></a>直接截图</h2><p>这恐怕是绝大多数网友使用的方法。使用多种绘图软件绘制图形,然后通过保存或者截图工具获得图像,放入图床网站然后导入网页中。<br>这种方法不免有所繁琐,但是这是需要前置知识最少的方法,简单粗暴。</p><h2 id="使用广泛的JS绘图库"><a href="#使用广泛的JS绘图库" class="headerlink" title="使用广泛的JS绘图库"></a>使用广泛的JS绘图库</h2><p>有一些特定的图表,已经被他人实现并编写成<code>JavaScript</code>库可供使用,例如</p><ul><li><a href="http://flowchart.js.org/">flowchart.js</a>提供了流程图(Flow Chart)的绘图工具</li><li><a href="https://bramp.github.io/js-sequence-diagrams/">JS-Sequence</a>提供了时序图(Sequence DIagrams)的绘图工具</li><li><a href="https://mermaid-js.github.io/mermaid/#/">mermaid</a>提供了甘特图、类图等常见图形的绘制方法</li></ul><p>这些在许多<code>Markdown</code>插件中已经移植过了,比如<code>Markdown Preview Enhanced</code>。但是毕竟网页上的显示方法和本地的<code>Markdown</code>插件还是有区别的。为了更好的视觉效果,自主在网页中添加上述库也是没有什么坏处的。有可能加载速度会变慢?本网站部署在<code>GitPages</code>上,加载速度本来就慢,无所谓了。</p><h2 id="使用TikZJax在网页中加载TikZ"><a href="#使用TikZJax在网页中加载TikZ" class="headerlink" title="使用TikZJax在网页中加载TikZ"></a>使用TikZJax在网页中加载TikZ</h2><p>这才是本篇杂谈的重点内容。<code>TikZJax</code>的工作原理是,将<code>TeX</code>代码交由<code>Web2js</code>编译,将编译结果转换成<code>svg</code>插入网页,从而实现了在网页中加载<code>TikZ</code>的功能。</p><p>要想使用本功能,需要在HTML的<code><head></code>区域加载如下代码</p><figure class="highlight html"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></div></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/css"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"http://tikzjax.com/v1/fonts.css"</span>></span><br><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"http://tikzjax.com/v1/tikzjax.js"</span>></span><span class="hljs-tag"></<span class="hljs-name">script</span>></span><br></code></pre></td></tr></table></figure><p>然后就可以使用如下代码框架绘制图形了。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs html"><span class="hljs-tag"><<span class="hljs-name">script</span> <span class="hljs-attr">type</span>=<span class="hljs-string">"text/tikz"</span>></span><br> \begin{tikzpicture}<br> \draw (0,0) circle (1in);<br> \end{tikzpicture}<br><span class="hljs-tag"></<span class="hljs-name">script</span>></span><br></code></pre></td></tr></table></figure><p>如果网络连接良好,可以得到渲染图如下。</p><script type="text/tikz"> \begin{tikzpicture} \draw (0,0) circle (1in); \end{tikzpicture}</script><p>值得注意的是,该程序使用的<code>TeX</code>有如下内容</p><figure class="highlight tex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs tex"><span class="hljs-keyword">\documentclass</span>[margin=0pt]{standalone}<br><span class="hljs-keyword">\def</span><span class="hljs-keyword">\pgfsysdriver</span>{pgfsys-ximera.def}<br><span class="hljs-keyword">\usepackage</span>{tikz}<br></code></pre></td></tr></table></figure><p>所以目前是无法使用其他<code>TikZ</code>宏包的。这是从一个使用者的角度出发的。学习知识并改善之是当前互联网精神的重要内核之一。将来会仔细研究相关知识,现在就先用着简单功能吧!</p>]]></content>
<categories>
<category>LaTeX</category>
</categories>
<tags>
<tag>LaTeX</tag>
<tag>杂谈</tag>
</tags>
</entry>
<entry>
<title>数理方程复习-分离变量法</title>
<link href="/2022/04/30/EquationsCP01/"/>
<url>/2022/04/30/EquationsCP01/</url>
<content type="html"><![CDATA[<p>分离变量法通常适用于条件齐全的混合问题。齐次方程的分解较为容易,非齐次方程的求解需要更多的处理。<br><span id="more"></span></p><h2 id="基本步骤"><a href="#基本步骤" class="headerlink" title="基本步骤"></a>基本步骤</h2><p>第一步:分离变量。根据变量的多少进行变量的分离</p><script type="math/tex; mode=display">u(t,x) = X(x)T(t)</script><script type="math/tex; mode=display">u(t,x,y,z) = X(x)Y(y)Z(z)T(t)</script><p>以如下问题为例完成基本步骤的讲解:</p><script type="math/tex; mode=display">\begin{cases}\displaystyle\frac{\partial^2 u}{\partial t^2} = a^2 \frac{\partial^2 u}{\partial x^2}, (x \in (0,l), t > 0) \\u(t,0) = u(t,l) = 0 \\u(0,x) = \varphi(x),u_t(0,x) = \psi(x)\end{cases}</script><p>将上面的 $ u(t,x) = X(x)T(t) $带入方程得到</p><script type="math/tex; mode=display">\frac{T^{''}(t)}{a^2T(t)} = \frac{X^{''}(x)}{X(x)} = -\lambda</script><p>其中$\lambda$是我们设定的值,称为<strong>固有值</strong>。我们会根据给出的条件,确定固有值的所有可能取值,从而得到相应的<strong>固有函数</strong>。因为初始条件和边界条件的存在,固有值一般不会是全体实数,那么固有函数系通常是可数的,方程的解也就可以表示成级数形式。</p><p>第二步:解固有值问题</p><p>根据条件的多少确定从哪个变量中求解出固有值的取值。通常是从边界条件入手,即</p><script type="math/tex; mode=display">\begin{cases}X^{''}(x) + \lambda X(x) = 0, (x \in (0, l)) \\X(0) = X(l) = 0 \\\end{cases}</script><p>分三种情况讨论:$\lambda > 0, \lambda < 0, \lambda = 0$。许多问题都会让你错在$\lambda = 0$的情况上。所以实际解题的时候必须将三种情况全部讨论完全,防止漏解。</p><p>本问题中得到的解为</p><script type="math/tex; mode=display">\lambda = \left(\frac{n\pi}{l}\right)^2, n = 1,2,\dots</script><script type="math/tex; mode=display">X_n(x) = B_n \sin\frac{n \pi x}{l}</script><p>将固有值带入$T$的常微分方程中,有</p><script type="math/tex; mode=display">T_n(t) = C_n \cos \frac{n \pi at}{l} + D_n \sin \frac{n \pi at}{l}</script><p>所以求得上式的解为</p><script type="math/tex; mode=display">u_n(t,x) = X_n(x)T_n(t) = \left(C_n \cos \frac{n \pi at}{l} + D_n \sin \frac{n \pi at}{l}\right)\sin\frac{n \pi x}{l}</script><p>第三步,将上述解进行级数叠加</p><script type="math/tex; mode=display">u(t,x)=\sum_{n=1}^{+\infty}u_n(t,x) =\sum_{n=1}^{+\infty} \left(C_n \cos \frac{n \pi at}{l} + D_n \sin \frac{n \pi at}{l}\right)\sin\frac{n \pi x}{l}</script><p>第四步,利用初始条件确定系数</p><script type="math/tex; mode=display">C_n = \frac{\left<\varphi(x), u_n(0,x)\right>}{\left<u_n(0,x), u_n(0,x)\right>}</script><p>这里实际上就是傅里叶展开后求出系数的过程。分母上是项的大小,即项和自己的内积。分子上是条件给定的函数和项的内积。它们的比值则确定了系数的大小。</p><p>这里我们看到的是很常见的展开系,它对应的内积是</p><script type="math/tex; mode=display">\newcommand{\d}{\mathrm{d}}\newcommand{\e}{\mathrm{e}}\left<f, g\right> = \int^{l}_{0} f(x)g(x)\d x</script><p>后面复习的施刘定理将确定任何可行的固有函数系的内积关系。</p><h2 id="极坐标系下-Delta-2-u-0-的边值问题"><a href="#极坐标系下-Delta-2-u-0-的边值问题" class="headerlink" title="极坐标系下$\Delta_2 u = 0$的边值问题"></a>极坐标系下$\Delta_2 u = 0$的边值问题</h2><p>问题的形式为</p><script type="math/tex; mode=display">\Delta_2 u = \frac{\partial^2 u}{\partial r^2} + \frac{1}{r}\frac{\partial u}{\partial r} = \frac{1}{r^2}\frac{\partial^2 u}{\partial \theta^2} = 0</script><p>令</p><script type="math/tex; mode=display">u(r,\theta) = R(r)\Theta (\theta)</script><p>带入得到</p><script type="math/tex; mode=display">r^2 R^{''}(r) + rR^{'}(r) - \lambda R(r) = 0</script><p>和关于$\Theta(\theta)$的固有值问题</p><script type="math/tex; mode=display">\begin{cases}\Theta^{''}+\lambda \Theta = 0 \\\Theta(\theta) = \Theta(\theta + 2\pi)\end{cases}</script><p>通常还会根据题目条件进一步限定上述方程的条件。</p><p>下面只给出最一般情况下的解。注意到$R(r)$的方程是一个欧拉方程,做代换$t=\ln r$即可求解。我们得到了如下的通解</p><script type="math/tex; mode=display">u(r,\theta) = A_0 + B_0\ln r + \sum_{k = 1}^{+\infty}(A_kr^k + B_kr^{-k})(C_k \cos k \theta + D_k \sin k \theta)</script><p>在问题限定范围比较宽的时候可以直接使用,否则需要重新进行分离变量将上述问题求解。</p><h2 id="施刘定理"><a href="#施刘定理" class="headerlink" title="施刘定理"></a>施刘定理</h2><h3 id="施刘定理的作用"><a href="#施刘定理的作用" class="headerlink" title="施刘定理的作用"></a>施刘定理的作用</h3><ol><li>推导出固有函数和固有值的相关性质</li><li>是固有函数和固有值的形式能够<strong>多样化</strong>,不局限于先前的三角函数系</li><li>得到固有函数系的内积</li></ol><h3 id="施刘定理的具体形式"><a href="#施刘定理的具体形式" class="headerlink" title="施刘定理的具体形式"></a>施刘定理的具体形式</h3><p>假设有方程</p><script type="math/tex; mode=display">b_0(x)y^{''}(x) + b_1(x)y^{'}(x) + b_2(x)y(x) + \lambda y(x) = 0</script><p>取函数$\rho(x)$满足关系式</p><script type="math/tex; mode=display">\newcommand{\d}{\mathrm{d}}\newcommand{\e}{\mathrm{e}}\rho(x) = \frac{1}{b_0(x)}\exp\left\{\int\frac{b_1(x)}{b_0(x)}\d x\right\}</script><p>其中的不定积分一般取最简的函数形式,或者使$\rho(x)$最简的函数形式。</p><p>那么有性质</p><script type="math/tex; mode=display">\left(\rho(x)b_0(x)\right)^{'} = \rho(x)b_1(x)</script><p>这个性质将在接下来的操作中发挥作用。</p><p>在原方程的两边同乘$\rho(x)$,可以得到</p><script type="math/tex; mode=display">\left[\rho(x)b_0(x)y^{'}(x)\right]^{'} + b_2(x)\rho(x)y^{'}(x) + \lambda\rho(x)y(x) = 0</script><p>为了简化方程,令$k(x)=\rho(x)b_0(x), -q(x) = b_2(x)\rho(x)$,有</p><script type="math/tex; mode=display">\left[k(x)y^{'}(x)\right]^{'} -q(x)y^{'}(x) + \lambda\rho(x)y(x) = 0</script><h3 id="施刘定理成立的五种边界条件"><a href="#施刘定理成立的五种边界条件" class="headerlink" title="施刘定理成立的五种边界条件"></a>施刘定理成立的五种边界条件</h3><p>取边界点为$a,b$</p><p>当$k(a) >0$时,应当有三种边界条件能够使下列两个式子满足先前复习过的<strong>第一、第二、第三边界条件</strong></p><script type="math/tex; mode=display">\alpha_1 y^{'}(a)- \beta_1 y(a) = 0</script><script type="math/tex; mode=display">\alpha_2 y^{'}(a)+ \beta_2 y(a) = 0</script><p>第一边界条件:只有$\alpha = 0$。<br>第二边界条件:只有$\beta = 0$。<br>第三边界条件:$\alpha,\beta$均非零。</p><p>这里因为引入了两种符号,所以可以直接认为$\alpha,\beta$都是非负的。</p><p>如果更有$k(a)=k(b) > 0$,那么还应该加上附加周期性条件</p><script type="math/tex; mode=display">y(a) = y(b)</script><script type="math/tex; mode=display">y^{'}(a) = y^{'}(b)</script><p>如果有$k(a) = 0$,可以证明有一个解$y_1(x)$在$x=a$附近无界。那么必须加上附加条件</p><script type="math/tex; mode=display">|y(a)|< +\infty</script><h3 id="施刘定理认为的固有值性质"><a href="#施刘定理认为的固有值性质" class="headerlink" title="施刘定理认为的固有值性质"></a>施刘定理认为的固有值性质</h3><ol><li>可数性:固有值可以和自然数集一一对应</li><li>非负性:固有值都是非负的值。固有值为零,当且仅当$q(x)\equiv 0$,不能取第一、三类边界条件、固有函数为常数时成立。</li><li>正交性:固有函数系有如下的正交关系<script type="math/tex; mode=display">\int^b_a\rho(x)y_m(x)y_n(x)\mathrm{d}x = 0, m \neq n</script>这也定义了固有函数系的内积关系</li><li>完备性。</li></ol><h3 id="施刘定理最常见的用法"><a href="#施刘定理最常见的用法" class="headerlink" title="施刘定理最常见的用法"></a>施刘定理最常见的用法</h3><p>求内积</p><script type="math/tex; mode=display">\left<y_m(x), y_n(x)\right> = \int^b_a\rho(x)y_m(x)y_n(x)\mathrm{d}x</script><h2 id="非齐次情形下问题的求解"><a href="#非齐次情形下问题的求解" class="headerlink" title="非齐次情形下问题的求解"></a>非齐次情形下问题的求解</h2><h3 id="固有函数方法"><a href="#固有函数方法" class="headerlink" title="固有函数方法"></a>固有函数方法</h3><p>固有函数方法的思路是把非齐次问题分离出来。</p><p>下面就是一个非齐次问题</p><script type="math/tex; mode=display">\begin{cases}u_{tt} = a^2 u_{xx} + f(t,x) \qquad (t > 0, x \in (0, l)) \\u(t, 0) = u(t, l) = 0 \\u(0, x) = \varphi(x) ,u_t(0,x) = \psi(x) \\\end{cases}</script><p>做分解</p><script type="math/tex; mode=display">u = w + v</script><p>满足</p><script type="math/tex; mode=display">\begin{cases}v_{tt} = a^2 v_{xx} \qquad (t > 0, x \in (0, l)) \\v(t, 0) = v(t, l) = 0 \\v(0, x) = \varphi(x) ,v_t(0,x) = \psi(x) \\\end{cases}</script><script type="math/tex; mode=display">\begin{cases}w_{tt} = a^2 w_{xx} + f(t,x) \qquad (t > 0, x \in (0, l)) \\w(t, 0) = w(t, l) = 0 \\w(0, x) = 0,w_t(0,x) = 0 \\\end{cases}</script><p>$v$的方程之前讨论过解法。对于$w$的方程,有方法如下</p><p>做出齐次方程的固有函数系,如</p><script type="math/tex; mode=display">\lambda_n = \left(\frac{n \pi}{l}\right)^2, n = 1, 2, \dots</script><script type="math/tex; mode=display">X_n(x) = \sin \frac{n \pi x}{l}</script><p>同时将$f(t,x),w(t,x)$进行展开</p><script type="math/tex; mode=display">w(t,x) = \sum_{n=1}^{+\infty}T_n(t)\sin \frac{n \pi x}{l}</script><script type="math/tex; mode=display">f(t,x) = \sum_{n=1}^{+\infty}f_n(t)\sin \frac{n \pi x}{l}</script><p>由相关的展开知识,这里的系数是</p><script type="math/tex; mode=display">\newcommand{\d}{\mathrm{d}}\newcommand{\e}{\mathrm{e}}f_n(t) = \frac{2}{l}\int^{l}_0f(t,x) \sin \frac{n \pi x}{l}\d x</script><p>代入方程即可得到我们需要的方程系</p><script type="math/tex; mode=display">\begin{cases}T^{''}_n(t) + \lambda_n a^2 T_n(t) = f_n(t)\\T_n(0) = T_n^{'}(0) = 0 , n = 1, 2, \dots \\\end{cases}</script><p>使用拉普拉斯变换的方法可以解这个二阶常系数非齐次微分方程。</p><h3 id="特解法"><a href="#特解法" class="headerlink" title="特解法"></a>特解法</h3><p>特解法是一种省略上述展开的方法。主要观点是,在$f(t,x)$足够简单,以至于$w(t,x)$的函数形式你可以直接口算出来,那么就不用展开了。作业题中有实例,这里不展开讲述。</p><h3 id="齐次化原理"><a href="#齐次化原理" class="headerlink" title="齐次化原理"></a>齐次化原理</h3><p>虽然与第一章相比时,这里的问题多出来了边界条件,但是齐次化原理依然能够正常使用。</p><p>第一步依然是令$u=v+w$,这里求解$w$的方法就可以使用齐次化原理。比如</p><script type="math/tex; mode=display">\begin{cases}\omega_{tt} = a^2 \omega_{xx} \qquad (t > 0, x \in (0, l)) \\\omega(t, 0) = \omega(t, l) = 0 \\\omega(\tau , x) = 0, \omega_t(\tau,x) = f(\tau, x) \\\end{cases}</script><p>则问题的解为</p><script type="math/tex; mode=display">\newcommand{\d}{\mathrm{d}}\newcommand{\e}{\mathrm{e}}w(t,x) = \int^t_0 \omega(t,x; \tau)\d \tau</script><p>使用起来还是比较简便的,就是计算比较困难。</p><h2 id="一般非齐次混合问题"><a href="#一般非齐次混合问题" class="headerlink" title="一般非齐次混合问题"></a>一般非齐次混合问题</h2><p>这里处理的问题是边界条件也是非齐次的混合问题,比如边界条件是$u(t,0)=0,u(t,l)=\sin \omega t$。</p><p>通常的做法是取$v(t,x) = A(t)x + B(t)$或者$v(t,x) = A(t)x^2 + B(t)$将非齐次的边界条件去除。</p><p>有的时候,这样处理会得到非齐次方程,有没有办法可以去除非齐次边界条件的同时,不得到非齐次方程呢?</p><p>在例题中,有</p><script type="math/tex; mode=display">\begin{cases}u_{tt} = a^2u_{xx} (x \in (0,l), t > 0)\\u(t,0) = 0, u(t, l) = \sin \omega t \\u(0, x) = 0, u_t(0, x) = 0 \\\end{cases}</script><p>使用最简单的思路,我们取</p><script type="math/tex; mode=display">v(t,x) = \frac{x}{l}\sin \omega t</script><p>得到剩下的方程</p><script type="math/tex; mode=display">\begin{cases}\displaystyle w_{tt} = a^2w_{xx} + \frac{\omega^2 x}{l}\sin \omega t (x \in (0,l), t > 0)\\w(t,0) = 0, w(t, l) =0 \\\displaystyle w(0, x) = 0, w_t(0, x) = -\frac{\omega x}{l} \\\end{cases}</script><p>这个问题的求解也需要分两步走,很麻烦我们不喜欢。</p><p>所以我们想要的是找到一个$v(t,x)$,既满足边界条件,又能满足齐次化方程,这样就不会有非齐次项。</p><p>在这个问题中,我们取</p><script type="math/tex; mode=display">v(t,x) = X(x)\sin \omega t,X(0) = 0, X(l)= 1</script><p>将函数带入原方程,可以得到</p><script type="math/tex; mode=display">X(x) = \frac{\sin\displaystyle\frac{\omega x}{a}}{\displaystyle\frac{\omega l}{a}}</script><p>带入原方程即可继续求解齐次方程。</p><h2 id="泊松方程的边值问题"><a href="#泊松方程的边值问题" class="headerlink" title="泊松方程的边值问题"></a>泊松方程的边值问题</h2><p>泊松方程通常的解法是,利用对称性将方程化为关于两个变量的偏微分方程,然后利用上文讨论过的方法求解。</p><p>比较值得注意的是,如果极坐标的$\theta$可以取遍全空间,我们可以直接使用极坐标系下拉普拉斯方程的一般解</p><script type="math/tex; mode=display">u(r,\theta) = A_0 + B_0\ln r + \sum_{k = 1}^{+\infty}(A_kr^k + B_kr^{-k})(C_k \cos k \theta + D_k \sin k \theta)</script>]]></content>
<categories>
<category>数学</category>
</categories>
<tags>
<tag>课内复习</tag>
<tag>数学</tag>
</tags>
</entry>
<entry>
<title>数理方程复习-数学物理中的偏微分方程</title>
<link href="/2022/04/30/EquationsCP02/"/>
<url>/2022/04/30/EquationsCP02/</url>
<content type="html"><![CDATA[<p>这里是为了应付数理方程期末考试而把整本书的重要公式抄写一遍的笔记。</p><span id="more"></span><h2 id="导入"><a href="#导入" class="headerlink" title="导入"></a>导入</h2><p>这里首先研究两个偏微分问题</p><p>在不考虑任何附加条件下,下面两个方程</p><script type="math/tex; mode=display">\frac{\partial^2 u}{\partial x\partial y} = 0</script><script type="math/tex; mode=display">\frac{\partial^2 u}{\partial x^2} = a^2 \frac{\partial^2 u}{\partial x^2}</script><p>分别可以解得</p><script type="math/tex; mode=display">u=f(x) + g(y),f,g\text{为任意一次可微函数}</script><script type="math/tex; mode=display">u=f(x+at) + g(x-at),f,g\text{为任意一次可微函数}</script><p>其中后者的证明使用到了$\xi = x+at, \zeta = x-at$进行变量代换。</p><h2 id="研究的三种方程"><a href="#研究的三种方程" class="headerlink" title="研究的三种方程"></a>研究的三种方程</h2><h3 id="波动方程"><a href="#波动方程" class="headerlink" title="波动方程"></a>波动方程</h3><script type="math/tex; mode=display">\frac{\partial ^2 u}{\partial t^2} = a^2 \Delta_3 u + f(t,x,y,z)</script><p>如果考虑物理意义,则</p><script type="math/tex; mode=display">a=\sqrt{\frac{T}{\rho}}, f = \frac{g}{\rho},g\text{为外力代表的函数}</script><h3 id="热传导方程"><a href="#热传导方程" class="headerlink" title="热传导方程"></a>热传导方程</h3><script type="math/tex; mode=display">\frac{\partial u}{\partial t} = a^2 \Delta_3 u + f(t,x,y,z)</script><p>如果考虑物理意义,则</p><script type="math/tex; mode=display">a=\sqrt{\frac{k}{c\rho}}, f = \frac{g}{c\rho},g\text{为代表热源的函数}</script><h3 id="泊松方程"><a href="#泊松方程" class="headerlink" title="泊松方程"></a>泊松方程</h3><script type="math/tex; mode=display">\Delta_3 u = f(x,y,z)</script><h2 id="定解条件"><a href="#定解条件" class="headerlink" title="定解条件"></a>定解条件</h2><p>定解条件是初始条件和边界条件的总称。假设该函数为$u(t,M)$,$M$为空间坐标。</p><h3 id="初始条件"><a href="#初始条件" class="headerlink" title="初始条件"></a>初始条件</h3><p>初始条件是指过程发生的初始状态,即条件</p><script type="math/tex; mode=display">u(t_0, M) = \varphi(M)</script><script type="math/tex; mode=display">u_t(t_0, M) = \psi(M)</script><p>通常取$t_0=0$,但不是强制要求。</p><h3 id="边界条件"><a href="#边界条件" class="headerlink" title="边界条件"></a>边界条件</h3><p>边界条件是指过程在边界上的状态。通常有如下形式</p><script type="math/tex; mode=display">\left.\left(\alpha \frac{\partial u}{\partial n} + \beta u \right)\right|_S = \varphi (x,y,z)</script><p>某些问题中也可以取$\varphi(t,x,y,z)$,比如强迫振动问题。</p><p>在$\alpha, \beta$不同取值时,通常问题的解答有所不同。</p><p>只有$\alpha = 0$时,条件变成$\beta u = \varphi$,称为<code>Dirichlet</code>条件,对应的问题称为<strong>第一边值问题</strong>。</p><p>只有$\beta = 0$时,条件变成$\alpha u_t = \varphi$,称为<code>Neumann</code>条件,对应的问题称为<strong>第二边值问题</strong>。</p><p>$\alpha,\beta$均不为零时,称为<code>Robin</code>条件,对应的问题称为<strong>第三边值问题</strong>。</p><h3 id="混合条件"><a href="#混合条件" class="headerlink" title="混合条件"></a>混合条件</h3><p>混合条件就是指一个问题即具有初始条件,又具有边界条件。</p><h2 id="达朗贝尔公式"><a href="#达朗贝尔公式" class="headerlink" title="达朗贝尔公式"></a>达朗贝尔公式</h2><p>对于<strong>一维无界波动方程的初值问题</strong>,我们可以直接求出它的全解。</p><p>该问题的数学描述为</p><script type="math/tex; mode=display">\begin{cases}\displaystyle\frac{\partial^2 u}{\partial t^2} = a^2 \frac{\partial^2 u}{\partial x^2} (x\in \mathrm{R}, t > 0)\\u(0,x) = \varphi(x) , u_t(0,x) = \psi(x) ,x\in\mathrm{R}\end{cases}</script><p>则它的解为</p><script type="math/tex; mode=display">\newcommand{\d}{\mathrm{d}}\newcommand{\e}{\mathrm{e}}u(t,x) = \frac{1}{2}\left(\varphi(x-at)+\varphi(x+at)\right) + \frac{1}{2a}\int^{x+at}_{x-at}\psi(\xi)\d\xi</script><h2 id="叠加原理"><a href="#叠加原理" class="headerlink" title="叠加原理"></a>叠加原理</h2><p>如果我们记<strong>二阶线性微分算子</strong></p><script type="math/tex; mode=display">L= \sum^n_{i, j = 1}a_{ij}\frac{\partial^2}{\partial x_i\partial y_i} + 2\sum^n_{i=1}b_i\frac{\partial}{\partial x_i} + c</script><p>设有一个函数$u=\sum_{i=1}^{n}c_iu_i$,可以得到如下性质</p><ol><li>若$Lu_i = f_i$,则$Lu = \sum_{i=1}^{n}c_if_i$。</li><li>若$Lu_i = f_i$,而且$n\rightarrow +\infty$通常的问题中可以认为$Lu = \sum_{i=1}^{+\infty}c_if_i$。</li><li><p>若</p><script type="math/tex; mode=display"> Lu = f(M,M_0)</script><script type="math/tex; mode=display"> \newcommand{\d}{\mathrm{d}} \newcommand{\e}{\mathrm{e}} U(M) = \int_V u(M, M_0)\d M_0</script><p> 可以认为</p><script type="math/tex; mode=display"> \newcommand{\d}{\mathrm{d}} \newcommand{\e}{\mathrm{e}} LU(M) = \int_V f(M,M_0)\d M_0</script><p> 上式可以解释为<strong>L和积分号可以交换</strong></p></li></ol><p>通常上文性质需要考虑过程的条件,但是本次考试中无需这么谨慎。</p><h2 id="齐次化原理-冲量原理"><a href="#齐次化原理-冲量原理" class="headerlink" title="齐次化原理/冲量原理"></a>齐次化原理/冲量原理</h2><p>齐次化原理,又名冲量原理,是用来解决一些非齐次的初始问题的方法。通常有两种形式,分别解决波动方程和热传导方程。</p><h3 id="齐次化形式一"><a href="#齐次化形式一" class="headerlink" title="齐次化形式一"></a>齐次化形式一</h3><script type="math/tex; mode=display">\begin{cases}\displaystyle\frac{\partial ^2 u}{\partial t^2} = Lu + f(t, M),(M\in \mathrm{R}^3, t>0) \\u|_{t=0} = 0,u_t|_{t=0} = 0\\\end{cases}</script><p>这种问题可以先求一个对应的方程$\omega(t,M;\tau)$</p><script type="math/tex; mode=display">\begin{cases}\displaystyle\frac{\partial ^2 \omega}{\partial t^2} = Lu,(M\in \mathrm{R}^3, t>\tau) \\\omega|_{t=\tau} = 0,\omega_t|_{t=\tau} = f(\tau, M)\\\end{cases}</script><p>有什么区别?这里将$f(t,M)$转化到了初始条件上,这个新的方程通常解法是达朗贝尔公式。</p><p>那么问题的解为</p><script type="math/tex; mode=display">\newcommand{\d}{\mathrm{d}}\newcommand{\e}{\mathrm{e}}u=\int^t_0\omega(t, M; \tau)\d \tau</script><h3 id="齐次化形式二"><a href="#齐次化形式二" class="headerlink" title="齐次化形式二"></a>齐次化形式二</h3><script type="math/tex; mode=display">\begin{cases}\displaystyle\frac{\partial u}{\partial t} = Lu + f(t, M),(M\in \mathrm{R}^3, t>0) \\u|_{t=0} = 0\\\end{cases}</script><p>这种问题可以先求一个对应的方程$\omega(t,M;\tau)$</p><script type="math/tex; mode=display">\begin{cases}\displaystyle\frac{\partial \omega}{\partial t} = L\omega,(M\in \mathrm{R}^3, t>0) \\u|_{t=\tau} = f(\tau, M)\\\end{cases}</script><p>新的方程通常解法是进行变量代换$\xi = x+at, \zeta = x-at$。</p><p>那么问题的解为</p><script type="math/tex; mode=display">\newcommand{\d}{\mathrm{d}}\newcommand{\e}{\mathrm{e}}u=\int^t_0\omega(t, M; \tau)\d \tau</script><h2 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h2><p>因为时间问题,后面的章节没有通过这种方式整理了。期末考试考了99分,挺好。</p>]]></content>
<categories>
<category>数学</category>
</categories>
<tags>
<tag>课内复习</tag>
<tag>数学</tag>
</tags>
</entry>
<entry>
<title>基础数学知识-拉普拉斯变换表</title>
<link href="/2022/04/29/Laplace/"/>
<url>/2022/04/29/Laplace/</url>
<content type="html"><![CDATA[<p>本文整理了常见的拉普拉斯变换形式。并为两种特殊的变换形式进行了简单叙述。</p><span id="more"></span><h2 id="公式"><a href="#公式" class="headerlink" title="公式"></a>公式</h2><div class="table-container"><table><thead><tr><th>$f(t) = \mathcal{L}^{-1}\{F(s)\}$</th><th>$F(s) = \mathcal{L}\{f(t)\}$</th></tr></thead><tbody><tr><td>$\delta (t)$</td><td>$1$</td></tr><tr><td>$\varepsilon(t)$</td><td>$\displaystyle\frac{1}{s}$</td></tr><tr><td>$t\varepsilon(t)$</td><td>$\displaystyle\frac{1}{s^2}$</td></tr><tr><td>$t^n\varepsilon(t)$</td><td>$\displaystyle\frac{n!}{s^{n+1}}$</td></tr><tr><td>$ \mathrm{e}^{\alpha t}\varepsilon(t)$</td><td>$\displaystyle\frac{1}{s-\alpha}$</td></tr><tr><td>$ t\mathrm{e}^{\alpha t}\varepsilon(t)$</td><td>$\displaystyle\frac{1}{(s-\alpha)^2}$</td></tr><tr><td>$ t^n\mathrm{e}^{\alpha t}\varepsilon(t)$</td><td>$\displaystyle\frac{n!}{(s-\alpha)^{n+1}}$</td></tr><tr><td>$\sin(\omega t)\varepsilon(t)$</td><td>$\displaystyle\frac{\omega}{s^2+\omega^2}$</td></tr><tr><td>$\cos(\omega t)\varepsilon(t)$</td><td>$\displaystyle\frac{s}{s^2+\omega^2}$</td></tr><tr><td>$\sinh(\beta t)\varepsilon(t)$</td><td>$\displaystyle\frac{\beta}{s^2-\beta^2}$</td></tr><tr><td>$\cosh(\beta t)\varepsilon(t)$</td><td>$\displaystyle\frac{s}{s^2-\beta^2}$</td></tr><tr><td>$\mathrm{e}^{\alpha t}\sin(\omega t)\varepsilon(t)$</td><td>$\displaystyle\frac{\omega}{(s-\alpha)^2+\omega^2}$</td></tr><tr><td>$\mathrm{e}^{\alpha t}\cos(\omega t)\varepsilon(t)$</td><td>$\displaystyle\frac{s-\alpha}{(s-\alpha)^2+\omega^2}$</td></tr></tbody></table></div><p>上面都是比较常规的,接下来列举两个奇怪的</p><p>若</p><script type="math/tex; mode=display">f(t) = 2r\mathrm{e}^{\alpha t}\cos (\omega t + \varphi)\varepsilon(t)</script><p>则</p><script type="math/tex; mode=display">F(s) = \frac{r\mathrm{e}^{j\varphi}}{s-\alpha -j\omega} + \frac{r\mathrm{e}^{-j\varphi}}{s-\alpha +j\omega}</script><p>若</p><script type="math/tex; mode=display">f(t) = \frac{1}{\omega_n\sqrt{1-\zeta^2}}\mathrm{e}^{-\zeta \omega_n t}\sin(\omega_n\sqrt{1-\zeta^2})t\varepsilon(t)</script><p>则</p><script type="math/tex; mode=display">F(s) = \frac{1}{s^2 + 2\zeta\omega_n s+\omega^2_n}</script><h3 id="最后两个公式的证明"><a href="#最后两个公式的证明" class="headerlink" title="最后两个公式的证明"></a>最后两个公式的证明</h3><p>证明前一个公式,只需要考虑$f(t) = \cos(\omega t + \varphi)$</p><script type="math/tex; mode=display">\cos(\omega t + \varphi) = \cos \omega t \cos \varphi - \sin \omega t \sin \varphi</script><script type="math/tex; mode=display">\begin{aligned}F(s) &=\frac{s}{s^2 + \omega^2} \cos \varphi - \frac{\omega}{s^2+\omega^2}\sin\varphi \\ &= \frac{1}{2}\left(\frac{1}{s+j\omega} + \frac{1}{s-j\omega}\right)\cos \varphi + \frac{j}{2}\left(\frac{1}{s-j\omega} - \frac{1}{s+j\omega}\right)\sin \varphi \\ &= \frac{1}{2}\frac{\cos\varphi - j \sin \varphi}{s+j\omega} + \frac{1}{2}\frac{\cos\varphi + j \sin \varphi}{s-j\omega} \\ &= \frac{1}{2}\frac{\mathrm{e}^{-j\varphi}}{s+j\omega} + \frac{1}{2}\frac{\mathrm{e}^{j\varphi}}{s-j\omega} \\\end{aligned}</script><p>两边同乘以$2r$,再时移即可。</p><p>后一个公式成立于$\zeta < 1$的情况下。可以由$\sin(\omega t)$进行时移后得到,不用单独证明。</p>]]></content>
<categories>
<category>数学</category>
</categories>
<tags>
<tag>课内复习</tag>
<tag>数学</tag>
</tags>
</entry>
<entry>
<title>基础数学知识-Gamma函数和Beta函数</title>
<link href="/2022/03/31/GammaBeta/"/>
<url>/2022/03/31/GammaBeta/</url>
<content type="html"><![CDATA[<p>由于在各种数学实践中出现了基础知识遗漏的问题,这里将需要着重记忆的数学知识再次回顾。</p><span id="more"></span><h2 id="Gamma函数"><a href="#Gamma函数" class="headerlink" title="Gamma函数"></a>Gamma函数</h2><p>$\Gamma(x)$,Gamma函数,通常被解释为阶乘的延拓。该函数在许多数学领域中均有重要的作用。</p><p>在实数域上,定义为</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}\Gamma (x) = \int_0^{+\infty}t^{x-1}\e^{-t}\d t(x > 0)</script><p>复数域上,可以延拓为</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}\Gamma (z) = \int_0^{+\infty}t^{z-1}\e^{-t}\d t (\mathrm{Re}(z) > 0)</script><p>通过变换,可以得到另一种表达方式</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}\Gamma (x) = 2\int_0^{+\infty}t^{2x-1}\e^{-t^2}\d t</script><p>通常使用的特殊值为</p><script type="math/tex; mode=display">\Gamma(1) = 1, \Gamma\left(\frac{1}{2}\right) = \sqrt{\pi}</script><p>通常我们需要记忆Gamma函数的如下性质:</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}\Gamma(x+1) = x\Gamma(x)</script><p>这个是Gamma函数作为阶乘延拓的主要性质。</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}B(m,n) = \frac{\Gamma(m)\Gamma(n)}{\Gamma(m+n)}</script><p>我们还常见一个公式,称为<strong>余元公式</strong></p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}\Gamma(1-x)\Gamma(x) = \frac{\pi}{\sin \pi x}</script><p>在概率论、数理统计和随机过程这些课程中,我们还接触了<strong>Gamma分布</strong>,它有如下的概率密度函数</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}f(X) = \frac{X^{\alpha - 1}\lambda^{\alpha}\e^{-\lambda X}}{\Gamma(\alpha)}</script><h2 id="Beta函数"><a href="#Beta函数" class="headerlink" title="Beta函数"></a>Beta函数</h2><p>Beta函数称为欧拉第一积分,有如下定义</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}B(m,n)=\int^1_0x^{m-1}(1-x)^{n-1}\d x</script><p>积分成立的条件是$\mathrm{Re}(m)>0,\mathrm{Re}(n)>0$。</p><p>Beta函数性质</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}B(m,n) = B(n,m)</script><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}B(s,1-s) = \int_0^{+\infty}\frac{x^{s-1}}{1+x}\d x = \Gamma(s)\Gamma(1-s) = \frac{\pi}{\sin s\pi}</script><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}\int^{\frac{\pi}{2}}_0\sin^{p}\theta\cos ^{q}\theta \d \theta = \frac{1}{2}B(\frac{p+1}{2}, \frac{q+1}{2})</script><p>最常见的性质还是Beta函数和Gamma函数的转化,然后可以根据Gamma的阶乘性质化简成阶乘或双阶乘的形式。</p><script type="math/tex; mode=display">\newcommand{\e}{\mathrm{e}}\newcommand{\d}{\mathrm{d}}B(m,n) = \frac{\Gamma(m)\Gamma(n)}{\Gamma(m+n)}</script><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>在工科学习过程中,主要掌握的性质集中于计算方面。限于时间问题,上述性质均未在本文中得到证明。以上。</p>]]></content>
<categories>
<category>数学</category>
</categories>
<tags>
<tag>课内复习</tag>
<tag>数学</tag>
</tags>
</entry>
<entry>
<title>电磁学C复习-磁学部分二</title>
<link href="/2022/02/02/ElecC3/"/>
<url>/2022/02/02/ElecC3/</url>
<content type="html"><![CDATA[<p>本文章是作者在学习电磁学时进行期末复习时做出的笔记。这里是磁学第二部分。</p><span id="more"></span><h2 id="电磁感应与磁场能量"><a href="#电磁感应与磁场能量" class="headerlink" title="电磁感应与磁场能量"></a>电磁感应与磁场能量</h2><h3 id="磁场的能量"><a href="#磁场的能量" class="headerlink" title="磁场的能量"></a>磁场的能量</h3><h4 id="线圈的自感磁能表达式"><a href="#线圈的自感磁能表达式" class="headerlink" title="线圈的自感磁能表达式"></a>线圈的自感磁能表达式</h4><script type="math/tex; mode=display">\newcommand{\oiint}{\subset\kern{-3pt}\supset\kern{-16.5pt}\iint}W_m = \int_0^ILI\text{d}I = \frac{1}{2}LI^2 = \frac{1}{2}I\Phi_m</script><p>其中$\Phi_m=LI$是通过线圈的全磁通。</p><h4 id="LC振荡电路"><a href="#LC振荡电路" class="headerlink" title="LC振荡电路"></a>LC振荡电路</h4><p>自己看PPT<br>Page 381</p><h4 id="载流线圈得到互能"><a href="#载流线圈得到互能" class="headerlink" title="载流线圈得到互能"></a>载流线圈得到互能</h4><p>推导的时候,可以先将其中一个线圈充满电,再考虑另一个线圈的充电过程。</p><p>产生了感应电动势,需要进行反抗,转化的功变成了磁能。</p><p>互能:</p><script type="math/tex; mode=display">W_{\text{互}} = MI_1I_2</script><h4 id="两个载流线圈系统的磁能"><a href="#两个载流线圈系统的磁能" class="headerlink" title="两个载流线圈系统的磁能"></a>两个载流线圈系统的磁能</h4><script type="math/tex; mode=display">W=\frac{1}{2}L_1I_1^2 + \frac{1}{2}L_2I_2^2 \pm MI_1I_2</script><p>互感磁能顺接为正,反接为负。</p><p>也可以表示为</p><script type="math/tex; mode=display">W_m = \frac{1}{2}\sum^2_{i,j=1}M_{ij}I_iI_j,M_{ii} = L_i</script><p>顺接时$M>0$,反接时$M<0$</p><h4 id="多个载流线圈系统的磁能"><a href="#多个载流线圈系统的磁能" class="headerlink" title="多个载流线圈系统的磁能"></a>多个载流线圈系统的磁能</h4><script type="math/tex; mode=display">W_m = \frac{1}{2}\sum^N_{i,j=1}M_{ij}I_iI_j,M_{ii} = L_i</script><p>不过瘾。</p><p>令第j个线圈的电流的磁场通过第i个线圈的磁通为</p><script type="math/tex; mode=display">\Phi_{ji} = M_{ji}I_j = M_{ij}I_j</script><p>且令</p><script type="math/tex; mode=display">\Phi_i = \sum^N_{j=1}\Phi_{ji} = \sum^N_{j=1}M_{ij}I_j</script><p>所以得到</p><script type="math/tex; mode=display">W_m = \frac{1}{2}\sum^N_{i=1}I_i\Phi_i</script><h4 id="载流线圈在外磁场中的磁能"><a href="#载流线圈在外磁场中的磁能" class="headerlink" title="载流线圈在外磁场中的磁能"></a>载流线圈在外磁场中的磁能</h4><p>计$W_{ij}$表示i,j载流线圈之间的互能。</p><script type="math/tex; mode=display">W_{12} = M_{12}I_1I_2 = \Phi_{12}I_2 = I_2\iint_{S_2}\boldsymbol{B}_{1}(\boldsymbol{r}_2)\cdot\text{d}\boldsymbol{S}</script><p>将其看成线圈2在外磁场$B_1$中具有的磁能,则</p><p>对<strong>均匀外磁场</strong>中的载流线圈或非均匀外磁场中的<strong>小</strong>载流线圈,有磁矩$m$在外磁场$B$中的磁能</p><script type="math/tex; mode=display">W_{12} = \boldsymbol{m} \cdot\boldsymbol{B}</script><p>对于N个线圈系统</p><script type="math/tex; mode=display">W_m = \sum^{N}_{k=1}I_k\iint_{S_k}\boldsymbol{B}(\boldsymbol{r})\cdot\text{d}\boldsymbol{S}</script><p>对于均匀的外磁场</p><script type="math/tex; mode=display">W_{12} = \boldsymbol{B}\cdot(\sum^N_{k=1}I_kS_k) = \boldsymbol{m}_{t}\cdot\boldsymbol{B}</script><p>其中$m_t$为总磁矩</p><h4 id="磁场的能量和磁能密度"><a href="#磁场的能量和磁能密度" class="headerlink" title="磁场的能量和磁能密度"></a>磁场的能量和磁能密度</h4><p>磁能同样存储在磁场中</p><p>定义磁能密度为$w_m$,可以计算得到</p><script type="math/tex; mode=display">{w}_m = \frac{1}{2}\boldsymbol{B}\cdot\boldsymbol{H}</script><p>当空间磁场不均匀时,总磁能时磁能密度的体积分</p><script type="math/tex; mode=display">W_m = \iiint_V w_m\text{d}V = \frac{1}{2}\iiint_V\boldsymbol{B}\cdot\boldsymbol{H}\text{d}V</script><p>上式中的B是总磁场,即计入了介质的磁化能,要求介质线性无损耗!</p><h4 id="使用磁能密度解决自感问题"><a href="#使用磁能密度解决自感问题" class="headerlink" title="使用磁能密度解决自感问题"></a>使用磁能密度解决自感问题</h4><script type="math/tex; mode=display">L = \frac{2W_m}{I^2}</script><p>其中$W_m$利用磁能密度积分求解。如果$I^2$不能消去,你就求错了。</p><h4 id="磁介质存在时的磁能"><a href="#磁介质存在时的磁能" class="headerlink" title="磁介质存在时的磁能"></a>磁介质存在时的磁能</h4><p>PPT404</p><p>直接上结论:</p><script type="math/tex; mode=display">w_m = \frac{1}{2}\mu_0H^2 + \frac{1}{2}\mu_0\boldsymbol{H}\cdot\boldsymbol{M}</script><p>这个公式实际上可以从下式得到。</p><script type="math/tex; mode=display">w_m = \frac{1}{2}\boldsymbol{B}\cdot\boldsymbol{H}= \frac{1}{2}\mu_0(\boldsymbol{H}+\boldsymbol{M})\cdot\boldsymbol{H}</script><p>这也解释了为什么磁滞回线使用$B$-$H$曲线,面积可以直接计算成能量。</p><h4 id="利用磁能求力和力矩"><a href="#利用磁能求力和力矩" class="headerlink" title="利用磁能求力和力矩"></a>利用磁能求力和力矩</h4><ol><li><p>电流保持不变</p><p> 磁力经虚位移$\delta \boldsymbol{r}$作功$\delta A$,是系统磁能减少;要维持电流不变,外界电源需要反抗感应电动势作功$\delta A^{‘}$,使磁能增加。<br> 由公式</p><script type="math/tex; mode=display"> (\delta W_m)_I = \delta A^{'} - \delta A</script><p> 电源作功的特点是</p><script type="math/tex; mode=display"> \delta A^{'} = 2(\delta W_m)_I</script><p> 所以</p><script type="math/tex; mode=display"> (\delta W_m)_I = \delta A = \boldsymbol{F}\cdot\delta\boldsymbol{r}</script><script type="math/tex; mode=display"> F = \left(\frac{\partial W_m}{\partial r}\right)_I = (\nabla W_m)_I</script></li><li><p>线圈各匝磁通不变</p><p> 磁力经虚位移$\delta \boldsymbol{r}$作功$\delta {A}$,线圈磁通保持不变,不会出现感应电动势,电源不做功。</p><script type="math/tex; mode=display"> (\delta W_m)_\Phi = \delta A^{'} - \delta A = -\delta A</script><p> 因此</p><script type="math/tex; mode=display"> F = -\left(\frac{\partial W_m}{\partial r}\right)_{\Phi} = -(\nabla W_m)_\Phi</script><p> 类似地,使用角位移可以得到磁力矩的公式</p><p> 以上的偏导均可以替换成nabla算子。为什么?</p><p> 因为如果先得到了力的方向,使用偏导是没有问题的。</p><p> 如果没有得到力的方向,直接使用nabla算子也是可以得到力和方向的。</p><script type="math/tex; mode=display"> L_\theta = \left(\frac{\partial W_m}{\partial \theta}\right)_I</script><script type="math/tex; mode=display"> L_\theta = -\left(\frac{\partial W_m}{\partial \theta}\right)_{\Phi}</script><p> 这里就不能使用nabla算子了。因为坐标系不同,不能简化计算。</p></li></ol><h4 id="外磁场作用下载流线圈的力与力矩"><a href="#外磁场作用下载流线圈的力与力矩" class="headerlink" title="外磁场作用下载流线圈的力与力矩"></a>外磁场作用下载流线圈的力与力矩</h4><p>可以从虚功原理推导出来</p><script type="math/tex; mode=display">\boldsymbol{F} = (\boldsymbol{m}\cdot\nabla)\boldsymbol{B}</script><script type="math/tex; mode=display">\boldsymbol{L}_\theta = \boldsymbol{m}\times\boldsymbol{B}</script><p>这也解释了nabla算子的由来。</p><p>PAGE 410</p><h2 id="交流电路与电力输送"><a href="#交流电路与电力输送" class="headerlink" title="交流电路与电力输送"></a>交流电路与电力输送</h2><h3 id="交流电的产生与基本特性"><a href="#交流电的产生与基本特性" class="headerlink" title="交流电的产生与基本特性"></a>交流电的产生与基本特性</h3><p>电阻</p><script type="math/tex; mode=display">Z_R = R</script><script type="math/tex; mode=display">\varphi = 0</script><p>电容</p><script type="math/tex; mode=display">Z_C = \frac{1}{\omega C}</script><script type="math/tex; mode=display">\varphi =\varphi_u-\varphi_i = -\frac{\pi}{2}</script><p>电压相位落后于电流相位,因为电荷需要积累才成拥有电势差。</p><p>注意<strong>波的落后</strong>在时间轴上向右</p><p>电感</p><script type="math/tex; mode=display">Z_L = \omega L</script><script type="math/tex; mode=display">\varphi = \varphi_u-\varphi_i=\frac{\pi}{2}</script><p>电压的相位超前于电流,因为要先产生自感电动势,才能产生感生电流。</p><h4 id="电路矢量图"><a href="#电路矢量图" class="headerlink" title="电路矢量图"></a>电路矢量图</h4><p>$x$轴正方向是$I$还是$U$取决于考虑的电路是串联还是并联的。</p><p>单个元器件通常使用$I$。</p><h4 id="串联电路的共振现象"><a href="#串联电路的共振现象" class="headerlink" title="串联电路的共振现象"></a>串联电路的共振现象</h4><p>串联电路阻抗为</p><script type="math/tex; mode=display">Z = R + j\omega L + \frac{1}{j\omega C}</script><p>即</p><script type="math/tex; mode=display">|Z| = \sqrt{R^2 + (\omega L - \frac{1}{\omega C})^2}</script><p>在固有频率下</p><script type="math/tex; mode=display">f = \frac{1}{2\pi\sqrt{LC}}</script><p>电路纯电阻。</p><p>共振的时候,电感或者电容两端的电压最大,等于电源电动势的Q倍</p><script type="math/tex; mode=display">U_{CLm} = Z_L I_m = \omega_0 L \varepsilon_m / R = 1 / \sqrt{LC} L/R \varepsilon_m = \frac{1}{R}\sqrt{\frac{L}{C}}\varepsilon_m</script><p>即</p><script type="math/tex; mode=display">Q = \frac{1}{R}\sqrt{\frac{L}{C}}</script><p>串联电路共振的应用</p><ol><li>电压信号倍增</li><li>选择共振,改变L,C,改变频率,选台</li></ol><p>Q值的意义</p><ol><li>表征电感和电容上得电压放大倍数</li><li>电路中储存的能量和每个周期内消耗的能量之比的$2\pi$倍</li></ol><p>第二条是哪里来的?</p><script type="math/tex; mode=display">W_S = \frac{1}{2}LI^2 + \frac{1}{2}CU^2</script><p>PAGE 429<br>推导得到</p><script type="math/tex; mode=display">W_S = \frac{1}{2}LI_m^2 = LI_e^2</script><p>解释一下,$I_m$是最大值,$I_e$是有效值。PPT上的推导,实际上是表示了这样一件事情:<br>电感电容上的能量之和相同,分配比例为$\sin^2\omega t : \cos^2\omega t$</p><p>因为有效值,消耗的能量为</p><script type="math/tex; mode=display">W_R = RI^2_eT</script><p>所以在一个周期内</p><script type="math/tex; mode=display">\frac{W_S}{W_R} = \frac{LI_e^2}{RI_e^2T} = \frac{L}{RT} = \frac{L}{R2\pi\sqrt{LC}} = \frac{1}{2\pi}\frac{1}{R}\sqrt{\frac{L}{C}} = \frac{Q}{2\pi}</script><p>得到</p><script type="math/tex; mode=display">Q= 2\pi\frac{W_S}{W_R}</script><h3 id="交流电的复数解法"><a href="#交流电的复数解法" class="headerlink" title="交流电的复数解法"></a>交流电的复数解法</h3><p>将交流电用余弦的形式表示,则可以用复数</p><script type="math/tex; mode=display">a(t) = A\cos(\omega t+ \varphi) = \text{Re}\left[A\text{e}^{j(\omega t + \varphi)}\right] = \text{Re}\left[\tilde{A}\text{e}^{j\omega t}\right]</script><h4 id="交流电路的欧姆定律"><a href="#交流电路的欧姆定律" class="headerlink" title="交流电路的欧姆定律"></a>交流电路的欧姆定律</h4><script type="math/tex; mode=display">\tilde{U} = \tilde{I}\tilde{Z}</script><script type="math/tex; mode=display">\begin{aligned}Z_R &= R \\Z_C &= \frac{1}{j\omega C} \\Z_L &= j\omega L \\\end{aligned}</script><p>串联</p><script type="math/tex; mode=display">\tilde {Z} = \tilde{Z}_1+\tilde{Z}_2</script><p>并联</p><script type="math/tex; mode=display">\frac{1}{\tilde{Z}} = \frac{1}{\tilde{Z}_1}+ \frac{1}{\tilde{Z}_2}</script><h3 id="交流电的功率"><a href="#交流电的功率" class="headerlink" title="交流电的功率"></a>交流电的功率</h3><h4 id="视在功率"><a href="#视在功率" class="headerlink" title="视在功率"></a>视在功率</h4><p>定义为额定电压与额定电流的乘积。单位为伏安</p><script type="math/tex; mode=display">P = S = I_eU_e</script><h4 id="有功功率"><a href="#有功功率" class="headerlink" title="有功功率"></a>有功功率</h4><p>定义为一个周期内含电阻的网络实际消耗的能量,即平均功率。为视在功率的余弦分量</p><script type="math/tex; mode=display">P_{\text{有功}} = P_{//} = U_eI_{e//} = U_eI_e\cos \varphi = P\cos\varphi</script><h4 id="无功功率"><a href="#无功功率" class="headerlink" title="无功功率"></a>无功功率</h4><p>一个周期内含电容电感的电路存储或释放的能量,为视在功率的正弦分量。无功功率表示能量只是在电路中交换,并未被负载消耗。</p><script type="math/tex; mode=display">P_{\text{无功}} = P_{\bot} = U_eI_{e\bot} = U_eI_e\sin \varphi = P\sin\varphi</script><h4 id="提高功率因数的方法"><a href="#提高功率因数的方法" class="headerlink" title="提高功率因数的方法"></a>提高功率因数的方法</h4><p>o<br>电感性网络并联一个适当的电容即可提高功率因数。</p><h2 id="电磁场基本规律与电磁波"><a href="#电磁场基本规律与电磁波" class="headerlink" title="电磁场基本规律与电磁波"></a>电磁场基本规律与电磁波</h2><h3 id="静态电磁场的基本规律"><a href="#静态电磁场的基本规律" class="headerlink" title="静态电磁场的基本规律"></a>静态电磁场的基本规律</h3><p>PPT 465总结静电学静磁学的所有规律</p><h4 id="静电学"><a href="#静电学" class="headerlink" title="静电学"></a>静电学</h4><p>库伦定律</p><script type="math/tex; mode=display">\boldsymbol{F}_{21} = \frac{1}{4\pi\varepsilon_0}\frac{q_1q_2}{r^3_{21}}\boldsymbol{r}_{21}</script><p>叠加原理</p><script type="math/tex; mode=display">\boldsymbol{F}_{j} = \frac{1}{4\pi\varepsilon_0}q_j\sum^N_{i=1,i\neq j}\frac{q_i}{|\boldsymbol{r}-\boldsymbol{r}_{i}|^3}(\boldsymbol{r}-\boldsymbol{r}_{i})</script><p>高斯定理</p><script type="math/tex; mode=display">\oiint_S\boldsymbol{E}\cdot\text{d}\boldsymbol{S} = \frac{Q}{\varepsilon_0}</script><script type="math/tex; mode=display">\nabla \cdot\boldsymbol{E} = \frac{\rho}{\varepsilon_0}</script><p>环路定理</p><script type="math/tex; mode=display">\oint_L \boldsymbol{E}\cdot\text{d}\boldsymbol{l} = 0</script><script type="math/tex; mode=display">\nabla\times\boldsymbol{E}= 0</script><h4 id="静磁学"><a href="#静磁学" class="headerlink" title="静磁学"></a>静磁学</h4><p>毕萨定律</p><script type="math/tex; mode=display">\text{d}\boldsymbol{B} = \frac{\mu_0}{4\pi}\frac{I\text{d}\boldsymbol{l}\times\boldsymbol{r}}{r^3}</script><p>安培定律</p><script type="math/tex; mode=display">\text{d}\boldsymbol{F}_{12} = \frac{\mu_0}{4\pi}\frac{I_2\text{d}\boldsymbol{l}_2\times(I_1\text{d}\boldsymbol{l}_1\times\boldsymbol{r}_{12})}{r_{12}^3}</script><p>高斯定理</p><script type="math/tex; mode=display">\oiint_S\boldsymbol{B}\cdot\text{d}\boldsymbol{S} =0</script><script type="math/tex; mode=display">\nabla \cdot\boldsymbol{B} =0</script><p>环路定理</p><script type="math/tex; mode=display">\oint_L \boldsymbol{B}\cdot\text{d}\boldsymbol{l} = \mu_0 \sum I</script><script type="math/tex; mode=display">\nabla\times\boldsymbol{E}= \mu_0 \boldsymbol{j}</script><h4 id="电荷守恒定律"><a href="#电荷守恒定律" class="headerlink" title="电荷守恒定律"></a>电荷守恒定律</h4><script type="math/tex; mode=display">\oiint_S \boldsymbol{j}\cdot\text{d}\boldsymbol{S} = -\frac{\text{d}q}{\text{d}t}</script><script type="math/tex; mode=display">\nabla\cdot\boldsymbol{j}+\frac{\partial \rho}{\partial t} = 0</script><h4 id="电磁感应实验规律"><a href="#电磁感应实验规律" class="headerlink" title="电磁感应实验规律"></a>电磁感应实验规律</h4><script type="math/tex; mode=display">\varepsilon = -\frac{\text{d}\Phi}{\text{d}t}</script><script type="math/tex; mode=display">\oint_L \boldsymbol{E}_{\text{旋}}\cdot\text{d}\boldsymbol{l} = -\oiint_S \frac{\partial \boldsymbol{B}}{\partial t}\cdot \text{d}\boldsymbol{S}</script><h3 id="时变电磁场的基本规律"><a href="#时变电磁场的基本规律" class="headerlink" title="时变电磁场的基本规律"></a>时变电磁场的基本规律</h3><h4 id="两个推广"><a href="#两个推广" class="headerlink" title="两个推广"></a>两个推广</h4><ol><li>介质中静电场的通量定理对随时间变化的电场同样适用。</li><li>介质中静磁场的通量定理对随时间变化的磁场同样适用。</li></ol><h4 id="两个假设"><a href="#两个假设" class="headerlink" title="两个假设"></a>两个假设</h4><ol><li><p>随时间变化的磁场会激发涡旋电场,感生电动势正是来源于涡旋电场所产生的非静电力。</p><script type="math/tex; mode=display"> \varepsilon = -\iint_{S_C}\frac{\partial\boldsymbol{B}}{\partial t}\cdot\text{d}\boldsymbol{S} = \oint_C\boldsymbol{E}\cdot\text{d}\boldsymbol{l}</script><p> 得到</p><script type="math/tex; mode=display"> \nabla \times \boldsymbol{E} = -\frac{\partial \boldsymbol{B}}{\partial t}</script></li><li><p>位移电流假设</p></li></ol><h4 id="位移电流假设"><a href="#位移电流假设" class="headerlink" title="位移电流假设"></a>位移电流假设</h4><p>随时间变化的电场和电流一样能激发磁场,引入位移电流密度</p><script type="math/tex; mode=display">\boldsymbol{j}_d \equiv \frac{\partial \boldsymbol{D}}{\partial t} = \varepsilon_0\frac{\partial \boldsymbol{E}}{\partial t} + \frac{\partial\boldsymbol{P}}{\partial t}</script><p>那么磁场的环路定理可以写成</p><script type="math/tex; mode=display">\oint_C\boldsymbol{H}\cdot\text{d}\boldsymbol{l} = \iint_S (\boldsymbol{j}_0 + \boldsymbol{j}_d)\cdot\text{d}\boldsymbol{S}= \iint_S (\boldsymbol{j}_0 +\frac{\partial \boldsymbol{D}}{\partial t} )\cdot\text{d}\boldsymbol{S}</script><p>即磁场强度的环量包含了传导电流与位移电流的贡献。</p><p>位移电流密度实际上是电荷守恒定律在非稳恒电流下成立的结果,它保证了非稳恒电流激发的磁场的环路定理右边的积分值唯一</p><p>PPT 477</p><p>即得到</p><script type="math/tex; mode=display">\nabla \times\boldsymbol{H} =\boldsymbol{j}_0 + \frac{\partial \boldsymbol{D}}{\partial t}</script><p>同时有上式,可以得到</p><script type="math/tex; mode=display">\oiint_S (\boldsymbol{j}_0 + \boldsymbol{j}_d)\cdot\text{d}\boldsymbol{S} = 0</script><p>可以分析,非稳恒情况下,传导电流断开处有位移电流接上。</p><p>位移电流并非自由电荷定向运动产生,在真空中和电介质中也可以存在。<br>位移电流没有焦耳热效应。<br>位移电流与外磁场没有安培力关系。</p><p>位移电流的物理本质是:空间中随时间变化的电场可以激发磁场。</p><h3 id="麦克斯韦方程组"><a href="#麦克斯韦方程组" class="headerlink" title="麦克斯韦方程组"></a>麦克斯韦方程组</h3><script type="math/tex; mode=display">\begin{aligned}\oiint_S \boldsymbol{D}\cdot\text{d}\boldsymbol{S} &= \iiint_V \rho_0\text{d}V \\\oint_C \boldsymbol{E}\cdot\text{d}\boldsymbol{l} &= -\iint_{S_C}\frac{\partial\boldsymbol{B}}{\partial t}\cdot\text{d}\boldsymbol{S} \\\oiint_S\boldsymbol{B}\cdot\text{d}\boldsymbol{S} &= 0 \\\oint_C \boldsymbol{H}\cdot\text{d}\boldsymbol{l}&= \iint_{S_C}(\boldsymbol{j}_0 + \frac{\partial\boldsymbol{D}}{\partial t}) \cdot\text{d}\boldsymbol{S}\end{aligned}</script><p>微分形式</p><script type="math/tex; mode=display">\begin{aligned}\nabla\cdot\boldsymbol{D}&=\rho_0 \\\nabla \times\boldsymbol{E}&=-\frac{\partial\boldsymbol{B}}{\partial t}\\\nabla \cdot\boldsymbol{B} &= 0\\\nabla\times\boldsymbol{H}&=\boldsymbol{j}_0 + \frac{\partial\boldsymbol{D}}{\partial t}\end{aligned}</script><p>性能方程</p><script type="math/tex; mode=display">\begin{aligned}\boldsymbol{D} &= \varepsilon \boldsymbol{E} \\\boldsymbol{B} &= \mu \boldsymbol{H}\\\boldsymbol{j}_0 &= \sigma \boldsymbol{E} \\\boldsymbol{P} &= \boldsymbol{D} - \varepsilon_0\boldsymbol{E} \\\boldsymbol{M} &= \frac{\boldsymbol{B}}{\mu_0} - \boldsymbol{H}\end{aligned}</script><p>真空中,$\sigma =0,\varepsilon=\varepsilon_0,\mu=\mu_0$</p><h4 id="边值关系"><a href="#边值关系" class="headerlink" title="边值关系"></a>边值关系</h4><p>由积分形式,作无限接近介质界面的回路或者曲面,从而得到边值关系</p><script type="math/tex; mode=display">\begin{aligned}\boldsymbol{n}\cdot(\boldsymbol{D}_2-\boldsymbol{D}_1) &= \sigma_0 \\\boldsymbol{n}\times(\boldsymbol{E}_2-\boldsymbol{E}_1) &= 0 \\\boldsymbol{n}\cdot(\boldsymbol{B}_2-\boldsymbol{B}_1) &= 0 \\\boldsymbol{n}\times(\boldsymbol{H}_2-\boldsymbol{H}_1) &= \boldsymbol{i}_0 \\\boldsymbol{n}\cdot(\boldsymbol{P}_1-\boldsymbol{P}_2) &= \sigma^{'} \\\boldsymbol{n}\times(\boldsymbol{M}_2-\boldsymbol{M}_1) &= \boldsymbol{i}^{'} \\\end{aligned}</script><h4 id="唯一性定理"><a href="#唯一性定理" class="headerlink" title="唯一性定理"></a>唯一性定理</h4><p>电磁场唯一性定理:空间电荷和电流分布给定,边值条件已知,麦克斯韦方程组由唯一确定解。</p><h4 id="电磁场中的受力情况"><a href="#电磁场中的受力情况" class="headerlink" title="电磁场中的受力情况"></a>电磁场中的受力情况</h4><p>带电粒子在磁场中的受力</p><script type="math/tex; mode=display">\boldsymbol{F} = q\boldsymbol{E}+q\boldsymbol{v}\times\boldsymbol{B}</script><p>洛伦兹力不做功,只传递能量。</p><p>安培力的本质是洛伦兹力。</p><p>电流在磁场中的受力</p><script type="math/tex; mode=display">\begin{aligned}\boldsymbol{F} &= q\boldsymbol{v}\times\boldsymbol{B} \\\boldsymbol{F} &= \oint_L I\text{d}\boldsymbol{l}\times\boldsymbol{B}\\\boldsymbol{F} &= \iint_S\boldsymbol{i}\times\boldsymbol{B}\text{d}{S} \\\boldsymbol{F} &= \iiint_V\boldsymbol{j}\times\boldsymbol{B}\text{d}V\\\end{aligned}</script><h3 id="平面电磁波"><a href="#平面电磁波" class="headerlink" title="平面电磁波"></a>平面电磁波</h3><p>自由空间介质中,$\boldsymbol{D} = \varepsilon\boldsymbol{E},\boldsymbol{B}=\mu\boldsymbol{H}$,而且$\rho=0,\boldsymbol{j}_0=0$</p><p>所以有如下方程组</p><script type="math/tex; mode=display">\nabla\cdot\boldsymbol{E} = 0 \\</script><script type="math/tex; mode=display">\nabla\cdot\boldsymbol{H} = 0 \\</script><script type="math/tex; mode=display">\nabla\times\boldsymbol{E} = -\mu\frac{\partial \boldsymbol{H}}{\partial t} \\</script><script type="math/tex; mode=display">\nabla\times\boldsymbol{H} = \varepsilon\frac{\partial \boldsymbol{E}}{\partial t} \\</script><p>在均匀各向同性介质中的平面电磁波中,可以取$\nabla = j\boldsymbol{k},\displaystyle\frac{\partial}{\partial t}=-j\omega$,将这些写成复数形式</p><script type="math/tex; mode=display">\boldsymbol{k}\cdot\boldsymbol{E} = 0 \\</script><script type="math/tex; mode=display">\boldsymbol{k}\cdot\boldsymbol{H} = 0 \\</script><script type="math/tex; mode=display">\boldsymbol{k}\times\boldsymbol{E} = \mu\omega\boldsymbol{H}\\</script><script type="math/tex; mode=display">\boldsymbol{k}\times\boldsymbol{H} = -\varepsilon \omega \boldsymbol{E} \\</script><p>$\boldsymbol{k}$指向波的前进方向。$E,H,k$右手系。</p><p>一些变量的关系</p><script type="math/tex; mode=display">v = \sqrt{\frac{1}{\mu\varepsilon}} = \sqrt{\frac{\mu_0\varepsilon_0}{\mu\varepsilon}}c</script><script type="math/tex; mode=display">c=\sqrt{\frac{1}{\mu_0\varepsilon_0}}</script><script type="math/tex; mode=display">k=\omega\sqrt{\mu\varepsilon}</script><p>$k$为波数,即$2\pi$米长度上波的数量。</p><script type="math/tex; mode=display">k=2\pi/\lambda</script><p>用复数法表示波的方程</p><script type="math/tex; mode=display">\boldsymbol{E} = \boldsymbol{E}_0\text{e}^{j(kx-\omega t)}</script><script type="math/tex; mode=display">\boldsymbol{H} = \boldsymbol{H}_0\text{e}^{j(kx-\omega t)}</script><p>其他关系:<br>真空中</p><script type="math/tex; mode=display">\frac{E_0}{B_0} = \sqrt{\frac{1}{\varepsilon_0\mu_0}} = c</script><p>介质中</p><script type="math/tex; mode=display">\frac{E_0}{B_0} = \sqrt{\frac{1}{\varepsilon\mu}} = \frac{c}{n}</script><p>以上说明,电磁波在传播过程中,电场强度与磁场强度的幅值成正比,而且任意一点的电场能量密度和磁场能量密度是相等的。<br>推导方法为$k$硬叉乘上去。</p><p>n为折射率,</p><script type="math/tex; mode=display">n=\sqrt{\frac{\varepsilon\mu}{\varepsilon_0\mu_0}}</script><p>通常介质的磁导率相差不大,可以认为$\mu\approx\mu_0$</p><h3 id="电磁场的能量、动量和角动量"><a href="#电磁场的能量、动量和角动量" class="headerlink" title="电磁场的能量、动量和角动量"></a>电磁场的能量、动量和角动量</h3><p>令$\boldsymbol{S}=\boldsymbol{E}\times\boldsymbol{H}$为电磁场的能流密度,又称作坡印廷矢量</p><script type="math/tex; mode=display">w\equiv \frac{1}{2}(\varepsilon E^2 + \frac{1}{\mu}B^2)</script><p>则有</p><script type="math/tex; mode=display">-\frac{\partial w}{\partial t} = \nabla\cdot\boldsymbol{S} + \boldsymbol{j}\cdot\boldsymbol{E}</script><p>电磁场对$\text{d}V$内顶电梯所做的功和流出空间$\text{d}V$的能量之和等于$\text{d}V$内电磁场能量的减少,本质上是能量守恒定律的体现。<br>o<br>积分得到</p><script type="math/tex; mode=display">-\oiint_S\boldsymbol{S}\cdot\text{d}\boldsymbol{s} = \frac{\text{d}}{\text{d}t}(W+W_n)</script><p>即电磁场流入封闭曲面$\boldsymbol{s}$的能量,等于$\boldsymbol{s}$内总能量的增加。</p><p>我们可以看到,坡印廷矢量和焦耳热效应完完全全代表了空间中电磁场能量的变化情况。类似于电流输入的问题都可以转化成为坡印亭矢量进行求解。</p><h4 id="平面电磁场的能量问题"><a href="#平面电磁场的能量问题" class="headerlink" title="平面电磁场的能量问题"></a>平面电磁场的能量问题</h4><p>$w=gv$的式子我不知道怎么来的。</p><p>总之,<br>电磁场能量密度</p><script type="math/tex; mode=display">w=\frac{1}{2}(\varepsilon E^2 + \frac{1}{\mu}B^2) = \varepsilon E^2 = \frac{1}{\mu}B^2 = \mu H^2</script><script type="math/tex; mode=display">\boldsymbol{S} = \boldsymbol{E}\times\boldsymbol{H} = w\boldsymbol{v} = \boldsymbol{g} v^2</script><p>动量密度</p><script type="math/tex; mode=display">\boldsymbol{g} = \boldsymbol{S}/v^2 = \mu\varepsilon(\boldsymbol{E}\times\boldsymbol{H}) = \boldsymbol{D}\times\boldsymbol{B}</script><p>角动量密度</p><script type="math/tex; mode=display">\boldsymbol{l}= \boldsymbol{r} \times\boldsymbol{g}</script><p>带入方程</p><script type="math/tex; mode=display">\boldsymbol{E}(\boldsymbol{r}, t) =E_0\cos(\boldsymbol{k}\cdot\boldsymbol{r}-\omega t + \delta) \hat{n}</script><script type="math/tex; mode=display">\boldsymbol{B}(\boldsymbol{r}, t) = \frac{1}{c}\hat{k}\times\boldsymbol{E}</script><p>计算得到</p><script type="math/tex; mode=display">w=\varepsilon_0 E^2_0\cos^2(\boldsymbol{k}\cdot\boldsymbol{r}-\omega t + \delta)</script><script type="math/tex; mode=display">\left<w\right> = \frac{1}{2}\varepsilon_0E_0^2 = \frac{1}{2\mu_0}B_0^2</script><script type="math/tex; mode=display">\boldsymbol{S} = \frac{1}{\mu_0}\boldsymbol{E}\times\boldsymbol{B} = c\varepsilon_0 E^2_0\cos^2(\boldsymbol{k}\cdot\boldsymbol{r}-\omega t + \delta)\hat{k} = cw\hat{k}</script><script type="math/tex; mode=display">\left<\boldsymbol{S}\right> = c\left<w\right>\hat{k}</script><p>电磁波的强度</p><script type="math/tex; mode=display">I=|\left<\boldsymbol{S}\right>| = c\frac{1}{2}\varepsilon_0E_0^2 = \frac{c}{2\mu_0}B_0^2</script><p>动量密度</p><script type="math/tex; mode=display">\boldsymbol{g} = \boldsymbol{D}\times\boldsymbol{B} = \frac{\boldsymbol{S}}{v^2} = \frac{w\boldsymbol{v}}{v^2}</script><script type="math/tex; mode=display">\boldsymbol{l}= \boldsymbol{r} \times\boldsymbol{g}</script><h4 id="电磁场能量在电路中的传输"><a href="#电磁场能量在电路中的传输" class="headerlink" title="电磁场能量在电路中的传输"></a>电磁场能量在电路中的传输</h4><p>电源内部:坡印廷矢量方向向外,输出能量。</p><p>导线上:内部电场平行于电流方向,坡印廷矢量指向内部;<br>外部有切向电场维持电荷的宏观移动,这部分的坡印廷矢量指向导线内部。</p><h4 id="光压"><a href="#光压" class="headerlink" title="光压"></a>光压</h4><script type="math/tex; mode=display">p=(1+R)w</script><p>$R$为反射系数或者反射率,$R=1$全反射,$R=0$全吸收。</p><p>$w$为能量密度。给出功率的话,需要计算能量密度</p><script type="math/tex; mode=display">w=\frac{\Delta W}{\Delta V}=\frac{P\Delta t}{c\Delta t S} = \frac{P}{cS}</script><p>$c$为光速。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>电磁学东西很多,即使只是C类课程也已经让我焦头烂额。好在整理了这些知识点后,对学过的东西和需要的东西有了更深的体会。期末虽然成绩不算优异,但是已经很满意了。</p>]]></content>
<categories>
<category>物理</category>
</categories>
<tags>
<tag>物理</tag>
<tag>课内复习</tag>
</tags>
</entry>
<entry>
<title>电磁学C复习-磁学部分一</title>
<link href="/2022/02/02/ElecC2/"/>
<url>/2022/02/02/ElecC2/</url>
<content type="html"><![CDATA[<p>本文章是作者在学习电磁学时进行期末复习时做出的笔记。磁学内容较多,分为两个部分。这里是第一部分。</p><p>限于版权问题,复习的PPT不能够外传。本笔记仅提供提纲。</p><span id="more"></span><h2 id="第四章"><a href="#第四章" class="headerlink" title="第四章"></a>第四章</h2><h3 id="第一节"><a href="#第一节" class="headerlink" title="第一节"></a>第一节</h3><h4 id="洛伦兹力公式"><a href="#洛伦兹力公式" class="headerlink" title="洛伦兹力公式"></a>洛伦兹力公式</h4><script type="math/tex; mode=display">\newcommand{\oiint}{\subset\kern{-3pt}\supset\kern{-16.5pt}\iint}\vec{F} = q\vec{v}\times \vec{B}</script><h4 id="安培力"><a href="#安培力" class="headerlink" title="安培力"></a>安培力</h4><p>电流密度公式</p><script type="math/tex; mode=display">\boldsymbol{j} = nq\boldsymbol{u}</script><p>每个载流子收到的洛伦兹力为</p><script type="math/tex; mode=display">q\boldsymbol{u}\times\boldsymbol{B}</script><p>则有安培力</p><script type="math/tex; mode=display">\text{d}\boldsymbol{F} = n\text{d}V q\boldsymbol{u}\times\boldsymbol{B} = \boldsymbol{j}\times\boldsymbol{B}\text{d}V</script><p>其中可以替换电流元</p><script type="math/tex; mode=display">\boldsymbol{j}\text{d}V = \boldsymbol{i}\text{d}S = I\text{d}\boldsymbol{l}</script><p>注意面电流元的表示方法。</p><p>也有公式总结如</p><script type="math/tex; mode=display">\boldsymbol{F}= \iiint_V\boldsymbol{j}\times\boldsymbol{B}\text{d}V</script><h4 id="安培定律"><a href="#安培定律" class="headerlink" title="安培定律"></a>安培定律</h4><p>两个电流源之间的作用力满足公式</p><script type="math/tex; mode=display">\text{d}\boldsymbol{F}_{12} = \frac{\mu_0}{4\pi}\frac{I_2\text{d}\boldsymbol{l}_2\times (I_1\text{d}\boldsymbol{l}_1\times \boldsymbol{r}_{12})}{r_{12}^3}</script><p>对于面电流元和体电流元也可以这样表示</p><script type="math/tex; mode=display">\text{d}\boldsymbol{F}_{12} = \frac{\mu_0}{4\pi}\frac{\boldsymbol{i}_2\text{d}{S}_2\times (\boldsymbol{i}_1\text{d}{S}_1\times \boldsymbol{r}_{12})}{r_{12}^3}</script><script type="math/tex; mode=display">\text{d}\boldsymbol{F}_{12} = \frac{\mu_0}{4\pi}\frac{\boldsymbol{j}_2\text{d}{V}_2\times (\boldsymbol{j}_1\text{d}{V}_1\times \boldsymbol{r}_{12})}{r_{12}^3}</script><p>电流元之间的相互作用力不一定满足牛顿第三定律,因为不存在孤立的恒稳电流元。</p><p>电流元在外磁场中受到的安培力为</p><script type="math/tex; mode=display"> \text{d}\boldsymbol{F} = I\text{d}\boldsymbol{l}\times \boldsymbol{B}</script><p>这在前文有所提及了。</p><h4 id="磁矩"><a href="#磁矩" class="headerlink" title="磁矩"></a>磁矩</h4><p>定义磁矩$\boldsymbol{m}$</p><script type="math/tex; mode=display">\boldsymbol{m} = I\boldsymbol{S}</script><h4 id="载流线圈在磁场中受到的力矩"><a href="#载流线圈在磁场中受到的力矩" class="headerlink" title="载流线圈在磁场中受到的力矩"></a>载流线圈在磁场中受到的力矩</h4><script type="math/tex; mode=display">\boldsymbol{L} = \boldsymbol{m}\times\boldsymbol{B}</script><p>作为对比,电偶极子在外电场中受到的力矩公式为$\boldsymbol{L} = \boldsymbol{P}\times\boldsymbol{E}$</p><h3 id="电流的磁场"><a href="#电流的磁场" class="headerlink" title="电流的磁场"></a>电流的磁场</h3><h4 id="磁场叠加原理"><a href="#磁场叠加原理" class="headerlink" title="磁场叠加原理"></a>磁场叠加原理</h4><script type="math/tex; mode=display">\boldsymbol{B} = \sum \boldsymbol{B}_i</script><script type="math/tex; mode=display">\boldsymbol{B} = \oint_L \text{d}\boldsymbol{B}</script><h4 id="毕奥-萨法尔定律"><a href="#毕奥-萨法尔定律" class="headerlink" title="毕奥-萨法尔定律"></a>毕奥-萨法尔定律</h4><script type="math/tex; mode=display">\text{d}\boldsymbol{B} = \frac{\mu_0}{4\pi}I\text{d}\boldsymbol{l} \times \frac{\boldsymbol{r}}{r^3}</script><p>这个可以由安培定律比较推导出来</p><script type="math/tex; mode=display">\text{d}\boldsymbol{F}_{12} = \frac{\mu_0}{4\pi}\frac{I_2\text{d}\boldsymbol{l}_2\times (I_1\text{d}\boldsymbol{l}_1\times \boldsymbol{r}_{12})}{r_{12}^3} = I_2\text{d}\boldsymbol{l}_2 \times \left(\frac{\mu_0}{4\pi}\frac{I_{1}\text{d}\boldsymbol{l}_1\times\boldsymbol{r_{12}}}{r_{12}^3}\right)</script><h4 id="积分形式"><a href="#积分形式" class="headerlink" title="积分形式"></a>积分形式</h4><script type="math/tex; mode=display">\boldsymbol{B} = \frac{\mu_0}{4\pi}\oint_L\frac{I\text{d}\boldsymbol{l}\times\boldsymbol{r}}{r^3}</script><h4 id="电流环产生的磁场"><a href="#电流环产生的磁场" class="headerlink" title="电流环产生的磁场"></a>电流环产生的磁场</h4><script type="math/tex; mode=display">\boldsymbol{B} = -\frac{\mu_0}{4\pi}\left(\frac{\boldsymbol{m}}{r^3}-\frac{3(\boldsymbol{m}\cdot\boldsymbol{r})\boldsymbol{r}}{r^5}\right)</script><p>任意均匀闭合回路均可。需要有几何中心。</p><h4 id="亥姆赫兹线圈"><a href="#亥姆赫兹线圈" class="headerlink" title="亥姆赫兹线圈"></a>亥姆赫兹线圈</h4><p>要求线圈之间的距离$d$ 等于线圈的半径$R$</p><script type="math/tex; mode=display">B_(x) = \frac{\mu_0NIR^2}{2\left(r^2+(\frac{d}{2}+x)^2\right)^{3/2}} + \frac{\mu_0NIR^2}{2\left(r^2+(\frac{d}{2}-x)^2\right)^{3/2}} = \left(\frac{4}{5}\right)^{3/2}\frac{\mu_0NI}{R}</script><h4 id="通电螺线管的磁场分布"><a href="#通电螺线管的磁场分布" class="headerlink" title="通电螺线管的磁场分布"></a>通电螺线管的磁场分布</h4><p>参考PPT4-2,太难了</p><p>使用三角函数辅助计算的方法。</p><script type="math/tex; mode=display">B = \frac{\mu_0nI}{2}(\cos \beta_1 - \cos\beta_2)</script><p>中间为$\mu_0nI$,两边为$\mu_0nI/2$</p><h4 id="运动电荷的磁场"><a href="#运动电荷的磁场" class="headerlink" title="运动电荷的磁场"></a>运动电荷的磁场</h4><p>单个运动电荷产生的磁场推导如下</p><script type="math/tex; mode=display">I=\frac{\Delta q}{\Delta t} = nqvS</script><script type="math/tex; mode=display">\text{d}N = n\text{d}V = nS\text{d}l</script><p>所以</p><script type="math/tex; mode=display">\boldsymbol{B} = \frac{\text{d}\boldsymbol{B}}{\text{d}N} = \frac{\mu_0}{4\pi}\frac{I\text{d}\boldsymbol{l}\times\boldsymbol{r}}{\text{d}Nr^3} = \frac{\mu_0}{4\pi}\frac{nqvS\text{d}\boldsymbol{l}\times\boldsymbol{r}}{\text{d}nS\text{d}lr^3} = \frac{\mu_0}{4\pi}\frac{q\boldsymbol{v}\times\boldsymbol{r}}{r^3}</script><p>可以得到</p><script type="math/tex; mode=display">\boldsymbol{B} = \mu_0\varepsilon_0\boldsymbol{v}\times\boldsymbol{E} = \frac{1}{c^2}\boldsymbol{v}\times\boldsymbol{E}</script><h4 id="磁场对电流的力与力矩"><a href="#磁场对电流的力与力矩" class="headerlink" title="磁场对电流的力与力矩"></a>磁场对电流的力与力矩</h4><p>带电粒子</p><script type="math/tex; mode=display">\boldsymbol{F} = q\boldsymbol{v}\times \boldsymbol{B}</script><p>电流受到的安培力,相当于把前文的电流元安培力进行了积分处理。</p><script type="math/tex; mode=display">\boldsymbol{F} = \oint_L I\text{d}\boldsymbol{l} \times \boldsymbol{B}</script><script type="math/tex; mode=display">\boldsymbol{F} = \iint_S\boldsymbol{i}\times\boldsymbol{B}\text{d}S</script><script type="math/tex; mode=display">\boldsymbol{F} = \iiint_V \boldsymbol{j}\times\boldsymbol{B}\text{d}V</script><p>力矩也是类似地进行了积分</p><script type="math/tex; mode=display">\boldsymbol{L} = \oint_L \boldsymbol{r} \times\left( I\text{d}\boldsymbol{l} \times \boldsymbol{B}\right)</script><script type="math/tex; mode=display">\boldsymbol{L} = \iint_S\boldsymbol{r}\times(\boldsymbol{i}\times\boldsymbol{B})\text{d}S</script><script type="math/tex; mode=display">\boldsymbol{L} = \iiint_V \boldsymbol{r}\times(\boldsymbol{j}\times\boldsymbol{B})\text{d}V</script><h4 id="载流线圈在非均匀磁场中受到的力和力矩"><a href="#载流线圈在非均匀磁场中受到的力和力矩" class="headerlink" title="载流线圈在非均匀磁场中受到的力和力矩"></a>载流线圈在非均匀磁场中受到的力和力矩</h4><script type="math/tex; mode=display">\boldsymbol{F} = (\boldsymbol{m}\cdot \nabla) \boldsymbol{B}</script><script type="math/tex; mode=display">\boldsymbol{F} = \boldsymbol{m} \times \boldsymbol{B}</script><h3 id="静磁场基本定理"><a href="#静磁场基本定理" class="headerlink" title="静磁场基本定理"></a>静磁场基本定理</h3><h4 id="磁通量"><a href="#磁通量" class="headerlink" title="磁通量"></a>磁通量</h4><script type="math/tex; mode=display">\boldsymbol{B}\cdot \Delta \boldsymbol{S} = \Delta \Phi_B</script><p>or</p><script type="math/tex; mode=display">\Phi_B = \iint_S \boldsymbol{B}\cdot\text{d}\boldsymbol{S}</script><p>单位韦伯Wb,1Wb = 1T$\cdot$m$^2$</p><h4 id="高斯定理"><a href="#高斯定理" class="headerlink" title="高斯定理"></a>高斯定理</h4><p>通过任意闭合曲面$S$的磁通量为零。</p><script type="math/tex; mode=display">\iint_S\boldsymbol{B}\cdot\text{d}\boldsymbol{S} = 0</script><h4 id="安培环路定理"><a href="#安培环路定理" class="headerlink" title="安培环路定理"></a>安培环路定理</h4><p>任意闭合曲线$L$的磁感应强度地环量等于穿过$L$的电流强度的代数和的$\mu_0$倍。</p><script type="math/tex; mode=display">\oint_L \boldsymbol{B}\cdot\text{d}\boldsymbol{L} = \mu_0\sum_L\pm I_{\text{内}}</script><p>磁场有旋。方向按照右手定则确定。</p><p>由斯托克斯公式</p><script type="math/tex; mode=display">\oint_L \boldsymbol{B}\cdot\text{d}\boldsymbol{L} = \iint_S (\nabla \times \boldsymbol{B})\cdot \text{d}\boldsymbol{S}</script><p>由电流的求和</p><script type="math/tex; mode=display">\sum I = \iint_S \boldsymbol{j} \cdot \text{d}\boldsymbol{S}</script><p>比较可得</p><script type="math/tex; mode=display">\nabla \times \boldsymbol{B} = \mu_0\boldsymbol{j}</script><p>这里可以注意到,$\boldsymbol{j}\cdot\text{d}\boldsymbol{S}$和$i\text{d}\boldsymbol{S}$是不同的。这里考虑的电流是体分布的,而不是面分布的。</p><h4 id="螺线管碎碎念"><a href="#螺线管碎碎念" class="headerlink" title="螺线管碎碎念"></a>螺线管碎碎念</h4><p>计算螺线管内部磁感应强度分布时,可以将螺线管看作电流环的叠加。</p><p>计算外部磁感应强度时,需要将螺线管近似成无限长直导线。那么可以求得$B_{\bot} = \displaystyle\frac{\mu_0I}{2\pi r}$.</p><h4 id="电流在外磁场中的受力问题"><a href="#电流在外磁场中的受力问题" class="headerlink" title="电流在外磁场中的受力问题"></a>电流在外磁场中的受力问题</h4><p>外磁场为处受力体电流之外所产生的磁场。</p><p>同样的,有如下的关系成立</p><script type="math/tex; mode=display">\boldsymbol{B} = \boldsymbol{B}_t - \boldsymbol{B}_1</script><p>因此应用毕奥萨法尔定理和环路定理得到磁感应分布,有</p><ol><li>体电流元$\boldsymbol{j}\text{d}V$在附近产生的磁感应强度为零。(使用毕奥定理论证)</li><li>面电流元$\boldsymbol{i}\text{d}{S}$在两侧产生的磁感应强度存在间断,大小为$\mu_0i/2$,方向相反,与面元相切。(使用环路定理论证,这时候代入公式的不是电流元而是电流$i\text{d}l$)</li><li>线电流元不能直接推广。必须引入有限截面,当作体电流元处理。(使用环路定理论证)</li></ol><p>外磁场$B$通常是连续的,总磁场$B_t$和自身磁场$B_1$通常是不连续的,但是相减后可以抵消。</p><p>这里去好好看看PPT例题和作业题,太难了吧。</p><h4 id="电流元"><a href="#电流元" class="headerlink" title="电流元"></a>电流元</h4><p>电流元既表示电流的大小,又表示电流的考察尺度和流动方向。通常的线电流元是</p><script type="math/tex; mode=display">I\text{d}\boldsymbol{l}</script><p>如果电流沿面分布,可以考虑电流的面密度,即电流穿过一个横截线的大小,$i = \displaystyle\frac{\text{d}I}{\text{d}l}$,那么电流元可以表示为</p><script type="math/tex; mode=display">\boldsymbol{i}\text{d}S</script><p>如果电流在空间内分布,可以考虑电流的体密度,即电流穿过一个平面的大小,$j = \displaystyle\frac{\text{d}I}{\text{d}S}$,那么电流元可以表示为</p><script type="math/tex; mode=display">\boldsymbol{j}\text{d}V</script><p>它们的量纲都是相同的。</p><p>PAGE 110 留念</p><h3 id="带电粒子在磁场中的运动"><a href="#带电粒子在磁场中的运动" class="headerlink" title="带电粒子在磁场中的运动"></a>带电粒子在磁场中的运动</h3><h4 id="洛伦兹力"><a href="#洛伦兹力" class="headerlink" title="洛伦兹力"></a>洛伦兹力</h4><script type="math/tex; mode=display">\boldsymbol{F} = q\boldsymbol{v}\times\boldsymbol{B}</script><h4 id="洛伦兹力做功"><a href="#洛伦兹力做功" class="headerlink" title="洛伦兹力做功"></a>洛伦兹力做功</h4><p>洛伦兹力不做功</p><script type="math/tex; mode=display">\boldsymbol{F} \cdot \boldsymbol{v} = q\boldsymbol{v}\times\boldsymbol{B} \cdot \boldsymbol{v} = 0</script><h4 id="带电粒子在匀强磁场中的运动"><a href="#带电粒子在匀强磁场中的运动" class="headerlink" title="带电粒子在匀强磁场中的运动"></a>带电粒子在匀强磁场中的运动</h4><p>运动方程</p><script type="math/tex; mode=display">m\frac{\text{d}\boldsymbol{v}}{\text{d}t} = q\boldsymbol{v}\times\boldsymbol{B}</script><p>$F$只在平面上有分布,假设为x-y平面,有</p><script type="math/tex; mode=display">\left\{\begin{aligned}\frac{\text{d}v_x}{\text{d}t} &= \frac{q}{m}v_yB \\\frac{\text{d}v_y}{\text{d}t} &= -\frac{q}{m}v_xB \\v_z &= \text{const}\end{aligned}\right.</script><p>可以解出轨迹方程。</p><p>回旋角频率</p><script type="math/tex; mode=display">\omega = \frac{qB}{m}</script><p>回旋周期</p><script type="math/tex; mode=display">T = \frac{2\pi m}{qB}</script><p>回旋半径</p><script type="math/tex; mode=display">R = \frac{v_{\bot}}{\omega} = \frac{v_{\bot}m}{qB}</script><p>回旋频率</p><script type="math/tex; mode=display">f = \frac{qB}{2\pi m}</script><h4 id="带电粒子在正交匀强电磁场中的运动"><a href="#带电粒子在正交匀强电磁场中的运动" class="headerlink" title="带电粒子在正交匀强电磁场中的运动"></a>带电粒子在正交匀强电磁场中的运动</h4><p>E沿y轴,B沿z轴,初速度$\boldsymbol{v}_0$</p><script type="math/tex; mode=display">\boldsymbol{v}_0 = v_0\cos\alpha \boldsymbol{i} + v_o\cos\beta\boldsymbol{j}+v_0\cos\gamma\boldsymbol{k}</script><p>运动方程为</p><script type="math/tex; mode=display">\left\{\begin{aligned}\frac{\text{d}v_x}{\text{d}t} &= \frac{q}{m}v_yB \\\frac{\text{d}v_y}{\text{d}t} &= \frac{q}{m}(E-v_xB) \\v_z &=\text{const}\end{aligned}\right.</script><p>解得</p><script type="math/tex; mode=display">\left\{\begin{aligned}v_x &= \frac{E}{B} + v_{\bot}\sin(\omega t + \varphi) \\v_y &= v_{\bot}\cos(\omega t + \varphi) \\v_z& = v_0\cos\gamma\end{aligned}\right.</script><p>这里$\omega$为回旋角频率,$\varphi$得取值使得$\boldsymbol{v}|_{t=0} = \boldsymbol{v}_0$</p><p>是一个漂移的圆周运动。</p><h4 id="带电粒子在缓变非均匀磁场中的运动"><a href="#带电粒子在缓变非均匀磁场中的运动" class="headerlink" title="带电粒子在缓变非均匀磁场中的运动"></a>带电粒子在缓变非均匀磁场中的运动</h4><p>非均匀尺度远大于带电粒子回旋半径。非均匀性将破坏$v_{\bot}$和$v_{//}$的守恒性。</p><p>在这一过程中,粒子的回旋磁矩是守恒的。带电粒子绕磁场的快速回旋形成了一个电流环,该电流环的磁矩称为粒子的回旋磁矩。</p><p>推导过程看PPT,这里给出结论</p><script type="math/tex; mode=display">\mu = I\Delta S = \frac{q\omega}{2\pi}\pi R^2 = \frac{\frac{1}{2}mv_{\bot}^2}{B} = \text{const}</script><p>回旋半径和回旋速度则可以使用回旋磁矩表示</p><script type="math/tex; mode=display">R = \sqrt{\frac{2\mu m}{q^2B}}</script><script type="math/tex; mode=display">v_{\bot} = \sqrt{\frac{2\mu B}{m}}</script><p>同时也能发现磁场穿过圆形轨道的磁通量守恒</p><script type="math/tex; mode=display">\Phi = BS = \pi R^2B = \frac{2\mu\pi m}{q^2} = \text{const}</script><p>这一节的应用,看PPT。</p><h4 id="磁镜磁约束"><a href="#磁镜磁约束" class="headerlink" title="磁镜磁约束"></a>磁镜磁约束</h4><p>看PPT的图。在磁场最弱的地方,投入粒子,投掷角为$\theta$。投掷角定义为$v_0\sin\theta = v_{0\bot}$</p><p>临界投掷角为$\theta_m$。由回旋磁矩守恒</p><script type="math/tex; mode=display">\frac{1}{2}mv^2\sin^2\theta_m/B_0 = \frac{1}{2}mv^2/B_{max}</script><p>即</p><script type="math/tex; mode=display">\sin^2\theta_m = \frac{B_0}{B_m} = \frac{1}{R_{mi}}</script><p>$R_{mi}$称为磁镜比。</p><h4 id="球冠面积和体积"><a href="#球冠面积和体积" class="headerlink" title="球冠面积和体积"></a>球冠面积和体积</h4><p>这是基本微积分可以解决的问题!!</p><p>有问题一定要考虑自己已经掌握了的知识!!我学过微积分了!我会积分的!</p><script type="math/tex; mode=display">S = 2\pi R^2H</script><h3 id="霍尔效应"><a href="#霍尔效应" class="headerlink" title="霍尔效应"></a>霍尔效应</h3><p>洛伦兹力和电力平衡$E_hq = qvB$</p><script type="math/tex; mode=display">V_h = E_hb = vbB</script><p>N型半导体中电子浓度为n,电流为</p><script type="math/tex; mode=display">I = nebdv</script><p>推导得到</p><script type="math/tex; mode=display">V_h = \frac{1}{ne}\frac{IB}{d} = R_h \frac{IB}{d} = K_hIB</script><p>物理量$\displaystyle R_h = \frac{1}{nq}$为霍尔系数,$K_h = R_h / d$为霍尔元件的灵敏度,$r_h = \displaystyle\frac{V_h}{I}=K_hB$为霍尔电阻。</p><p>你需要知道什么是霍尔效应。看PPT去吧。霍尔电阻只是具有电阻的量纲,没有电阻效应。</p><h2 id="第五章"><a href="#第五章" class="headerlink" title="第五章"></a>第五章</h2><h3 id="磁介质及其磁化"><a href="#磁介质及其磁化" class="headerlink" title="磁介质及其磁化"></a>磁介质及其磁化</h3><p>有介质时的总磁场</p><script type="math/tex; mode=display">\boldsymbol{B} = \boldsymbol{B}_0 + \boldsymbol{B}^{'} = \mu_r\boldsymbol{B}_0</script><h4 id="磁化电流"><a href="#磁化电流" class="headerlink" title="磁化电流"></a>磁化电流</h4><p>在磁化状态下,由于分子电流的有序排列,磁介质中将出现宏观电流,称为磁化电流。</p><ol><li>磁化电流不伴随电荷的宏观位移。</li><li>磁化电流可存在于一切磁介质中,不具有焦耳热效应。</li><li>在激发磁场和受磁场作用方面磁化电流和传导电流相同。</li></ol><h4 id="磁化强度"><a href="#磁化强度" class="headerlink" title="磁化强度"></a>磁化强度</h4><p>磁化强度定义为体积元内分子磁矩的矢量和。</p><script type="math/tex; mode=display">\boldsymbol{M} = \frac{\sum \boldsymbol{m}_{\text{分子}}}{\Delta V}</script><p>$\boldsymbol{M}=0$时磁介质处于非磁化态。</p><h4 id="分子平均磁矩"><a href="#分子平均磁矩" class="headerlink" title="分子平均磁矩"></a>分子平均磁矩</h4><p>分子平均磁矩定义为</p><script type="math/tex; mode=display">\boldsymbol{m}_a = \frac{\sum \boldsymbol{m}_{\text{分子}}}{n\Delta V} = \frac{\boldsymbol{M}}{n}</script><p>$\boldsymbol{m}_a$可以认为是平均分子电流产生的,电流强度为$I_a$,所围成的面积矢量为$S_a$,则</p><script type="math/tex; mode=display">\boldsymbol{m}_a=I_a\boldsymbol{S}_a,\boldsymbol{M}_a=nI_a\boldsymbol{S}_a</script><h4 id="磁化电流与磁化强度"><a href="#磁化电流与磁化强度" class="headerlink" title="磁化电流与磁化强度"></a>磁化电流与磁化强度</h4><script type="math/tex; mode=display">\oint_L\boldsymbol{M}\cdot\text{d}\boldsymbol{l} = \sum I^{'}</script><p>即</p><script type="math/tex; mode=display">\nabla \times \boldsymbol{M} = \boldsymbol{j}^{'}</script><p>均匀磁化介质内部,磁化电流为零。</p><p>一般地,在介质表面和两种介质交界面上,会有面分布的磁化电流。</p><p>在介质表面,磁化面电流可以这样求得</p><script type="math/tex; mode=display">\boldsymbol{i}^{'} = \boldsymbol{M}\times\boldsymbol{n}</script><p>PAGE 184</p><h3 id="磁性材料"><a href="#磁性材料" class="headerlink" title="磁性材料"></a>磁性材料</h3><p>磁介质在外磁场$B_0$中磁化,产生的磁化电流激发新的磁场$B^{‘}$,总磁场应为$B=B_0+B^{‘}$</p><p>由高斯定理和安培环路定理</p><script type="math/tex; mode=display">\oiint_S\boldsymbol{B}\cdot\text{d}\boldsymbol{S} = 0</script><script type="math/tex; mode=display">\oint_L \boldsymbol{B}\cdot\text{d}\boldsymbol{l} = \mu_0\sum I_0 + \mu_0 \sum I^{'}</script><h4 id="磁场强度"><a href="#磁场强度" class="headerlink" title="磁场强度"></a>磁场强度</h4><p>有安培环路定理</p><script type="math/tex; mode=display">\oint_L \left(\frac{\boldsymbol{B}}{\mu_0}-\boldsymbol{M}\right)\cdot\text{d}\boldsymbol{l} = \sum I_0</script><p>令</p><script type="math/tex; mode=display">\boldsymbol{H} = \frac{\boldsymbol{B}}{\mu_0} - \boldsymbol{M}</script><p>有磁介质中的静磁场安培环路定理</p><script type="math/tex; mode=display">\oint_L \boldsymbol{H}\cdot\text{d}\boldsymbol{l} = \sum I_0</script><h4 id="介质的磁化规律"><a href="#介质的磁化规律" class="headerlink" title="介质的磁化规律"></a>介质的磁化规律</h4><script type="math/tex; mode=display">\boldsymbol{M} = \chi _m \boldsymbol{H}</script><p>其中$\chi_m$为磁化率。</p><script type="math/tex; mode=display">\boldsymbol{B}=\mu_0(\boldsymbol{H}+\boldsymbol{M}) = \mu_0(1+\chi_m)\boldsymbol{H} = \mu\boldsymbol{H}</script><p>$\mu = \mu_0(1+\chi_m)$为绝对磁导率。</p><p>$\mu_r = \mu / \mu_0= 1+\chi_m$为相对磁导率</p><p>线性各向同性介质中,$\chi_m$为常数。</p><h4 id="磁场在磁介质界面上的边值关系"><a href="#磁场在磁介质界面上的边值关系" class="headerlink" title="磁场在磁介质界面上的边值关系"></a>磁场在磁介质界面上的边值关系</h4><p>分界面处$\boldsymbol{B}$法向连续</p><p>取圆柱面使用高斯定理即可。侧面的高度趋近于0,则法向大小相抵消,连续。</p><p>分界面的磁化电流,可以使用安培环路定理</p><script type="math/tex; mode=display">\boldsymbol{i}^{'} = (\boldsymbol{M}_1 - \boldsymbol{M}_2) \times \boldsymbol{n}</script><p>方向参考右手系。</p><p>分界面的传导电流,使用安培环路定理</p><script type="math/tex; mode=display">\boldsymbol{i}_{0} = (\boldsymbol{H}_1 - \boldsymbol{H}_2) \times \boldsymbol{n}</script><p>如果没有传导电流的话,磁场强度在界面切向连续。</p><script type="math/tex; mode=display">H_{\tau 1} = H_{\tau 2}</script><h4 id="界面磁感应线的折射定理"><a href="#界面磁感应线的折射定理" class="headerlink" title="界面磁感应线的折射定理"></a>界面磁感应线的折射定理</h4><p>B线和H线均有对应的折射性质。</p><script type="math/tex; mode=display">\left\{\begin{aligned}B_{2n} &= B_{1n} \\H_{2\tau} &= H_{1\tau} \\B &= \mu H\end{aligned}\right.</script><p>推导出</p><script type="math/tex; mode=display">\left\{\begin{aligned}B_{2\tau} &= \frac{\mu_2}{\mu_1}B_{1\tau} \\H_{2n} &= \frac{\mu_2}{\mu_1}H_{1n}\end{aligned}\right.</script><p>然后折射性便能很简单得到了。</p><script type="math/tex; mode=display">\frac{\tan \theta_1}{\tan \theta_2} = \frac{\mu_1}{\mu_2}</script><p>角度对应关系自己推导一下。</p><h4 id="介质表面与磁感应线重合"><a href="#介质表面与磁感应线重合" class="headerlink" title="介质表面与磁感应线重合"></a>介质表面与磁感应线重合</h4><p>这时候考虑切向的量。正好H有切向的分量关系。H线无视介质,先求H,传导电流。</p><p>有一个奇怪的式子</p><script type="math/tex; mode=display">M_1 - M_2 = (B_1/\mu_0 - H) - (B_2/\mu_0-H) = (B_1-B_2)/\mu_0</script><p>乍一看,好像搞错成了$M=B/\mu_0$。但其实,$M=B/\mu_0-H$,这里消去了相同的H。</p><h4 id="介质表面与磁感应线垂直"><a href="#介质表面与磁感应线垂直" class="headerlink" title="介质表面与磁感应线垂直"></a>介质表面与磁感应线垂直</h4><p>B线无视介质。<br><strong>认为磁感应线是规律的!</strong> 不然不能做题了。</p><p>由于磁化强度与界面垂直,而且连续,界面没有磁化面电流。</p><p>这种情况就不用考虑磁化电流了吗?不是的,在其他有磁化强度的地方依然会产生磁化面电流。满足条件即会产生。</p><p>题目中给出的”通过电缆的电流强度”是传导电流。考虑定义即可知道原因。</p><p>传导电流的作用是传导,因此它是”通过电缆的电流”。磁化电流并不会通过电缆,不伴随电荷移动。</p><p>因此解题方法方法为</p><script type="math/tex; mode=display">\sum \oint_L \frac{\boldsymbol{B}}{\mu_i}\cdot\text{d}\boldsymbol{l} = \sum I</script><p>得到$\boldsymbol{B}$,无视介质。</p><p>然后得到H,M。根据定义得到磁化面电流和传导面电流。</p><p>这时候你忽然发现你又求到了传导面电流。它们一样吗?积分出来其实是一样的。</p><p>综上,总是可以利用$H=B/\mu_0-M$和$M=\chi_mH$,$B=\mu H$的关系进行计算。</p><p>题目给出的电流是传导电流,给出的电荷是总电荷。这是电学和磁学的不同之处。</p><h3 id="磁性材料-1"><a href="#磁性材料-1" class="headerlink" title="磁性材料_"></a>磁性材料_</h3><h4 id="磁化规律"><a href="#磁化规律" class="headerlink" title="磁化规律"></a>磁化规律</h4><p>顺磁材料$\chi_m > 0, \mu_r > 1,\chi_m = 10^{-4}\sim 10^{-5}$,弱磁性<br>抗磁材料$\chi_m < 0, \mu_r < 1,-\chi_m = 10^{-5}\sim 10^{-7}$,弱磁性<br>铁磁材料$\chi_m \gg 0, \mu_r \gg 1, \chi_m = 10^{3}\sim 10^{6}$,强磁性</p><h4 id="顺磁材料的磁化机制"><a href="#顺磁材料的磁化机制" class="headerlink" title="顺磁材料的磁化机制"></a>顺磁材料的磁化机制</h4><script type="math/tex; mode=display">\chi_m = \frac{b}{T} \propto\frac{1}{T}</script><h4 id="抗磁材料的磁化规律"><a href="#抗磁材料的磁化规律" class="headerlink" title="抗磁材料的磁化规律"></a>抗磁材料的磁化规律</h4><script type="math/tex; mode=display">\chi_m = -\frac{\mu_0n_0Ze^2\left<r^2\right>}{6m_e}</script><p>抗磁的本质是由轨道电子在外磁场中产生的<strong>附加磁矩</strong>造成的,而附加磁矩比轨道磁矩和自旋磁矩小得多,因此顺磁介质中抗磁效应也存在,但是远小于顺磁效应。</p><h4 id="贴磁介质"><a href="#贴磁介质" class="headerlink" title="贴磁介质"></a>贴磁介质</h4><script type="math/tex; mode=display">\chi_m = \chi_m(\boldsymbol{H})</script><p>M的值和H间的函数关系复杂,而且取决于磁化的历史。</p><p>外界环境改变的是H,通过材料的B,展现出M的大小,<br>因此可以通过B-H曲线表示磁化性质,即磁滞回线。</p><p>软磁材料,硬磁材料,矩磁材料,看PPT</p><h4 id="铁磁材料的居里温度"><a href="#铁磁材料的居里温度" class="headerlink" title="铁磁材料的居里温度"></a>铁磁材料的居里温度</h4><script type="math/tex; mode=display">\chi_m = \frac{c}{T-T_c}</script><h3 id="磁路定理与磁屏蔽"><a href="#磁路定理与磁屏蔽" class="headerlink" title="磁路定理与磁屏蔽"></a>磁路定理与磁屏蔽</h3><p>约束在磁心范围内的磁场叫做磁路。</p><p>磁路与电路的对比看PPT249页。</p><div class="table-container"><table><thead><tr><th>电路</th><th>磁路</th></tr></thead><tbody><tr><td>$\displaystyle\newcommand{\oiint}{\subset\kern{-3pt}\supset\kern{-16.5pt}\iint}\oiint \boldsymbol{j}\cdot\text{d}\boldsymbol{S}=0$</td><td>$\displaystyle\oiint \boldsymbol{B}\cdot\text{d}\boldsymbol{S}=0$</td></tr><tr><td>$I = \boldsymbol{j} \cdot\boldsymbol{S}=\text{const}$</td><td>$\Phi = \boldsymbol{B}\cdot\boldsymbol{S}=\text{const}$</td></tr><tr><td>$\boldsymbol{j} = \sigma \boldsymbol{E}$</td><td>$\boldsymbol{B} = \mu\boldsymbol{H}$</td></tr><tr><td>$R=\displaystyle\int\frac{\text{d}l}{\sigma S}$</td><td>$R_m = \displaystyle\int \frac{\text{d}l}{\mu S}$</td></tr><tr><td>$U=\displaystyle \int \boldsymbol{E}\cdot\text{d}\boldsymbol{l}=IR$</td><td>$U_m = \displaystyle\int\boldsymbol{H}\cdot{\text{d}\boldsymbol{l}}{} = \Phi R_m$</td></tr></tbody></table></div><h4 id="磁阻"><a href="#磁阻" class="headerlink" title="磁阻"></a>磁阻</h4><script type="math/tex; mode=display">R_m = \int \frac{\text{d}l}{\mu S}</script><p>PAGE 250</p><h4 id="磁路定理"><a href="#磁路定理" class="headerlink" title="磁路定理"></a>磁路定理</h4><ol><li>沿磁力线管的磁通量$\Phi$是常量.</li><li>磁通与该段磁路的磁阻之积等于磁势降。</li></ol><script type="math/tex; mode=display">\int \boldsymbol{H}\cdot\text{d}\boldsymbol{l} = \int \frac{\boldsymbol{B}}{\mu}\cdot \text{d}\boldsymbol{l} = \int \frac{\Phi}{\mu S}\text{d}l = \Phi R_m = U_m</script><p>即</p><script type="math/tex; mode=display">U_m = \Phi R_m</script><p>此即磁路定理</p><h4 id="磁路"><a href="#磁路" class="headerlink" title="磁路"></a>磁路</h4><p>也有KVL:</p><script type="math/tex; mode=display">\varepsilon_m = \Phi(R_m + r_m)</script><h4 id="理想磁路的条件"><a href="#理想磁路的条件" class="headerlink" title="理想磁路的条件"></a>理想磁路的条件</h4><p>闭合铁芯的磁导率远远大于$\mu_0$</p><h4 id="磁路的基尔霍夫定律"><a href="#磁路的基尔霍夫定律" class="headerlink" title="磁路的基尔霍夫定律"></a>磁路的基尔霍夫定律</h4><ol><li><p>对于磁路磁通量守恒,流入结点的磁通等于流出结点的磁通。</p><script type="math/tex; mode=display">\sum \Phi_i = 0</script></li><li><p>沿回路的磁势降之和等于线圈提供的磁动势之和,即</p><script type="math/tex; mode=display">\sum \varepsilon_m = \sum \Phi R_m</script></li></ol><p>$\varepsilon$的方向按照右手定则。与回路绕行方向相同取正,反之取负。<br>$\Phi$的方向与回路绕行方向相同取正,反之取负。</p><h4 id="磁路做题"><a href="#磁路做题" class="headerlink" title="磁路做题"></a>磁路做题</h4><p>磁动势取$NI$即可。<br>气隙当作磁导率为$\mu_0$的磁路。<br>磁路中不存在”导线”,所有部分都是磁阻。<br>磁通中的$S$和磁阻中的$S$消去了,可以只写$B$。</p><p>示例如下</p><script type="math/tex; mode=display">B(\frac{l}{\mu_r\mu_0}+\frac{l_0}{\mu_0}) = NI</script><h4 id="电磁铁"><a href="#电磁铁" class="headerlink" title="电磁铁"></a>电磁铁</h4><p>气隙截面积为$S_0$,气隙中磁感应强度为$B_0$。气隙宽度可以忽略时,如下。</p><p>直流电磁铁吸力</p><script type="math/tex; mode=display">F = \frac{B_0^2 S_0}{2\mu_0}</script><p>交流电磁铁吸力</p><script type="math/tex; mode=display">F = \frac{B_0^2 S_0}{2\mu_0}\sin^2\omega t</script><p>平均吸力</p><script type="math/tex; mode=display">\bar{F} = \frac{B_0^2 S_0}{4\mu_0}</script><h4 id="磁屏蔽"><a href="#磁屏蔽" class="headerlink" title="磁屏蔽"></a>磁屏蔽</h4><p>屏蔽系数定义为腔内场强$H_1$,与腔外场强$H_0$的比值</p><script type="math/tex; mode=display">K=\frac{H_1}{H_0}</script><p>使用球壳屏蔽时,材料磁导率为$\mu_r$,有关系</p><script type="math/tex; mode=display">K=\frac{2}{\mu_r(1-(R_1/R_2)^2)}</script><h2 id="电磁感应与磁场能量"><a href="#电磁感应与磁场能量" class="headerlink" title="电磁感应与磁场能量"></a>电磁感应与磁场能量</h2><h3 id="电磁感应定律,动生与感生"><a href="#电磁感应定律,动生与感生" class="headerlink" title="电磁感应定律,动生与感生"></a>电磁感应定律,动生与感生</h3><h4 id="法拉第电磁感应定律"><a href="#法拉第电磁感应定律" class="headerlink" title="法拉第电磁感应定律"></a>法拉第电磁感应定律</h4><script type="math/tex; mode=display">\varepsilon = -\frac{\text{d}\Phi}{\text{d}t}</script><p>1.多匝线圈</p><script type="math/tex; mode=display">\varepsilon = -\frac{\text{d}\Psi}{\text{d}t} = -\sum \frac{\text{d}\Phi_i}{\text{d}t}</script><p>若各匝线圈磁通量相同</p><script type="math/tex; mode=display">\varepsilon = -\frac{\text{d}\Psi}{\text{d}t} = - N \frac{\text{d}\Phi}{\text{d}t}</script><ol><li>在回路中产生感应电动势的原因是通过回路平面的磁通量的变化,而不是磁通量本身。</li></ol><script type="math/tex; mode=display">\varepsilon = -\frac{\text{d}\Phi}{\text{d}t}= -\frac{\text{d}(BS\cos \theta)}{\text{d}t} = -S\cos\theta\frac{\text{d}B}{\text{d}t} -B\cos\theta\frac{\text{d}S}{\text{d}t} + BS\sin \theta\frac{\text{d}\theta}{\text{d}t}</script><p>三种引起磁通量变化的原因:磁感应强度随时间的变化,回路的面积的变化,回路与磁感应强度的夹角的变化。</p><ol><li>符号指明了感应电动势的方向。</li></ol><h4 id="楞次定律"><a href="#楞次定律" class="headerlink" title="楞次定律"></a>楞次定律</h4><p>由 感应电动势引起的感应电流 所产生的磁场 通过回路的磁通量 总是阻碍 引起感应电流的磁通量 的变化。</p><p>由感应电动势引起的感应电流所产生的磁场通过回路的磁通量总是阻碍引起感应电流的磁通量的变化。</p><p>这句话不能速读。</p><p>当导体在磁场中运动时,导体中由于出现感应电流而收到的磁场力必然阻碍此导体的运动。</p><p>楞次定律的实质是能量守恒定律。</p><h4 id="动生电动势"><a href="#动生电动势" class="headerlink" title="动生电动势"></a>动生电动势</h4><p>首先由高级的微积分技术得到</p><script type="math/tex; mode=display">\frac{\text{d}\boldsymbol{B}}{\text{d}t} = \frac{\partial \boldsymbol{B}}{\partial t} + \nabla \times(\boldsymbol{B}\times\boldsymbol{v})</script><p>v是什么鬼?这里是指选取的测量点的速度。如果测量点静止,那么自然只与时间有关。如果测量点在移动,正好磁场也是空间的函数。</p><p>动生电动势情况下,$\displaystyle\frac{\partial \boldsymbol{B}}{\partial t} =0$</p><p>所以</p><script type="math/tex; mode=display">\varepsilon = -\iint_S\frac{\text{d}\boldsymbol{B}}{\text{d}t}\cdot\text{d}\boldsymbol{S} = -\iint_S\nabla\times(\boldsymbol{B}\times\boldsymbol{v})\cdot\text{d}\boldsymbol{S}</script><p>即</p><script type="math/tex; mode=display">\varepsilon = \oint(\boldsymbol{v}\times\boldsymbol{B})\cdot\text{d}\boldsymbol{l}</script><p>任意导体棒的感应电动势都可以使用如下公式求解</p><script type="math/tex; mode=display">\varepsilon = \int_A^B (\boldsymbol{v}\times\boldsymbol{B})\cdot\text{d}\boldsymbol{l}</script><p>直导体可以使用</p><script type="math/tex; mode=display">\varepsilon = vBL</script><h4 id="恒定磁场"><a href="#恒定磁场" class="headerlink" title="恒定磁场"></a>恒定磁场</h4><p>恒定磁场不一定是均匀磁场</p><p>!! !!!!!!!!!! 错了一次</p><h4 id="感生电动势"><a href="#感生电动势" class="headerlink" title="感生电动势"></a>感生电动势</h4><p>磁场随时间变化时,在空间激发了新的电场,导体中的载流子在这个电场的作用下,在闭合回路中产生了感应电流。</p><p>变化的磁场激发涡旋电场,涡旋电场产生感应电动势。</p><p>对涡旋电场,</p><script type="math/tex; mode=display">\varepsilon = \oint_L\boldsymbol{E}_{\text{旋}}\cdot\text{d}\boldsymbol{l} = -\frac{\text{d}}{\text{d}t}\iint_S\boldsymbol{B}\cdot\text{d}\boldsymbol{S} = -\iint_S\frac{\partial \boldsymbol{B}}{\partial t}\cdot\text{d}\boldsymbol{S}</script><p>时变磁场在周围空间激发涡旋电场,是非保守立场,即无势场。</p><script type="math/tex; mode=display">\nabla\times \boldsymbol{E} = -\frac{\partial \boldsymbol{B}}{\partial t}</script><h4 id="磁矢势"><a href="#磁矢势" class="headerlink" title="磁矢势"></a>磁矢势</h4><script type="math/tex; mode=display">\boldsymbol{B} = \nabla\times\boldsymbol{A}</script><p>其中的$\boldsymbol{A}$就是磁矢势。</p><p>可以根据毕奥-萨法尔定理推导出来</p><script type="math/tex; mode=display">\boldsymbol{A}=\frac{\mu_0}{4\pi}\oint_L\frac{I\text{d}\boldsymbol{l}}{r}</script><p>所有有$B$的地方都可以带入$A$</p><script type="math/tex; mode=display">\boldsymbol{E}_{\text{旋}} = -\frac{\partial \boldsymbol{A}}{\partial t}</script><script type="math/tex; mode=display">\Phi = \oint_L \boldsymbol{A}\cdot\text{d}\boldsymbol{l}</script><p>这时候可以回顾电场的公式</p><script type="math/tex; mode=display">\boldsymbol{E} = -\nabla U - \frac{\partial \boldsymbol{A}}{\partial t}</script><p>左为库伦电场,右为涡旋电场</p><p>PAGE 309</p><p>记得复习马原精简版</p><h4 id="涡旋电场的验证与应用"><a href="#涡旋电场的验证与应用" class="headerlink" title="涡旋电场的验证与应用"></a>涡旋电场的验证与应用</h4><p>涡电流</p><p>金属中载流子在涡旋电场作用下运动产生的电流。</p><p>感应加热</p><p>金属的电阻很小,不大的感应电动势便能产生较强的涡电流,在金属中产生大量的焦耳热。</p><p>电磁阻尼</p><p>楞次定律</p><p>PPT309</p><p>焦耳热损耗</p><p>高电阻材料,如硅钢(钢材料中加入硅),不影响导磁性</p><p>多层绝缘片叠加而成,减少涡电流的导体横截面积</p><p>趋肤效应</p><p>交变电流靠近导表面处。</p><p>趋肤效应的结果使电流传输的有效横截面积减少,电阻增加,导体表面温度高。</p><h3 id="互感和自感"><a href="#互感和自感" class="headerlink" title="互感和自感"></a>互感和自感</h3><p>当一个线圈中的电流发生变化时,将在周围空间中产生变化的磁场,从而在它附近的另一个线圈中产生感应电动势,这种现象称为互感现象。</p><p>有</p><script type="math/tex; mode=display">\Psi_{21} = M_{21}I_1</script><script type="math/tex; mode=display">\Psi_{12} = M_{12}I_2</script><p>可以证明</p><script type="math/tex; mode=display">M_{12} = M_{21} = M</script><p>PAGE 319</p><p>可以推导出来公式</p><script type="math/tex; mode=display">M_{ij} = \frac{\mu_0}{4\pi}\oint_{L_i}\oint_{L_{j}}\frac{\text{d}\boldsymbol{l}_i\cdot\text{d}\boldsymbol{l}_j}{r_{ij}}</script><p>推导使用的公式为</p><script type="math/tex; mode=display">\Psi = \oint_L\boldsymbol{A}\cdot\text{d}\boldsymbol{l}</script><p>和</p><script type="math/tex; mode=display">M_{21}=\frac{\Psi_{21}}{I_1}</script><h4 id="互感电动势"><a href="#互感电动势" class="headerlink" title="互感电动势"></a>互感电动势</h4><p>$I_1$变化激发空间磁场引起线圈2中的感应电动势为</p><script type="math/tex; mode=display">\varepsilon_2 = -\frac{\text{d}\Psi_{21}}{\text{d}t} = -M\frac{\text{d}I_1}{\text{d}t}</script><p>$I_2$变化激发空间磁场引起线圈1中的感应电动势为</p><script type="math/tex; mode=display">\varepsilon_1 = -\frac{\text{d}\Psi_{12}}{\text{d}t} = -M\frac{\text{d}I_2}{\text{d}t}</script><h4 id="互感系数的计算方法"><a href="#互感系数的计算方法" class="headerlink" title="互感系数的计算方法"></a>互感系数的计算方法</h4><p>先假设电流,再计算磁通,利用$M=\Psi/I$求得。</p><h4 id="重叠螺线管的互感系数"><a href="#重叠螺线管的互感系数" class="headerlink" title="重叠螺线管的互感系数"></a>重叠螺线管的互感系数</h4><script type="math/tex; mode=display">M=\mu_0n_1n_2V</script><p>推导过程:</p><script type="math/tex; mode=display">B_1 = \mu_0n_1I_1</script><script type="math/tex; mode=display">\Phi_{21} = N_2B_1S = \mu_0n_1n_2SlI_1 = \mu_0n_1n_2VI_1</script><script type="math/tex; mode=display">M = \Phi_{21}/I_1 = \mu_0n_1n_2V</script><h4 id="自感现象"><a href="#自感现象" class="headerlink" title="自感现象"></a>自感现象</h4><p>当一个线圈中的电流发生变化时,它所激发的磁场穿过每匝线圈自身平面的磁通量也随之发生变化,从而使线圈产生感应电动势。<br>这种因线圈中的电流发生变化而在线圈自身中产生感应电动势的情况,称为自感应现象。所产生的感应电动势称为自感电动势。</p><p>根据楞次定律,线圈产生的自感电动势总是反抗电流变化的。可以称之为<em>电惯性</em>。</p><h4 id="自感系数"><a href="#自感系数" class="headerlink" title="自感系数"></a>自感系数</h4><p>穿过线圈的总磁通$\Psi$与电流$I$成正比</p><script type="math/tex; mode=display">\Psi = LI</script><p>$L$称之为自感系数,简称自感,又叫电磁惯量。之和线圈回路几何形状和介质特性有关。单位与互感相同</p><p>当电流随时间变化时,在线圈中产生的自感电动势为</p><script type="math/tex; mode=display">\varepsilon = -\frac{\text{d}\Psi}{\text{d}t} =-L\frac{\text{d}I}{\text{d}t}</script><h4 id="自感系数的计算"><a href="#自感系数的计算" class="headerlink" title="自感系数的计算"></a>自感系数的计算</h4><script type="math/tex; mode=display">L=\frac{\Psi}{I} = -\varepsilon/\frac{\text{d}I}{\text{d}t} = \frac{2W_m}{I^2}</script><p>例如理想螺线管的自感系数</p><script type="math/tex; mode=display">\Phi = NBS = NS\mu_0nI</script><script type="math/tex; mode=display">L=\Psi/I=NS\mu_0n = \mu_0n^2V</script><p>这里利用了$N=nl$</p><h4 id="利用磁通求自感的电流交链问题"><a href="#利用磁通求自感的电流交链问题" class="headerlink" title="利用磁通求自感的电流交链问题"></a>利用磁通求自感的电流交链问题</h4><p>根据定义</p><script type="math/tex; mode=display">L=\frac{\Psi}{I}</script><p>在利用磁通分析自感问题时,应当注意磁感应线未圈围全部电流的情形。</p><p>有粗细的导线,看作电流$I$均匀在圆柱体内流动,则不同磁感应线将交链不同的电流$I^{‘}$,因此在算磁通时,应计算有效的磁通$\text{d}\Psi$,称为磁通匝链数;圈围的电流所占的份额$I/I^{‘}$,称为分数匝数</p><p>PAGE 332</p><p>一般外部磁场为零。</p><p>还是看不懂。我太菜了。<br>PAGE335</p><h4 id="电感的串并联"><a href="#电感的串并联" class="headerlink" title="电感的串并联"></a>电感的串并联</h4><p>同名端异名端:</p><p>电流从<strong>同名端</strong>流入时,同一线圈的自感磁通和互感磁通同相。</p><h4 id="串联线圈的自感"><a href="#串联线圈的自感" class="headerlink" title="串联线圈的自感"></a>串联线圈的自感</h4><p>顺接:电流从同名端流入<br>反接:电流从异名端流入</p><p>顺接时,</p><script type="math/tex; mode=display">L = L_1 + L_2 + 2M</script><p>推导:</p><script type="math/tex; mode=display">\varepsilon_1 = -(L_1\frac{\text{d}I}{\text{d}t} + M\frac{\text{d}I}{\text{d}t}) = -(L_1+M)\frac{\text{d}I}{\text{d}t}</script><script type="math/tex; mode=display">\varepsilon_2 = -(M\frac{\text{d}I}{\text{d}t} + L_2\frac{\text{d}I}{\text{d}t}) = -(L_2+M)\frac{\text{d}I}{\text{d}t}</script><p>反接:</p><script type="math/tex; mode=display">L=L_1+L_2-2M</script><p>$L>0$即$L_1+L_2 > 2M$</p><h4 id="电感线圈的并联"><a href="#电感线圈的并联" class="headerlink" title="电感线圈的并联"></a>电感线圈的并联</h4><p>同名端并联</p><script type="math/tex; mode=display">L=\frac{L_1L_2-M^2}{L_1+L_2-2M}</script><p>推导:</p><script type="math/tex; mode=display">\left\{\begin{aligned}\varepsilon &= -(L_1\frac{\text{d}I_1}{\text{d}t} + M\frac{\text{d}I_2}{\text{d}t}) = -(L_2\frac{\text{d}I_2}{\text{d}t} + M\frac{\text{d}I_1}{\text{d}t}) \\\frac{\text{d}I}{\text{d}t} &= \frac{\text{d}I_1}{\text{d}t} + \frac{\text{d}I_2}{\text{d}t}\\\end{aligned}\right.</script><p>异名端:</p><script type="math/tex; mode=display">L=\frac{L_1L_2-M^2}{L_1+L_2+2M}</script><h4 id="自感系数和互感系数的关系"><a href="#自感系数和互感系数的关系" class="headerlink" title="自感系数和互感系数的关系"></a>自感系数和互感系数的关系</h4><script type="math/tex; mode=display">M\leq \sqrt{L_1L_2}</script><p>即令</p><script type="math/tex; mode=display">M=k\sqrt{L_1L_2},0\leq k\leq1</script><p>$k$为耦合系数。</p><h3 id="似稳电路和暂态过程"><a href="#似稳电路和暂态过程" class="headerlink" title="似稳电路和暂态过程"></a>似稳电路和暂态过程</h3><p>似稳电路的条件:电源随时间变化很慢,电路的尺度远小于光在这一周期内的移动距离</p><script type="math/tex; mode=display">\frac{1}{f} \gg \frac{l}{c}\rightarrow \lambda \equiv \frac{c}{f} \gg l</script><p>市电下,这一条件为6000km.</p><h4 id="似稳电路"><a href="#似稳电路" class="headerlink" title="似稳电路"></a>似稳电路</h4><script type="math/tex; mode=display">\boldsymbol{j} = \sigma \boldsymbol{E} = \sigma (\boldsymbol{E}_{\text{位}}+\boldsymbol{E}_{\text{旋}}+\boldsymbol{K})</script><p>因为引入了涡旋电场,对总电路的基尔霍夫定律不再成立。</p><script type="math/tex; mode=display">\oiint _S\boldsymbol{j}\cdot\text{d}\boldsymbol{S}\neq0,\oint_L\boldsymbol{E}\cdot\text{d}\boldsymbol{l}\neq0</script><p>但是对于$\boldsymbol{E}_{\text{位}}$,环路定理依然成立。</p><p>PPT PAGE 362</p><p>没看懂,做题吧</p><h4 id="似稳电路的基本方程"><a href="#似稳电路的基本方程" class="headerlink" title="似稳电路的基本方程"></a>似稳电路的基本方程</h4><script type="math/tex; mode=display">\varepsilon = iR+\frac{1}{C}\int i\text{d}t + \left(L\frac{\text{d}i}{\text{d}t}+M\frac{\text{d}i^{'}}{\text{d}t}\right)</script><p>注意:这里与电路理论得到的方程不同。具体细分如下</p><p>先前一直在使用的方程</p><script type="math/tex; mode=display">\varepsilon = -L\frac{\text{d}i}{\text{d}t}</script><p>其中的符号表示产生的感应电动势阻碍电流,不表示参考方向。而且这里的$\varepsilon$应当算在电动势里面,而不是等式右边。所以正确性和电路理论相吻合。</p><p>在进行分析的时候,建议使用电路理论的方程式</p><script type="math/tex; mode=display">\varepsilon = L\frac{\text{d}i}{\text{d}t}</script><p>并使用同一参考方向,减少犯错误的可能性。</p><p>接下来分析了RL,RC电路的暂态过程。看PPT366,写的很详细了。</p><p>这部分电路理论可以直接分析。不需要电磁学知识,反而容易出错呢。</p>]]></content>
<categories>
<category>物理</category>
</categories>
<tags>
<tag>物理</tag>
<tag>课内复习</tag>
</tags>
</entry>
<entry>
<title>电磁学C复习-电学部分</title>
<link href="/2022/01/18/ElecC1/"/>
<url>/2022/01/18/ElecC1/</url>
<content type="html"><![CDATA[<p>本文章是作者在学习电磁学时进行期中复习时做出的笔记。</p><span id="more"></span><h2 id="第一章"><a href="#第一章" class="headerlink" title="第一章"></a>第一章</h2><h3 id="电荷守恒定律"><a href="#电荷守恒定律" class="headerlink" title="电荷守恒定律"></a>电荷守恒定律</h3><script type="math/tex; mode=display">\newcommand{\oiint}{\subset\kern{-3pt}\supset\kern{-16.5pt}\iint} \oiint_S \vec{j}\cdot\text{d}\vec{s} = -\frac{\partial}{\partial t} \iiint_V \rho \cdot \text{d}V</script><p>即</p><script type="math/tex; mode=display"> \nabla \cdot \vec{j} = -\frac{\partial \rho}{\partial t}</script><h3 id="库仑定律"><a href="#库仑定律" class="headerlink" title="库仑定律"></a>库仑定律</h3><p>$\vec{F}_{12}$为2对1的作用力,有</p><script type="math/tex; mode=display"> \vec{F}_{12} = k\frac{q_1q_2}{r_{12}^2}\vec{e_r}</script><p>同时满足牛顿第三定律</p><script type="math/tex; mode=display"> \vec{F}_{12} = -\vec{F}_{21}</script><p>其中</p><script type="math/tex; mode=display"> k = \frac{1}{4\pi \varepsilon_0}, \varepsilon_0 = 9\times 10^9 Nm^2/C^2</script><h3 id="矢量操作"><a href="#矢量操作" class="headerlink" title="矢量操作"></a>矢量操作</h3><h4 id="矢量分解"><a href="#矢量分解" class="headerlink" title="矢量分解"></a>矢量分解</h4><script type="math/tex; mode=display">\vec{A} = (\vec{A} \cdot \vec{n})\vec{n} + \vec{n} \times (\vec{A} \times \vec{n})</script><h4 id="运算方法"><a href="#运算方法" class="headerlink" title="运算方法"></a>运算方法</h4><script type="math/tex; mode=display"> \nabla = \vec{e}_x \frac{\partial}{\partial x} + \vec{e}_y \frac{\partial}{\partial y} + \vec{e}_z \frac{\partial}{\partial z}</script><h4 id="矢量微元"><a href="#矢量微元" class="headerlink" title="矢量微元"></a>矢量微元</h4><p>直角坐标系</p><script type="math/tex; mode=display"> \text{d} \vec{l} = \text{d} x\vec{x} + \text{d} y\vec{y}+ \text{d} z\vec{z}</script><script type="math/tex; mode=display"> \text{d} \vec{S}_x = \text{d} y \text{d} z \vec{x}</script><script type="math/tex; mode=display"> \text{d} \vec{S}_y = \text{d} z \text{d} x \vec{y}</script><script type="math/tex; mode=display"> \text{d} \vec{S}_z = \text{d} x \text{d} y \vec{z}</script><script type="math/tex; mode=display">\text{d} {V} = \text{d} x\text{d}y\text{d}z</script><p>柱坐标系</p><script type="math/tex; mode=display"> \text{d} \vec{l} = \text{d}r\vec{r} + r\text{d}\varphi\vec{\varphi} + \text{d} z\vec{z}</script><p>球坐标系</p><script type="math/tex; mode=display"> \text{d} \vec{l} = \text{d}R\vec{r} + R\text{d}\theta \vec{\theta} + R\sin \theta \text{d} \varphi \vec{\varphi}</script><h3 id="叠加原理"><a href="#叠加原理" class="headerlink" title="叠加原理"></a>叠加原理</h3><script type="math/tex; mode=display">F_i = \frac{1}{4\pi\varepsilon_0}q_i \sum_{j=1, i\neq i}^{N}\frac{q_j}{|\boldsymbol{r}-\boldsymbol{r_j}|^3}(\boldsymbol{r} - \boldsymbol{r_j})</script><h3 id="电荷密度"><a href="#电荷密度" class="headerlink" title="电荷密度"></a>电荷密度</h3><script type="math/tex; mode=display">\rho = \frac{\Delta q}{\Delta V}</script><script type="math/tex; mode=display">\sigma = \frac{\Delta q}{\Delta S}</script><script type="math/tex; mode=display">\lambda = \frac{\Delta q}{\Delta l}</script><h3 id="带电体之间的作用力"><a href="#带电体之间的作用力" class="headerlink" title="带电体之间的作用力"></a>带电体之间的作用力</h3><script type="math/tex; mode=display">F_{12} = \frac{1}{4\pi\varepsilon_0}\iiint_{V_1}\iiint_{V_2}\frac{\rho_1(\boldsymbol{r_1})\rho_2(\boldsymbol{r_2})}{|\boldsymbol{r_2} - \boldsymbol{r_1}|^3}(\boldsymbol{r_2} - \boldsymbol{r_1})\text{d}V_1\text{d}V_2</script><h3 id="电偶极子"><a href="#电偶极子" class="headerlink" title="电偶极子"></a>电偶极子</h3><p>电偶极矩$\boldsymbol{p}$,大小为$p=ql$,方向由负电荷指向正电荷。</p><p>设$\boldsymbol{n}$是$\boldsymbol{r}$方向的单位矢量,则有</p><script type="math/tex; mode=display">\vec{E} = \frac{1}{4\pi\varepsilon_0} \frac{3\vec{n}(\vec{p}\cdot\vec{n})-\vec{p}}{r^3}</script><h3 id="电通量"><a href="#电通量" class="headerlink" title="电通量"></a>电通量</h3><script type="math/tex; mode=display">\Delta \Phi = \vec{E}\cdot \Delta \vec{S}</script><script type="math/tex; mode=display">\Phi_E = \iint_S \vec{E}\cdot \text{d} \vec{S}</script><p>开曲面:凸侧一方的方向的外法线方向为正<br>闭曲面:外法线方向为正,内法线方向为负</p><p>电通量满足叠加原理,是标量。</p><h3 id="立体角"><a href="#立体角" class="headerlink" title="立体角"></a>立体角</h3><script type="math/tex; mode=display">\Omega = \frac{S_r}{r^2}</script><h3 id="静电场的高斯定理"><a href="#静电场的高斯定理" class="headerlink" title="静电场的高斯定理"></a>静电场的高斯定理</h3><script type="math/tex; mode=display">\oiint_S \vec{E}\cdot \text{d}\vec{S} = \frac{1}{\varepsilon_0}\sum^{N}_{i=1}q_i^{in}</script><p>对连续分布的电荷</p><script type="math/tex; mode=display">\oiint_S \vec{E}\cdot \text{d}\vec{S} =\frac{1}{\varepsilon_0}\iiint_V\rho \text{d} V</script><p>由数学公式推导得到</p><script type="math/tex; mode=display">\nabla \cdot \vec{E} = \frac{\rho}{\varepsilon_0}</script><h3 id="环量"><a href="#环量" class="headerlink" title="环量"></a>环量</h3><script type="math/tex; mode=display">\oint_L\boldsymbol \cdot \text{d}\boldsymbol{L}</script><h3 id="静电场的环路定理"><a href="#静电场的环路定理" class="headerlink" title="静电场的环路定理"></a>静电场的环路定理</h3><script type="math/tex; mode=display">\oint_L \vec{E}\cdot\text{d}\vec{l} = 0</script><p>由数学公式推导得到</p><script type="math/tex; mode=display">\nabla \times \vec{E} = 0</script><h3 id="电势能"><a href="#电势能" class="headerlink" title="电势能"></a>电势能</h3><script type="math/tex; mode=display">W_P = q_0 \int^{\infty}_P\vec{E}\cdot \text{d}\vec{l}</script><h3 id="电势差"><a href="#电势差" class="headerlink" title="电势差"></a>电势差</h3><script type="math/tex; mode=display">U_{PQ} = \int^{Q}_{P}\vec{E}\cdot\text{d}\vec{l}</script><h3 id="电势"><a href="#电势" class="headerlink" title="电势"></a>电势</h3><script type="math/tex; mode=display">U_P = \int^{\infty}_{P} \vec{E}\cdot\text{d}\vec{l}</script><p>电势满足叠加原理,电势是标量。</p><script type="math/tex; mode=display">U(\boldsymbol{r}) = \sum_{i}U_i(\boldsymbol{r}) = \frac{1}{4\pi\varepsilon_0}\sum_{i}\frac{q_i}{|\boldsymbol{r} - \boldsymbol{r}_i|}</script><h3 id="点电荷电势"><a href="#点电荷电势" class="headerlink" title="点电荷电势"></a>点电荷电势</h3><script type="math/tex; mode=display">U(r) = \frac{q}{4\pi\varepsilon_0 r}</script><h3 id="带电体电势"><a href="#带电体电势" class="headerlink" title="带电体电势"></a>带电体电势</h3><p>将$\displaystyle\frac{\text{d}q}{|\boldsymbol{r}-\boldsymbol{r}^{‘}|}$ 转化成体、面、线电荷元积分即可。</p><h3 id="电场强度和电势的关系"><a href="#电场强度和电势的关系" class="headerlink" title="电场强度和电势的关系"></a>电场强度和电势的关系</h3><script type="math/tex; mode=display">\vec{E} = -\nabla U</script><p>即</p><script type="math/tex; mode=display">E_x = -\frac{\partial U}{\partial x}, E_y = -\frac{\partial U}{\partial y}, E_z = -\frac{\partial U}{\partial z}</script><h3 id="泊松方程"><a href="#泊松方程" class="headerlink" title="泊松方程"></a>泊松方程</h3><script type="math/tex; mode=display">\nabla^2 U = -\frac{\rho}{\varepsilon_0}</script><h3 id="电偶极子电势分布和电场分布"><a href="#电偶极子电势分布和电场分布" class="headerlink" title="电偶极子电势分布和电场分布"></a>电偶极子电势分布和电场分布</h3><script type="math/tex; mode=display">U(\boldsymbol{r}) = \frac{1}{4\pi\varepsilon_0}\frac{\boldsymbol{p}\cdot\boldsymbol{r}}{r^3}</script><script type="math/tex; mode=display">E(\boldsymbol{r}) = -\frac{\boldsymbol{p}}{4\pi\varepsilon_0 r^3} + \frac{3(\boldsymbol{p}\cdot \boldsymbol{r})}{4\pi\varepsilon_0r^5}\boldsymbol{r}</script><h2 id="第二章"><a href="#第二章" class="headerlink" title="第二章"></a>第二章</h2><h3 id="电阻率"><a href="#电阻率" class="headerlink" title="电阻率"></a>电阻率</h3><script type="math/tex; mode=display">\rho = \frac{RS}{l}</script><h3 id="静电平衡"><a href="#静电平衡" class="headerlink" title="静电平衡"></a>静电平衡</h3><p>导体内部电场强度处处为零。</p><p>静电平衡时内部电荷按照指数衰减</p><script type="math/tex; mode=display">\rho(t) = \rho_0\text{e}^{-t/\tau}</script><h3 id="静电屏蔽"><a href="#静电屏蔽" class="headerlink" title="静电屏蔽"></a>静电屏蔽</h3><p>腔外不影响腔内,腔内影响腔外。对地接空腔,内外不影响。</p><h3 id="电荷系统在静电场中的受力问题"><a href="#电荷系统在静电场中的受力问题" class="headerlink" title="电荷系统在静电场中的受力问题"></a>电荷系统在静电场中的受力问题</h3><p>$E=E_t-E_1$,分别为外场,总电场,和受力带电体的电场。</p><p>体电荷$E_1(r) = \rho_e r/(3\varepsilon_0) \rightarrow 0$<br>面电荷$E_1 = \pm \sigma_e / (2\varepsilon_0)$<br>线电荷$E_1 = \lambda_e / (2\pi\varepsilon_0 r) \rightarrow \infty$</p><h3 id="电偶极子在外电场中的受力问题"><a href="#电偶极子在外电场中的受力问题" class="headerlink" title="电偶极子在外电场中的受力问题"></a>电偶极子在外电场中的受力问题</h3><script type="math/tex; mode=display">\boldsymbol{F} = (\boldsymbol{p}\cdot \nabla)\boldsymbol{E}(\boldsymbol{r})</script><p>力矩参考点为电偶极子中点</p><script type="math/tex; mode=display">\boldsymbol{L} = \boldsymbol{p}\times \boldsymbol{E}</script><h3 id="常见电容器"><a href="#常见电容器" class="headerlink" title="常见电容器"></a>常见电容器</h3><p>球体电容器</p><script type="math/tex; mode=display">C = 4\pi\varepsilon_0R</script><p>平行板电容器</p><script type="math/tex; mode=display">C=\varepsilon_0S/d</script><p>球形电容器</p><script type="math/tex; mode=display">C=4\pi\varepsilon_0\frac{R_AR_B}{R_B-R_A}</script><p>同轴圆柱形电容器</p><script type="math/tex; mode=display">C=\frac{2\pi\varepsilon_0L}{\ln R_B/R_A}</script><h3 id="极化强度矢量"><a href="#极化强度矢量" class="headerlink" title="极化强度矢量"></a>极化强度矢量</h3><p>Definition: 单位体积内分子电偶极矩矢量和</p><script type="math/tex; mode=display">\vec{P} = \lim_{\Delta V\rightarrow 0}\frac{\sum \vec{p}_i}{\Delta V}</script><p>平衡时有</p><script type="math/tex; mode=display">\vec{E} = \vec{E}_0 + \vec{E}^{'}</script><h3 id="电荷的分布情况"><a href="#电荷的分布情况" class="headerlink" title="电荷的分布情况"></a>电荷的分布情况</h3><p>极化电荷</p><script type="math/tex; mode=display">\nabla \cdot \boldsymbol{P} = -\rho^{'}</script><p>边界上</p><script type="math/tex; mode=display">\sigma ^{'} = -(\boldsymbol{P}_2 - \boldsymbol{P}_1) \cdot \boldsymbol{n}</script><h3 id="极化强度与电场的关系"><a href="#极化强度与电场的关系" class="headerlink" title="极化强度与电场的关系"></a>极化强度与电场的关系</h3><p>各向同性电介质中</p><script type="math/tex; mode=display">\boldsymbol{P} = \chi_e\varepsilon_0\boldsymbol{E}</script><p>$\chi_e$为电极化率,$\boldsymbol{E}$为极化后的总电场。</p><script type="math/tex; mode=display">\varepsilon_r \equiv 1 + \chi_e</script><h3 id="电介质中静电场高斯定理"><a href="#电介质中静电场高斯定理" class="headerlink" title="电介质中静电场高斯定理"></a>电介质中静电场高斯定理</h3><p>定义电位移矢量</p><script type="math/tex; mode=display">\boldsymbol{D} = \varepsilon_0\boldsymbol{E} + \boldsymbol{P}</script><p>则有</p><script type="math/tex; mode=display">\oiint_S \boldsymbol{D} \cdot \text{d}\boldsymbol{S} = \sum_{S}q_0</script><p>而且</p><script type="math/tex; mode=display">\boldsymbol{D} = \varepsilon_0\boldsymbol{E} + \boldsymbol{P} = \varepsilon_0\boldsymbol{E} + \chi_e\varepsilon_0\boldsymbol{E} = \varepsilon_r\varepsilon_0\boldsymbol{E} = \varepsilon\boldsymbol{E}</script><p>写成连续形式也可以,将$q_0$换成$\iiint_V \rho_0\text{d}V$即可。</p><p>同时有微分形式</p><script type="math/tex; mode=display">\nabla \cdot \boldsymbol{D} = \rho_0</script><p>介质中静电场仍然是一个无旋的保守场。</p><p>交界面无自由电荷,D线连续,E线通常不连续。</p><h3 id="电介质交界面上的物理量"><a href="#电介质交界面上的物理量" class="headerlink" title="电介质交界面上的物理量"></a>电介质交界面上的物理量</h3><p>交界面上的电场强度切向分量总是相等的。</p><p>交界面上的电位移矢量有如下关系</p><script type="math/tex; mode=display">D_{2n} - D_{1n} = \sigma_0</script><p>无自由电荷时,交界面的电位移矢量连续。</p><p>即</p><script type="math/tex; mode=display">(\boldsymbol{D}_2 - \boldsymbol{D}_1)\cdot \boldsymbol{n} = \sigma_0</script><script type="math/tex; mode=display">(\boldsymbol{P}_1 - \boldsymbol{P}_2)\cdot \boldsymbol{n} = \sigma^{'}</script><script type="math/tex; mode=display">(\boldsymbol{E}_2 - \boldsymbol{E}_1)\cdot \boldsymbol{n} = \sigma/\varepsilon_0</script><p>交界面上的电势总是连续的。</p><h3 id="介质中静电场基本方程"><a href="#介质中静电场基本方程" class="headerlink" title="介质中静电场基本方程"></a>介质中静电场基本方程</h3><p>高斯定理</p><script type="math/tex; mode=display">\oiint_S\vec{D}\cdot\text{d}\vec{S} = \sum_Sq_0</script><p>本构方程</p><script type="math/tex; mode=display">\vec{D} = \varepsilon_r\varepsilon_0\vec{E}</script><p>环路定理</p><script type="math/tex; mode=display">\oint_L\vec{E}\cdot\text{d}\vec{l}= 0</script><p>边值条件,上一节</p><h4 id="介质界面与电场线重合"><a href="#介质界面与电场线重合" class="headerlink" title="介质界面与电场线重合"></a>介质界面与电场线重合</h4><p>电场强度连续</p><h4 id="介质表面与等势面重合"><a href="#介质表面与等势面重合" class="headerlink" title="介质表面与等势面重合"></a>介质表面与等势面重合</h4><p>电位移矢量连续,且相当于真空中的情况,即</p><script type="math/tex; mode=display">\boldsymbol{D} = \varepsilon_r\varepsilon_0\boldsymbol{E} = \varepsilon_0\boldsymbol{E}_0</script><p>第二个等号由连续性得到,相当于延伸到真空的情况。</p><h3 id="电场的能量"><a href="#电场的能量" class="headerlink" title="电场的能量"></a>电场的能量</h3><p>N个点电荷体系</p><script type="math/tex; mode=display">W_{\text{互}} = \frac{1}{2}\sum_{i=1}^{N}W_i = \frac{1}{2}\sum_{i=1}^{N}q_iU_i</script><p>其中</p><script type="math/tex; mode=display">U_i = \sum_{j=1,i\neq j}^{N}U_{ji} = \frac{1}{4\pi\varepsilon_0}\sum_{j =1, i\neq j}^{N}\frac{q_j}{r_{ij}}</script><p>一个点电荷的电势能为</p><script type="math/tex; mode=display">W_i = q_iU_i</script><h3 id="体电荷分布自能"><a href="#体电荷分布自能" class="headerlink" title="体电荷分布自能"></a>体电荷分布自能</h3><script type="math/tex; mode=display">W_e = \frac{1}{2}\iiint_V\rho(\boldsymbol{r})U(\boldsymbol{r})\text{d}V</script><h3 id="面电荷分布自能"><a href="#面电荷分布自能" class="headerlink" title="面电荷分布自能"></a>面电荷分布自能</h3><script type="math/tex; mode=display">W_e=\frac{1}{2}\iint_S\sigma(\boldsymbol{r})U(\boldsymbol{r})\text{d}S</script><p>线电荷不能求自能</p><h3 id="空间电势能"><a href="#空间电势能" class="headerlink" title="空间电势能"></a>空间电势能</h3><p>空间总电势为</p><script type="math/tex; mode=display">U(\boldsymbol{r}) = U_i(\boldsymbol{r}) + U^{(i)}(\boldsymbol{r})</script><p>$U_i$:除第i个带电体外所有其他带电体在r产生的电势<br>$U^{(i)}$:第i个带电体在r处产生的电势</p><p>总电势能</p><script type="math/tex; mode=display">W_e = \frac{1}{2}\sum_{i=1}^{N}\iiint_V\rho(\boldsymbol{r})U(\boldsymbol{r})\text{d}V \\ = \frac{1}{2}\sum_{i=1}^{N}\iiint_V\rho(\boldsymbol{r})U^{(i)}(\boldsymbol{r})\text{d}V + \frac{1}{2}\sum_{i=1}^{N}\iiint_V\rho(\boldsymbol{r})U_i(\boldsymbol{r})\text{d}V</script><p>即</p><script type="math/tex; mode=display">W_{\text{静}} = W_{\text{自}} + W_{\text{互}}</script><p>互能可以当成点电荷处理。</p><h3 id="孤立带电球体的自能"><a href="#孤立带电球体的自能" class="headerlink" title="孤立带电球体的自能"></a>孤立带电球体的自能</h3><script type="math/tex; mode=display">W_{\text{自}} = \frac{4\pi\rho^2R^5}{15\varepsilon_0}</script><h3 id="带电导体的静电能"><a href="#带电导体的静电能" class="headerlink" title="带电导体的静电能"></a>带电导体的静电能</h3><p>带电导体电荷分布在外表面</p><script type="math/tex; mode=display">W_e = \frac{1}{2}\sum_{i=1}^{N}\iint_S\sigma U\text{d}S = \frac{1}{2}\sum_{i=1}^{N}q_iU_i</script><h3 id="电偶极子的静电能"><a href="#电偶极子的静电能" class="headerlink" title="电偶极子的静电能"></a>电偶极子的静电能</h3><script type="math/tex; mode=display">W = -\vec{p} \cdot\vec{E}</script><p>所以p平行于外场且指向外场方向时,能量最低。</p><h3 id="电容器的能量"><a href="#电容器的能量" class="headerlink" title="电容器的能量"></a>电容器的能量</h3><script type="math/tex; mode=display">W_e = \frac{1}{2}QU</script><p>其中U为电势差</p><h3 id="电介质存在时带电系统的静电能"><a href="#电介质存在时带电系统的静电能" class="headerlink" title="电介质存在时带电系统的静电能"></a>电介质存在时带电系统的静电能</h3><p>静电能时建立自由电荷分布所需要的外界做功,但是电势U包括了所有电荷的贡献</p><script type="math/tex; mode=display">W_e = \frac{1}{2}\iiint_V\rho_0(\boldsymbol{r})U(\boldsymbol{r})\text{d}V</script><h3 id="宏观静电能"><a href="#宏观静电能" class="headerlink" title="宏观静电能"></a>宏观静电能</h3><p>若</p><script type="math/tex; mode=display">\rho({\boldsymbol{r}})=\rho_0({\boldsymbol{r}}) + \rho^{'}(\boldsymbol{r})</script><p>定义宏观静电能</p><script type="math/tex; mode=display">W_{e0} = \frac{1}{2}\iiint_{V_0}\rho_0(\boldsymbol{r})U(\boldsymbol{r})\text{d}V + \frac{1}{2}\iiint_{V^{'}}\rho({\boldsymbol{r}})U(\boldsymbol{r})\text{d}V</script><p>为建立宏观电荷分布$\rho_0(\boldsymbol{r}) + \rho^{‘}(\boldsymbol{r})$过程中系统储存的静电能。</p><p>静电能时在建立该状态过程中外界对系统所做的功,事实上仅相当于对自由电荷所做的功。在完成自由电荷的分布后,极化电荷自发产生,产生了宏观静电能的概念。</p><p>静电能等于宏观静电能加上极化能,即</p><script type="math/tex; mode=display">W_e = W_{e0} + W_{\text{极}}</script><p>计算得到极化能</p><script type="math/tex; mode=display">W_{\text{极}} = -\frac{1}{2}\iiint_{V^{'}}\rho^{'}(\boldsymbol{r})U(\boldsymbol{r})\text{d}V</script><h3 id="电场的能量密度"><a href="#电场的能量密度" class="headerlink" title="电场的能量密度"></a>电场的能量密度</h3><script type="math/tex; mode=display">\omega_e = \frac{W_e}{V} = \frac{1}{2}\vec{D}\cdot\vec{E}</script><p>静电能</p><script type="math/tex; mode=display">W_e = \iiint_V\omega_e\text{d}V</script><p>PPT上用了复杂的方法推导这个关系,但是我很菜,记住就好。</p><p>对导体或者真空($\varepsilon = \varepsilon_0$的情况)</p><script type="math/tex; mode=display">\omega_e = \omega_{e0} = \frac{1}{2}\varepsilon_0E^2</script><p>对均匀介质,</p><script type="math/tex; mode=display">\omega_e = \omega_{e0} + \omega_{\text{极}} = \frac{1}{2}\varepsilon_0E^2 + \frac{1}{2}\vec{P}\cdot\vec{E}</script><h3 id="虚功原理"><a href="#虚功原理" class="headerlink" title="虚功原理"></a>虚功原理</h3><p>对孤立带点体,若电量Q保持不变,</p><script type="math/tex; mode=display">\vec{F}\cdot\text{d}\vec{r} = -(\Delta W)_Q \rightarrow \vec{F} = -\left(\frac{\partial W}{\partial \vec{r}}\right)_Q</script><p>对非孤立带电体,若电势U保持不变,</p><script type="math/tex; mode=display">\vec{F}\cdot\text{d}\vec{r} = (\Delta W)_U \rightarrow \vec{F} = \left(\frac{\partial W}{\partial \vec{r}}\right)_U</script><p>推导:<br>对于一个稳定系统,发生虚位移后</p><script type="math/tex; mode=display">\text{d}W = \delta A - \delta A^{'}</script><p>其中$\delta A$为外界电源做功,$\delta A^{‘}$为静电力做功。静电力作功与能量有着功能原理,所以是负号。<br>在连接外部电源时,有关系$\delta A = 2 \delta A^{‘}$,可以由电容的公式推广得到。</p><p>所以自然有了虚功原理的公式。其中的符号也得到了解释。</p><h2 id="第三章"><a href="#第三章" class="headerlink" title="第三章"></a>第三章</h2><h3 id="电流强度"><a href="#电流强度" class="headerlink" title="电流强度"></a>电流强度</h3><script type="math/tex; mode=display">I = \frac{\text{d}Q}{\text{d}t}</script><h3 id="电流密度"><a href="#电流密度" class="headerlink" title="电流密度"></a>电流密度</h3><p>作一单位矢量为电流方向,取一面元$\Delta S_0$与$\boldsymbol{n}_0$垂直,设通过$\Delta S_0$的电流强度为$\Delta I$,则电流密度为</p><script type="math/tex; mode=display">\vec{j} = \frac{\Delta I}{\Delta S_0}\vec{n}_0</script><p>所以通过任意有限截面$S$的电流强度为</p><script type="math/tex; mode=display">I = \iint_S\vec{j}\cdot\text{d}\vec{S}</script><h3 id="电流密度的微观图像"><a href="#电流密度的微观图像" class="headerlink" title="电流密度的微观图像"></a>电流密度的微观图像</h3><p>导体中有k种带电粒子,其中第i种带电粒子的电量、带电粒子数密度、平均速度为$q_i, n_i, \boldsymbol{\bar{u}}_i$</p><p>则</p><script type="math/tex; mode=display">\vec{j} = \sum_{i=1}^{N}q_in_i\boldsymbol{\bar{u}}_i</script><p>注意到$q_in_i = \rho_i$,有</p><script type="math/tex; mode=display">\vec{j} = \sum_{i=1}^{N}\rho_i\boldsymbol{\bar{u}}_i</script><h3 id="电流连续性方程"><a href="#电流连续性方程" class="headerlink" title="电流连续性方程"></a>电流连续性方程</h3><script type="math/tex; mode=display">\oiint_S \vec{j}\cdot \text{d}\vec{S} = -\iiint_V \frac{\partial \rho}{\partial t}\text{d} V = -\frac{\text{d} q}{\text{d} t}</script><p>即</p><script type="math/tex; mode=display">\nabla \cdot \vec{j} + \frac{\partial \rho}{\partial t} = 0</script><h3 id="稳恒条件"><a href="#稳恒条件" class="headerlink" title="稳恒条件"></a>稳恒条件</h3><p>稳恒电流的闭合性;电荷的分布不因电流的存在而随时间变化,产生的电场不随时间变化。</p><p>电流线或者电流是闭合的,不可能有起点或者终点。<br>沿任一电流管的各截面电流强度都相等。</p><h3 id="欧姆定律"><a href="#欧姆定律" class="headerlink" title="欧姆定律"></a>欧姆定律</h3><script type="math/tex; mode=display">I=\frac{U}{R} = GU, U = IR</script><script type="math/tex; mode=display">R= \rho\frac{l}{S}, G=\sigma\frac{S}{l}</script><h3 id="欧姆定律的微观形式"><a href="#欧姆定律的微观形式" class="headerlink" title="欧姆定律的微观形式"></a>欧姆定律的微观形式</h3><script type="math/tex; mode=display">\vec{j} =\sigma\vec{E},\vec{E} = \rho\vec{j}</script><p>可以用之求解电阻,一般地,可以用</p><script type="math/tex; mode=display">R=\int\rho\frac{\text{d}l}{S}</script><p>和/即</p><script type="math/tex; mode=display">R = \frac{U}{I} = \frac{\int \vec{E}\cdot \text{d}\vec{l}}{I} = \frac{\int \rho \vec{j}\cdot\text{d}\vec{l}}{I}</script><h3 id="焦耳定律"><a href="#焦耳定律" class="headerlink" title="焦耳定律"></a>焦耳定律</h3><p>单位时间内电场做的功,即电流的功率为</p><script type="math/tex; mode=display">P_e = \frac{\text{d}A}{\text{d}t} = IU</script><p>电功率密度定义为</p><script type="math/tex; mode=display">p = \frac{P}{V} = \frac{I^2R}{V}</script><p>利用电流管,证明得到</p><script type="math/tex; mode=display">p = \vec{j}\cdot\vec{E} = \frac{j^2}{\sigma} = \rho j^2</script><h3 id="导电介质问题"><a href="#导电介质问题" class="headerlink" title="导电介质问题"></a>导电介质问题</h3><p>基本定理</p><script type="math/tex; mode=display">\oint_L \vec{E}\cdot\text{d}\vec{l} = 0</script><script type="math/tex; mode=display">\oiint_S \vec{j}\cdot \text{d}\vec{S} = 0</script><p>性能方程</p><script type="math/tex; mode=display">\vec{j} = \sigma \vec{E}</script><script type="math/tex; mode=display">\vec{D} = \varepsilon\vec{E}</script><p>边界条件</p><script type="math/tex; mode=display">\vec{n}\times(\vec{E}_2 - \vec{E}_1) = 0</script><script type="math/tex; mode=display">\vec{n}\cdot(\vec{j}_2 - \vec{j}_1) = 0</script><p>参考<a href="#电介质交界面上的物理量">电介质交界面上的物理量</a></p><p>一般步骤</p><p>先根据导电性质求出电场分布,再根据介质性质求出极化的情况。计划性质决定了自由电荷和极化电荷在总电荷中所占的比例,与介电常量有关。</p><script type="math/tex; mode=display">\oiint_S \vec{E}\cdot \text{d}\vec{S} = \frac{Q}{\varepsilon_0} = \frac{Q_0}{\varepsilon}</script><p>得到</p><script type="math/tex; mode=display">\frac{Q^{'}}{Q} = \frac{Q-Q_0}{Q} = \frac{\varepsilon_0 - \varepsilon}{\varepsilon_0}</script><h3 id="导电介质的电容与电阻"><a href="#导电介质的电容与电阻" class="headerlink" title="导电介质的电容与电阻"></a>导电介质的电容与电阻</h3><script type="math/tex; mode=display">C=\frac{Q_0}{\Delta U} = \frac{\varepsilon}{\Delta U}\oiint_S \vec{E}\cdot\text{d}\vec{S}</script><script type="math/tex; mode=display">\frac{1}{R} = \frac{I}{\Delta U} = \frac{\sigma}{\Delta U}\oiint_S \vec{E}\cdot \text{d}\vec{S}</script><p>得到时间常数</p><script type="math/tex; mode=display">\tau = RC = \frac{\varepsilon}{\sigma} = \rho\varepsilon</script><h3 id="全电路欧姆定律"><a href="#全电路欧姆定律" class="headerlink" title="全电路欧姆定律"></a>全电路欧姆定律</h3><p>U为路端电压</p><script type="math/tex; mode=display">U = \varepsilon - Ir</script><h3 id="奇怪电阻回路"><a href="#奇怪电阻回路" class="headerlink" title="奇怪电阻回路"></a>奇怪电阻回路</h3><p>假设电流法,对称法,断开节点法</p><h3 id="Y——Delta转换"><a href="#Y——Delta转换" class="headerlink" title="Y——Delta转换"></a>Y——Delta转换</h3><script type="math/tex; mode=display">R_{12} = \frac{G_1 + G_2 + G_3}{G_1G_2}</script><script type="math/tex; mode=display">R_{23} = \frac{G_1 + G_2 + G_3}{G_2G_3}</script><script type="math/tex; mode=display">R_{31} = \frac{G_1 + G_2 + G_3}{G_3G_1}</script><script type="math/tex; mode=display">G_1 = \frac{R_{12} + R_{23} + R_{31}}{R_{12}R_{31}}</script><script type="math/tex; mode=display">G_2 = \frac{R_{12} + R_{23} + R_{31}}{R_{12}R_{23}}</script><script type="math/tex; mode=display">G_3 = \frac{R_{12} + R_{23} + R_{31}}{R_{23}R_{31}}</script>]]></content>
<categories>
<category>物理</category>
</categories>
<tags>
<tag>物理</tag>
<tag>课内复习</tag>
</tags>
</entry>
<entry>
<title>Minimal TikZ 学习笔记</title>
<link href="/2021/09/10/Minimal-TikZ-/"/>
<url>/2021/09/10/Minimal-TikZ-/</url>
<content type="html"><![CDATA[<p>本文为<code>A very minimal introduction to TikZ</code>学习笔记,主要将一些重点内容用中文记录下来。基本原因是我看英语看得头疼。<br><span id="more"></span><br>该指南作者为Jacques Cr´emer,内容发表于2011年3月11日。</p><!-- 由于网站平台限制,文中的代码将无法执行,所以无法直观地看到输出结果。有兴趣的读者可以自行输入和编译并观察实验结果。 --><p>本文使用<code>TikZJax</code>进行<code>TikZ</code>代码执行。在网络不好的情况下无法显示出执行效果。请自行准备科学工具?</p><h2 id="Picture环境"><a href="#Picture环境" class="headerlink" title="Picture环境"></a>Picture环境</h2><p>通常使用如下基本配置,实现中文环境下文章的编辑。通常情况下,我们会外套table环境用于图片定位。</p><figure class="highlight latex"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></div></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\documentclass</span>[tikz]{article}<br><span class="hljs-keyword">\usepackage</span>{tikz}<br><span class="hljs-keyword">\usepackage</span>[UTF8]{ctex}<br><span class="hljs-keyword">\begin</span>{document}<br> <span class="hljs-keyword">\begin</span>{figure}<br> <span class="hljs-keyword">\begin</span>{tikzpicture}<br> code here<br> <span class="hljs-keyword">\end</span>{tikzpicture}<br> <span class="hljs-keyword">\caption</span>{CAPTION}<br> <span class="hljs-keyword">\end</span>{figure}<br><span class="hljs-keyword">\end</span>{document}<br></code></pre></td></tr></table></figure><p>如果只希望进行配图的生成,使用如下配置。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\documentclass</span>[margin=10pt,tikz]{standalone}<br><span class="hljs-keyword">\usepackage</span>{tikz}<br><span class="hljs-keyword">\usepackage</span>[UTF8]{ctex}<br><span class="hljs-keyword">\begin</span>{document}<br> <span class="hljs-keyword">\begin</span>{tikzpicture}<br> code here<br> <span class="hljs-keyword">\end</span>{tikzpicture}<br><span class="hljs-keyword">\end</span>{document}<br></code></pre></td></tr></table></figure><h2 id="基本绘图"><a href="#基本绘图" class="headerlink" title="基本绘图"></a>基本绘图</h2><p>TikZ使用坐标系来精确定位图像元素的位置,请在绘图时将图像坐标牢记于心。</p><p>我们会建议用户使用结点<code>\node</code>来标记元素坐标,而不是直接使用立即数。但是,教程中我们采取了后者,为了清晰可见的视觉效果。</p><h3 id="直线"><a href="#直线" class="headerlink" title="直线"></a>直线</h3><p>一条直线,注意分号是必须的。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> (0, 0) -- (1, 2);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz"> \begin{tikzpicture} \draw (0, 0) -- (1, 2); \end{tikzpicture}</script><p>一条折线</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> (0, 0) -- (1, 2) -- (2, 3) -- (1, 0);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw (0, 0) -- (1, 2) -- (2, 3) -- (1, 0);\end{tikzpicture}</script><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [help lines] (0, 0) grid (4, 4);<br> <span class="hljs-keyword">\draw</span> (0, 0) -- (1, 2) -- (2, 3) -- (1, 0);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><p>带有辅助网格的折线,辅助网格可以帮助用户定位。辅助网格使用风格<code>help lines</code>,推荐在其他元素之前绘制,防止覆盖和叠加。</p><script type="text/tikz">\begin{tikzpicture} \draw [help lines] (0, 0) grid (4, 4); \draw (0, 0) -- (1, 2) -- (2, 3) -- (1, 0);\end{tikzpicture}</script><h3 id="图像缩放"><a href="#图像缩放" class="headerlink" title="图像缩放"></a>图像缩放</h3><p>通过在环境上添加<code>scale</code>的值,可以调整图片的缩放尺度。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}[scale=3]<br> <span class="hljs-keyword">\draw</span> (0, 0) -- (1, 1);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture}[scale=3] \draw (0, 0) -- (1, 1);\end{tikzpicture}</script><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}[xscale=2, yscale=3]<br> <span class="hljs-keyword">\draw</span> (0, 0) -- (1, 1);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture}[xscale=2, yscale=3] \draw (0, 0) -- (1, 1);\end{tikzpicture}</script><h3 id="箭头,和对应衍生物"><a href="#箭头,和对应衍生物" class="headerlink" title="箭头,和对应衍生物"></a>箭头,和对应衍生物</h3><p>线可以添加相应的”装饰”。通常来说,箭头类装饰只会出现在线的两侧,折线也是如此。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [->] (0, 0) -- (2, 0);<br> <span class="hljs-keyword">\draw</span> [<-] (0, -0.5) -- (2,-0.5);<br><span class="hljs-keyword">\draw</span> [|->] (0,-1) -- (2,-1);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [->] (0, 0) -- (2, 0); \draw [<-] (0, -0.5) -- (2,-0.5);\draw [|->] (0,-1) -- (2,-1);\end{tikzpicture}</script><p>双向箭头可以作为一种取巧的方式产生坐标系。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [<->] (0,2) -- (0,0) -- (3,0);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [<->] (0,2) -- (0,0) -- (3,0);\end{tikzpicture}</script><h3 id="改变线的宽度"><a href="#改变线的宽度" class="headerlink" title="改变线的宽度"></a>改变线的宽度</h3><p>通过各种<code>decoration</code>来改变线的风格,宽度的风格有<code>ultra thin, very thin, thin, semithick, thick, very thick, ultra thick</code></p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [ultra thick] (0,1) -- (2,1);<br> <span class="hljs-keyword">\draw</span> [thick] (0,0.5) -- (2,0.5);<br> <span class="hljs-keyword">\draw</span> [thin] (0,0) -- (2,0);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [ultra thick] (0,1) -- (2,1); \draw [thick] (0,0.5) -- (2,0.5); \draw [thin] (0,0) -- (2,0);\end{tikzpicture}</script><p>先前提及的<code>help lines</code>,其实是一种<code>fine gray</code>的装饰,可以用作各种辅助线。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [<->] (0,2) -- (0,0) -- (4,0);<br> <span class="hljs-keyword">\draw</span> [thick] (0,1.5) -- (3,0);<br> <span class="hljs-keyword">\draw</span> [ultra thick] (0,0) -- (2,2);<br> <span class="hljs-keyword">\draw</span> [help lines] (1,0) -- (1,1) -- (0,1);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [<->] (0,2) -- (0,0) -- (4,0); \draw [thick] (0,1.5) -- (3,0); \draw [ultra thick] (0,0) -- (2,2); \draw [help lines] (1,0) -- (1,1) -- (0,1);\end{tikzpicture}</script><p>当然可以自由指定线宽。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [line width=12] (0,0) -- (2,0);<br> <span class="hljs-keyword">\draw</span> [line width=0.2cm] (4,.75) -- (5,.25);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [line width=12] (0,0) -- (2,0); \draw [line width=0.2cm] (4,.75) -- (5,.25);\end{tikzpicture}</script><h3 id="dashes-and-dots"><a href="#dashes-and-dots" class="headerlink" title="dashes and dots"></a>dashes and dots</h3><p>可以使用散点和散线。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [dashed, ultra thick] (0,1) -- (2,1);<br> <span class="hljs-keyword">\draw</span> [dashed] (0, 0.5) -- (2,0.5);<br> <span class="hljs-keyword">\draw</span> [dotted] (0,0) -- (2,0);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [dashed, ultra thick] (0,1) -- (2,1); \draw [dashed] (0, 0.5) -- (2,0.5); \draw [dotted] (0,0) -- (2,0);\end{tikzpicture}</script><h3 id="颜色"><a href="#颜色" class="headerlink" title="颜色"></a>颜色</h3><p>可以直接指定颜色,包括<code>red, green, blue, cyan, magenta, yellow, black, gray, darkgray, lightgray, brown, lime, olive, orange, pink, purple, teal, violet, white</code>,也可以通过不同方法定义自己的颜色。参考手册即可。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [gray] (0,1) -- (2,1);<br> <span class="hljs-keyword">\draw</span> [red] (0, 0.5) -- (2,0.5);<br> <span class="hljs-keyword">\draw</span> [blue] (0,0) -- (2,0);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [gray] (0,1) -- (2,1); \draw [red] (0, 0.5) -- (2,0.5); \draw [blue] (0,0) -- (2,0);\end{tikzpicture}</script><h3 id="文中符号和图形"><a href="#文中符号和图形" class="headerlink" title="文中符号和图形"></a>文中符号和图形</h3><p>事实上,如果不外套figure环境,你可以做到行内符号和图形。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture} <span class="hljs-keyword">\draw</span> [yellow, line width=6] (0,0) -- (.5,0); <span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><p>限于工具的使用,这里就不在网页中展示行内符号的样式了。可以自行测试。</p><h3 id="曲线"><a href="#曲线" class="headerlink" title="曲线"></a>曲线</h3><p>TikZ提供各种各样的曲线。示例如下。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br><span class="hljs-keyword">\draw</span> [blue] (0,0) rectangle (1.5,1);<br><span class="hljs-keyword">\draw</span> [red, ultra thick] (3,0.5) circle [radius=0.5];<br><span class="hljs-keyword">\draw</span> [gray] (6,0) arc [radius=1, start angle=45, end angle= 120];<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture}\draw [blue] (0,0) rectangle (1.5,1);\draw [red, ultra thick] (3,0.5) circle [radius=0.5];\draw [gray] (6,0) arc [radius=1, start angle=45, end angle= 120];\end{tikzpicture}</script><p><code>arc</code>中,各个参数有这样的含义,即radius表示半径,start angle 表示起始点的角度,end angle 表示终止点的角度。</p><p>TikZ也允许你获得圆滑的路径。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [<->, rounded corners, thick, purple] (0,2) -- (0,0) -- (3,0);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [<->, rounded corners, thick, purple] (0,2) -- (0,0) -- (3,0);\end{tikzpicture}</script><p>其他的曲线呢?TikZ允许你通过大量的点,(x, y)模拟一条曲线。当然这不是最佳的选择。TikZ提供了数学工具,可以产生大致的曲线。不过你需要指定起点终点的倾角。这个倾角的取值范围为[0, 360),大概。我没看手册,应该吧。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span>[very thick] (0,0) to [out=90,in=195] (2,1.5);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw[very thick] (0,0) to [out=90,in=195] (2,1.5);\end{tikzpicture}</script><p>注意这里使用了<code>to</code>关键词表示你制定了一条曲线。值得提醒的是,你也可以使用<code><-></code>之类的符号给曲线增加箭头。</p><h3 id="数学作图"><a href="#数学作图" class="headerlink" title="数学作图"></a>数学作图</h3><p>TikZ允许你通过数学公式绘制图像。代码如下。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}[xscale=13,yscale=3.8]<br> <span class="hljs-keyword">\draw</span> [<->] (0,0.8) -- (0,0) -- (0.5,0);<br> <span class="hljs-keyword">\draw</span>[green, ultra thick, domain=0:0.5] plot (<span class="hljs-keyword">\x</span>, {0.025+<span class="hljs-keyword">\x</span>+<span class="hljs-keyword">\x</span>*<span class="hljs-keyword">\x</span>});<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture}[xscale=13,yscale=3.8] \draw [<->] (0,0.8) -- (0,0) -- (0.5,0); \draw[green, ultra thick, domain=0:0.5] plot (\x, {0.025+\x+\x*\x});\end{tikzpicture}</script><p>这里的<code>\x</code>事实上是点的真实坐标。<code>domain</code>提供了定义域的范围。除了这些函数,TkiZ还提供了</p><ul><li><code>factorial(\x)</code></li><li><code>sqrt(\x),</code></li><li><code>pow(\x, y)</code>,x的y次幂。</li><li><code>exp(\x)</code></li><li><code>ln(\x)</code></li><li><code>log10(\x)</code></li><li><code>log2(\x)</code></li><li><code>abs(\x)</code>,x的绝对值。</li><li><code>mod(\x, y)</code>,x 模 y。</li><li><code>round(\x)</code>,取值到最近的整数。</li><li><code>floor(\x)</code>,下取整数。</li><li><code>ceil(\x)</code>,上取整数。</li><li><code>sin(\x)</code>,x是角度,如果想使用弧度,请使用函数sin(\x r)。</li><li><code>cos(\x)</code>,x是角度,如果想使用弧度,请使用函数cos(\x r)。</li><li><code>tan(\x)</code>, x是角度,如果想使用弧度,请使用函数tan(\x r)。</li><li><code>min(\x, y)</code>。</li><li><code>max(\x, y)</code>。</li></ul><p>和<code>rnd</code>产生[0,1]中随机数的函数,和两个常数<code>e = 2.718281828, pi = 3.141592654</code>。</p><p>下面的图象有不错的视觉效果。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [help lines, <->] (0,0) -- (6.5,0);<br> <span class="hljs-keyword">\draw</span> [help lines, ->] (0,-1.1) -- (0,1.1);<br> <span class="hljs-keyword">\draw</span> [green,domain=0:2*pi] plot (<span class="hljs-keyword">\x</span>, {(sin(<span class="hljs-keyword">\x</span> r)* ln(<span class="hljs-keyword">\x</span>+1))/2});<br> <span class="hljs-keyword">\draw</span> [red,domain=0:pi] plot (<span class="hljs-keyword">\x</span>, {sin(<span class="hljs-keyword">\x</span> r)});<br> <span class="hljs-keyword">\draw</span> [blue, domain=pi:2*pi] plot (<span class="hljs-keyword">\x</span>, {cos(<span class="hljs-keyword">\x</span> r)*exp(<span class="hljs-keyword">\x</span>/exp(2*pi))});<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [help lines, <->] (0,0) -- (6.5,0); \draw [help lines, ->] (0,-1.1) -- (0,1.1); \draw [green,domain=0:2*pi] plot (\x, {(sin(\x r)* ln(\x+1))/2}); \draw [red,domain=0:pi] plot (\x, {sin(\x r)}); \draw [blue, domain=pi:2*pi] plot (\x, {cos(\x r)*exp(\x/exp(2*pi))});\end{tikzpicture}</script><h3 id="填充区域"><a href="#填充区域" class="headerlink" title="填充区域"></a>填充区域</h3><p>简单使用<code>fill</code>参数即可将闭曲线填充。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [fill=red,ultra thick] (0,0) rectangle (1,1);<br> <span class="hljs-keyword">\draw</span> [fill=red,ultra thick,red] (2,0) rectangle (3,1);<br> <span class="hljs-keyword">\draw</span> [blue, fill=blue] (4,0) -- (5,1) -- (4.75,0.15) -- (4,0);<br> <span class="hljs-keyword">\draw</span> [fill] (7,0.5) circle [radius=0.1];<br> <span class="hljs-keyword">\draw</span> [fill=orange] (9,0) rectangle (11,1);<br> <span class="hljs-keyword">\draw</span> [fill=white] (9.25,0.25) rectangle (10,1.5);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [fill=red,ultra thick] (0,0) rectangle (1,1); \draw [fill=red,ultra thick,red] (2,0) rectangle (3,1); \draw [blue, fill=blue] (4,0) -- (5,1) -- (4.75,0.15) -- (4,0); \draw [fill] (7,0.5) circle [radius=0.1]; \draw [fill=orange] (9,0) rectangle (11,1); \draw [fill=white] (9.25,0.25) rectangle (10,1.5);\end{tikzpicture}</script><p><code>fill = red</code>告诉TikZ你想要用红色填充,<code>red</code>告诉TikZ你想用红色绘制路径。</p><p>有的时候你不想看到路径,即边框线。那么可以使用<code>\path</code>指令实现这一功能。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br><span class="hljs-keyword">\path</span> [fill=gray] (0,0) rectangle (1.5,1);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture}\path [fill=gray] (0,0) rectangle (1.5,1);\end{tikzpicture}</script><h3 id="复杂路径仍然可以填充"><a href="#复杂路径仍然可以填充" class="headerlink" title="复杂路径仍然可以填充"></a>复杂路径仍然可以填充</h3><p>只要路径的终点和起点相吻合,图形一样可以填充。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [ultra thick] (0,0) to [out=87,in=150] (1,1) -- (.85,.15) -- (0,0);<br> <span class="hljs-keyword">\draw</span> [ultra thick, fill=purple] (2,0) to [out=87,in=150] (3,1) -- (2.85,.15) -- (2,0);<br> <span class="hljs-keyword">\path</span> [fill=purple] (4,0) to [out=87,in=150] (5,1) -- (4.85,.15) -- (4,0);<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [ultra thick] (0,0) to [out=87,in=150] (1,1) -- (.85,.15) -- (0,0); \draw [ultra thick, fill=purple] (2,0) to [out=87,in=150] (3,1) -- (2.85,.15) -- (2,0); \path [fill=purple] (4,0) to [out=87,in=150] (5,1) -- (4.85,.15) -- (4,0);\end{tikzpicture}</script><h3 id="图像中放置标签"><a href="#图像中放置标签" class="headerlink" title="图像中放置标签"></a>图像中放置标签</h3><p>标签的放置可以通过<code>\node</code>实现。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [thick, <->] (0,2) -- (0,0) -- (2,0);<br> <span class="hljs-keyword">\node</span> at (1,1) {yes};<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [thick, <->] (0,2) -- (0,0) -- (2,0); \node at (1,1) {yes};\end{tikzpicture}</script><p><code>\node</code> 可以添加标记,即<code>\node(node name)</code>。如果只是为了标记,可以使用<code>\node (node name) at (x, y)</code>定义坐标点。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [thick, <->] (0,2) -- (0,0) -- (2,0);<br> <span class="hljs-keyword">\draw</span> [fill] (1,1) circle [radius=0.025];<br> <span class="hljs-keyword">\node</span> [below] at (1,1) {below};<br> <span class="hljs-keyword">\node</span> [above] at (1,1) {above};<br> <span class="hljs-keyword">\node</span> [left] at (1,1) {left};<br> <span class="hljs-keyword">\node</span> [right] at (1,1) {right};<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [thick, <->] (0,2) -- (0,0) -- (2,0); \draw [fill] (1,1) circle [radius=0.025]; \node [below] at (1,1) {below}; \node [above] at (1,1) {above}; \node [left] at (1,1) {left}; \node [right] at (1,1) {right};\end{tikzpicture}</script><p>也有更加绚丽的图片。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [thick, <->] (0,1) -- (0,0) -- (1,0);<br> <span class="hljs-keyword">\draw</span>[fill] (1,1) circle [radius=0.025];<br> <span class="hljs-keyword">\node</span> [below right, red] at (.5,.75) {below right};<br> <span class="hljs-keyword">\node</span> [above left, green] at (.5,.75) {above left};<br> <span class="hljs-keyword">\node</span> [below left, purple] at (.5,.75) {below left};<br> <span class="hljs-keyword">\node</span> [above right, magenta] at (.5,.75) {above right};<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [thick, <->] (0,1) -- (0,0) -- (1,0); \draw[fill] (1,1) circle [radius=0.025]; \node [below right, red] at (.5,.75) {below right}; \node [above left, green] at (.5,.75) {above left}; \node [below left, purple] at (.5,.75) {below left}; \node [above right, magenta] at (.5,.75) {above right};\end{tikzpicture}</script><p>这种情况下,我们可以获得一个完美的坐标系。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [thick, <->] (0,1) -- (0,0) -- (1,0);<br> <span class="hljs-keyword">\node</span> [below right] at (1,0) {<span class="hljs-built_in">$</span>x<span class="hljs-built_in">$</span>};<br> <span class="hljs-keyword">\node</span> [left] at (0,1) {<span class="hljs-built_in">$</span>y<span class="hljs-built_in">$</span>};<br> <span class="hljs-keyword">\draw</span>[fill] (.4,.6) circle [radius=.5pt];<br> <span class="hljs-keyword">\node</span>[above right] (.4,.6) {<span class="hljs-built_in">$</span>A<span class="hljs-built_in">$</span>};<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [thick, <->] (0,1) -- (0,0) -- (1,0); \node [below right] at (1,0) {$x$}; \node [left] at (0,1) {$y$}; \draw[fill] (.4,.6) circle [radius=.5pt]; \node[above right] (.4,.6) {$A$};\end{tikzpicture}</script><p>当然我们可以将指令合在一起写,省去结点的声明。不过这样的话不符合我们先前约定的规范。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [thick, <->] (0,1) node [left] {<span class="hljs-built_in">$</span>y<span class="hljs-built_in">$</span>}<br> -- (0,0) -- (1,0) node [below right] {<span class="hljs-built_in">$</span>x<span class="hljs-built_in">$</span>};<br> <span class="hljs-keyword">\draw</span>[fill] (.4,.6) circle [radius=.5pt]<br> node[above right] (.4,.6) {<span class="hljs-built_in">$</span>A<span class="hljs-built_in">$</span>};<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [thick, <->] (0,1) node [left] {$y$} -- (0,0) -- (1,0) node [below right] {$x$}; \draw[fill] (.4,.6) circle [radius=.5pt] node[above right] (.4,.6) {$A$};\end{tikzpicture}</script><p>在一个结点内,如果你想要产生多行文字,你需要告诉TikZ你在哪个地方换行,使用<code>\\</code>符号。同时,你需要指定对齐方式,否则TikZ将不会渲染。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [thick] (0,0) -- (9,0);<br> <span class="hljs-keyword">\draw</span> (0,-.2) -- (0, .2);<br> <span class="hljs-keyword">\draw</span> (3,-.2) -- (3, .2);<br> <span class="hljs-keyword">\draw</span> (6,-.2) -- (6, .2);<br> <span class="hljs-keyword">\draw</span> (9,-.2) -- (9, .2);<br> <span class="hljs-keyword">\node</span>[align=left, below] at (1.5,-.5)<span class="hljs-comment">%</span><br> {This happens<span class="hljs-keyword">\\</span>in period 1<span class="hljs-keyword">\\</span>and is aligned<span class="hljs-keyword">\\</span> left};<br> <span class="hljs-keyword">\node</span>[align=center, below] at (4.5,-.5)<span class="hljs-comment">%</span><br> {This happens<span class="hljs-keyword">\\</span>in period 2<span class="hljs-keyword">\\</span>and is centered};<br> <span class="hljs-keyword">\node</span>[align=right, below] at (7.5,-.5)<span class="hljs-comment">%</span><br> {This happens<span class="hljs-keyword">\\</span>in period 2<span class="hljs-keyword">\\</span>and is right<span class="hljs-keyword">\\</span>aligned};<br><span class="hljs-keyword">\end</span>{tikzpicture}<br></code></pre></td></tr></table></figure><script type="text/tikz">\begin{tikzpicture} \draw [thick] (0,0) -- (9,0); \draw (0,-.2) -- (0, .2); \draw (3,-.2) -- (3, .2); \draw (6,-.2) -- (6, .2); \draw (9,-.2) -- (9, .2); \node[align=left, below] at (1.5,-.5)% {This happens\\in period 1\\and is aligned\\ left}; \node[align=center, below] at (4.5,-.5)% {This happens\\in period 2\\and is centered}; \node[align=right, below] at (7.5,-.5)% {This happens\\in period 2\\and is right\\aligned};\end{tikzpicture}</script><h3 id="集成进入Beamer"><a href="#集成进入Beamer" class="headerlink" title="集成进入Beamer"></a>集成进入Beamer</h3><p>Beamer 和 TikZ出于同一个作者之手,当然具有良好的集成性。在Beamer中,可以直接使用TikZ。</p><figure class="highlight latex"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><code class="hljs latex"><span class="hljs-keyword">\begin</span>{frame}<br> a few lines<br> <span class="hljs-keyword">\begin</span>{center}<br> <span class="hljs-keyword">\begin</span>{tikzpicture}<br> <span class="hljs-keyword">\draw</span> [blue, ultra thick] (-1,2) -- (6,3);<br> <span class="hljs-keyword">\uncover</span><1>{<span class="hljs-keyword">\draw</span> [green,thick] (-4,3) -- (2,2.5);}<br> <span class="hljs-keyword">\uncover</span><2>{<span class="hljs-keyword">\draw</span> [red,thick] (0,0) -- (0,5);}<br> <span class="hljs-keyword">\end</span>{tikzpicture}<br> <span class="hljs-keyword">\end</span>{center}<br> and something under.<br><span class="hljs-keyword">\end</span>{frame}<br></code></pre></td></tr></table></figure><p>其中<code>\uncover</code>不能换成<code>\only</code>,否则其他元素的位置将会改变。</p><h2 id="结语"><a href="#结语" class="headerlink" title="结语"></a>结语</h2><p>学习TikZ是一个漫长的过程。TikZ功能强大,还有许多宏包辅助功能,这些都会在将来的实践中发挥作用。</p>]]></content>
<categories>
<category>LaTeX</category>
</categories>
<tags>
<tag>LaTeX</tag>
</tags>
</entry>
<entry>
<title>遇到的bug汇总-初学者的Bug List!</title>
<link href="/2021/08/29/Bugs/"/>
<url>/2021/08/29/Bugs/</url>
<content type="html"><![CDATA[<p>作为一个能力不足的人,在日常生活中,总会有那么一些bug让我难以接受。我将其中的部分汇总如下,聊以慰藉。</p><span id="more"></span><p>本文理论上是长期更新的,不要嫌文章短(</p><h2 id="时间流逝造成的未知错误"><a href="#时间流逝造成的未知错误" class="headerlink" title="时间流逝造成的未知错误"></a>时间流逝造成的未知错误</h2><h3 id="PowerToys-的bug"><a href="#PowerToys-的bug" class="headerlink" title="PowerToys 的bug"></a>PowerToys 的bug</h3><p>作为Vim用户,交换Caps Lock和Esc键是常规操作了。为了体现Geek风范,我使用了 MicroSoft维护的PowerToys来实现键盘重映射。</p><p>但是,我没有想到的是,当前版本的PowerToys存在假死的情况。假死过后,会强制软件激活Caps Lock,造成我编码的误操作。令人惊奇的是,激活的Caps Lock,我需要按两次才能取消。第一次是硬件激活,第二次是硬件取消。可以算是步调不一致了。</p><h3 id="“-target”?-你从哪里来?"><a href="#“-target”?-你从哪里来?" class="headerlink" title="“-target”? 你从哪里来?"></a>“-target”? 你从哪里来?</h3><p>先前在调试clang的时候,在系统变量中添加了<code>CXXFLAGS</code> 和它的值 <code>-target XXXX</code>。后来因为clang 始终无法测试成功,便卸载了clang。但是,系统变量没有被删除。</p><p>后来,我再调试CMake的时候,无论怎么make都会显示无法通过编译器测试,显示<code>Uknown command line "-target"</code>。</p><p>我怎么想,都觉得不可思议。明明g++使用格式为<code>--target</code>,为什么CMake会这么不合常理地使用这样的编译选项,反而告诉我无法编译呢?</p><p>可想而知,耗费三个小时后,我灵光一闪,删除了系统变量中的<code>CXXFLAGS</code>。编译通过了。</p><p>所以clang和g++读取同一个系统变量,这种原因我不得而知。</p><h3 id="关我Anaconda何事?"><a href="#关我Anaconda何事?" class="headerlink" title="关我Anaconda何事?"></a>关我Anaconda何事?</h3><p>首次使用VSCode编辑Qt6生成的CMake工程时,Intelligence总是提示错误的引用。仔细一看,include到了<code>Anaconda/Library/Qt</code>里面的文件。这就问题很大了。</p><p>思索再三,我发现VSCode的<code>C/C++</code>扩展中对include path的定义,是先在系统环境变量中搜索的。那么,Anaconda的路径在Qt之前,便会直接从Anaconda中include,这就产生了错误。</p><p>将环境变量的顺序调整了之后,问题不再复现。</p><h2 id="编程技术造成的错误"><a href="#编程技术造成的错误" class="headerlink" title="编程技术造成的错误"></a>编程技术造成的错误</h2><h3 id="C语言篇"><a href="#C语言篇" class="headerlink" title="C语言篇"></a>C语言篇</h3><h4 id="忘记加括号"><a href="#忘记加括号" class="headerlink" title="忘记加括号"></a>忘记加括号</h4><figure class="highlight c"><table><tr><td class="gutter"><div class="code-wrapper"><pre><span class="line">1</span><br></pre></div></td><td class="code"><pre><code class="hljs c">PWM_SetPWM_ByDutyCycle(SteerNumber, (<span class="hljs-type">uint16_t</span>)(angle * <span class="hljs-number">2.0</span> / <span class="hljs-number">180</span> + <span class="hljs-number">0.5</span>) / <span class="hljs-number">20</span> * <span class="hljs-number">4096</span>);<br></code></pre></td></tr></table></figure><p>这样的代码会将任何angle输入,变成0的。因为uint16_t的作用对象错了,应该是整个表达式的值。表达式的类型是double,在进行计算的时候精度损失可以忽略。但是uint16_t位置不对,提前变换成了整型,这不是胡闹吗?</p><p>正确修改如下。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c">PWM_SetPWM_ByDutyCycle(SteerNumber, (<span class="hljs-type">uint16_t</span>)((angle * <span class="hljs-number">2.0</span> / <span class="hljs-number">180</span> + <span class="hljs-number">0.5</span>) / <span class="hljs-number">20</span> * <span class="hljs-number">4096</span>));<br></code></pre></td></tr></table></figure><h4 id="volatile-并行计算需要好好学习"><a href="#volatile-并行计算需要好好学习" class="headerlink" title="volatile?并行计算需要好好学习"></a>volatile?并行计算需要好好学习</h4><p>多次读取一个变化的值,读出来的竟然是相同的。这是正常现象,编译器做出来的优化,只需要加上volatile关键词即可。问题的根本在于并行计算理解不够,有待更加深入学习并行计算理论了。</p><h4 id="造轮子是需要水平的,溢出是需要检查的"><a href="#造轮子是需要水平的,溢出是需要检查的" class="headerlink" title="造轮子是需要水平的,溢出是需要检查的"></a>造轮子是需要水平的,溢出是需要检查的</h4><p>课程要求我手动造轮子。可惜能力不足,出现了内存溢出。但是我怎么检查,怎么测试,都不可能出现溢出啊?最后发现,是<strong>没有赋初始值</strong>造成的数据错乱,而不是指向了释放的内存空间。所以,造轮子需谨慎,我仍然是一个菜鸡。</p><h3 id="CMake篇"><a href="#CMake篇" class="headerlink" title="CMake篇"></a>CMake篇</h3><h4 id="“默认化的默认构造函数不能为constexpr”"><a href="#“默认化的默认构造函数不能为constexpr”" class="headerlink" title="“默认化的默认构造函数不能为constexpr”"></a>“默认化的默认构造函数不能为constexpr”</h4><p>首次尝试利用Qt Creator生成mingw工程并利用Visual Studio 2022调试时,就连最基本的代码都无法编译通过。报错就是标题内容,尽管是自动生成的代码。仔细检查后 发现,Visual Studio读取CMake文件时,没有读取到正确的CMake生成器,默认使用了Ninja,这个我可不会。</p><p>在VS的某个界面中,修改CMake工程的生成器,为Unix Makefiles,这样就编译通过了。</p><h3 id="C-篇"><a href="#C-篇" class="headerlink" title="C++篇"></a>C++篇</h3><h4 id="vector数据存储在哪"><a href="#vector数据存储在哪" class="headerlink" title="vector数据存储在哪"></a>vector数据存储在哪</h4><p>在阅读OpenGL教程时,发现了如下语句。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><code class="hljs cpp">vector<Vertex> vertices;<br><span class="hljs-comment">// ... lots of code</span><br><span class="hljs-built_in">glBufferData</span>(GL_ARRAY_BUFFER, vertices.<span class="hljs-built_in">size</span>() * <span class="hljs-built_in">sizeof</span>(Vertex), &vertices[<span class="hljs-number">0</span>], GL_STATIC_DRAW);<br></code></pre></td></tr></table></figure><p>这时发现vector被当成了数组使用。但是记得vector是特殊的结构,不能直接读取才对,怎么回事?</p><p>这是因为vector本身的存储结构是特殊的,但是对于数据的存储位置来说,数据始终是连续的。这也保证了vector是可以随机读写的。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><code class="hljs cpp">std::vector<<span class="hljs-type">int</span>> a = {<span class="hljs-number">0</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>};<br>std::cout << <span class="hljs-built_in">sizeof</span>(a) << std::endl; <span class="hljs-comment">// 24 Bytes</span><br>std::cout << a[<span class="hljs-number">0</span>] << std::endl; <span class="hljs-comment">// 0</span><br>std::cout << *((<span class="hljs-type">int</span> *)&(a[<span class="hljs-number">0</span>])+<span class="hljs-number">1</span>) << std::endl; <span class="hljs-comment">// 1,是索引为1的元素,证明存储是连续的。</span><br></code></pre></td></tr></table></figure><h3 id="通病"><a href="#通病" class="headerlink" title="通病"></a>通病</h3><h4 id="无后效性提醒"><a href="#无后效性提醒" class="headerlink" title="无后效性提醒"></a>无后效性提醒</h4><p>在一次编程实践中,我发现系统出现了不应该的异常抖动。代码如下。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><code class="hljs c"><span class="hljs-type">void</span> <span class="hljs-title function_">Motor_Decode</span><span class="hljs-params">(MotorInput_t x, MotorInput_t y, MotorInput_t w)</span> {<br><br> <span class="hljs-comment">// 反向的速度才是正方向</span><br> x = -x;<br> y = -y;<br><br> <span class="hljs-comment">// 保存速度结果,便于调试运动状态</span><br> Motor_InputInstance.x = x;<br> Motor_InputInstance.y = y;<br> Motor_InputInstance.w = w;<br><br> Motor_TargetSpeed[<span class="hljs-number">0</span>] = MotorDecodeOutputFix(Motor_InputInstance.Kx * x +<br> Motor_InputInstance.Ky * y +<br> Motor_InputInstance.Kw * w);<br> Motor_TargetSpeed[<span class="hljs-number">1</span>] = MotorDecodeOutputFix(-Motor_InputInstance.Kx * x +<br> Motor_InputInstance.Ky * y -<br> Motor_InputInstance.Kw * w);<br> Motor_TargetSpeed[<span class="hljs-number">2</span>] = MotorDecodeOutputFix(-Motor_InputInstance.Kx * x +<br> Motor_InputInstance.Ky * y +<br> Motor_InputInstance.Kw * w);<br> Motor_TargetSpeed[<span class="hljs-number">3</span>] = MotorDecodeOutputFix(Motor_InputInstance.Kx * x +<br> Motor_InputInstance.Ky * y -<br> Motor_InputInstance.Kw * w);<br>}<br></code></pre></td></tr></table></figure><p>测试的时候,出现了异常的速度抖动,方向频繁切换。但是,使用如下代码就可以解决。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><code class="hljs c">Motor_Decode(new_x, new_y, new_z);<br>Motor_Decode(Motor_InputInstace.x, Motor_InputInstace.y, Motor_InputInstace.w);<br></code></pre></td></tr></table></figure><p>需要我写两遍?</p><p>不,真正的原因是,代码中的<code>x = -x; y = -y;</code>具有后效性,将速度反向放在这个地方没有任何道理,只会造成相同调用条件产生反向的输出结果。将这两行代码删除后,问题得到解决。</p><p>也许单看这个解释读者仍然不能理解。那么看下面的一个使用案例。</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><code class="hljs cpp"><span class="hljs-function">__STATIC_FORCEINLINE <span class="hljs-type">void</span> <span class="hljs-title">Motor_AddX</span><span class="hljs-params">(MotorInput_t x)</span> </span>{<br> Motor_InputInstance.x += x;<br> <span class="hljs-built_in">Motor_Decode</span>(Motor_InputInstance.x, Motor_InputInstance.y,<br> Motor_InputInstance.w);<br>}<br></code></pre></td></tr></table></figure><p>周期调用这个函数会发生什么?流程大概是这样的</p><figure class="highlight text"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><code class="hljs text">Motro_InputInstance.x == X0<br>Motro_InputInstance.x == X0 + x<br>Motro_InputInstance.x == - X0 - x<br>// 第一遍执行完毕<br>Motro_InputInstance.x == - X0 - x<br>Motro_InputInstance.x == - X0<br>Motro_InputInstance.x == X0<br>// 第二遍执行完毕<br></code></pre></td></tr></table></figure><p>看到了吗?它的数据在震荡!</p><h2 id="硬件设计中出现的问题"><a href="#硬件设计中出现的问题" class="headerlink" title="硬件设计中出现的问题"></a>硬件设计中出现的问题</h2><h3 id="程序设计"><a href="#程序设计" class="headerlink" title="程序设计"></a>程序设计</h3><h4 id="中断函数提高速度"><a href="#中断函数提高速度" class="headerlink" title="中断函数提高速度"></a>中断函数提高速度</h4><p>中断函数中一定不能写延时,中断函数的速度也需要尽可能提高。如果出现了中断重叠,可能会产生意料之外的错误。例如部分外设频繁死机之类,不容易检查的。</p><h4 id="外设错误调用"><a href="#外设错误调用" class="headerlink" title="外设错误调用"></a>外设错误调用</h4><p>STM32中外设的使用需要提前配置。不仅如此,如果外设配置了某一种调用模式,而你却采用了另一种模式调用,也会出现严重问题,比如,卡死<code>HardFault</code>。举个例子,如果你外设没有配置DMA,或者配置DMA之后使用了阻塞模式,那么,当你下一次尝试使用DMA模式时,会进入<code>HardFault</code>。</p><h3 id="接线错误"><a href="#接线错误" class="headerlink" title="接线错误"></a>接线错误</h3><h4 id="“target-dll-canceled”"><a href="#“target-dll-canceled”" class="headerlink" title="“target dll canceled”"></a>“target dll canceled”</h4><p>通常来说,STM32的调试SWD位于PA13,PA14。由于PCB绘制过程中,出现了与USART1接口相邻的情况,接线同学在接线时,误将串口线接在了PA14上。所以,无法进行任何烧写动作了。任何操作都会显示无法连接。</p><p>重新将串口线接在USART1的接线柱上,问题得到解决。</p><h3 id="异常现象"><a href="#异常现象" class="headerlink" title="异常现象"></a>异常现象</h3><h4 id="未知重启"><a href="#未知重启" class="headerlink" title="未知重启"></a>未知重启</h4><p>2021年10月1日的一次调试中,STM32芯片出现了多次的异常重启。经过分析,一共有两种原因,二者交替触发,造成问题难以定位。这两种原因分别是内存泄漏单片机挂起重启,和电压不稳芯片重启。</p><p>正常情况下,内存泄漏应该进入HardFault中断中阻塞全部程序。但本次实验中,STM32在遍历了全部内存空间后,产生了某种异常,形成了软件重启。表现为调试串口信号从起始位置重新开始。</p><p>在之后的实验中,出现了杜邦线端口松动,电压断供的情况。表现为调试串口信号乱码,且代码从头开始执行。</p><p>本人根据调试串口信号的复位信息得到了上述两种复位方式。在修复了相应漏洞后,程序恢复正常,</p><h4 id="晶振不起振"><a href="#晶振不起振" class="headerlink" title="晶振不起振"></a>晶振不起振</h4><p>目前遇到的晶振无法起振问题,主要有三种原因。</p><p>第一种原因是多次拆焊造成晶振内部结构受损。第二种原因是QFN封装造成的焊盘未连接。第三种原因是气温问题,造成芯片HSI和HSE偏差过大,芯片自检不通过无法起振,或者晶振无法起振。</p><h3 id="芯片不正常使用"><a href="#芯片不正常使用" class="headerlink" title="芯片不正常使用"></a>芯片不正常使用</h3><h4 id="LDO篇"><a href="#LDO篇" class="headerlink" title="LDO篇"></a>LDO篇</h4><p>通常在使用LDO的时候,会用到一颗进行<code>5V->3.3V</code>的芯片。而在调试的时候,通常会使用3.3V供电,这样MCU通电工作,而其他芯片可以保持较低的水平。但是有的时候会忘记这一点,从而调试时发现其他芯片不能正常工作。比如轨降较大的运放,就会出现直接饱和的现象。</p><h4 id="运放篇"><a href="#运放篇" class="headerlink" title="运放篇"></a>运放篇</h4><p>通常买的的便宜运放都不是轨到轨的。在<a href="#LDO篇">LDO篇</a>中提到了,调试供电情况下,5V获得的反相电压通常只有2.5V,那么放到运放上,饱和电压就只有1.3V了。这显然会产生很大的测量误差。应当铭记这一点。</p><h2 id="官方出现的问题"><a href="#官方出现的问题" class="headerlink" title="官方出现的问题"></a>官方出现的问题</h2><h3 id="STM32CubeMX已知问题"><a href="#STM32CubeMX已知问题" class="headerlink" title="STM32CubeMX已知问题"></a>STM32CubeMX已知问题</h3><p>CubeMX生成的HAL库文件出现的问题,多半是顺序问题。</p><p>这里推荐今后使用<code>assert</code>,方便排查ST自己的问题。因为我已经多次被ST坑到。</p><h4 id="I2C异常现象"><a href="#I2C异常现象" class="headerlink" title="I2C异常现象"></a>I2C异常现象</h4><p>代码</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c">__HAL_RCC_I2C2_CLK_ENABLE();<br></code></pre></td></tr></table></figure><p>需要在<code>I2C</code>初始化之前完成。而生成的代码中,该函数通常在函数末尾。这就会造成初始化失败,无法通信。</p><h4 id="DMA初始化失败"><a href="#DMA初始化失败" class="headerlink" title="DMA初始化失败"></a>DMA初始化失败</h4><p>代码</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><code class="hljs c">MX_DMA_Init();<br></code></pre></td></tr></table></figure><p>必须在调用DMA的外设初始化之前完成。而CubeMX的初始化顺序和<code>CubeMX配置顺序</code>有关,而不是<code>逻辑顺序</code>或者<code>依赖关系</code>。在这一点上,早在20年便有人指出这样的错误。直到今天(2022年3月13日)ST依然没有改正这个错误。</p>]]></content>
<categories>
<category>经验分享</category>
</categories>
<tags>
<tag>经验分享</tag>
<tag>编程</tag>
</tags>
</entry>
<entry>
<title>如何理解FOC和SVPWM技术</title>
<link href="/2021/07/19/FOCSVPWM/"/>
<url>/2021/07/19/FOCSVPWM/</url>
<content type="html"><![CDATA[<p>期末考试结束,RoboGame的各种任务又接踵而至。 在电机的驱动方面,我发现野火的驱动方法不是简单的PWM。 这时,我才学习到,无刷直流电机的控制方法并不是一件简单的事情。</p><span id="more"></span><p>接下来,本人将简单梳理FOC和SVPWM的基础内容。 本文是在互联网学习资源上的个人总结,仅供学习参考和备忘。有疑问处可以查找更加详细的资料。</p><h2 id="基础知识"><a href="#基础知识" class="headerlink" title="基础知识"></a>基础知识</h2><h3 id="FOC-简介"><a href="#FOC-简介" class="headerlink" title="FOC 简介"></a>FOC 简介</h3><p>FOC,Field Oriented Control,是目前无刷直流电机(BLDC)和永磁同步电机(PMSM)高效 控制的最优方法之一。 FOC旨在通过精确地控制磁场大小与方向,使得电机的运动转矩平稳、噪声小、效率高,并且具有高速的动态响应。</p><p>FOC具有如下优势:</p><ul><li>低转速下控制<br>由于控制原理的区别,无刷电调只能控制电机工作在高转速下,低速下无法控制;而FOC控制器则完全没有这个限制,不论在什么转速下都可以实现精确控制。</li><li>电机换向<br>同上面的理由,由于电调无法反馈转子位置,因此很难实现电机正反转的换向(当然有感电调可以实现);而FOC驱动器的换向性能极其优秀,最高转速下正反转切换可以非常顺畅;此外FOC还可以以能量回收的形式进行刹车控制。</li><li>力矩控制<br>普通电调都只能控制电机转速,而FOC可以进行电流(力矩)、速度、位置三个闭环控制。</li><li>噪音<br>FOC驱动器的噪音会比电调小很多,原因是普通电调采用方波驱动,而FOC是正弦波。</li></ul><h3 id="三相星形联结无刷电机"><a href="#三相星形联结无刷电机" class="headerlink" title="三相星形联结无刷电机"></a>三相星形联结无刷电机</h3><p>三相星形联结无刷电机中,三相的连接方式是,<strong>每一相引出导线的一头,而另一头和其他相两两相连</strong>。</p><p><a href="https://imgtu.com/i/W8TODx"><img src="https://z3.ax1x.com/2021/07/19/W8TODx.md.png" alt="W8TODx.md.png"></a></p><p>对其中两极施加电压,通过右手螺旋定则和磁感应强度的合成,可以判断线圈磁极的方向。 在这种情况下,转子会倾向于转动到力矩最小的角度,这时转子将会与磁极连线平行, 且磁铁<strong>内部磁力线</strong>方向和磁极间磁力线方向一致。</p><p><a href="https://imgtu.com/i/W87Mxs"><img src="https://z3.ax1x.com/2021/07/19/W87Mxs.png" alt="W87Mxs.png"></a></p><p>因此,无刷电机是通过电子转向来驱动转子不停地转动,换向的频率决定了电机的转速。</p><h3 id="BLDC和PMSM"><a href="#BLDC和PMSM" class="headerlink" title="BLDC和PMSM"></a>BLDC和PMSM</h3><p>无刷电机其实可以分为<strong>无刷直流电机</strong>(BLDC)和<strong>永磁同步电机</strong>(PMSM),结构大同小异,主要区别在于制造方式(线圈绕组方式)不同导致的一些特性差异(比如反电动势的波形)。</p><p>BLDC是从硬件出发,采用方波驱动,增加了电机槽和极对数,降低了转子转动的“颗粒感”,达到了平滑驱动的目的。</p><p>PMSM是从软件出发,抛弃了方波,而是使用<strong>正弦波</strong>来完成驱动的平滑化。自然在产生良好特性的正弦波、旋转磁场的同时,会大大<br>增加驱动器、控制算法的复杂程度。好在野火有例程(</p><h3 id="驱动电路"><a href="#驱动电路" class="headerlink" title="驱动电路"></a>驱动电路</h3><p>无刷电机的驱动电力主要使用<strong>三相逆变电路</strong>实现。</p><p><a href="https://imgtu.com/i/W8HSe0"><img src="https://z3.ax1x.com/2021/07/19/W8HSe0.md.png" alt="W8HSe0.md.png"></a></p><p>逆变电路是指,将<strong>直流电</strong>变换为<strong>交流电</strong>的电路。 逆变电路的具体实现通常是<strong>半路MOS电路</strong>,原型很简单, 由两个MOS管组成<strong>上桥臂</strong>和<strong>下桥臂</strong>,中间引出输出线即可。</p><p><a href="https://imgtu.com/i/W8Hmex"><img src="https://z3.ax1x.com/2021/07/19/W8Hmex.md.png" alt="W8Hmex.md.png"></a></p><p>用3个半桥电路就可以组合成三相逆变电路,每个半桥引出的一根输出线跟无刷电机的一根相线相连,就完成了最基本的无刷驱动电路。</p><p>值得注意的是,原作者在这里提醒到,半桥上下同时导通,则电源短路;同时关闭,则产生了力矩浪费。所以通常半桥工作时,上下两桥臂有且仅有一个导通。</p><h3 id="三相电机波形"><a href="#三相电机波形" class="headerlink" title="三相电机波形"></a>三相电机波形</h3><p>手动转动无刷电机的转子,利用示波器观察它的三相输出电压,可以得到三根正弦曲线,两两相位差为$120^{\text{o}}$。</p><p><a href="https://imgtu.com/i/W8HyXn"><img src="https://z3.ax1x.com/2021/07/19/W8HyXn.md.png" alt="W8HyXn.md.png"></a></p><p>相反地,在三相无刷电机的三相线圈上输入这样的三相正弦电压,就可以驱动无刷电机平稳旋转。</p><p>于此,可以提出FOC主要驱动手段,即<strong>计算所需电压矢量,利用SVPWM技术产生调试信号,驱动三相逆变电路,合成等效的三相正弦电压驱动电机</strong>。</p><h2 id="FOC控制原理"><a href="#FOC控制原理" class="headerlink" title="FOC控制原理"></a>FOC控制原理</h2><p>一个基本的FOC控制流程如下所示。</p><p><a href="https://imgtu.com/i/W8biHP"><img src="https://z3.ax1x.com/2021/07/19/W8biHP.md.png" alt="W8biHP.md.png"></a></p><!-- 这里的MathJax把我害惨了!!!!! --><p>该流程的作用是,利用输入的$I_q $_$ref$和$I_d $_$ ref$,使电机始终产生一个恒定的力矩。</p><p>控制流程为</p><ol><li>对电机三相电流进行采样得到$I_a, I_b, I_c$。</li><li>将$I_a, I_b, I_c$经过 <code>Clark变换</code>得到$I_{\alpha}, I_{\beta}$。</li><li>将$I_{\alpha}, I_{\beta}$经过<code>Park变换</code>得到$I_q, I_d$。</li><li>计算$I_q, I_d$和其设定值$I_q$_$ref$ $I_d $_$ ref$的误差。</li><li>将误差输入PID控制器,得到输出的控制电压$U_q, U_d$。</li><li>将$U_q, U_d$进行 <code>反Park变换</code> 得到$U_{\alpha}, U_{\beta}$。</li><li>用$U_{\alpha}, U_{\beta}$合成电压空间矢量,输入<code>SVPWM模块</code>进行调制,输出此时刻三个半桥的状态编码值。</li><li>按照状态编码值控制三相逆变器的MOS开关,驱动电机。</li><li>循环以上步骤。</li></ol><h3 id="Clark变换"><a href="#Clark变换" class="headerlink" title="Clark变换"></a>Clark变换</h3><p>首先需要对电机的三个相电流进行采用。</p><p>根据基尔霍夫定律(KCL),在任一时刻,流入节点的电流之和等于流出节点的电流之和,也就是说</p><script type="math/tex; mode=display"> I_a + I_b + I_c = 0</script><p>因此,三相电流事实上只需要两相即可确定。</p><p>三相坐标系$(I_a, I_b, I_c)$如下。</p><p><a href="https://imgtu.com/i/W8LElQ"><img src="https://z3.ax1x.com/2021/07/19/W8LElQ.png" alt="W8LElQ.png"></a></p><p>利用线性代数中的基变换,我们将三相电流转换为直角坐标系下的参量。令新的直角坐标系为$\alpha - \beta$坐标系。</p><script type="math/tex; mode=display"> \begin{cases} I_\alpha = I_a - \cos (\frac{\pi}{3})I_b - \cos (\frac{2\pi}{3})I_c \\ I_\beta = \sin (\frac{\pi}{3})I_b - \sin(\frac{\pi}{3})I_c \end{cases}</script><p>或表示为矩阵形式</p><script type="math/tex; mode=display"> \begin{pmatrix} I_\alpha \\ I_\beta \\ \end{pmatrix} = \begin{pmatrix} 1 & -\frac{1}{2} & -\frac{1}{2} \\ 0 & \frac{\sqrt{3}}{2} & -\frac{\sqrt{3}}{2} \end{pmatrix} \begin{pmatrix} I_a \\ I_b \\ I_c \end{pmatrix}</script><p>便可以减少一维变量。</p><p><img src="https://pic1.zhimg.com/80/v2-ddb74b212baee03b36eecb32ec54e420_720w.jpg" alt="pic"></p><h3 id="Park变换"><a href="#Park变换" class="headerlink" title="Park变换"></a>Park变换</h3><p>Park变换可以将$I_{\alpha}, I_{\beta}$ 转换为线性的。工作原理依然是线性代数原理,即将$\alpha - \beta$坐标系旋转$\theta$角度,其中$\theta$是转子当前的角度。</p><p><img src="https://pic4.zhimg.com/80/v2-d15d057327992a5c50016aea5bb7201b_720w.jpg" alt="pic"></p><p>变换公式如下</p><script type="math/tex; mode=display"> \begin{cases} I_d = I_\alpha \cos (\theta) + I_\beta \sin(\theta) \\ I_q = -I_\alpha \sin(\theta) + I_\beta \cos(\theta) \end{cases}</script><p>或者为矩阵形式</p><script type="math/tex; mode=display"> \begin{pmatrix} I_d \\ I_q \end{pmatrix} = \begin{pmatrix} \cos \theta & \sin \theta \\ -\sin \theta & \cos \theta \end{pmatrix} \begin{pmatrix} I_\alpha \\ I_\beta \end{pmatrix}</script><p>其中$\theta$的获取,需要编码器实时输入转子的实时旋转角度。经过Park变换,一个匀速旋转的向量被转化成了一个定值,两个控制变量也被线性化了。</p><p><img src="https://pic1.zhimg.com/80/v2-d6116ce165ec51df51469ad6ddd4d134_720w.jpg" alt="pic"></p><p>接下里以$I_q, I_d$两个值作为反馈控制的对象,可以用一些线性控制器来进行控制。工业界偏爱PID(</p><h3 id="PID-控制"><a href="#PID-控制" class="headerlink" title="PID 控制"></a>PID 控制</h3><p>FOC控制中主要使用三个PID环,分别是电流环、速度环和位置环。</p><p>具体流程为<strong>通过电流反馈控制电机电流(扭矩)</strong> -> <strong>通过控制扭矩来控制电机的转速</strong> -> <strong>通过控制电机ed转速控制电机位置</strong>。</p><h4 id="电流控制环"><a href="#电流控制环" class="headerlink" title="电流控制环"></a>电流控制环</h4><p>电流环具有如下控制框图。</p><p><img src="https://pic4.zhimg.com/80/v2-92e0d6eaa15bff745a4cd024362f53eb_720w.jpg" alt="pic"></p><p>其中的$I_q, I_d$的物理意义如下。</p><ul><li>$I_d$ 为转子旋转的切向变量,是期望的力矩输出。</li><li>$I_q$ 为转子旋转的径向变量,是不期望的力矩输出,期望值为0</li></ul><p><a href="https://imgtu.com/i/WGGiNj"><img src="https://z3.ax1x.com/2021/07/19/WGGiNj.jpg" alt="WGGiNj.jpg"></a></p><p>事实上,<code>Clark变换</code> 和 <code>Park变换</code>将转子磁链解耦成了转子旋转的<strong>径向</strong>和<strong>切向</strong>两个方向的变量。</p><p>我们希望通过PID控制器,利用上述输入(电流采样,编码器反馈)和输出(MOS管开关状态)完成对电机电流的闭环控制。</p><h4 id="速度控制环"><a href="#速度控制环" class="headerlink" title="速度控制环"></a>速度控制环</h4><p>在电流环的外部嵌套速度环,即可获得速度-电流双环控制。</p><p><a href="https://imgtu.com/i/WGG5Ps"><img src="https://z3.ax1x.com/2021/07/19/WGG5Ps.md.png" alt="WGG5Ps.md.png"></a></p><p>$Speed_{ref}$ 是速度设定值,$\omega$是电机的转速反馈,可以通过电机编码器或者霍尔传感器计算得到。<br>将电机速度$\omega$和速度设定值$Speed_{ref}$进行误差值计算,带入速度环PI,计算的结果作为电流环的输入,就实现了速度-电流的双闭环控制。</p><h4 id="位置控制环"><a href="#位置控制环" class="headerlink" title="位置控制环"></a>位置控制环</h4><p>在电流环外部嵌套位置环,即可获得位置-电流双环控制。</p><p><a href="https://imgtu.com/i/WGYl11"><img src="https://z3.ax1x.com/2021/07/19/WGYl11.md.png" alt="WGYl11.md.png"></a></p><p>由于不存在速度环,这里位置环使用了完整的PID控制。具体原因是,位置的微分是速度,德阳可以减小位置控制的震荡,加快收敛;积分项可以消除静态误差。</p><h3 id="空间电压矢量和SVPWM"><a href="#空间电压矢量和SVPWM" class="headerlink" title="空间电压矢量和SVPWM"></a>空间电压矢量和SVPWM</h3><h4 id="空间电压矢量"><a href="#空间电压矢量" class="headerlink" title="空间电压矢量"></a>空间电压矢量</h4><p>SVPWM的目的,是使用三相桥的开关状态把在空间中旋转的矢量表示出来,这个矢量被称为<strong>空间电压矢量</strong>。</p><p>对于三项桥的任意一种状态,利用数学工具,我们可以计算出三项桥产生的电压矢量$\vec{U}$具有特定的幅值,即相电压峰值$U_{dc}$。这个电压矢量应当具有$\omega=2\pi f$的角速度,才能满足旋转的需要。</p><p>使用数学公式</p><script type="math/tex; mode=display"> \begin{cases} U_A(t) = U_{dc}\cos(2\pi f t) \\ U_B(t) = U_{dc}\cos(2\pi ft - \frac{2\pi}{3}) \\ U_C(t) = U_{dc}\cos(2\pi ft + \frac{2\pi}{3}) \end{cases}</script><!-- 两个inline math 的\$ 连在一起,挂掉了我的vscode 的\$\$解析 --><p>定义开关函数$S_x(x\in a, b, c)$。</p><script type="math/tex; mode=display"> S_x = \begin{cases} 1, & \text{上桥臂导通} \\ 0, & \text{下桥臂导通} \end{cases}</script><p>$(S_a, S_b, S_c)$的全部可能组合共有8中,其中有6个非零矢量</p><script type="math/tex; mode=display"> U_1(001),U_2(010),U_3(011),U_4(100),U_5(101),U_6(110)</script><p>和两个零矢量</p><script type="math/tex; mode=display"> U_0(000), U_7(111)</script><p>可以绘制出各矢量的图像。</p><p><a href="https://imgtu.com/i/WGdnzj"><img src="https://z3.ax1x.com/2021/07/19/WGdnzj.md.png" alt="WGdnzj.md.png"></a></p><h4 id="SVPWM技术"><a href="#SVPWM技术" class="headerlink" title="SVPWM技术"></a>SVPWM技术</h4><p>利用这6个空间电压矢量作为基向量,可以合成任意矢量。在每一个扇区,选取相邻的两个电压矢量以及零矢量,按照<strong>伏秒平衡原则</strong>来合成每个扇区内的任意电压矢量,即:</p><script type="math/tex; mode=display"> \int^T_0 U_{ref}\text{d}t = \int^{T_x}_0 U_x\text{d}t + \int^{T_x + T_y}_{T_x} U_y\text{d}t + \int^{T}_{T_x+T_y} U_0^{*}\text{d}t</script><p>离散化获得公式</p><script type="math/tex; mode=display">U_{ref}\cdot T = U_x \cdot T_x + U_y \cdot T_y + U_0^{*} \cdot T_0^{*}</script><p>其中$U_{ref}$是我们期望的电压矢量,T是一个PWM周期。</p><p>$U_x, U_y$的选取,应当是$U_{ref}$所在扇区的两侧。</p><p>$U_0^{*}$指的是两个零矢量,可以是$U_0$或者$U_7$,零矢量的选择比较灵活,通过合理地配置零向量可以让空间电压矢量的切换更平缓。</p><p>因此,只需要周期性的切换不同空间电压矢量,合理配置不同基向量在一个周期中的占空比,就可以合成出等效的任意空间电压矢量。</p><h4 id="七段式SVPWM调制法"><a href="#七段式SVPWM调制法" class="headerlink" title="七段式SVPWM调制法"></a>七段式SVPWM调制法</h4><p>七段式SVPWM是指,合理安排SVPWM中的各空间矢量的占空位置,使得MOS管的开关次数最小,最大限度地减少开关损耗的一种调制思路。</p><p>依照$U_{ref}$的所在扇区,可以计算得到如下开关切换顺序</p><div class="table-container"><table><thead><tr><th>$U_{ref}$ 所在扇区</th><th>开关切换顺序</th></tr></thead><tbody><tr><td>Ⅰ区</td><td>$…0-4-6-7-7-6-4-0…$</td></tr><tr><td>Ⅱ区</td><td>$…0-2-6-7-7-6-2-0…$</td></tr><tr><td>Ⅲ区</td><td>$…0-2-3-7-7-3-2-0…$</td></tr><tr><td>Ⅳ区</td><td>$…0-1-3-7-7-3-1-0…$</td></tr><tr><td>Ⅴ区</td><td>$…0-1-5-7-7-5-1-0…$</td></tr><tr><td>Ⅵ区</td><td>$…0-4-5-7-7-5-4-0…$</td></tr></tbody></table></div><p>至此,SVPWM的任务完成,只需要在处理器中赋值给对应通道的捕获比较寄存器产生相应的三个PWM波形,控制MOS管的开关,进而产生期望的电压、电流和力矩。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>“矢量控制”事实上是一种<strong>解耦合</strong>,把相互耦合的三相磁链解耦为容易控制的两轴$I_q$和$I_d$,计算得到响应结果后,再将控制信号耦合传回电机。</p>]]></content>
<categories>
<category>算法</category>
</categories>
<tags>
<tag>算法</tag>
</tags>
</entry>
<entry>
<title>利用uVision5建立STM32F10x标准库工程</title>
<link href="/2021/05/27/STM32SPL/"/>
<url>/2021/05/27/STM32SPL/</url>
<content type="html"><![CDATA[<p>电子设计实践大作业开始在即,即使力学考试就在眼前,我仍然花费一段时间来调试这样的程序。<br>何等的敬业精神。<br>在使用uVision建立新工程的时候,我发现过程相对繁琐且缺乏条理。于是便整理过程如下。<br><span id="more"></span></p><p>本文依然无图(笑</p><h2 id="下载STM32F10x-标准库"><a href="#下载STM32F10x-标准库" class="headerlink" title="下载STM32F10x 标准库"></a>下载STM32F10x 标准库</h2><p>进入链接<a href="https://www.st.com/en/embedded-software/stsw-stm32054.html">https://www.st.com/en/embedded-software/stsw-stm32054.html</a><br>下载即可。</p><h2 id="新建工程"><a href="#新建工程" class="headerlink" title="新建工程"></a>新建工程</h2><p>打开uVision5, 进入<code>Project</code> -> <code>New uVision Project</code>,<br>选择工程文件目录,选择使用的芯片型号即可。</p><h2 id="拷贝库文件"><a href="#拷贝库文件" class="headerlink" title="拷贝库文件"></a>拷贝库文件</h2><p>在工程文件目录附近新建几个文件夹,如下</p><div class="code-wrapper"><pre><code class="hljs">DocLibraries CMSIS STM32F10x_StdPeriph_DriverListingOutputProject MDK xxx.uvprojxUser</code></pre></div><p>其中<code>CMSIS</code> <code>STM...</code>是下载好的标准库文件中的同名目录,<code>xxx.uvprojx</code>是你刚刚新建的工程文件。</p><p>然后将标准库文件中的示例<code>Template</code>中的文件<code>stm32f10x_conf.h stm32f10x_it.c stm32f10x_it.h</code>文件复制到<code>User</code>目录下。<br>如果<code>stm32f10x_it.c</code>中有<code>#include "main.h"</code>,删去。如果Systick中断函数中有内容,全部注释掉即可。</p><h2 id="将文件添加到工程"><a href="#将文件添加到工程" class="headerlink" title="将文件添加到工程"></a>将文件添加到工程</h2><p>打开uVision5, 选中魔术棒右边的一个按钮,添加分组<code>Startup CMSIS STM32F10x_StdPeriph_Driver User DOc</code>。</p><p>然后,分别点击<code>Add Files</code>,将对应的所有可以找到的.c文件添加到相关分组。</p><p>注意,<code>Startup</code>分组中添加的是<code>startup_stm32f10x_hd.s</code>一个汇编文件。其位于<code>arm</code>目录下,<br>因为我们使用的是MDK的编译器,自然选择arm。</p><h2 id="Option中设计工程"><a href="#Option中设计工程" class="headerlink" title="Option中设计工程"></a>Option中设计工程</h2><p>点开魔术棒,进行如下设置:</p><p><code>Target</code>栏目中,设置芯片默认主频为<code>8MHz</code>,这里没有计入倍频。使用armcc5的编译器,在<code>Code Generation</code>中设置。</p><p><code>Output</code>栏目中,选择目录为先前创建的<code>Output</code>目录。勾选<code>Create HEX File</code>便于以后的使用。<code>Listing</code>栏目同理。</p><p><code>C/C++</code>栏目中,<code>Define</code>填入<code>USE_STDPERIPH_DRIVER</code>,不需要填入芯片型号,因为Keil为你自动添加过了,再次添加会无法编译通过。<br>这是不同于网上教程的一点。</p><p>接着,在<code>Include Paths</code>中填入所有你看到的含有.h文件的目录。</p><p><code>Debug</code>栏目右上角,选择你使用的仿真器。</p><p><code>Utilities</code>中选择<code>Use Debug Driver</code>,进入<code>Settings</code>,在<code>Flash Download</code>栏目中,检查Flash大小是不是与芯片实际大小一致。左翻进入<code>Debug</code>栏目,<code>Port</code>选择<code>SW</code>方式,<code>Clock</code>调整下载速度为1MHz。<br>然后确认退出即可。</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>这个时候就可以加载LED测试代码检查是否配置完好了。</p><p>配置过程中心思想就是,uVision对你的代码结构一无所知,对你的芯片需求一无所知。<br>你需要做的就是,在Group中告诉它你是如何组织代码的,告诉它代码放在哪里。<br>在Include Paths中告诉它你的头文件放在哪里。<br>在魔术棒菜单中,告诉它你的芯片是如何工作的。</p><p>仅此而已的工作。</p>]]></content>
<categories>
<category>嵌入式</category>
</categories>
<tags>
<tag>嵌入式</tag>
</tags>
</entry>
<entry>
<title>利用Hexo&GitPages建立自己的博客</title>
<link href="/2021/05/22/HexoGitpages/"/>
<url>/2021/05/22/HexoGitpages/</url>
<content type="html"><![CDATA[<p>Hexo是一款基于Node.js的静态博客框架,依赖少易于安装使用,可以方便的生成静态网页托管在GitHub和Heroku上,是搭建博客的首选框架。</p><span id="more"></span><p>一般而言,建立自己的博客之后,我们会赋予它一个独特的域名。仅仅拥有<code>xxx.github.io</code>的域名,不足以满足大多数人的野心。</p><p>在这个不想学习的夜晚,我来整理一下我构建网站的过程,一来记录我的第一次前端(抄作业)项目,二来放松身心,三来给其他同学提供参考。</p><h2 id="任务"><a href="#任务" class="headerlink" title="任务"></a>任务</h2><ul><li>获得个人域名</li><li>GitHub创建个人仓库</li><li>安装Node.js,Hexo,git</li><li>推送网站</li><li>绑定域名</li><li>发布文章</li><li>寻找图床</li></ul><h2 id="行动"><a href="#行动" class="headerlink" title="行动"></a>行动</h2><h3 id="获得个人域名"><a href="#获得个人域名" class="headerlink" title="获得个人域名"></a>获得个人域名</h3><p>为了避免实名认证的费时费力,我选择了<a href="https://www.namesilo.com">NameSilo</a>网站,花了一美元获得了这个域名。事实上,<code>.xyz</code>域名相对价格很低,如果不是很在意的话,可以使用。</p><p>在选择域名时,有几个要点需要注意:</p><ul><li>填写Primary Address时要勾选<code>Keep my information private</code>,这样可以让保护隐私变为默认选项</li><li>除了邮箱,其他的没有必要填真实信息。手机填成真实的也无所谓。</li><li>购买域名时,注意选择<code>WHOIS Privacy</code>,让NameSilo替你成为注册人,防止真实信息暴露公网。</li><li>DNS解析时,可以填写五条解析规则。四条<code>A type</code>的规则指向GitPages的四个IPv4地址,参考<a href="https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-an-apex-domain">GitPages 官方手册</a>;另一条规则<code>CNAME type</code>指向你的GitHub库,具体问题之后详述。</li></ul><h3 id="GitHub创建个人仓库"><a href="#GitHub创建个人仓库" class="headerlink" title="GitHub创建个人仓库"></a>GitHub创建个人仓库</h3><p>这一步相当简单。只需要在GitHub创建一个<code>用户名.github.io</code>的Repo。</p><p>顺带一提,这样做还可以顺便发现一个Special Repository,自己尝试(:</p><h3 id="安装Node-js-Hexo-git"><a href="#安装Node-js-Hexo-git" class="headerlink" title="安装Node.js, Hexo, git"></a>安装Node.js, Hexo, git</h3><p>安装是一件相当愉快的事情。<br>先安装Git,一路next即可。<br>再安装Node.js,也是一路快乐。<br>最后打开terminal,输入</p><div class="code-wrapper"><pre><code class="hljs">node -vnpm -v</code></pre></div><p>检查是否正确安装Node.js。之后输入</p><div class="code-wrapper"><pre><code class="hljs">npm install -g hexo-cli</code></pre></div><p>让它自动安装Hexo即可。</p><p>然后我们需要设置一下Git的ssh密钥,便于我们文章的发布。</p><p>打开安装好的Git Bash, 输入</p><div class="code-wrapper"><pre><code class="hljs">git config --global user.name "你的GitHub用户名"git config --global user.email "你的GitHub注册邮箱"ssh-keygen -t rsa -C "你的GitHub注册邮箱"</code></pre></div><p> 一路回车键,找到自己电脑上的User\你的Windows用户名\.ssh\id_rsa和id_rsa.pub两个文件。把后一个文件里的全部内容复制,粘贴到GitHub个人页面右上角下拉框->Settings->SSH and GPG keys-> SSH Keys -> New SSH keys这个界面中,添加即可。</p><p> 这里应该有图片的,我之后再传吧。</p><p> 回到Git Bash,输入</p><div class="code-wrapper"><pre><code class="hljs"> ssh git@github.com</code></pre></div><p>多输几次,不报错了就好了。(玄学X</p><h3 id="推送网站"><a href="#推送网站" class="headerlink" title="推送网站"></a>推送网站</h3><p>随便打开一个你想要放置博客的目录,打开terminal,定位到此处,输入</p><div class="code-wrapper"><pre><code class="hljs">hexo init</code></pre></div><p>hexo就会在该目录下创建博客的基本内容。网络不好就挂代理,我反正下了几遍才下好。</p><p>继续输入</p><div class="code-wrapper"><pre><code class="hljs">hexo new testhexo generatehexo server</code></pre></div><p>打开浏览器进入网址localhost:4000,即可看到你的博客——最原始的样子。</p><p>这是本地预览,怎么放到网上呢?GitPages就是一个好的部署地点!</p><p>在设置之前,需要解释一个概念,在blog根目录里的_config.yml文件称为<strong>站点配置文件</strong>,进入根目录里的themes文件夹,里面也有个_config.yml文件,这个称为<strong>主题配置文件</strong>。</p><p>打开前一个站点配置文件,找到deploy这个单词,填充如下内容:</p><div class="code-wrapper"><pre><code class="hljs">deploy: type: git repo: git@github.com/GitHub用户名/GitHub用户名.github.io.git branch: main</code></pre></div><p>注意repo使用git@才能ssh登录,改成https的话,每次deploy都需要输入密码。<br>再注意branch 要使用main,因为GitHub整顿后,将新Repo的默认分支从<code>master</code> 改成了<code>main</code>。</p><p>回到项目根目录,打开terminal,输入</p><div class="code-wrapper"><pre><code class="hljs">npm install hexo-deployer-git --save</code></pre></div><p>和</p><div class="code-wrapper"><pre><code class="hljs">hexo cleanhexo ghexo d</code></pre></div><p>网络足够好的情况下,可以在网址<code>GitHub用户名.github.io</code>上看到你的博客了。</p><h3 id="绑定域名"><a href="#绑定域名" class="headerlink" title="绑定域名"></a>绑定域名</h3><p>打开你的GitHub,在博客Repo的Settings里面,找到左侧Pages,点进去,右边找到Custom domain,填入你先前注册的域名,再勾选下面的Enforce HTTPS,就搞定了。</p><p>这时候可以回到第一步,把 <code>GitHub用户名.github.io</code>填入先前DNS解析的步骤。Host name填入www, 这样也可以解析www.开头的你的域名。</p><p>我觉得需要图片,到时候再说。</p><p>假说你博客的根目录是/,现进入/source目录,理论上应该有一个<code>_posts</code>文件夹。在它的旁边创建名为<code>CNAME</code>的文件,输入<strong>不带www</strong>的你的域名。</p><p>这时候打开浏览器在地址栏输入你的个性化域名将会直接进入你自己搭建的网站。如果没有,就deploy几次(莽撞</p><p>不需要改动_config.yml里面的内容。</p><h3 id="发布文章"><a href="#发布文章" class="headerlink" title="发布文章"></a>发布文章</h3><p>在terminal里使用</p><div class="code-wrapper"><pre><code class="hljs">hexo new 文章名</code></pre></div><p>即可创建一篇文章,位于/source/_posts/目录下的一个.md文件。</p><p>用markdown语法写文章即可。</p><p>发布?<br>在terminal里使用</p><div class="code-wrapper"><pre><code class="hljs">hexo cleanhexo generatehexo deploy</code></pre></div><p>即可发布到你的GitHub Repo上,从而在你的域名上可见。</p><p>建议是先用<code>hexo server</code>在本地预览,给GitHub送去一点善意。</p><p>如果发现发布后主页没有变化,可以尝试重新<code>hexo clean</code>再deploy一次。熟悉这样的节奏就好。</p><h3 id="寻找图床"><a href="#寻找图床" class="headerlink" title="寻找图床"></a>寻找图床</h3><p>图床自己找。我用的是<a href="https://imgtu.com">路过图床</a>,虽然有广告,但是它免费(:</p><h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>虽然本文较为简略,且全程没有图片配备。但是通过参考资料的补充,读者依然可以得到相应的知识来建立自己的博客。</p><!-- 这就是颓废大学生摸鱼的方式吗?! --><!-- 更多资料自己寻找(: --><h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><p><a href="https://zhuanlan.zhihu.com/p/26625249">吴润-知乎</a></p><p><a href="https://qwerty200696.github.io/2017/09/08/blog_setup/">wangwlj’s Blog</a></p><p><a href="https://hexo.io/zh-cn/docs/">Hexo 官方文档</a></p><p><a href="https://hexo.fluid-dev.com/docs/guide/">Fluid 配置文档</a></p>]]></content>
<categories>
<category>博客</category>
</categories>
<tags>
<tag>博客</tag>
<tag>学习</tag>
</tags>
</entry>
</search>