Tutorial for the FMPlot Package
FM Spectral Plots in Mathematica
Craig Stuart Sapp
craig@ccrma.stanford.edu
23 March 1995

Getting Started

First, load in the FMPlot package so that it can be used in a Mathematica notebook.  Specify the filename of the package source code to be loaded below:

<< "FMPlot.m"

To see all of the functions defined in FMPlot:

?FMPlot`*

To get help on a particular function:

?FMPlot

Double click on the right side of each heading below to open/close a section of this notebook:

Plotting FM Spectra

The main function for this package is FMPlot, which plots the FM spectrum of a given carrier / modulator pair as we hear it.  The FMPlot function plots  spectral lines and gives a title which lists the three variables of carrier frequency, modulator frequency, and index.  All frequencies are positive for this plot since the negative frequencies are folded over and added or subtracted from the positive spectrum as necessary.

FMPlot[200, 100, 3];

FMPlot[200, 10, 3];

The default size of the plots may be slightly smaller than I would like, depending on the version of Mathematica which you are using. Since I use a larger font size than the default,  you may have to increase the size of the plot by clicking on the plot and then dragging one of the corners.

FMPlot[1, 2, 3];

You can also draw just the spectral lines without any text:

Show[SpectralLines[AbsPositiveFMSpectrum[1, 2, 3]]];

You can change the thickness of the  spectral lines as well.  The default is 0.02, and the range of values is [0..1]:

Show[SpectralLines[AbsPositiveFMSpectrum[1, 2, 3], 0.2], 
      PlotRange -> All];

Show[SpectralLines[AbsPositiveFMSpectrum[1, 2, 3], 0.005], 
      PlotRange -> All];

In FMPlot, you can specify the lower threshold for plotted amplitude of the spectral lines.  The main spectral frequencies extend (carrier ± k * modulator), where k = index + 2.  These lines will always be plotted no matter what, but you can extend the outer limits of the plotted spectrum to include additional insignificant harmonics which are present, but in very small quantities.  The default minimum amplitude is 0.045, and lowering this parameter may add frequencies that are normally ignored.  This  amplitude is the value of the Bessel function, which can range from 0 to 1, but the maximum unnormalized value for any carrier/modulator/index amplitude is not always (nearly never) 1.

FMPlot[220, 220, 2];

FMPlot[220, 220, 2, 0.00001];

Changing the widths of the spectral lines in the plots:

FMPlot[220, 220, 2, 0.00001, 0.05];

You can tailor the plot style to your likening by using the same options available with ListPlot:

Options[ListPlot]

\(\(FMPlot[440\ 3, 440\ 2, 4, 1, 0.025, 
\ \ \ 
      DefaultFont -> {"Courier", 10}, 
\ \ \ 
      FrameLabel 
        -> {"Frequency in Hz", "", 
          FontForm["FM Clarinet at A440", {"Courier", 18}], ""}, 
      
\ \ \ FrameTicks 
        -> {Table[440\ i, {i, 1, 17, 2}], None, None, None}, 
\ \ \ 
      GridLines -> {None, Automatic}, 
\ \ \ AspectRatio -> 1/3]; 
    \)\)

Spectral Manipulation

Creating  FM Spectra

You can also manipulate FM spectra in the form of lists.  The example below shows the spectral amplitude data used to create a previous plot.  Spectra are stored in lists, with each element of a list being it self a list of two numbers – first, the frequcency and second, the relative amplitude:

TableForm[Reverse[FMSpectrum[220, 220, 2, 0.00001]]]

Notice that there are negative frequencies.  These frequencies are the mathematical representations of positive frequencies with a phase difference of 180°, or π radians from the phase of the positive frequencies.

TableForm[Reverse[PositiveFMSpectrum[220, 220, 2, 0.00001]]]

Now all of the frequencies listed in the first column are positive.  Note, however, that 220 Hz has a negative amplitude which means that it is 180° out of phase relative to the rest of the harmonics.  This  phase difference is not audible (in almost all cases) to human ears, so we can look at just the absolute value of the amplitudes:

TableForm[Reverse[AbsPositiveFMSpectrum[220, 220, 2, 0.00001]]]

This  is the data which is plotted in the   plot  below; however, notice that the maximum amplitude in this data is 0.576725, and in the plot, the maximum is 1.  Since the absolute amplitudes of the spectrum are not important and the relative amplitudes are, the loudest frequency is set to an amplitude of 1 in the plots.  This can be done to spectral lists with the function NormalizeSpectrum.

FMPlot[220,  220,  2,  0.00001];

TableForm[
      Reverse[NormalizeSpectrum[AbsPositiveFMSpectrum[220, 220, 2, 0.00001]]]]

Or if you prefer to see the relative amplitudes in terms of percentages of the maximum amplitude:

spectrum = AbsPositiveFMSpectrum[220, 220, 2, 0.00001]; TableForm[Reverse[NormalizeSpectrum[spectrum, 100]]]

spectrum = AbsPositiveFMSpectrum[220, 220, 2, 0.00001]; {frequencies, amplitudes} = 
      Transpose[Reverse[NormalizeSpectrum[spectrum, 100]]]; amplitudes = Round[amplitudes]; spectrum = Transpose[{frequencies, amplitudes}]; TableForm[spectrum, TableAlignments -> {Center, Center}, 
      TableHeadings 
        -> {None, {"Frequency (Hz)", "Strength (% of Max)"}}, 
      TableSpacing -> {0.5, 4}]

Generalized Spectral Plotting

The function SpectralPlot is similar to FMPlot, but you can manipulate the spectrum before you plot it:

spectrum = FMSpectrum[186, 35, 10]; SpectralPlot[spectrum];

SpectralPlot[NormalizeSpectrum[spectrum, 100], 0.01];

Options can also be used as in FMPlot:

x = AbsPositiveFMSpectrum[440 3, 440 2, 4, 1]; SpectralPlot[x, 0.025, DefaultFont -> {"Courier", 10}, 
      FrameLabel 
        -> {"Frequency in Hz", "", 
          FontForm["FM Clarinet at A440", {"Courier-Bold", 16}], 
          ""}, FrameTicks -> {SpectralFreq[x], None, None, None}, 
      GridLines -> {None, Automatic}, AspectRatio -> (1/3)];

Combining Spectra

CombineSpectra allows you to mix any number of spectra together:

x = PositiveFMSpectrum[100, 100, 1]

y = PositiveFMSpectrum[600, 100, 1]

z = PositiveFMSpectrum[900, 50, 3]

CombineSpectra[x, y]

Once you have created  a combined spectral list which contains phase information, you can remove the phase by using RemovePhase:

SpectralPlot[CombineSpectra[x, y, z]];

SpectralPlot[RemovePhase[CombineSpectra[x, y, z]]];

Note that if you remove the phase information from the spectra before you combine the spectra, you will not be able to accurately combine the spectra.

Also, you can combine duplicate frequency listings in a single spectral list:

CombineSpectra[{{1, 1}, {3, 3}, {1, -2}}]

Additive Synthesis Uses

You can create your own spectra and plot it with FMPlot.  A spectral list is a list of lists, where the inner lists contain two numbers.  The first of these numbers is the frequency, and the second of these numbers is the amplitude of that frequency.

spectrum = {{220, 1}, {440, 1}, {660, 1}, {880, 1}}; SpectralPlot[spectrum, 0.025, 
      FrameTicks 
        -> {SpectralFreq[spectrum], Automatic,  None,  None}];

You are able to test your spectrum to see if it is a well-formed spectral list by using SpectralListQ:

SpectralListQ[spectrum]

SpectralListQ[{0, 1}]

SpectralListQ[17]

!!! Special Feature of SpectrumPlot !!!

Control of the plotting domain is possible by creating a zero amplitude frequency on the outer ends of the spectral list:

newSpectrum = Join[{{0, 0}}, spectrum, {{1000, 0}}]

SpectralPlot[newSpectrum, 0.025, 
      FrameTicks -> {SpectralFreq[spectrum], Automatic}];

There can be a zero frequency on just one side of the spectral list as well:

notherSpectrum = Drop[newSpectrum, -1]

SpectralPlot[notherSpectrum, 0.025, 
      FrameTicks 
        -> {
          Transpose[spectrum][[1]], 
          Automatic}];

Disable this feature by making sure amplitudes are real, i.e., they have a decimal point after them: 0. or 0.0   .

newSpectrum = Join[{{0, 0.}}, spectrum, {{1000, 0.}}]

SpectralPlot[newSpectrum, 0.025, 
      FrameTicks 
        -> {
          Transpose[spectrum][[1]], 
          Automatic}];

Animations of a dynamic index of modulation are possible using this plot-range feature.  Double click on the picture cell below to start the animation of an increasing index of modulation.  Once you start the animation, buttons appear at the bottom of the window that allow you to control the speed of the animation and how to loop the animation.  Try circular looping.  This animation starts at an index of 0 and ends at an index of 6.

x = 
      Table[Join[{{20, 0}}, 
          AbsPositiveFMSpectrum[1000, 100, 
            N[3 (1 + Sin[((2 π i)/36) - (π/2)])]], {{2000, 
              0}, {2000, 1.1}}], {i, 0, 17}];

(SpectralPlot[#1, 0.05]&) /@ x

Description of Functions in the FMPlot Package

A spectral list is a list of this form: {{frequency1,amplitude1},...,{frequencyN,AmplitudeN}}

AbsPositiveFMSpectrum

?AbsPositiveFMSpectrum

AbsPositiveFMSpectrum creates a spectral list of  positive frequencies for  the specifies carrier/modulator combination with no phase information in the amplitues; so, both the frequencies and amplitudes in the spectral list are positive. Any negative frequencies  are first folded over onto the positive frequencies, then the phase  of the negative frequency is reversed and added to the amplitude of any existing positive frequency component that

CombineSpectra

?CombineSpectra

CombineSpectra combines different spectra into a single spectral list where there all frequencies are unique.  Any number of spectral lists can be passed as an argument to CombineSpectra. Also, if there are two frequencies in a single spectral list, CombineSpectra will add those two spectral elements together.  Note that if you remove the phase information from the spectra before you combine the spectra, you will not be able to accurately combine the spectra.

Deviation

?Deviation

The deviation (Δf) is the maximum frequency deviation in Hertz from the carrier frequency (the average frequency).  The deviation is related to the amplitude of the modulator frequency – the larger the amplitude of the modulator, the greater the deviation will be.

FMPlot

?FMPlot

FMPlot  plots the FM spectrum of a  given carrier / modulator pair as we hear it. This function plots the spectral lines and gives a title that lists the three variables of carrier frequency, modulator frequency and  index.  All frequencies are positive for this plot since the negative frequencies are folded over and added or subtracted from the positive spectrum as necessary.

FMSpectrum

?FMSpectrum

FMSpectrum returns a spectral list of all the sidebands created along with the carrier frequency, as well as their relative amplitudes.  Frequencies and amplitudes can be either positive or negative.

Index

?Index

The index in FM synthesis is the ratio of the deviation to the modulator frequency (Δf / fm) .  The index must always be greater or equal to zero.

NormalizeSpectrum

?NormalizeSpectrum

PlotAbsPositiveFMSpectrum

?PlotAbsPositiveFMSpectrum

PlotAbsPositiveFMSpectrum is identical to FMPlot,which plots the  FM spectrum of a  given carrier / modulator pair as we hear it. This function plots  the spectral lines and gives a title that lists the three variables of carrier frequency, modulator frequency and  index.  All frequencies are positive for this plot since the negative frequencies are folded over and added or subtracted from the positive spectrum as necessary.

PositiveFMSpectrum

?PositiveFMSpectrum

PositiveFMSpectrum is similar to FMSpectrum, but any negative frequencies are converted into positive frequencies and combined with any positive spectral frequencies in the spectral list.

RemovePhase

?RemovePhase

RemovePhase converts a spectral list into another spectral list that contains only real frequencies and amplitudes that are greater or equal to 0.  Negative frequencies are assumed to be 180° out of phase from positive frequencies.

SpectralAmp

?SpectralAmp

SpectralAmp returns a list of the amplitudes in a spectral list.  Useful if you want to find the maximum or minimum amplitude in a spectral list.

SpectralFreq

?SpectralFreq

SpectralFreq returns a list of the frequencies in a spectral list.  Useful if you want to label the individual spectral frequencies in a plot.

SpectralLines

?SpectralLines

SpectralLines returns a Graphics list of the spectral lines and can be mixed with other graphics or plots if desired.

SpectralListQ

?SpectralListQ

SpectralListQ returns true if the given object is a list that contains at least one element and each of the elements in the list is a list of two elements.  It is assumed that if you can make that much of the spectral list correctly that you will be nice and put only numbers inside the inner lists, since SpectralListQ does not check the actual contents of the inner lists.

SpectralPlot

?SpectralPlot

SpectralPlot plots a spectral list using spectral lines.  All frequencies and amplitudes are allowable.  Most options valid for Plot can also be used. You can also control the plotting domain by creating a zero amplitude frequency on the outter ends of the spectral list: There can also be a zero frequency on just one side of the spectral list: You can disable this feature by making sure amplitudes are real, i.e., they have a decimal point after them: 0. or 0.0   .