Visualizing periodic functions

By Gianluca Gorni, University of Udine, Italy. Latest revision: December 16, 2006.

Description: Drawing graphs of real periodic functions of one variable, either as a function from the real line or as a function on the unit complex circle.

Instructions: load the package by clicking on the button below, then evaluate the examples.

Button[StyleForm["Click here to load package!",FontColor->RGBColor[1,0,0],FontSize->14],ButtonFunction:>FrontEndExecute[FrontEndToken["EvaluateInitialization"]],ButtonEvaluator->None,Active->True]

Mathematica package

BeginPackage["PeriodicPlot`","Utilities`FilterOptions`"];

Unprotect["`*"];
ClearAll["`*"];

PeriodicPlot::usage="PeriodicPlot[expression,{var,varMin,varMax},opts] 
turns the expression into a periodic function of var;
the interval that is to be repeated is assigned by
by the option PeriodStart (with default -Pi),
and PeriodLength (with default 2Pi).
The resulting function is then plotted for var
from varMin to varMax, with the main period interval
drawn with style assigned by the option HighlightStyle
(the default being thick and red). PlotStyle controls
the style of the plot outside the main period interval.
PeriodicPlot also accepts a list of functions
instead of a single function, and HighlightStyle behaves
as PlotStyle in Plot.
Example: PeriodicPlot[x^2,{x,-2Pi,2Pi}]";

PeriodLength::usage="PlotStyle is an option for PeriodicPlot that specifies the style of lines to be plotted inside the main period interval.";

Highlight::usage="Highlight is an option for PeriodicPlot, that decides whether to use a special style for the plot in the main period interval. It can take the values True or False.";

PeriodStart::usage="PeriodStart is an option for PeriodicPlot, that decides where the main period interval starts. The default is -Pi.";

PeriodLength::usage="PeriodLength is an option for PeriodicPlot, that decides the length of the main period interval. The default is 2Pi.";

HighlightStyle::usage="HighlightStyle is an option for PeriodicPlot, that decides the style for the main period interval. The default is thick and red.";

PeriodicPlot3D::usage="PeriodicPlot3D[expression,var,opts] draws a 3D plot of the (real-valued) expression as a function defined on the unit circle in the complex plane.
Example: PeriodicPlot3D[Re[z^2],z].";

PeriodicPlotDouble::usage="PeriodicPlotDouble[expression,{var,varMin,varMax},opts] draws PeriodicPlot and PeriodicPlot3D side by side.";

Options[PeriodicPlot]={PeriodLength->2 π,Highlight->True,PeriodStart->-π,HighlightStyle->{{Thickness[0.006],RGBColor[1,0,0]}}};

Begin["`Private`"];

Needs["Utilities`FilterOptions`"];

SetAttributes[PeriodicPlot,HoldAll];

scaleTicksByPeriodo[ticksList_List,periodo_,inizioPeriodo_]:=Module[{a,b,c,d},{a,b,c,d}=Transpose[ticksList];Transpose[{N[periodo a+inizioPeriodo],Rationalize[b,.001]/.x_?NumericQ:>periodo x+inizioPeriodo,c,d}]];

PeriodicPlot[funzione_/;$VersionNumber<4.,{x_Symbol,xMinimo_,xMassimo_},opts___]:=Module[{periodo,evidenziareQ,a,b,opzioniPlot,quantiASinistra,quantiADestra,funzionePeriodicizzata,t,base,marchi,marchiPeriodo,generico,sfondo,plotGenerico},{periodo,evidenziareQ,a,b}={PeriodLength,Highlight,PeriodStart,PeriodStart+PeriodLength}/.{opts}/.Options[PeriodicPlot];
opzioniPlot=FilterOptions[Plot,{opts}];quantiASinistra=Ceiling[((a-xMinimo)/periodo)];quantiADestra=Ceiling[((xMassimo-b)/periodo)];funzionePeriodicizzata=Block[{x},funzione/.x->a+Mod[t-a,periodo]];base=Plot[Evaluate[funzionePeriodicizzata],{t,a,b},PlotStyle->(HighlightStyle/.{opts}/.Options[PeriodicPlot]),DisplayFunction->Identity];marchi=FullOptions[Plot[0,{x,((xMinimo-a)/periodo),((xMassimo-a)/periodo)},PlotRange->FullOptions[base,PlotRange][[2]],DisplayFunction->Identity],Ticks];marchiPeriodo={((scaleTicksByPeriodo[#1,periodo,a]&)/@marchi)[[1]],Automatic};generico[n_]:=Plot[Evaluate[funzionePeriodicizzata],{t,Max[xMinimo,a+n periodo],Min[xMassimo,a+(n+1) periodo]},DisplayFunction->Identity,Evaluate[opzioniPlot]];sfondo=generico/@Complement[Range[-quantiASinistra,quantiADestra],{0}];Options[plotGenerico]=Join[(Options[Plot])⋂(Options[DensityPlot]),{AspectRatio->Automatic}];Show[{base,sfondo},FilterOptions[plotGenerico,{opts}],Ticks->(Ticks/.{opts}/.Ticks->marchiPeriodo),DisplayFunction->(DisplayFunction/.{opts}/.DisplayFunction->$DisplayFunction)]];

PeriodicPlot[funzione_/;$VersionNumber>=4.,{x_Symbol,xMinimo_,xMassimo_},opts___]:=Module[{periodo,evidenziareQ,a,b,opzioniPlot,quantiASinistra,quantiADestra,funzionePeriodicizzata,t,base,marchi,marchiPeriodo,generico,sfondo,plotGenerico},{periodo,evidenziareQ,a,b}={PeriodLength,Highlight,PeriodStart,PeriodStart+PeriodLength}/.{opts}/.Options[PeriodicPlot];
opzioniPlot=FilterOptions[Plot,{opts}];quantiASinistra=Ceiling[((a-xMinimo)/periodo)];quantiADestra=Ceiling[((xMassimo-b)/periodo)];funzionePeriodicizzata=Block[{x},funzione/.x->a+Mod[t-a,periodo]];base=Plot[Evaluate[funzionePeriodicizzata],{t,a,b},PlotStyle->(HighlightStyle/.{opts}/.Options[PeriodicPlot]),DisplayFunction->Identity];marchi=Ticks/.AbsoluteOptions[Plot[0,{x,((xMinimo-a)/periodo),((xMassimo-a)/periodo)},PlotRange->(PlotRange/.AbsoluteOptions[base,PlotRange])[[2]],DisplayFunction->Identity],Ticks];marchiPeriodo={((scaleTicksByPeriodo[#1,periodo,a]&)/@marchi)[[1]],Automatic};generico[n_]:=Plot[Evaluate[funzionePeriodicizzata],{t,Max[xMinimo,a+n periodo],Min[xMassimo,a+(n+1) periodo]},DisplayFunction->Identity,Evaluate[opzioniPlot]];sfondo=generico/@Complement[Range[-quantiASinistra,quantiADestra],{0}];Options[plotGenerico]=(Options[Plot]⋂Options[DensityPlot])~Join~{AspectRatio->Automatic};Show[{base,sfondo},FilterOptions[plotGenerico,{opts}],Ticks->(Ticks/.{opts}/.Ticks->marchiPeriodo),DisplayFunction->(DisplayFunction/.{opts}/.DisplayFunction->$DisplayFunction)]];

SetAttributes[PeriodicPlot3D,HoldAll];

PeriodicPlot3D[funzione_,z_Symbol,opts___]:=Module[{complexToReal,opzioni2D,opzioni3D,func,t,datiGrafico,coord,base,treD,bordo,cerchio,assi},
complexToReal={Re[#1],Im[#1]}&;{opzioni2D,opzioni3D}=({FilterOptions[#1,{opts}]}&)/@{Plot,Graphics3D};
func=Block[{z},funzione/.z->(E^(I t))];
graficoBidimesionale=Cases[Plot[Chop[func],{t,0,2 π},DisplayFunction->Identity,Evaluate[FilterOptions[Plot,opts]]][[1]],_Line,{1,Infinity}];
graficoConZeriEspliciti=graficoBidimesionale//.Line[{a___,{b_,c_Real},{d_,e_},f___}/;c e<0]:>Line[{a,{b,c},{b-((c (d-b))/(e-c)),0},{d,e},f}];
graficoTridSoloLinea=
graficoConZeriEspliciti/.Line[pts_]:>Line[Map[Join[complexToReal[(E^(I #[[1]]))],{#[[2]]}]&,pts]];
cerchio=graficoTridSoloLinea/.{x_,y_,h_?NumericQ}:>{x,y,0};
mandaIn3D[pts_List]:=Partition[pts,2,1]/.{{cerchio1__,h1_?NumericQ},{cerchio2___,h2_}}:>Polygon[{{cerchio1,h1},{cerchio2,h2},{cerchio2,0},{cerchio1,0},{cerchio1,h1}}];
superficie=Flatten@{EdgeForm[],PlotStyle/.{opts}/.{PlotStyle:>Sequence@@{}},graficoTridSoloLinea/.Line[pts_]:>mandaIn3D[pts]};
assi=Flatten@{Thickness[0.01],AxesStyle/.{opts}/.{AxesStyle:>Sequence@@{}},Line[{-{1.2,0,0},{1.2,0,0}}],Line[{-{0,1.2,0},{0,1.2,0}}]};Show@Graphics3D[{Flatten@{PlotStyle/.{opts}/.{PlotStyle:>Sequence@@{}},graficoTridSoloLinea,cerchio},assi,superficie},opzioni3D]];

SetAttributes[PeriodicPlotDouble,HoldAll];

PeriodicPlotDouble[f_,{x_,xMin_,xMax_},opts___Rule]:=Module[{perSt,perLen,tm,twoD,threeD,rat},
{perSt,perLen}={PeriodStart,PeriodLength}/.{opts}/.Options[PeriodicPlot];
threeD=PeriodicPlot3D[f/.x->2Pi*Log[z*E^(-I(Pi-perSt))]/(I*perLen),z,DisplayFunction->Identity,FilterOptions[ParametricPlot3D,opts]];
rat=If[$VersionNumber≥4.,AspectRatio/.AbsoluteOptions[threeD,AspectRatio],FullOptions[threeD,AspectRatio]];
twoD=PeriodicPlot[f,{x,xMin,xMax},AspectRatio->rat,FilterOptions[PeriodicPlot,opts],DisplayFunction->Identity,FilterOptions[Plot,opts]];
Show[GraphicsArray[{twoD,threeD}],PlotRange->All,FilterOptions[GraphicsArray,opts],DisplayFunction->$DisplayFunction]];

End[];

Protect["`*"];

EndPackage[];

Application examples

Basic trigonometric functions

PeriodicPlot[Cos[2 t],{t,-((3 π)/2),((3 π)/2)}]

PeriodicPlot3D[Im[z],z,PlotRange->{-2,2},PlotRange->{-1,1}]

Show[GraphicsArray[Partition[Table[Show[PeriodicPlotDouble[Sin[n*t], {t, -Pi, Pi}, PlotRange -> {-2, 2}, DisplayFunction -> Identity], PlotLabel -> StringJoin["Sin[n*t],n=", ToString[n]]], {n, 0, 3}], 2]], DisplayFunction -> $DisplayFunction]

Show[GraphicsArray[Flatten/@Partition[Table[{PeriodicPlot[Sin[n t],{t,-π,π},PlotRange->{-2,2},AspectRatio->Automatic,Ticks->None,DisplayFunction->Identity],PeriodicPlot3D[Im[(z^n)],z,PlotRange->{-1,1},BoxRatios->{3,3,2},DisplayFunction->Identity]},{n,0,6}],2],
GraphicsSpacing->{0,0.3}],
DisplayFunction->$DisplayFunction]

Square wave and its Fourier series

PeriodicPlot[Sign[x], {x, -2*Pi, 2*Pi}]

PeriodicPlot3D[Sign[Im[z]], z]

squareFourierCoeff[n_Integer]:=squareFourierCoeff[n]=(((∫_0^π)(E^(-I n t))\[DifferentialD]t-(∫_(-π)^0)(E^(-I n t))\[DifferentialD]t)/(2 π));

squareFourierPartialSum[n_Integer]:=fourierPartialSum[n]=(∑_(k=-n)^n)squareFourierCoeff[k] (z^k);

PeriodicPlot[{Sign[t], Chop[squareFourierPartialSum[4] /. z -> E^(I*t)]}, {t, -((3*Pi)/2), (3*Pi)/2}, HighlightStyle -> {{RGBColor[0, 1, 0]}, {RGBColor[1, 0, 0]}}]

PeriodicPlot3D[Chop[squareFourierPartialSum[4]], z]

squareplots[nmin_,nmax_]:=Show[GraphicsArray[{{PeriodicPlot[Sign[x],{x,-2 π,2 π},DisplayFunction->Identity],PeriodicPlot3D[Sign[Im[z]],z,DisplayFunction->Identity]}}~Join~Table[{PeriodicPlot[{Sign[t],Chop[squareFourierPartialSum[n]/.z->(E^(I t))]},{t,-((3 π)/2),((3 π)/2)},HighlightStyle->{{RGBColor[0,1,0]},{RGBColor[1,0,0]}},DisplayFunction->Identity,PlotLabel->(HoldForm[n]==n)],PeriodicPlot3D[Chop[squareFourierPartialSum[n]],z,DisplayFunction->Identity]},{n,nmin,nmax,2}]],DisplayFunction->$DisplayFunction,ImageSize->500];

squareplots[1,5];

Sawtooth wave and its Fourier series

PeriodicPlot[(Pi - x)/2, {x, -2*Pi, 4*Pi}, PeriodStart -> 0, AspectRatio -> Automatic]

PeriodicPlot3D[(1/2)*(Pi - (Pi + Arg[-z])), z]

sawtoothFourierCoeff[n_Integer]:=sawtoothFourierCoeff[n]=(((∫_0^(2 π))(1/2) (E^(-I n t)) (π-t)\[DifferentialD]t)/(2 π));

sawtoothFourierPartialSum[n_Integer]:=sawtoothFourierPartialSum[n]=(∑_(k=-n)^n)sawtoothFourierCoeff[k] (z^k);

PeriodicPlot[{(Pi - t)/2, Chop[sawtoothFourierPartialSum[4] /. z -> E^(I*t)]}, {t, -((3*Pi)/2), (5*Pi)/2}, HighlightStyle -> {{RGBColor[0, 1, 0]}, {RGBColor[1, 0, 0]}}, PeriodStart -> 0]

PeriodicPlot3D[Chop[sawtoothFourierPartialSum[4]], z]

sawtoothplots[nmin_,nmax_]:=Show[GraphicsArray[{{PeriodicPlot[((π-x)/2),{x,-2 π,4 π},PeriodStart->0,DisplayFunction->Identity],PeriodicPlot3D[(1/2) (π-(π+Arg[-z])),z,DisplayFunction->Identity]}}~Join~Table[{PeriodicPlot[{((π-t)/2),Chop[sawtoothFourierPartialSum[n]/.z->(E^(I t))]},{t,-2 π,4 π},PeriodStart->0,HighlightStyle->{{RGBColor[0,1,0]},{RGBColor[1,0,0]}},DisplayFunction->Identity,PlotLabel->(HoldForm[n]==n)],PeriodicPlot3D[Chop[sawtoothFourierPartialSum[n]],z,DisplayFunction->Identity]},{n,nmin,nmax,2}]],DisplayFunction->$DisplayFunction,ImageSize->500];

sawtoothplots[1,5];

"Quadratic" wave and its Fourier series

PeriodicPlot[x^2, {x, -3*Pi, 3*Pi}]

PeriodicPlot3D[Arg[z]^2, z, BoxRatios -> {1, 1, 2}, PlotRange -> All]

quadraticFourierCoeff[n_Integer]:=quadraticFourierCoeff[n]=(((∫_(-π)^π)(E^(-I n t)) (t^2)\[DifferentialD]t)/(2 π));

quadraticFourierPartialSum[n_Integer]:=quadraticFourierPartialSum[n]=(∑_(k=-n)^n)quadraticFourierCoeff[k] (z^k);

PeriodicPlot[{t^2, Chop[quadraticFourierPartialSum[4] /. z -> E^(I*t)]}, {t, -3*Pi, 3*Pi}, HighlightStyle -> {{RGBColor[0, 1, 0]}, {RGBColor[1, 0, 0]}}]

PeriodicPlot3D[Chop[quadraticFourierPartialSum[4]], z, BoxRatios -> {1, 1, 2}, PlotRange -> All]

quadraticplots[nmin_,nmax_]:=Show[GraphicsArray[{{PeriodicPlot[(x^2),{x,-3 π,3 π},DisplayFunction->Identity],PeriodicPlot3D[((Arg[z])^2),z,BoxRatios->{1,1,2},PlotRange->All,DisplayFunction->Identity]}}~Join~Table[{PeriodicPlot[{(t^2),Chop[quadraticFourierPartialSum[n]/.z->(E^(I t))]},{t,-3 π,3 π},HighlightStyle->{{RGBColor[0,1,0]},{RGBColor[1,0,0]}},DisplayFunction->Identity,PlotLabel->(HoldForm[n]==n)],PeriodicPlot3D[Chop[quadraticFourierPartialSum[n]],z,DisplayFunction->Identity,PlotRange->{-1,11},BoxRatios->{1,1,2}]},{n,nmin,nmax}]],DisplayFunction->$DisplayFunction,ImageSize->500];

quadraticplots[0,2];

Dirichlet kernel

DirichletKernel[n_Integer]:=(∑_(k=-n)^n)(z^k);

PeriodicPlot[{Chop[DirichletKernel[4] /. z -> E^(I*t)], 1/Sin[t/2], -(1/Sin[t/2])}, {t, -2*Pi, 2*Pi}, HighlightStyle -> {{RGBColor[1, 0, 0]}, {Dashing[{0.01, 0.01}]}, {Dashing[{0.01, 0.01}]}}, PlotStyle -> {{}, {Dashing[{0.01, 0.01}]}, {Dashing[{0.01, 0.01}]}}]

PeriodicPlot3D[Chop[DirichletKernel[4]], z, PlotRange -> All]

dueD[k_]:=PeriodicPlot[{Chop[DirichletKernel[k]/.z->Exp[I*t]],1/Sin[t/2],-1/Sin[t/2]},{t,-2Pi,2Pi},HighlightStyle->{{Thickness[.01],RGBColor[1,0,0]},{Dashing[{.01,.01}]},{Dashing[{.01,.01}]}},PlotStyle->{{Thickness[.01]},{Dashing[{.01,.01}]},{Dashing[{.01,.01}]}},
PlotRange->{-3,12},
DisplayFunction->Identity,PlotLabel->(HoldForm[n]==k)];

Show[dueD[2], DisplayFunction -> $DisplayFunction]

treD[k_]:=PeriodicPlot3D[Chop[DirichletKernel[k]],z,DisplayFunction->Identity,PlotRange->{-3,12},BoxRatios->{1,1,5},PlotLabel->(HoldForm[n]==k)];

Show[GraphicsArray[{{dueD[0], dueD[1]}, {dueD[2], dueD[3]}, {dueD[4], dueD[5]}}], DisplayFunction -> $DisplayFunction, GraphicsSpacing -> 0.2, ImageSize -> 500]

Show[GraphicsArray[{treD[0], treD[1], treD[2], treD[3], treD[4], treD[5]}], DisplayFunction -> $DisplayFunction, GraphicsSpacing -> 0.3, ImageSize -> 500]

Fejér kernel

DirichletKernel[n_Integer]:=(∑_(k=-n)^n)(z^k);

FejerKernel[n_Integer]:=FejerKernel[n]=(((∑_(k=0)^n)DirichletKernel[k])/(n+1));

PeriodicPlot[FejerKernel[4] /. z -> E^(I*t), {t, -2*Pi, 2*Pi}, PlotRange -> All]

PeriodicPlot3D[FejerKernel[4], z, PlotRange -> All]

Show[GraphicsArray[Flatten /@ Partition[Table[{PeriodicPlot[FejerKernel[n] /. z -> E^(I*t), {t, -Pi, Pi}, PlotRange -> {0, 6}, AspectRatio -> Automatic, Ticks -> None, DisplayFunction -> Identity, PlotLabel -> HoldForm[n] == n], PeriodicPlot3D[FejerKernel[n], z, PlotRange -> {0, 6}, BoxRatios -> {3, 3, 2}, DisplayFunction -> Identity]}, {n, 0, 6}], 2], GraphicsSpacing -> {0, 0.3}], DisplayFunction -> $DisplayFunction]

A simple kernel for convolution

SimpleKernel[n_Integer]:=SimpleKernel[n]=(((((1/2) (1+(1/2) (z+(1/z)))))^n)/((∫_0^(2 π))(((((1/2) (1+(1/2) (z+(1/z)))))^n)/.z->(E^(I t)))\[DifferentialD]t));

PeriodicPlot[SimpleKernel[4] /. z -> E^(I*t), {t, -2*Pi, 2*Pi}, PlotRange -> All]

PeriodicPlot3D[SimpleKernel[4], z, PlotRange -> All, BoxRatios -> {1, 1, 4}]

Show[GraphicsArray[Flatten /@ Partition[Table[{PeriodicPlot[SimpleKernel[n] /. z -> E^(I*t), {t, -Pi, Pi}, PlotRange -> {0, 4}, AspectRatio -> Automatic, Ticks -> None, DisplayFunction -> Identity, PlotLabel -> HoldForm[n] == n], PeriodicPlot3D[SimpleKernel[n], z, PlotRange -> {0, 4}, BoxRatios -> {3, 3, 2}, DisplayFunction -> Identity]}, {n, 0, 6}], 2], GraphicsSpacing -> {0, 0.3}], DisplayFunction -> $DisplayFunction]

Piano waveform

pianoforte=100 (0.0054 Sin[4.1+x]+0.0052 Sin[3.9+x]+0.0046 Sin[4.5+2 x]+0.00464 Sin[3.9+2 x]+0.00563 Sin[1.3+2 x]+0.00988 Sin[2.9+2 x]+0.03775 Sin[5.4+2 x]+0.01262 Sin[0.6+2 x]+0.03709 Sin[5.2+2 x]+0.01541 Sin[1.1+2 x]+0.01075 Sin[3.1+2 x]+0.00664 Sin[2.4+2 x]+0.00574 Sin[3.8+2 x]+0.00495 Sin[1.5+2 x]+0.0041 Sin[1.4+2 x]+0.00725 Sin[1.9+3 x]+0.015 Sin[3.9+3 x]+0.01196 Sin[0.+3 x]+0.00937 Sin[6.+3 x]+0.00452 Sin[3.1+4 x]+0.00811 Sin[2.3+5 x]+0.0075 Sin[0.3+5 x]+0.00607 Sin[1.1+6 x]+0.00495 Sin[0.9+6 x]);

PeriodicPlot[pianoforte, {x, -2*Pi, 2*Pi}]

PeriodicPlot3D[TrigToExp[pianoforte] /. x -> Log[z]/I, z, BoxRatios -> {1, 1, 2}, PlotRange -> All]