about summary refs log blame commit diff stats
path: root/js/games/nluqo.github.io/~bh/v2ch13/v2ch13.html
blob: 74ea2c4adcd0b4f6d95e75510b2c0f17ae4ffd0a (plain) (tree)
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
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853




















































































































































































































































































































































































































































































































































































































































































































































































































































































                                                                                                                                      
<HTML>
<HEAD>
<TITLE>Computer Science Logo Style vol 2 ch 13: Example: Fourier Series Plotter</TITLE>
</HEAD>
<BODY>
<CITE>Computer Science Logo Style</CITE> volume 2:
<CITE>Advanced Techniques</CITE> 2/e Copyright (C) 1997 MIT
<H1>Example: Fourier Series Plotter</H1>

<TABLE width="100%"><TR><TD>
<IMG SRC="../csls2.jpg" ALT="cover photo">
<TD><TABLE>
<TR><TD align="right"><CITE><A HREF="http://www.cs.berkeley.edu/~bh/">Brian
Harvey</A><BR>University of California, Berkeley</CITE>
<TR><TD align="right"><BR>
<TR><TD align="right"><A HREF="../pdf/v2ch13.pdf">Download PDF version</A>
<TR><TD align="right"><A HREF="../v2-toc2.html">Back to Table of Contents</A>
<TR><TD align="right"><A HREF="https://people.eecs.berkeley.edu/~bh/v2ch12/v2ch12.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../v2ch14/manual.html"><STRONG>NEXT</STRONG></A>
<TR><TD align="right"><A HREF="https://mitpress.mit.edu/books/computer-science-logo-style-second-edition-volume-2">MIT
Press web page for <CITE>Computer Science Logo Style</CITE></A>
</TABLE></TABLE>

<HR><P>Program file for this chapter: <A HREF="https://people.eecs.berkeley.edu/~bh/v2ch13/plot.lg"><CODE>plot</CODE></A>

<P>A particular musical note (middle C, say) played on a piano and played
on a violin sound similar in some ways and different in other ways.
Two different notes played on the violin also have similarities and
differences.  How do you hear which note is being played, and how
do you know what instrument you're listening to?

<P>To do justice to these questions would fill up an entire book.  For example,
a piano produces sound when a felt-covered wooden hammer hits metal wires,
or strings.  Each piano key controls one hammer, but each hammer may hit
from one to three strings.  It turns out that the strings for a particular
note are not tuned to exactly the same pitch.  Part of the richness of the
piano's sound comes from the interplay of slightly different pitches making
up the same note.

<P>Another contributing factor to the recognition of different instruments is
their differences in attack and decay.  Does the sound of a note start
abruptly, or gradually?  The differences are not only a matter of loudness,
though.  A few instruments start out each note with a very pure, simple tone
like a tuning fork.  Gradually, the tone becomes more complex until it
finally reaches the timbre you associate with the instrument.  But a bowed
violin, a more typical example, starts out each note almost as a burst of
pure noise, as the bow hits the strings, and gradually mellows into the
sound of a particular note.  If you are experimentally inclined, try tape
recording the same note as played by several instruments.  Then cut out the
beginnings and ends of the notes, and retain only the middle section.  Play
these to people and see how well they can identify the instruments, compared
to their ability to identify the complete recorded notes.

<P>

For this chapter, though, I'm going to ignore these complications, and
concentrate on the differences in the <EM>steady-state</EM> central part of a
note as played by a particular instrument.  What all such steady
musical sounds have in common is that they are largely <EM>
periodic</EM>.  This means that if you graph the air pressure produced by the
instrument over time (or the voltage when the sound is represented
electrically in a hifi system), the same pattern of high and low pressures
repeats again and again.  Here is an example.  In this picture, the motion
of your eye from left to right represents the passing of time.

<P><CENTER><IMG SRC="squig5.gif" ALT="figure: squig5"></CENTER>

<P>

The height of the squiggle on the page, at
any particular moment, represents the sound pressure at that moment.  So
what this picture shows is that there are many small up-and-down
oscillations superimposed on one large, regular up-and-down motion.  (This
one large oscillation is called the <EM>fundamental</EM> frequency.)  You can
see that the entire picture consists of five repetitions of a smaller
squiggle with just one of the large oscillations.

<P>From what I've said about oscillations, you might get the impression
that this is a picture of something like a foghorn or siren, in which
you can hear an alternation of loud and soft moments.  But this is
actually the picture of what sounds like a perfectly steady tone.
The entire width of the page represents about one one-hundredth of
a second.  There are a few hundred repetitions of the single large
up-and-down cycle in each second of a musical note.  The exact number
of repetitions is the <EM>frequency</EM> of the note,
and is the same for every instrument.  For example, the note A above
middle C has a pitch of 440 cycles per second, or 440 Hertz.

<P>All instruments playing A above middle C will have a picture with
the same fundamental frequency of 440 Hertz.  What is different from
one instrument to another is the exact shape of the squiggle.  (By
the way, the technical name for a squiggle is a <EM>waveform.</EM>  You
can see the waveform for a note by connecting a microphone to an oscilloscope,
a device that shows the waveform on a TV-like screen.)

<P>Here is a picture of the simplest, purest possible tone:

<P><CENTER><IMG SRC="sine5.gif" ALT="figure: sine5"></CENTER>

<P>This is the waveform you'd get from an ideal tuning fork,
with no impurities or bumps.  It is called a <EM>sine wave.</EM>  This
particular kind of oscillation turns up in many situations, not just musical
sounds.  For example, suppose you write a program that starts a turtle
moving in a circle forever.

<P><PRE>to circle
fd 1
rt 1
circle
end
</PRE>

<P>Think about the motion of the turtle, and concentrate only
on its vertical position on the screen.  Never mind its motion from
left to right.  The up-and-down part of the turtle's motion over time
looks just like this sine wave.

<P>This says more than simply that the turtle alternates moving up and
down.  For example, the turtle's vertical motion might have looked
like this over time:

<P><CENTER><IMG SRC="tri5.gif" ALT="figure: tri5"></CENTER>

<P>If
this were the picture of the turtle's motion, it would mean that
the turtle's vertical position climbed at a steady rate until it reached
the top of the circle, then abruptly turned around and started down
again.  But in fact what happens is that the height of the turtle
changes most quickly when the turtle is near the &quot;Equator&quot;
of its circle.  The turtle's vertical speed gets less and less as
the turtle gets near the &quot;poles.&quot;  This speed change corresponds
to the gradual flattening of the sine wave near the top and bottom.
(You may find it confusing when I say that the turtle's vertical motion
slows down, because the turtle's speed doesn't seem to change as it
draws.  But what happens is that near the Equator, the turtle's speed
is mostly vertical; near the poles, its speed is mostly horizontal.
We aren't thinking about the horizontal aspect of its motion right
now.)

<P><CENTER><IMG SRC="motion.gif" ALT="figure: motion"></CENTER>

<P>What makes sine waves most important, though, is that <EM>any</EM> periodic
waveform can be analyzed as the sum of a bunch of sine waves of different
frequencies.  (Sometimes an infinite number of since waves must be
added together.)  The frequencies of the sine waves will always be
multiples of the fundamental frequency.  This important mathematical
result was discovered by the French mathematician
Jean-Baptiste-Joseph Fourier (1768-1830).  The representation of
a mathematical function as a sum of sine waves is called a <EM>
Fourier series.</EM>

<P>For example, when a violin plays A above middle C, the waveform that
results will include a sine wave with frequency 440 Hertz, one with
frequency 880 Hertz, one at 1320 Hertz, and so on.  Not all of these
contribute equally to the complete waveform.  The <EM>amplitude</EM> of
each sine wave (the amount of swing, or the vertical distance in the
picture) will be different for each.  Typically, the fundamental frequency
has the largest amplitude, and the others (which are called <EM>
harmonics</EM> or <EM>overtones</EM>) have smaller amplitudes.  The
precise amplitudes of each harmonic are what determine the steady-state
timbre of a particular instrument.

<P><H2>Square Waves</H2>

<P>Two traditional musical instruments, the clarinet and the
pipe organ, share a curious characteristic: their Fourier series
contain only odd harmonics.  In other words, if a clarinet is
playing A above middle C, the waveform includes frequencies of 440 Hertz,
1320 Hertz (3 times 440), 2200 Hertz (5 times 440), and so on.  But the
waveform does not include frequencies of 880 Hertz (2 times 440), 1760 Hertz
(4 times 440), and so on.  (I'm oversimplifying a bit in the case of the
pipe organ.  What I've said about only odd harmonics is true about each
pipe, but the organ can be set up to combine several pipes in order to
include even harmonics of a note.)

<P>In recent times, a third musical instrument has come to share this
peculiar Fourier series: the computer.  (Perhaps you were wondering
where computers come into this.)  Today there are computer-controlled
musical instruments that can generate
any possible sound.  Musicians have even used computers to create
new instrument timbres that are not possible with ordinary instruments.
But the particular timbre that most people associate with
computer music is the one produced by the simplest possible
computer sound generator.  Instead of a steady oscillation in sound
pressure, this simple device can only be on or off at a given moment.  The
computer produces sound by flipping the device from on to off and back at a
particular rate.  Such a device produces a <EM>square wave</EM>, like
this:

<P><CENTER><IMG SRC="square5.gif" ALT="figure: square5"></CENTER>

<P>No sound that occurs in nature has a waveform that turns
corners so abruptly.  But what is &quot;natural&quot; in nature isn't necessarily
what's &quot;natural&quot; for a computer.  For many years, computer-generated
music invariably meant square waves except in very fancy music research
centers.

<P>More recently, new integrated circuit technology has made
it relatively inexpensive to equip computers with &quot;music chips&quot;
that generate sine waves.  The stereotyped sound of computer music
is becoming uncommon.  But I still find square waves fascinating
for several reasons.

<P>One place where square waves are still used is in the hifi magazines,
in their tests of amplifiers.  The testing laboratories feed a square
wave into an amplifier, and show oscilloscope pictures of the waveform
going into the amp and the waveform coming out.  Here is an example:

<P>
<CENTER><IMG SRC="scope.gif" ALT="figure: scope"></CENTER>


<P>The oscillation that is visible in the output near the corners of
the input is called <EM>ringing</EM>.  A lot of ringing indicates that
the amplifier doesn't have good high-frequency response.

<P>Here is why a square wave is a good test of high frequencies:  The
Fourier series corresponding to the square wave includes an infinite
number of odd-harmonic sine wave components.  In other words, a perfect
square wave includes infinitely high frequencies.  (In practice, the
input picture isn't a perfect square wave.  You can see that the vertical
segments aren't <EM>quite</EM> truly vertical, for example.)  No amplifier
can reproduce infinitely high frequencies faithfully.  The result
is that the output from the amplifier includes only some of the harmonics
that make up the input.  It turns out that such a <EM>partial series</EM>,
with relatively few of the harmonics included, produces a waveform
in which the ringing phenomenon at the corners is clearly visible.

<P>If you think about it, that's a bit unexpected.  Normally, the more
harmonics, the more complicated the waveform.  For example, the simplest
waveform is the one with only the fundamental, and no added harmonics.
Yet, <EM>removing</EM> harmonics from the square wave produces a <EM>
more</EM> complicated picture.  I like paradoxes like that.  I wanted
to write a computer program to help me understand this one.

<P>Before you can look into the square wave in detail, you have to know
not only the fact that it uses odd harmonics, but also the amplitude
of each harmonic.  A square wave with fundamental frequency <EM>f</EM>
has this formula: <P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v2ch13/math1.gif" ALT="math display"></CENTER>
<P>The dots at the end indicate that this series goes on forever.
The amplitude of each sine wave is the reciprocal of the harmonic
number (one divided by the number).

<P>This project draws pictures of waveforms containing some number of
terms of this series.  (Each sine wave is called a term.)  The program
allows many different ways of controlling exactly what is drawn.

<P>To start with something very simple, try this instruction:

<P><PRE>plot 1
</PRE>

<P>The effect of this command is to draw one cycle of a pure
sine wave:

<P><CENTER><IMG SRC="plot1.gif" ALT="figure: plot1"></CENTER>

<P>This
is the first term of the series for the square wave.  Now try
this:

<P><PRE>plot 5
</PRE>

<P><CENTER><IMG SRC="plot5.gif" ALT="figure: plot5"></CENTER>

<P>The
input to <CODE>plot</CODE> is the harmonic number of the highest harmonic.
In this example, we've drawn three sine waves added together: the
fundamental, third harmonic, and fifth harmonic.

<P>To see a plot looking somewhat more like the pictures in the amplifier
tests, try

<P><PRE>plot 23
</PRE>

<P><CENTER><IMG SRC="plot23.gif" ALT="figure: plot23"></CENTER>

<P>This
contains the first 12 odd harmonics.  (Remember to use an odd
number as input, if you want to see something that looks like a square
wave.)  You can see that the result still includes some oscillation
in the horizontal sections, but does have an overall square shape.

<P>A mediocre hifi amp has a frequency response that is good to about
20,000 Hertz.  This is about the 45th harmonic of 440 Hertz.  To see
how A above middle C would come out on such an amplifier, try

<P><PRE>plot 45
</PRE>

<P><CENTER><IMG SRC="plot45.gif" ALT="figure: plot45"></CENTER>

<P>There
is still some ringing near the corners, but the middle of the
horizontal segment is starting to look really flat.  A better amplifier
might be good to 30,000 Hertz.  To see how that would look, try

<P><PRE>plot 77
</PRE>

<P><CENTER><IMG SRC="plot77.gif" ALT="figure: plot77"></CENTER>

<P>(The
drawing of the picture takes longer when you use a larger input
to <CODE>plot</CODE>, because the program has to calculate more terms of the series.)

<P>So far, we have only changed one of the possible parameters controlling
the waveform, namely the highest harmonic.  The program allows you
to control several other elements of the picture.  For example, try
this:

<P><PRE>plot [maxharm 77 yscale 140 deltax 1]
</PRE>

<P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v2ch13/plot77big.gif" ALT="figure: plot77big"></CENTER>

<P><CODE>
Plot</CODE> takes one input, but this time the input is a list instead of
a single number.  The members of the list are used as sort of &quot;sub-inputs.&quot;
The odd-numbered members are the <EM>names</EM> of parameters,
for which the even-numbered members provide <EM>values.</EM>

<P><CODE>Maxharm</CODE> stands for &quot;maximum harmonic&quot;; it is the parameter you were
setting when you used a single number as the input.  <CODE>Yscale</CODE> is an
adjustment for the height of the plot.  (To &quot;scale&quot; a bunch of numbers
means to multiply all of them by some constant value, the &quot;scale factor.&quot;)
You may have noticed that as the
number of harmonics has increased, the pictures have been getting smaller in
the vertical direction; by increasing the value of <CODE>yscale</CODE> we can
expand the height of the plot to show more detail.  Similarly, <CODE>deltax</CODE>
allows us to show more horizontal detail, not by widening the picture but by
computing the value for every dot.  Ordinarily, the program saves time by
calculating every second dot.  This approximation is usually good enough,
but sometimes not.  (<CODE>Deltax</CODE> means &quot;change in X.&quot;  Delta is the
name of the Greek letter D (&Delta;), which mathematicians use to represent
a small change in something.)

<P>Here's another example:

<P><PRE>plot [11 cycles 5]
</PRE>

<P><CENTER><IMG SRC="plot11by5.gif" ALT="figure: plot11by5"></CENTER>

<P><CODE>Cycles</CODE> indicates
the number of complete cycles you want to see.  By saying <CODE>cycles 5</CODE>
in this example, I drew a picture like the ones near the beginning
of this chapter, with five repetitions of the fundamental oscillation.

<P>Notice also that we didn't have to say <CODE>maxharm</CODE>.  If a number
appears in the input list where a name should be, it's automatically assigned
to <CODE>maxharm</CODE>.

<P><CODE>Plot</CODE> allows you to specify any of six parameters.  Each parameter
has a <EM>default</EM> value, the value that is used if you don't say
anything about it.  For example, the default value for <CODE>deltax</CODE> is 2.
Here are all the parameters:

<P><TABLE>
<TR><TH>name<TH>default<TH>purpose
<TR><TD>maxharm<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;highest harmonic number included in series
<TR><TD>deltax<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;number of turtle steps skipped between calculations
<TR><TD>yscale<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;75<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;vertical motion is multiplied by this number
<TR><TD>cycles<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;number of cycles of fundamental shown
<TR><TD>xrange<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;230<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;highest X coordinate allowed
<TR><TD>skip<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2<TD>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;number of harmonics skipped between terms
</TABLE>

<P>You've already seen what <CODE>maxharm</CODE>, <CODE>yscale</CODE>, <CODE>deltax</CODE>,
and <CODE>cycles</CODE> are
for.  Now I'll explain the others.

<P><CODE>Xrange</CODE> is mainly changed when moving the program from
one computer to another.  Each computer allows a particular number
of turtle steps to fit on the screen in each dimension, horizontal
and vertical.  <CODE>Xrange</CODE> is the largest horizontal position <CODE>plot</CODE>
is allowed
to use.  This is set a little below the largest possible X coordinate,
just to make sure that there is no problem with wrapping around the
screen.

<P><CODE>Skip</CODE> is the number of harmonics skipped between terms.  To get odd
harmonics, which we need for the square wave, we have to skip by 2
each time, from 1 to 3, from 3 to 5, and so on.  Different values
for <CODE>skip</CODE> will give very different shapes.

<P>For example, if you are at all adventurous, you must have tried an
even value of <CODE>maxharm</CODE> a while ago, getting a result like this:

<P><PRE>plot 6
</PRE>

<P><CENTER><IMG SRC="plot6.gif" ALT="figure: plot6"></CENTER>

<P>What
you see is two cycles of an approximation to another shape, the
<EM>sawtooth</EM>:

<P><CENTER><IMG SRC="saw.gif" ALT="figure: saw"></CENTER>

<P>Why
two cycles?  Well, <CODE>plot 6</CODE> uses the
second, fourth, and sixth harmonics.
Supposing that the fundamental frequency is 440 again, this means
that <CODE>plot</CODE> added frequencies of 880, 1760, and 2640 Hertz.  But these
are also the fundamental, second harmonic, and third harmonic of 880
Hertz.  By choosing only even harmonics, you've essentially chosen
<EM>all</EM> the harmonics of <EM>twice the fundamental frequency</EM> you
had in mind.  It is this doubling of the fundamental frequency that
produces two cycles on the screen.  You could get one cycle of the
same waveform by saying <CODE>plot [3 skip 1]</CODE>:

<P><CENTER><IMG SRC="plot3skip1.gif" ALT="figure: plot3skip1"></CENTER>

<P>You can see much more bizarre waveforms by using other values of <CODE>skip</CODE>.
The best one I've found is <CODE>plot [16 skip 3]</CODE>:

<P><CENTER><IMG SRC="plot16skip3.gif" ALT="figure: plot16skip3"></CENTER>

<P>I
chose a <CODE>maxharm</CODE> of 16 because it includes the fundamental plus five
additional harmonics (4, 7, 10, 13, 16).  If I'd made <CODE>maxharm</CODE> 15 or
17, I wouldn't have included the fundamental.

<P><H2>Keyword Inputs</H2>





<P>There are two different points of interest about this project.  One
is the whole business of waveforms and Fourier series.  The second
is the use of <EM>keyword</EM> inputs, which is the name for this system
of giving information to <CODE>plot</CODE>.  The more usual style of Logo programming
would have been to make <CODE>plot</CODE> a procedure with six inputs.  To draw
a default graph, you would then have had to say

<P><PRE>plot 5 2 75 1 230 2
</PRE>

<P>Since most of the time you want to use the default values
for most of the inputs, all this typing would be an annoyance.  It
would also be easy to make a mistake about the correct order of the
inputs.  (This more usual Logo technique is called <EM>positional</EM>
inputs.)  The combination of many necessary inputs with standard
values for most of them makes the keyword technique appropriate here.
It isn't always appropriate.  You wouldn't want to have to say

<P><PRE>print item [index 2 list [vanilla chocolate strawberry]]
</PRE>

<P>because you have no trouble remembering which input to <CODE>item</CODE>
is which, and you always want to provide both of them.

<P>The procedure that interprets the keyword inputs is called <CODE>keyword</CODE>.
<CODE>Keyword</CODE> was written to be a general tool, not limited to this particular
program.  It takes two inputs.  The first is the input that you,
the user, provide.  The second is a list of defaults.  When <CODE>plot</CODE> invokes
<CODE>keyword</CODE>, the second input is this:

<P><PRE>[maxharm 5 deltax 2 yscale 75 cycles 1 xrange 230 skip 2]
</PRE>

<P>This input tells <CODE>keyword</CODE> the names of all the keyword inputs
as well as their default values.  It's in the same form as the actual
input you give (a list of alternating names and values), and in fact
<CODE>keyword</CODE> uses a single subprocedure, first to process the default list
and then to process your input.

<P><CODE>Keyword</CODE> is actually not <EM>perfectly</EM> general because it uses the
assumption that all the values it gets are numeric.  The virtue of this
assumption is that it allows <CODE>keyword</CODE> to recognize a number without a
name as implicitly referring to the <CODE>maxharm</CODE> keyword.  (The name <CODE>
maxharm</CODE> is not built into the procedure.  Instead, the first name in the
list of default values is used.)  To use <CODE>keyword</CODE> in a context in which
non-numeric words could be values as well as names, this assumption would
have to be removed.

<P>I didn't have keyword inputs in mind from the beginning.  When I started
working on this project, the only input to <CODE>plot</CODE> was what I now call
<CODE>maxharm</CODE>, the highest harmonic number to include.  All the other numbers
were &quot;wired in&quot;; if I wanted to change something like what is now
called <CODE>:xrange</CODE>, I'd edit all the procedures and change the numbers
in the editor.

<P>Editing all the procedures wasn't too difficult, since without the
keyword-processing procedures everything fits in a single screenful.
Changing the resolution (what is now <CODE>:deltax</CODE>) was a bit annoying,
since I had to edit three different parts of the program.  (You can
see that <CODE>:deltax</CODE> appears three times in the final version.)  When
I finally got tired of that editing process, I decided to use keyword
inputs.

<P><H2>Making the Variables Local</H2>

<P>The job of <CODE>keyword</CODE> is to create variables, one for each keyword,
and assign a value to each variable.  If the user provides a value for
a particular keyword, that's the value to use; if not, the default
value is used.

<P>When I first did this project, I wrote a version of <CODE>keyword</CODE> that
creates global variables for the keywords:

<P><PRE>to keyword :inputs :defaults
if or (wordp :inputs) (numberp first :inputs) ~
   [make &quot;inputs sentence (first :defaults) :inputs]
setup.values :defaults
setup.values :inputs
end

to setup.values :list
if emptyp :list [stop]
make first :list first butfirst :list
setup.values butfirst butfirst :list
end
</PRE>

<P><CODE>Keyword</CODE> checks for the special cases of a single number
(as in <CODE>plot 5</CODE>) or a list beginning with a number; in either case,
a new list is made with the first keyword (<CODE>maxharm</CODE>) inserted before
the number.  Then the default values are assigned to all the keyword
variables, and finally the user's values are assigned to whatever keywords
the user provided, replacing the defaults.

<P>Since these keyword variables are only used within the <CODE>plot</CODE> program,
it would be cleaner to make them local to <CODE>plot</CODE>, just as ordinary
positional inputs are automatically local to a procedure.  I could have
had <CODE>plot</CODE> take care of this before calling <CODE>keyword</CODE>:

<P><PRE>to plot :inputs
local [maxharm deltax yscale cycles xrange skip]
keyword :inputs [maxharm 5 deltax 2 yscale 75 cycles 1 xrange 230 skip 2]
...
</PRE>

<P>but I thought it would be unaesthetic to have to type the
names twice!  What I really want is for <CODE>keyword</CODE> to be able to
make the variables local.  But I can't just say

<P><PRE>to keyword :inputs :defaults
<U>local filter [not numberp ?] :defaults</U>
if or (wordp :inputs) (numberp first :inputs) ~
   [make &quot;inputs sentence (first :defaults) :inputs]
setup.values :defaults
setup.values :inputs
end
</PRE>

<P>because that would make the variables local to <CODE>keyword</CODE>
itself, not to its caller, <CODE>plot</CODE>.  This is the same problem I had
in writing <CODE>localmake</CODE> in Chapter 12, and the solution is the
same:  Make <CODE>keyword</CODE> a macro!

<P><PRE>.macro keyword :inputs :defaults
if or (wordp :inputs) (numberp first :inputs) ~
   [make &quot;inputs sentence (first :defaults) :inputs]
output `[local ,[filter [not numberp ?] :defaults]
         setup.values ,[:defaults]
         setup.values ,[:inputs]]
end
</PRE>

<P>Now it will be <CODE>plot</CODE>, instead of <CODE>keyword</CODE>, that creates the
local variables and calls <CODE>setup.values</CODE>.

<P><H2>Indirect Assignment</H2>

<P>The actual assignment of values to the keywords is a good illustration of
indirect assignment in Logo.  The instruction that does the
assignment is this:

<P><PRE>make first :list first butfirst :list
</PRE>

<P>Usually the first input to <CODE>make</CODE> is an explicit quoted word,
but in this program the variable names are computed, not explicit.
This technique would be impossible in most programming languages.

<P><H2>Numeric Precision</H2>



<P>It's important that the program computes the Fourier
series starting with the higher harmonic numbers, adding in the fundamental
term last.  Recall the formula for the series:
<P><CENTER><IMG SRC="https://people.eecs.berkeley.edu/~bh/v2ch13/math1.gif" ALT="math display"></CENTER><P>
The value of the sine function for each term is divided
by the harmonic number of the term.  In general, this means that the
terms for higher numbered harmonics contribute smaller values to the
sum.

<P>Theoretically, it shouldn't matter in what order you add up a bunch
of numbers.  But computers carry out numeric computations with only
a limited precision.  Usually there is a particular number of <EM>
significant digits</EM> that the computer can handle.  It doesn't matter
how big or small the number is.  The numbers 1234, 1.234, and 0.00000001234
all have four significant digits.

<P>To take a slightly oversimplified case, suppose your computer can
handle six significant digits.  Suppose that the value of the fundamental
term is exactly 1.  Then the computer could add 0.00001 to that 1
and get 1.00001 as the result.  But if you tried to add 0.000001 to
1, the result (1.000001) would require seven significant digits. 
The computer would round this off to exactly 1.

<P>Now suppose that the 23rd term in some series is 0.000004, the 24th
term is 0.000003, and the 25th is 0.000002.  (I just made up
these values, but the general idea
that they'd be quite small is true.)  Suppose we are adding the terms
from left to right in the formula, and the sum of the first 22 terms
is 2.73.  Adding the 23rd term would make it 2.730004, which is too
many significant digits.  This sum would be rounded off to 2.73 again.
Similarly, the 24th and 25th terms would make absolutely no difference
to the result.

<P>But now suppose we add up the terms from right to left.  The sum of
the 25th and 24th terms is 0.000005, and adding in the 23rd term give
0.000009.  If we were to add this to 2.73 the result would be 2.730009.
Although this is still too many significant digits, the computer would
round it off to 2.73001.  The three terms at the end <EM>would</EM> make
a small difference in the result.

<P>In the square wave series, the successive terms get smaller quite
slowly.  You'd have to add very many terms before the problem I'm
describing would really be important.  But other series have terms
that get smaller quickly, so that even for a small number of terms it's
important to add in the smaller terms before the larger ones.

<P>

<P>By the way, the procedure <CODE>series</CODE> that computes the value of the
series for some particular <CODE>x</CODE> value is written recursively, but
its task is iterative.  I could have said

<P><PRE>to series
localmake &quot;result 0
for [harmonic :maxharm 1 [-:skip]] ~
    [make &quot;result :result + (term :harmonic)]
output :result
end
</PRE>

<P>but the use of <CODE>make</CODE> to change the value of a variable
repeatedly isn't very good Logo style.  What I really want is an <EM>
operation</EM> corresponding to <CODE>for</CODE>, analogous to <CODE>map</CODE> as the
operation corresponding to <CODE>foreach</CODE>.  Then I could say

<P><PRE>to series
output accumulate &quot;sum [harmonic :maxharm 1 [-:skip]] [term :harmonic]
end
</PRE>

<P>You might enjoy using the techniques of Chapter 10 to
implement <CODE>accumulate</CODE>.

<P><H2>Dynamic Scope</H2>

<P>One final point about the programming style of this project has to
do with the use of Logo's dynamic scope.  Every procedure has access
to the variables of its superprocedures, and this project takes advantage
of the fact.  Many people think it's better style if every procedure is given
all the information it needs as inputs.  I didn't follow that rule
in this project because, as I've said, many of the variables were
invented late in the development process, and I did as little rewriting
as possible.

<P>For example, here is the procedure that computes one term of the
Fourier series:

<P><PRE>to term :harmonic
output (sin :xscale * :harmonic * :x) / :harmonic
end
</PRE>

<P>Of the three numbers that are used in this computation, <CODE>
:xscale</CODE> is constant throughout the program, so it's not unreasonable for it
to be used globally.  But <CODE>:x</CODE> changes for every point.  <CODE>X</CODE> is, in
fact, a local variable, but it's local to <CODE>plot</CODE> rather than to <CODE>
term</CODE>.

<P>

<P>Why does it matter?  One reason is that people find it easier to understand
a program if it's made very clear where each variable gets its value.  In
this example, it's easy to miss the fact that <CODE>x</CODE> is the index variable
in a <CODE>for</CODE> loop.  The second reason is that as written, <CODE>term</CODE> can
be used only within <CODE>plot</CODE>.  If we wanted to compute the value of a
Fourier series for some reason other than plotting it, we couldn't easily
use the same procedures.

<P>I decided to leave the program as it is, instead of cleaning it up
for publication, so that you could see an example of a style that,
after all, Logo makes possible by choosing to use dynamic scope. 
In some ways, this style is simpler than one in which each procedure
would have several more inputs.  You can decide for yourself if you
find it easier or harder to read the program this way, compared to
the officially approved style:

<P><PRE>to term :x :harmonic :xscale
output (sin :xscale * :harmonic * :x) / :harmonic
end
</PRE>

<P>In this version of the procedure, I've made <CODE>x</CODE> the first
input to <CODE>term</CODE>.  This seems most natural to me, considering that <CODE>
term</CODE>'s job is to compute an algebraic function of <CODE>x</CODE>.  The argument to
a function is very naturally represented in a computer program as
the input to a procedure.

<P>All I've changed in <CODE>term</CODE> itself is the title line.  But of course
the invocation of <CODE>term</CODE>, which is in the procedure <CODE>series</CODE>, must
be changed also.  And to be consistent, <CODE>series</CODE> should get <EM>its</EM>
needed values as explicit inputs, too:

<P><PRE>to series :x :harmonic :skip :xscale
if :harmonic &lt; 1 [output 0]
output (term :harmonic)+(series :harmonic-:skip)
end
</PRE>

<P>We're up to four inputs, and it'd be easy to get them out of
order when <CODE>series</CODE> is invoked by <CODE>plot</CODE>.  You can see why
&quot;inheriting&quot; variables from a procedure's caller can simplify its use.

<P><H2>Further Explorations</H2>

<P>The fact that each term in the series is divided by <CODE>:harmonic</CODE> limits this
program to a particular family of waveforms, the family that includes
square waves and sawtooth waves.  In general, real musical instruments
don't have such regularity in the extent to which each term contributes
to the sum.  For example, I started
by saying that clarinets and pipe
organs are made of odd harmonics, just as square waves are.  But clarinets
don't sound like organs, and neither sound like square waves.  There
is a family resemblance, but there are definite differences too. 
The differences are due to the different &quot;weights&quot; that each instrument
gives to each harmonic.

<P>Instead of the <CODE>maxharm</CODE> and <CODE>skip</CODE>
variables in the program as I've written
it, you could have an input called <CODE>timbre</CODE> (a French word for
the characteristic sound of an instrument, pronounced sort of like
&quot;tamper&quot; with a B instead of the P) that would be a list of
weighting factors.  The equivalent of <CODE>plot 5</CODE> would be this timbre
list:

<P><PRE>[1 0 0.3333 0 0.2]
</PRE>

<P>This list says that the fundamental has a weight of 1, the
second harmonic has a weight of 0 (so it's not used at all), the third
harmonic has a weight of 1/3, and so on.

<P>The <CODE>timbre</CODE> version of the program would be perfectly general.  You
could create any instrument, if you could find the right weighting
factors.  But so much generality makes it hard to know where to begin
exploring all the possibilities.  Another thing you could do would
be to try different kinds of formulas for weighting factors.  For
example, you could write this new version of <CODE>term</CODE>:

<P><PRE>to term :harmonic
op (sin :xscale * :harmonic * :x)/(:harmonic * :harmonic)
end
</PRE>

<P>What waveforms would result from this change?

<P>If you're really interested in computer-generated music, you'll want
to hear what these waveforms sound like.  Unfortunately, it's hard
to do that with the standard sound generators in personal computers,
which allow little or no control of timbre.  But if you have one
of the computer-controllable musical instruments that have become
available recently, you may be able to program them to reproduce
the timbre of your choice.

<P>On the other hand, you can hear the effect of different waveforms
without a computer if you visit the <A HREF="http://www.exploratorium.edu/">Exploratorium</A>
in San Francisco,
the world's best museum.  Among their exhibits are several that let
you experiment with different ways of generating sounds.  One of these
exhibits is a machine that does audibly the same thing we've been
doing graphically, adding up selected harmonics of a fundamental pitch.
If you don't live near San Francisco, the Exploratorium is well worth
the trip, no matter how far away you are!

<P>
<TABLE width="100%"><TR><TD><A HREF="../v2-toc2.html">(back to Table of Contents)</A>
<TD align="right"><A HREF="https://people.eecs.berkeley.edu/~bh/v2ch12/v2ch12.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../v2ch14/manual.html"><STRONG>NEXT</STRONG></A>
</TABLE>

<P><H2>Program Listing</H2>

<P>As mentioned in the text, the appropriate value of <CODE>xrange</CODE> may be
different depending on which computer you're using.

<P><P>
<P><PRE>
to plot :inputs
keyword :inputs ~
        [maxharm 5 deltax 2 yscale 75 cycles 1 xrange 230 skip 2]
localmake "xscale :cycles*180/:xrange
splitscreen clearscreen hideturtle penup
setpos list (-:xrange) 0
pendown
for [x :deltax [2*:xrange] :deltax] ~
    [setpos list (xcor+:deltax) (:yscale * series :maxharm)]
end

;; Compute the Fourier series values

to series :harmonic
if :harmonic < 1 [output 0]
output (term :harmonic)+(series :harmonic-:skip)
end

to term :harmonic
output (sin :xscale * :harmonic * :x) / :harmonic
end

;; Handle keyword inputs

.macro keyword :inputs :defaults
if or (wordp :inputs) (numberp first :inputs) ~
   [make "inputs sentence (first :defaults) :inputs]
output `[local ,[filter [not numberp ?] :defaults]
         setup.values ,[:defaults]
         setup.values ,[:inputs]]
end

to setup.values :list
if emptyp :list [stop]
make first :list first butfirst :list
setup.values butfirst butfirst :list
end
</PRE><P>




<P><A HREF="../v2-toc2.html">(back to Table of Contents)</A>
<P><A HREF="https://people.eecs.berkeley.edu/~bh/v2ch12/v2ch12.html"><STRONG>BACK</STRONG></A>
chapter thread <A HREF="../v2ch14/manual.html"><STRONG>NEXT</STRONG></A>

<P>
<ADDRESS>
<A HREF="../index.html">Brian Harvey</A>, 
<CODE>bh@cs.berkeley.edu</CODE>
</ADDRESS>
</BODY>
</HTML>