-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgen_ft_figures.py
More file actions
623 lines (583 loc) · 30.9 KB
/
Copy pathgen_ft_figures.py
File metadata and controls
623 lines (583 loc) · 30.9 KB
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
import matplotlib.pyplot as plt
import numpy as np
import os
out = '/Users/hesiqi/Desktop/note/note/images'
plt.rcParams.update({'font.family': 'serif', 'font.size': 10, 'axes.titlesize': 11,
'figure.dpi': 140, 'savefig.dpi': 140, 'savefig.bbox': 'tight'})
def save_td_fd(fig, name):
fig.savefig(os.path.join(out, name))
plt.close(fig)
# ========== 1. δ(t) <-> 1 ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
ax1.annotate('', xy=(0, 1), xytext=(0, 0), arrowprops=dict(arrowstyle='->', color='b', lw=2.5))
ax1.text(0.3, 0.55, '1', fontsize=12, color='b')
ax1.set_title(r'$f(t)=\delta(t)$', fontsize=11)
ax1.set_xlim(-3, 3); ax1.set_ylim(-0.2, 1.5)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
ax2.axhline(1, color='r', lw=2)
ax2.set_title(r'$F(j\omega)=1$', fontsize=11)
ax2.set_xlim(-3, 3); ax2.set_ylim(-0.2, 1.8)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_01.png')
# ========== 2. u(t) <-> πδ(ω) + 1/jω ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
t = np.linspace(-3, 3, 1000)
ax1.plot(t, np.heaviside(t, 1), 'b', lw=2)
ax1.set_title(r'$f(t)=u(t)$', fontsize=11)
ax1.set_xlim(-3, 3); ax1.set_ylim(-0.2, 1.5)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
w = np.linspace(0.15, 4, 500)
ax2.annotate('', xy=(0, 1), xytext=(0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.text(0.3, 0.55, r'$\pi$', fontsize=11, color='r')
ax2.plot(w, 1/np.abs(w), 'r', lw=2, label=r'$1/|\omega|$')
ax2.plot(-w, 1/np.abs(-w), 'r', lw=2)
ax2.set_title(r'$|F(j\omega)| = \pi\delta(\omega) + 1/|\omega|$', fontsize=10)
ax2.set_ylabel(r'$|F(j\omega)|$')
ax2.set_xlim(-4, 4); ax2.set_ylim(-0.3, 5)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$'); ax2.legend(fontsize=7)
fig.tight_layout(); save_td_fd(fig, 'xh_ft_02.png')
# ========== 3. sgn(t) <-> 2/jω ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
t = np.linspace(-3, 3, 1000)
ax1.plot(t[t<0], -np.ones_like(t[t<0]), 'b', lw=2)
ax1.plot(t[t>0], np.ones_like(t[t>0]), 'b', lw=2)
ax1.plot([0,0], [-1,1], 'b', lw=2)
ax1.set_title(r'$f(t)=\mathrm{sgn}(t)$', fontsize=11)
ax1.set_xlim(-3, 3); ax1.set_ylim(-1.5, 1.5)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
w = np.linspace(0.15, 4, 500)
ax2.plot(w, 2/w, 'r', lw=2)
ax2.plot(-w, 2/np.abs(-w), 'r', lw=2)
ax2.set_title(r'$|F(j\omega)| = 2/|\omega|$', fontsize=11)
ax2.set_ylabel(r'$|F(j\omega)|$')
ax2.set_xlim(-4, 4); ax2.set_ylim(-0.5, 14)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_03.png')
# ========== 4. 1 <-> 2πδ(ω) ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
ax1.axhline(1, color='b', lw=2)
ax1.set_title(r'$f(t)=1$', fontsize=11)
ax1.set_xlim(-3, 3); ax1.set_ylim(-0.2, 1.8)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
ax2.annotate('', xy=(0, 1), xytext=(0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.text(0.4, 0.55, r'$2\pi$', fontsize=11, color='r')
ax2.set_title(r'$F(j\omega)=2\pi\delta(\omega)$', fontsize=11)
ax2.set_xlim(-3, 3); ax2.set_ylim(-0.2, 2.2)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_04.png')
# ========== 5. e^{-αt}u(t) <-> 1/(α+jω) ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
alpha = 1.0; t = np.linspace(-0.5, 5, 1000); f = np.exp(-alpha*t) * np.heaviside(t, 1)
ax1.plot(t, f, 'b', lw=2)
ax1.set_title(r'$f(t)=e^{-\alpha t}u(t)\ (\alpha=1)$', fontsize=11)
ax1.set_xlim(-0.5, 5); ax1.set_ylim(-0.1, 1.2)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
w = np.linspace(-8, 8, 1000)
mag = 1/np.sqrt(alpha**2 + w**2)
ax2.plot(w, mag, 'r', lw=2, label=r'$|F|$')
ax2.set_title(r'$|F(j\omega)| = 1/\sqrt{\alpha^2+\omega^2}$', fontsize=11)
ax2.set_xlim(-8, 8); ax2.set_ylim(-0.1, 1.2)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$'); ax2.legend(fontsize=8)
fig.tight_layout(); save_td_fd(fig, 'xh_ft_05.png')
# ========== 6. e^{-α|t|} <-> 2α/(α²+ω²) ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
alpha = 1.0; t = np.linspace(-4, 4, 1000); f = np.exp(-alpha*np.abs(t))
ax1.plot(t, f, 'b', lw=2)
ax1.set_title(r'$f(t)=e^{-\alpha|t|}\ (\alpha=1)$', fontsize=11)
ax1.set_xlim(-4, 4); ax1.set_ylim(-0.1, 1.2)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
w = np.linspace(-5, 5, 1000); F = 2*alpha/(alpha**2 + w**2)
ax2.plot(w, F, 'r', lw=2)
ax2.set_title(r'$|F(j\omega)| = 2\alpha/(\alpha^2+\omega^2)$', fontsize=11)
ax2.set_xlim(-5, 5); ax2.set_ylim(-0.2, 2.2)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_06.png')
# ========== 7. t e^{-αt} u(t) <-> 1/(α+jω)² ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
alpha = 1.0; t = np.linspace(-0.5, 8, 1000); f = t*np.exp(-alpha*t)*np.heaviside(t,1)
ax1.plot(t, f, 'b', lw=2)
ax1.set_title(r'$f(t)=t e^{-\alpha t}u(t)\ (\alpha=1)$', fontsize=11)
ax1.set_xlim(-0.5, 8); ax1.set_ylim(-0.05, 0.45)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
w = np.linspace(-8, 8, 1000); mag = 1/(alpha**2 + w**2)
ax2.plot(w, mag, 'r', lw=2)
ax2.set_title(r'$|F(j\omega)| = 1/(\alpha^2+\omega^2)$', fontsize=11)
ax2.set_xlim(-8, 8); ax2.set_ylim(-0.05, 1.2)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_07.png')
# ========== 8. cos ω₀t <-> π[δ(ω+ω₀)+δ(ω-ω₀)] ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
w0 = 2; t = np.linspace(-np.pi, np.pi, 1000)
ax1.plot(t, np.cos(w0*t), 'b', lw=2)
ax1.set_title(r'$f(t)=\cos\omega_0 t\ (\omega_0=2)$', fontsize=11)
ax1.set_xlim(-np.pi, np.pi); ax1.set_ylim(-1.5, 1.5)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
ax2.annotate('', xy=(-w0, 0.8), xytext=(-w0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.annotate('', xy=(w0, 0.8), xytext=(w0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.text(-w0+0.2, 0.55, r'$\pi$', fontsize=10, color='r')
ax2.text(w0+0.2, 0.55, r'$\pi$', fontsize=10, color='r')
ax2.set_title(r'$F=\pi[\delta(\omega+\omega_0)+\delta(\omega-\omega_0)]$', fontsize=11)
ax2.set_xlim(-5, 5); ax2.set_ylim(-0.2, 1.2)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_08.png')
# ========== 9. sin ω₀t <-> jπ[δ(ω+ω₀)-δ(ω-ω₀)] ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
ax1.plot(t, np.sin(w0*t), 'b', lw=2)
ax1.set_title(r'$f(t)=\sin\omega_0 t\ (\omega_0=2)$', fontsize=11)
ax1.set_xlim(-np.pi, np.pi); ax1.set_ylim(-1.5, 1.5)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
# |F| = πδ(ω+ω₀) + πδ(ω-ω₀) — same magnitude as cos!
ax2.annotate('', xy=(-w0, 0.8), xytext=(-w0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.annotate('', xy=(w0, 0.8), xytext=(w0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.text(-w0+0.2, 0.55, r'$\pi$', fontsize=10, color='r')
ax2.text(w0+0.2, 0.55, r'$\pi$', fontsize=10, color='r')
ax2.set_title(r'$|F(j\omega)| = \pi\delta(\omega+\omega_0) + \pi\delta(\omega-\omega_0)$', fontsize=10)
ax2.set_ylabel(r'$|F(j\omega)|$')
ax2.set_xlim(-5, 5); ax2.set_ylim(-0.2, 1.2)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_09.png')
# ========== 10. e^{-αt} sin ω₀t u(t) <-> ω₀/((α+jω)²+ω₀²) ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
alpha=0.5; w0=3; t=np.linspace(0, 10, 1000); f=np.exp(-alpha*t)*np.sin(w0*t)
ax1.plot(t, f, 'b', lw=1.5)
ax1.set_title(r'$f(t)=e^{-\alpha t}\sin\omega_0 t\ u(t)$', fontsize=11)
ax1.set_xlim(0, 10); ax1.set_ylim(-0.8, 0.8)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
w=np.linspace(-8, 8, 1000); mag=w0/np.sqrt((alpha**2+w0**2-w**2)**2 + 4*alpha**2*w**2)
ax2.plot(w, mag, 'r', lw=2)
ax2.set_title(r'$|F(j\omega)|$ (bandpass)', fontsize=10)
ax2.set_xlim(-8, 8); ax2.set_ylim(-0.05, 1.3)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_10.png')
# ========== 11. sin ω₀t u(t) <-> ... ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
w0=2; t=np.linspace(0, 4*np.pi, 1000); f=np.sin(w0*t)
ax1.plot(t, f, 'b', lw=1.5)
ax1.set_title(r'$f(t)=\sin\omega_0 t\ u(t)$', fontsize=11)
ax1.set_xlim(0, 4*np.pi); ax1.set_ylim(-1.2, 1.2)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
w=np.linspace(-8, 8, 2000)
mask = (np.abs(w - w0) > 0.1) & (np.abs(w + w0) > 0.1)
ax2.annotate('', xy=(-w0, 0.8), xytext=(-w0, 0), arrowprops=dict(arrowstyle='->', color='b', lw=2.5))
ax2.annotate('', xy=(w0, 0.8), xytext=(w0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.text(-w0+0.2, 0.55, r'$\pi/2$', fontsize=9, color='b')
ax2.text(w0+0.2, 0.55, r'$\pi/2$', fontsize=9, color='r')
w_sub = w[(w>-5)&mask[:len(w)]]
mag = np.abs(w0/(w0**2 - w[w>-5]**2))
ax2.plot(w[w>-5], mag, 'r', lw=1.5, alpha=0.7, label=r'$|\omega_0/(\omega_0^2-\omega^2)|$')
ax2.set_title(r'$|F(j\omega)|$ (deltas at $\pm\omega_0$)', fontsize=10)
ax2.set_ylabel(r'$|F(j\omega)|$')
ax2.set_xlim(-5, 5); ax2.set_ylim(-0.2, 4)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$'); ax2.legend(fontsize=7)
fig.tight_layout(); save_td_fd(fig, 'xh_ft_11.png')
# ========== 12. cos ω₀t u(t) <-> ... ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
t=np.linspace(0, 4*np.pi, 1000); f=np.cos(w0*t)
ax1.plot(t, f, 'b', lw=1.5)
ax1.set_title(r'$f(t)=\cos\omega_0 t\ u(t)$', fontsize=11)
ax1.set_xlim(0, 4*np.pi); ax1.set_ylim(-1.2, 1.2)
ax1.axhline(0, color='gray', lw=0.5); ax1.grid(True, alpha=0.2)
ax1.set_xlabel('$t$')
w=np.linspace(-8, 8, 2000)
ax2.annotate('', xy=(-w0, 0.8), xytext=(-w0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.annotate('', xy=(w0, 0.8), xytext=(w0, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2.5))
ax2.text(-w0+0.2, 0.55, r'$\pi/2$', fontsize=9, color='r')
ax2.text(w0+0.2, 0.55, r'$\pi/2$', fontsize=9, color='r')
mag = np.abs(w[w>-5]/(w0**2 - w[w>-5]**2))
ax2.plot(w[w>-5], mag, 'r', lw=1.5, alpha=0.7, label=r'$|\omega/(\omega_0^2-\omega^2)|$')
ax2.set_title(r'$|F(j\omega)|$ (deltas at $\pm\omega_0$)', fontsize=10)
ax2.set_ylabel(r'$|F(j\omega)|$')
ax2.set_xlim(-5, 5); ax2.set_ylim(-0.2, 4)
ax2.axhline(0, color='gray', lw=0.5); ax2.grid(True, alpha=0.2)
ax2.set_xlabel(r'$\omega$'); ax2.legend(fontsize=7)
fig.tight_layout(); save_td_fd(fig, 'xh_ft_12.png')
# ========== 13. Gate <-> τ Sa ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
tau=2; t=np.linspace(-4,4,1000); f=np.heaviside(t+tau/2,1)-np.heaviside(t-tau/2,1)
ax1.plot(t, f, 'b', lw=2); ax1.fill_between(t, f, alpha=0.1, color='b')
ax1.set_title(r'$G_\tau(t)=u(t+\tau/2)-u(t-\tau/2)$', fontsize=10)
ax1.set_xlim(-3,3); ax1.set_ylim(-0.2,1.5)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.2); ax1.set_xlabel('$t$')
w=np.linspace(-12,12,3000); F=tau*np.sinc(w*tau/2/np.pi)
ax2.plot(w, np.abs(F), 'r', lw=2)
ax2.set_title(r'$|F(j\omega)| = \tau|\mathrm{Sa}(\omega\tau/2)|$', fontsize=11)
ax2.set_ylabel(r'$|F(j\omega)|$')
ax2.set_xlim(-12,12); ax2.set_ylim(-0.2,2.2)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.2); ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_13.png')
# ========== 14. Sa <-> Gate (dual of 13) ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
Omega=4; t=np.linspace(-8,8,2000); f=np.sinc(Omega*t/2/np.pi)
ax1.plot(t, f, 'b', lw=1.5)
ax1.set_title(r'$f(t)=\mathrm{Sa}(\Omega t/2)$', fontsize=11)
ax1.set_xlim(-8,8); ax1.set_ylim(-0.4,1.2)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.2); ax1.set_xlabel('$t$')
w=np.linspace(-5,5,1000); F=(2*np.pi/Omega)*(np.heaviside(w+Omega/2,1)-np.heaviside(w-Omega/2,1))
ax2.plot(w, F, 'r', lw=2); ax2.fill_between(w, F, alpha=0.1, color='r')
ax2.set_title(r'$|F(j\omega)| = \frac{2\pi}{\Omega}\ \mathrm{rect}$', fontsize=10)
ax2.set_xlim(-5,5); ax2.set_ylim(-0.2,4)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.2); ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_14.png')
# ========== 15. Raised cosine pulse ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
T=2; t=np.linspace(-2,2,1000); f=(1+np.cos(2*np.pi*t/T))*(np.heaviside(t+T/2,1)-np.heaviside(t-T/2,1))
ax1.plot(t, f, 'b', lw=2); ax1.fill_between(t, f, alpha=0.1, color='b')
ax1.set_title(r'$f(t)=[1+\cos(2\pi t/T)]\,G_T(t)$', fontsize=10)
ax1.set_xlim(-2,2); ax1.set_ylim(-0.2,2.3)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.2); ax1.set_xlabel('$t$')
w=np.linspace(-15,15,3000); F=np.where(np.abs(w)<1e-9, T, 8*np.pi**2*np.sin(T*w/2)/(w*(4*np.pi**2-T**2*w**2)))
ax2.plot(w, np.abs(F), 'r', lw=1.5)
ax2.set_title(r'$|F(j\omega)|$', fontsize=10)
ax2.set_ylabel(r'$|F(j\omega)|$')
ax2.set_xlim(-15,15); ax2.set_ylim(-0.2,2.5)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.2); ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_15.png')
# ========== 16. Half-cosine pulse ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
tau=2; t=np.linspace(-2,2,1000); f=np.cos(np.pi*t/tau)*(np.heaviside(t+tau/2,1)-np.heaviside(t-tau/2,1))
ax1.plot(t, f, 'b', lw=2); ax1.fill_between(t, f, alpha=0.1, color='b')
ax1.set_title(r'$f(t)=\cos(\pi t/\tau)\,G_\tau(t)$', fontsize=10)
ax1.set_xlim(-2,2); ax1.set_ylim(-0.2,1.3)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.2); ax1.set_xlabel('$t$')
w=np.linspace(-12,12,3000); denom=1-tau**2*w**2/np.pi**2; F=np.where(np.abs(denom)>1e-6, 2*tau/np.pi*np.cos(tau*w/2)/denom, 0)
ax2.plot(w, np.abs(F), 'r', lw=1.5)
ax2.set_title(r'$|F(j\omega)|$', fontsize=10)
ax2.set_ylabel(r'$|F(j\omega)|$')
ax2.set_xlim(-12,12); ax2.set_ylim(-0.2,1.5)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.2); ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_16.png')
# ========== 17. Triangle <-> τ Sa² ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
tau=3; t=np.linspace(-5,5,1000); f=np.maximum(1-np.abs(t)/tau, 0)
ax1.plot(t, f, 'b', lw=2); ax1.fill_between(t, f, alpha=0.1, color='b')
ax1.set_title(r'$f(t)=1-|t|/\tau\ (\tau=3)$', fontsize=11)
ax1.set_xlim(-5,5); ax1.set_ylim(-0.1,1.2)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.2); ax1.set_xlabel('$t$')
w=np.linspace(-8,8,2000); F=tau*(np.sinc(w*tau/2/np.pi))**2
ax2.plot(w, F, 'r', lw=2)
ax2.set_title(r'$|F(j\omega)| = \tau[\mathrm{Sa}(\omega\tau/2)]^2$', fontsize=11)
ax2.set_xlim(-8,8); ax2.set_ylim(-0.2,3.2)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.2); ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_17.png')
# ========== 18. Gaussian <-> Gaussian ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
tau=1; t=np.linspace(-4,4,1000); f=np.exp(-(t/tau)**2)
ax1.plot(t, f, 'b', lw=2)
ax1.set_title(r'$f(t)=e^{-(t/\tau)^2}\ (\tau=1)$', fontsize=11)
ax1.set_xlim(-4,4); ax1.set_ylim(-0.1,1.2)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.2); ax1.set_xlabel('$t$')
w=np.linspace(-4,4,1000); F=np.sqrt(np.pi)*tau*np.exp(-(tau*w/2)**2)
ax2.plot(w, F, 'r', lw=2)
ax2.set_title(r'$|F(j\omega)| = \sqrt{\pi}\tau e^{-(\tau\omega/2)^2}$', fontsize=11)
ax2.set_xlim(-4,4); ax2.set_ylim(-0.1,2)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.2); ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_18.png')
# ========== 19. Impulse train <-> Impulse train ==========
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(7, 2.5))
T=2; Omega=2*np.pi/T
t=np.linspace(-6,6,1000)
for n in range(-3,4):
ax1.annotate('', xy=(n*T, 1), xytext=(n*T, 0), arrowprops=dict(arrowstyle='->', color='b', lw=2))
ax1.set_title(r'$\delta_T(t)=\sum_n\delta(t-nT)\ (T=2)$', fontsize=10)
ax1.set_xlim(-6,6); ax1.set_ylim(-0.2,1.5)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.2); ax1.set_xlabel('$t$')
for n in range(-3,4):
ax2.annotate('', xy=(n*Omega, 1), xytext=(n*Omega, 0), arrowprops=dict(arrowstyle='->', color='r', lw=2))
ax2.set_title(r'$\Omega\delta_\Omega(\omega)=\Omega\sum_n\delta(\omega-n\Omega)$', fontsize=10)
ax2.set_xlim(-10,10); ax2.set_ylim(-0.2,1.5)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.2); ax2.set_xlabel(r'$\omega$')
fig.tight_layout(); save_td_fd(fig, 'xh_ft_19.png')
# ============================================================
# Example figures for section 3.6
# ============================================================
# --- Ex1: Two gate functions ---
fig, ax = plt.subplots(figsize=(8, 3))
tau=1; t=np.linspace(-2.5, 2.5, 1000)
f1=np.heaviside(t+tau/2,1)-np.heaviside(t-tau/2,1)
f2=np.heaviside(t+tau,1)-np.heaviside(t-tau,1)
f=f1+f2
ax.plot(t, f, 'b', lw=2)
ax.fill_between(t, f, alpha=0.15, color='b')
ax.set_title(r'Ex1: $f(t)=G_\tau(t)+G_{2\tau}(t)$ ($\tau=1$)', fontsize=12)
ax.set_xlabel('$t$'); ax.set_xlim(-2.5, 2.5); ax.set_ylim(-0.2, 2.5)
ax.axhline(0,color='gray',lw=0.5); ax.grid(True,alpha=0.3)
# annotate
ax.annotate(r'$G_\tau$', xy=(-0.5,1.1), fontsize=10, ha='center')
ax.annotate(r'$G_{2\tau}$', xy=(0.5,2.1), fontsize=10, ha='center')
fig.tight_layout(); fig.savefig(os.path.join(out, 'xh_ex1.png')); plt.close(fig)
# --- Ex2: Three-pulse signal ---
fig, ax = plt.subplots(figsize=(8, 3))
tau=0.8; T=2; t=np.linspace(-4.5, 4.5, 2000)
f0=lambda x: np.heaviside(x+tau/2,1)-np.heaviside(x-tau/2,1)
f=f0(t)+f0(t+T)+f0(t-T)
ax.plot(t, f, 'b', lw=2)
for x0 in [0, T, -T]:
ax.fill_between(t, f0(t-x0), alpha=0.15, color='b')
ax.axvline(x0, color='red', linestyle='--', lw=0.6, alpha=0.5)
ax.set_title(r'Ex2: $f(t)=f_0(t)+f_0(t+T)+f_0(t-T)$ ($T=2,\tau=0.8$)', fontsize=12)
ax.set_xlabel('$t$'); ax.set_xlim(-4.5, 4.5); ax.set_ylim(-0.2, 1.5)
ax.axhline(0,color='gray',lw=0.5); ax.grid(True,alpha=0.3)
fig.tight_layout(); fig.savefig(os.path.join(out, 'xh_ex2.png')); plt.close(fig)
# --- Ex5: f(t) = -u(-t) + u(t-1) ---
fig, ax = plt.subplots(figsize=(8, 3))
t=np.linspace(-3, 4, 1000); f=-np.heaviside(-t,1)+np.heaviside(t-1,1)
ax.plot(t, f, 'b', lw=2)
ax.set_title(r'Ex5: $f(t)=-u(-t)+u(t-1)$', fontsize=12)
ax.set_xlabel('$t$'); ax.set_xlim(-3, 4); ax.set_ylim(-1.5, 1.5)
ax.axhline(0,color='gray',lw=0.5); ax.axvline(0,color='gray',lw=0.5)
ax.axvline(1,color='red',linestyle='--',lw=0.6,alpha=0.5)
ax.grid(True,alpha=0.3)
fig.tight_layout(); fig.savefig(os.path.join(out, 'xh_ex5.png')); plt.close(fig)
# --- Ex6: Cosine pulse (gate × cos ω₀t) ---
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3.5))
tau=3; w0=4; t=np.linspace(-2.5, 2.5, 1000)
gate=np.heaviside(t+tau/2,1)-np.heaviside(t-tau/2,1)
f=gate*np.cos(w0*t)
ax1.plot(t, f, 'b', lw=1.8); ax1.fill_between(t, f, alpha=0.1, color='b')
ax1.plot(t, gate, 'gray', lw=0.8, linestyle='--', alpha=0.5, label='gate envelope')
ax1.plot(t, -gate, 'gray', lw=0.8, linestyle='--', alpha=0.5)
ax1.set_title(r'Ex6: $f(t)=\cos\omega_0 t\cdot G_\tau(t)$', fontsize=11)
ax1.set_xlabel('$t$'); ax1.set_xlim(-2.5, 2.5); ax1.set_ylim(-1.3, 1.3)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.3); ax1.legend(fontsize=8)
w=np.linspace(-12, 12, 2000)
F=tau/2*(np.sinc((w-w0)*tau/2/np.pi)+np.sinc((w+w0)*tau/2/np.pi))
ax2.plot(w, F, 'r', lw=1.8)
ax2.set_title(r'Spectrum: shifted $\mathrm{Sa}$ functions', fontsize=11)
ax2.set_xlabel(r'$\omega$'); ax2.set_xlim(-12, 12)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.3)
ax2.axvline(w0,color='red',linestyle='--',lw=0.5,alpha=0.4)
ax2.axvline(-w0,color='red',linestyle='--',lw=0.5,alpha=0.4)
fig.tight_layout(); fig.savefig(os.path.join(out, 'xh_ex6.png')); plt.close(fig)
# --- Ex7: Two gates → triangle (convolution) ---
fig, axes = plt.subplots(1, 3, figsize=(13, 4))
tau=2; t=np.linspace(-3, 3, 1000)
g=np.heaviside(t+tau/2,1)-np.heaviside(t-tau/2,1)
axes[0].plot(t, g, 'b', lw=2); axes[0].fill_between(t, g, alpha=0.15, color='b')
axes[0].set_title(r'$g(t)$: gate', fontsize=11)
axes[0].set_xlabel('$t$'); axes[0].set_xlim(-3,3); axes[0].set_ylim(-0.2,1.5)
axes[0].axhline(0,color='gray',lw=0.5); axes[0].grid(True,alpha=0.3)
axes[1].plot(t, g, 'b', lw=2); axes[1].fill_between(t, g, alpha=0.15, color='b')
axes[1].set_title(r'$g(t)$: gate (same)', fontsize=11)
axes[1].set_xlabel('$t$'); axes[1].set_xlim(-3,3); axes[1].set_ylim(-0.2,1.5)
axes[1].axhline(0,color='gray',lw=0.5); axes[1].grid(True,alpha=0.3)
tri=np.maximum(1-np.abs(t)/(tau), 0)*tau # area = tau
axes[2].plot(t, tri, 'r', lw=2); axes[2].fill_between(t, tri, alpha=0.15, color='r')
axes[2].set_title(r'$g(t)*g(t)$: triangle', fontsize=11)
axes[2].set_xlabel('$t$'); axes[2].set_xlim(-3,3); axes[2].set_ylim(-0.2,2.5)
axes[2].axhline(0,color='gray',lw=0.5); axes[2].grid(True,alpha=0.3)
axes[0].text(-1.8, 1.8, r'$*$', fontsize=18, color='purple')
axes[1].text(-1.8, 1.8, r'$=$', fontsize=18, color='purple')
fig.suptitle('Ex7: Triangular pulse = convolution of two gates', fontsize=13, fontweight='bold')
fig.tight_layout()
fig.savefig(os.path.join(out, 'xh_ex7.png')); plt.close(fig)
# --- Ex8: Triangular AM wave ---
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(10, 3.5))
tau=3; w0=6; t=np.linspace(-2.5, 2.5, 1000)
tri_env=np.maximum(1-2*np.abs(t)/tau, 0)
f=tri_env*np.cos(w0*t)
ax1.plot(t, f, 'b', lw=1.5)
ax1.plot(t, tri_env, 'gray', lw=0.8, linestyle='--', alpha=0.6, label='envelope')
ax1.plot(t, -tri_env, 'gray', lw=0.8, linestyle='--', alpha=0.6)
ax1.set_title(r'Ex8: Triangular AM wave', fontsize=12)
ax1.set_xlabel('$t$'); ax1.set_xlim(-2.5, 2.5); ax1.set_ylim(-1.3, 1.3)
ax1.axhline(0,color='gray',lw=0.5); ax1.grid(True,alpha=0.3); ax1.legend(fontsize=8)
w=np.linspace(-15, 15, 3000)
F0=tau/2*(np.sinc(w*tau/4/np.pi))**2
F=tau/4*((np.sinc((w-w0)*tau/4/np.pi))**2+(np.sinc((w+w0)*tau/4/np.pi))**2)
ax2.plot(w, F, 'r', lw=1.8)
ax2.set_title(r'Spectrum: shifted $\mathrm{Sa}^2$ functions', fontsize=12)
ax2.set_xlabel(r'$\omega$'); ax2.set_xlim(-15, 15)
ax2.axhline(0,color='gray',lw=0.5); ax2.grid(True,alpha=0.3)
ax2.axvline(w0,color='red',linestyle='--',lw=0.5,alpha=0.4)
ax2.axvline(-w0,color='red',linestyle='--',lw=0.5,alpha=0.4)
fig.tight_layout(); fig.savefig(os.path.join(out, 'xh_ex8.png')); plt.close(fig)
print("Example figures saved.")
# ============================================================
# Chapter 4 figures
# ============================================================
# --- Ch4-1: Example 4-1 frequency response ---
fig, axes = plt.subplots(2, 2, figsize=(11, 7))
# |H(ω)| triangular
w = np.linspace(-3, 3, 1000)
Hmag = np.maximum(2 - np.abs(w), 0)
axes[0, 0].plot(w, Hmag, 'b', lw=2)
axes[0, 0].fill_between(w, Hmag, alpha=0.1, color='b')
axes[0, 0].set_title(r'$|H(j\omega)|$', fontsize=12)
axes[0, 0].set_xlabel(r'$\omega$'); axes[0, 0].set_ylabel(r'$|H|$')
axes[0, 0].set_xlim(-3, 3); axes[0, 0].set_ylim(-0.2, 2.5)
axes[0, 0].axhline(0, color='gray', lw=0.5); axes[0, 0].grid(True, alpha=0.3)
# φ(ω)
w = np.linspace(-2.5, 2.5, 1000)
phi = -np.pi/2 * w
axes[0, 1].plot(w, phi, 'r', lw=2)
axes[0, 1].set_title(r'$\varphi(\omega)=-\frac{\pi}{2}\omega$', fontsize=12)
axes[0, 1].set_xlabel(r'$\omega$'); axes[0, 1].set_ylabel(r'$\varphi(\omega)$')
axes[0, 1].set_xlim(-3, 3)
axes[0, 1].axhline(0, color='gray', lw=0.5); axes[0, 1].grid(True, alpha=0.3)
# Input e(t)
t = np.linspace(0, 4*np.pi, 1000)
e = 2 + 2*np.cos(t) + 2*np.cos(2*t)
axes[1, 0].plot(t, e, 'b', lw=1.5)
axes[1, 0].set_title(r'Input $e(t)=2+2\cos t+2\cos(2t)$', fontsize=11)
axes[1, 0].set_xlabel('$t$'); axes[1, 0].set_xlim(0, 4*np.pi); axes[1, 0].set_ylim(-3, 7)
axes[1, 0].axhline(0, color='gray', lw=0.5); axes[1, 0].grid(True, alpha=0.3)
# Output r(t)
r = 4 + 2*np.sin(t)
axes[1, 1].plot(t, r, 'r', lw=1.5)
axes[1, 1].set_title(r'Output $r(t)=4+2\sin t$', fontsize=11)
axes[1, 1].set_xlabel('$t$'); axes[1, 1].set_xlim(0, 4*np.pi); axes[1, 1].set_ylim(0, 7)
axes[1, 1].axhline(0, color='gray', lw=0.5); axes[1, 1].grid(True, alpha=0.3)
fig.suptitle('Example 4-1: Frequency Response & System Response', fontsize=13, fontweight='bold')
fig.tight_layout()
fig.savefig(os.path.join(out, 'xh_ch4_ex1.png')); plt.close(fig)
# --- Ch4-2: Ideal LPF frequency response + h(t) ---
fig, axes = plt.subplots(1, 3, figsize=(14, 4))
wc = 2; t0 = 1
# |H(ω)|
w = np.linspace(-5, 5, 1000)
Hmag = np.heaviside(w + wc, 1) - np.heaviside(w - wc, 1)
axes[0].plot(w, Hmag, 'b', lw=2); axes[0].fill_between(w, Hmag, alpha=0.1, color='b')
axes[0].set_title(r'$|H(j\omega)|$ (ideal LPF)', fontsize=11)
axes[0].set_xlabel(r'$\omega$'); axes[0].set_xlim(-5, 5); axes[0].set_ylim(-0.1, 1.3)
axes[0].axhline(0, color='gray', lw=0.5); axes[0].axvline(-wc, color='red', linestyle='--', lw=0.6)
axes[0].axvline(wc, color='red', linestyle='--', lw=0.6)
axes[0].text(wc+0.15, 1.1, r'$\omega_c$', fontsize=10, color='red')
axes[0].grid(True, alpha=0.3)
# φ(ω)
w_linear = np.linspace(-wc, wc, 500)
phi = -w_linear * t0
axes[1].plot(w_linear, phi, 'r', lw=2)
axes[1].set_title(r'$\varphi(\omega)=-\omega t_0$', fontsize=11)
axes[1].set_xlabel(r'$\omega$'); axes[1].set_xlim(-wc-0.5, wc+0.5)
axes[1].axhline(0, color='gray', lw=0.5); axes[1].grid(True, alpha=0.3)
# h(t)
t = np.linspace(-3, 5, 1000)
h = wc/np.pi * np.sinc(wc*(t - t0)/np.pi)
axes[2].plot(t, h, 'b', lw=1.5)
axes[2].axvline(t0, color='red', linestyle='--', lw=0.6)
axes[2].text(t0+0.1, h.max()*0.9, r'$t_0$', fontsize=10, color='red')
axes[2].set_title(r'$h(t)=\frac{\omega_c}{\pi}\mathrm{Sa}[\omega_c(t-t_0)]$', fontsize=11)
axes[2].set_xlabel('$t$'); axes[2].set_xlim(-3, 5)
axes[2].axhline(0, color='gray', lw=0.5); axes[2].grid(True, alpha=0.3)
fig.suptitle('Ideal Low-Pass Filter', fontsize=13, fontweight='bold')
fig.tight_layout()
fig.savefig(os.path.join(out, 'xh_ch4_ideal_lpf.png')); plt.close(fig)
# --- Ch4-3: Si(y) function ---
fig, ax = plt.subplots(figsize=(8, 4))
y = np.linspace(-15, 15, 2000)
# Si(y) via cumulative integral of sinc
from scipy import special
Si = special.sici(y)[0] if hasattr(special, 'sici') else np.cumsum(np.sinc(y/np.pi)) * (y[1]-y[0])
try:
Si = special.sici(y)[0]
except:
dy = y[1]-y[0]
Si = np.cumsum(np.sinc(y/np.pi)) * dy - np.pi/2 # rough approx
ax.plot(y, Si, 'b', lw=2)
ax.axhline(np.pi/2, color='red', linestyle='--', lw=0.8, alpha=0.5, label=r'$\pi/2$')
ax.axhline(-np.pi/2, color='red', linestyle='--', lw=0.8, alpha=0.5, label=r'$-\pi/2$')
ax.set_title(r'Sine integral: $\mathrm{Si}(y)=\int_0^y \frac{\sin x}{x}dx$', fontsize=13)
ax.set_xlabel('$y$'); ax.set_ylabel('$\mathrm{Si}(y)$')
ax.set_xlim(-15, 15); ax.set_ylim(-2, 2)
ax.axhline(0, color='gray', lw=0.5); ax.axvline(0, color='gray', lw=0.5)
ax.legend(fontsize=9); ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig(os.path.join(out, 'xh_ch4_Si.png')); plt.close(fig)
# --- Ch4-4: LPF step response ---
fig, ax = plt.subplots(figsize=(9, 4))
t0 = 1; wc_vals = [2, 4, 8]
t = np.linspace(-1, 4, 2000)
colors = ['blue', 'orange', 'green']
for wc, c in zip(wc_vals, colors):
x = wc * (t - t0)
Si = special.sici(x)[0]
ru = 0.5 + Si/np.pi
ax.plot(t, ru, color=c, lw=1.5, label=rf'$\omega_c={wc}$')
ax.axhline(0.5, color='gray', linestyle='--', lw=0.5, alpha=0.5)
ax.axvline(t0, color='red', linestyle='--', lw=0.6, alpha=0.5, label=r'$t_0=1$')
ax.set_title(r'LPF Step Response: $r_u(t)=\frac{1}{2}+\frac{1}{\pi}\mathrm{Si}[\omega_c(t-t_0)]$', fontsize=12)
ax.set_xlabel('$t$'); ax.set_xlim(-1, 4); ax.set_ylim(-0.1, 1.2)
ax.axhline(0, color='gray', lw=0.5)
ax.legend(fontsize=9); ax.grid(True, alpha=0.3)
fig.tight_layout()
fig.savefig(os.path.join(out, 'xh_ch4_step.png')); plt.close(fig)
# --- Ch4-5: AM-SC modulation & demodulation spectrum ---
fig, axes = plt.subplots(2, 2, figsize=(12, 7))
w = np.linspace(-8, 8, 2000)
# G(ω) - triangular baseband
G = np.maximum(1 - np.abs(w)/2, 0)
axes[0, 0].plot(w, G, 'b', lw=2); axes[0, 0].fill_between(w, G, alpha=0.1, color='b')
axes[0, 0].set_title(r'Baseband $G(\omega)$', fontsize=11)
axes[0, 0].set_xlabel(r'$\omega$'); axes[0, 0].set_xlim(-8, 8); axes[0, 0].set_ylim(-0.1, 1.3)
axes[0, 0].axhline(0, color='gray', lw=0.5); axes[0, 0].grid(True, alpha=0.3)
# F(ω) - modulated
w0 = 5; F = 0.5*(np.maximum(1-np.abs(w + w0)/2, 0) + np.maximum(1-np.abs(w - w0)/2, 0))
axes[0, 1].plot(w, F, 'r', lw=2); axes[0, 1].fill_between(w, F, alpha=0.1, color='r')
axes[0, 1].axvline(w0, color='gray', linestyle='--', lw=0.5); axes[0, 1].axvline(-w0, color='gray', linestyle='--', lw=0.5)
axes[0, 1].set_title(r'Modulated $F(\omega)=\frac{1}{2}[G(\omega+\omega_0)+G(\omega-\omega_0)]$', fontsize=10)
axes[0, 1].set_xlabel(r'$\omega$'); axes[0, 1].set_xlim(-8, 8); axes[0, 1].set_ylim(-0.1, 0.7)
axes[0, 1].axhline(0, color='gray', lw=0.5); axes[0, 1].grid(True, alpha=0.3)
# After 2nd multiplication
G0 = 0.5*G + 0.25*(np.maximum(1-np.abs(w+2*w0)/2,0) + np.maximum(1-np.abs(w-2*w0)/2,0))
axes[1, 0].plot(w, G0, 'purple', lw=2)
axes[1, 0].fill_between(w[np.abs(w)<3], G0[np.abs(w)<3], alpha=0.15, color='purple')
axes[1, 0].set_title(r'After $\times\cos\omega_0 t$ again + LPF', fontsize=11)
axes[1, 0].set_xlabel(r'$\omega$'); axes[1, 0].set_xlim(-8, 8); axes[1, 0].set_ylim(-0.1, 0.7)
axes[1, 0].axhline(0, color='gray', lw=0.5); axes[1, 0].grid(True, alpha=0.3)
# Recovered
axes[1, 1].plot(w, 0.5*G, 'b', lw=2); axes[1, 1].fill_between(w, 0.5*G, alpha=0.1, color='b')
axes[1, 1].set_title(r'Recovered $\frac{1}{2}G(\omega)$ (after LPF)', fontsize=11)
axes[1, 1].set_xlabel(r'$\omega$'); axes[1, 1].set_xlim(-8, 8); axes[1, 1].set_ylim(-0.1, 0.7)
axes[1, 1].axhline(0, color='gray', lw=0.5); axes[1, 1].grid(True, alpha=0.3)
fig.suptitle('AM-SC Modulation & Synchronous Demodulation', fontsize=13, fontweight='bold')
fig.tight_layout()
fig.savefig(os.path.join(out, 'xh_ch4_am.png')); plt.close(fig)
# --- Ch4-6: FDM concept ---
fig, ax = plt.subplots(figsize=(10, 4))
w = np.linspace(0, 15, 2000)
# Three channels at different carrier frequencies
ch1 = np.maximum(1 - np.abs(w - 2)/1.5, 0)
ch2 = np.maximum(1 - np.abs(w - 6)/1.5, 0)
ch3 = np.maximum(1 - np.abs(w - 11)/1.5, 0)
ax.plot(w, ch1, 'b', lw=1.5, label='Channel 1')
ax.plot(w, ch2, 'r', lw=1.5, label='Channel 2')
ax.plot(w, ch3, 'g', lw=1.5, label='Channel 3')
ax.fill_between(w, ch1, alpha=0.1, color='b')
ax.fill_between(w, ch2, alpha=0.1, color='r')
ax.fill_between(w, ch3, alpha=0.1, color='g')
# guard bands
for x in [3.5, 8.5]:
ax.axvline(x, color='gray', linestyle=':', lw=0.8, alpha=0.5)
ax.set_title('Frequency Division Multiplexing (FDM)', fontsize=13, fontweight='bold')
ax.set_xlabel(r'$\omega$'); ax.set_xlim(0, 15); ax.set_ylim(-0.1, 1.3)
ax.set_ylabel(''); ax.legend(fontsize=9)
ax.axhline(0, color='gray', lw=0.5); ax.grid(True, alpha=0.3)
ax.text(2, 1.15, r'$f_1$', ha='center', fontsize=10)
ax.text(6, 1.15, r'$f_2$', ha='center', fontsize=10)
ax.text(11, 1.15, r'$f_3$', ha='center', fontsize=10)
fig.tight_layout()
fig.savefig(os.path.join(out, 'xh_ch4_fdm.png')); plt.close(fig)
print("Chapter 4 figures saved.")
print("All 19 FT table figures saved.")