Lanczos interpolation explained

This is a rendered version of the notebook. Head over to the Mathematica file for a version you can actually play with (although you will have to buy Mathematica itself).

The problem, and some solutions

The wobbly example function:

fun=Sin[t π/5]+Cos[t π]/2+Sin[2t π]/3

Evenly spaced samples, symmetric about the y axis.

Options[SymmetricTable]={SampleAtZero->True};

SymmetricTable[expr_,{i_,min_/;min<0,max_/;max>0,step_},OptionsPattern[]]:=Join[
Reverse[Table[expr,{i,-If[OptionValue@SampleAtZero,step,step/2],min,-step}]],
If[OptionValue@SampleAtZero,{expr/.i->0},{}],
Table[expr,{i,If[OptionValue@SampleAtZero,step,step/2],max,step}]
];
SetAttributes[SymmetricTable,HoldAll]

Generate evenly spaced samples for a given expression.

Sample[expr_,{i_,min_,max_,ξ_},opts:OptionsPattern[]]:=SymmetricTable[{i,expr},{i,min,max,1/ξ},opts];
SetAttributes[Sample,HoldAll]

The first example sampled function.

plot=With[
{samples=Sample[fun,{t,-5,5,24/10}]},
Show[
Plot[
fun,{t,-5,5},PlotLegends->Placed[{f[t]},Above],
Frame->True,GridLines->{#[[1]]&/@samples,None},
PlotRange->{{-5,5},Automatic},
FrameTicks->None
],
ListPlot[samples,PlotStyle->Black,PlotRange->{{-5,5},Automatic}]
]
];Export["/home/bitonic/src/website/assets/images/lanczos-example-fun.svg",plot];plot

A wrapper to render interpolations nicely (signal in blue, interpolation in gold).

PlotInterpolation[
fun_,{interp_,interpname_String},{x_,min_,max_,frequency_},legend_,opts:OptionsPattern[]
]:=With[
{samples=Sample[fun,{x,min-1/frequency,max+1/frequency,frequency},opts]},
Show[
Plot[
{fun,interp[samples]},{x,min,max},
PlotLegends->Placed[{legend[x],StringForm["``, ``",OverBar[legend][x],interpname]},Above],
Frame->True,
Frame->True,GridLines->{#[[1]]&/@samples,None},
PlotRange->{{min,max},Automatic},
FrameTicks->If[Length[samples]<
15,{{None,None},{{#[[1]],FractionToRow[#[[1]]]}&/@samples,None}},None]
],
ListPlot[samples,PlotStyle->Black,PlotRange->{{min,max},Automatic}]
]
];
SetAttributes[PlotInterpolation,HoldAll]

Linear interpolation examples.

plot=PlotInterpolation[fun,{(Interpolation[#,InterpolationOrder->1][t])&,"linear"},{t,-5,5,24/10},f];
Export["/home/bitonic/src/website/assets/images/lanczos-example-fun-linear.svg",plot];
plot

plot=PlotInterpolation[fun,{(Interpolation[#,InterpolationOrder->1][t])&,"linear"},{t,-5,5,32/10},f];
Export["/home/bitonic/src/website/assets/images/lanczos-example-fun-linear-more-samples.svg",plot];
plot

Cubic interpolation example.

plot=PlotInterpolation[fun,{(Interpolation[#,Method->"Spline"][t])&,"cubic"},{t,-5,5,22/10},f];
Export["/home/bitonic/src/website/assets/images/lanczos-example-fun-cubic.svg",plot];
plot

Interpolation and convolution

Display fractions on a single line (for higher legibility in legends).

FractionToRow=RawBoxes@*ReplaceAll[FractionBox->(RowBox[{#,"/",#2}]&)]@*ToBoxes@*TraditionalForm

Our sample function, again.

plot=With[
{samples=Sample[fun,{t,-2.5,2.5,10/5}]},
Show[
Plot[fun,{t,-2.5,2.5},PlotRange->{{-2.5,2.5},Automatic},PlotLegends->Placed[{f[t]},Above],FrameTicks->{{None,None},{N[#[[1]]]&/@samples,None}},Frame->True,GridLines->{#[[1]]&/@samples,None}
],
ListPlot[samples,PlotStyle->Black,PlotRange->{{-2.5,2.5},Automatic}],
ImageSize->Medium
]
];Export["/home/bitonic/src/website/assets/images/lanczos-evenly-spaced.svg",plot];plot

The triangle interpolation function.

plot=Plot[UnitTriangle[t],{t,-1.5,1.5},Ticks->{{{-1,FractionToRow[-1/ξ]},{1,FractionToRow[+1/ξ]}},{1}},PlotLegends->Placed[{FractionToRow[triangle[ξ t]]},Above],ImageSize->Medium];
Export["/home/bitonic/src/website/assets/images/lanczos-triangle.svg",plot];
plot

Given an interpolation function, a frequency, and a point, stretches it to the frequency, and centers it around the point.

ConvolutionFunctionForPoint[g0_,{x_,ξ_},x0_]:=g0/.x->((x-x0)*ξ);SetAttributes[ConvolutionFunctionForPoint,HoldAll]

Evaluates and plots a single point using convolution.

PlotConvolutionPoint[
f_,g0_,{x_,min_,max_,ξ_},n_,x0_,opts:OptionsPattern[]
]:=Module[
{g,fsamples,gsamples,convolved},
g=ConvolutionFunctionForPoint[g0,{x,ξ},x0];
fsamples=Sample[f,{x,min-1/ξ,max+1/ξ,ξ},Evaluate[FilterRules[{opts},Options[SymmetricTable]]]];
gsamples=Sample[g,{x ,-n ξ/2,n ξ/2,ξ},Evaluate[FilterRules[{opts},Options[SymmetricTable]]]];
convolved={#[[1]],(f/.x->#[[1]])#[[2]]}&/@gsamples;
Show[
Plot[
{f,g},
{x,min,max},
Evaluate[Join[
FilterRules[{opts},Options[Plot]],
{
PlotStyle->{ColorData[97,"ColorList"][[1]],ColorData[97,"ColorList"][[3]]},
PlotRange->{{min,max},Automatic},
Frame->True,
FrameTicks->{{{1},{1}},{{#[[1]],FractionToRow[#[[1]]]}&/@fsamples,None}},Frame->True,GridLines->{#[[1]]&/@fsamples,{1}}
}
]]
],
ListPlot[
{fsamples,Select[convolved,(#[[1]]>=min&&#[[1]]<=max)&],{{x0,Total[convolved][[2]]}}},
PlotStyle->{Black,ColorData[97,"ColorList"][[3]],ColorData[97,"ColorList"][[2]]},
PlotRange->{{min,max},Automatic}
]
]
];
SetAttributes[PlotConvolutionPoint,HoldAll]

Convolve was already taken by Mathematica, and mine is slightly different.

MyConvolve[g_,x_,samples_]:=
With[
{interval=samples[[2]][[1]]-samples[[1]][[1]]},
Total[(g[(x-#[[1]])/interval]#[[2]])&/@samples]
];
SetAttributes[MyConvolve,HoldAll]

Plots the whole convolution.

PlotConvolution[
fs0_,g_,{x_,min_,max_,ξ_},n_,opts:OptionsPattern[]
]:=Module[
{f,fs,samples,shownsamples,interpolated},
f=If[ListQ[fs0],fs0[[1]],fs0];
fs=If[ListQ[fs0],Drop[fs0,1],{}];
samples=Sample[f,{x,-n ξ/2,n ξ/2,ξ},Evaluate[FilterRules[{opts},Options[SymmetricTable]]]];
shownsamples=Select[samples,(#[[1]]>=min&&#[[1]]<=max)&];
interpolated=MyConvolve[g,x,samples];
Show[
Plot[
Evaluate[Join[{f,interpolated},fs]],
{x,min,max},
Evaluate[Join[
FilterRules[{opts},Options[Plot]],
{PlotRange->{{min,max},Automatic},
Frame->True,
FrameTicks->{{None,None},{{#[[1]],FractionToRow[#[[1]]]}&/@shownsamples,None}},
Frame->True,
GridLines->{#[[1]]&/@shownsamples,None}}
]]
],
ListPlot[
{shownsamples},
PlotStyle->{Black},
PlotRange->{{min,max},Automatic}
]
]
];
SetAttributes[PlotConvolution,HoldAll]

The samples do not change after convolutions (for well behaved interpolation functions).

plot=PlotConvolutionPoint[fun,UnitTriangle[t],{t,-2.5,2.5,2},100,-1.5,PlotLegends->Placed[{f[t],ConvolutionFunctionForPoint[triangle[t],{t,2},-1.5]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-triangle-1.svg",plot];plot

Visual aid for triangle = linear interpolation.

plot=PlotConvolutionPoint[fun,UnitTriangle[t],{t,-2.5,2.5,2},100,-1.8,PlotLegends->Placed[{f[t],ConvolutionFunctionForPoint[triangle[t],{t,2},-1.8]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-triangle-2.svg",plot];plot

plot=PlotConvolutionPoint[fun,UnitTriangle[t],{t,-2.5,2.5,2},100,1.8,PlotLegends->Placed[{f[t],ConvolutionFunctionForPoint[triangle[t],{t,2},1.8]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-triangle-3.svg",plot];plot

Full linear interpolation through convolution.

plot=PlotConvolution[fun,UnitTriangle,{t,-2.5,2.5,2},5,PlotLegends->Placed[{f[x],StringForm["``, ``",OverBar[f][x],triangle]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-triangle-linear.svg",plot];
plot

sinc, master interpolator

sinc in all its glory.

plot=Plot[Sinc[t],{t,-5*Pi,5*Pi},PlotRange->{{-5*Pi,5*Pi},{-0.3,1.1}},Frame->True,FrameTicks->{{None,1},{Table[i,{i,-5*Pi,5*Pi,Pi}],None}},GridLines->{Table[i,{i,-5*Pi,5*Pi, Pi}],{1}},PlotLegends->Placed[{Sinc[t]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc.svg",plot];
plot

Again, the samples stay put.

plot=PlotConvolutionPoint[fun,Sinc[π t],{t,-2.5,2.5,2},1000,-1.5,PlotLegends->Placed[{f[t],ConvolutionFunctionForPoint[Sinc[π t],{t,2},-1.5]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-1.svg",plot];plot

But in between, all other samples contribute to the interpolation.

plot=PlotConvolutionPoint[fun,Sinc[π t],{t,-1.8-2.5,-1.8+2.5,2},1000,-1.8,PlotLegends->Placed[{f[t],ConvolutionFunctionForPoint[Sinc[π t],{t,2},-1.8]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-2.svg",plot];plot

plot=PlotConvolutionPoint[fun,Sinc[π t],{t,1.8-2.5,1.8+2.5,2},100,1.8,PlotLegends->Placed[{f[t],ConvolutionFunctionForPoint[Sinc[π t],{t,2},1.8]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-3.svg",plot];plot

plot=PlotConvolution[fun,Sinc[π #]&,{t,-2.5,2.5,2},100,PlotLegends->Placed[{f[t],StringForm["``, sinc",OverBar[f][t]]},Above]];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-convolution.svg",plot];
plot

Fourier transform, and inverse.

FT[f_]:=FourierTransform[f,t,ξ,FourierParameters->{0, -2*Pi}];

IFT[f_]:=InverseFourierTransform[f,ξ,t,FourierParameters->{0, -2*Pi}];

sinc and triangle and their Fourier transforms, compared.

plot=Plot[{Sinc[π t],UnitTriangle[t]},{t,-4,4},PlotRange->{{-4,4},{-0.3,1.1}},Frame->True,PlotLegends->Placed[{Sinc[π t],triangle[t]},Above],GridLines->{Table[i,{i,-4,4}],{1}},FrameTicks->{{None,1},{Table[i,{i,-4,4}],None}}];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-vs-triangle.svg",plot];
plot

plot=Plot[{FT[Sinc[π t]],FT[UnitTriangle[t]]},{ξ,0,1},PlotLegends->Placed[{HoldForm[ℱ[sinc[π t]]],HoldForm[ℱ[triangle[t]]]},Above],Ticks->{Table[i,{i,0,1,0.25}], Table[i,{i,0,1,0.25}]},Filling->Bottom];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-vs-triangle-spectrum.svg",plot];
plot

Different width sincs  compared.

plot=Plot[{Sinc[π t],Sinc[π 2 t]},{t,-4,4},PlotRange->{{-4,4},{-0.3,1.1}},Frame->True,PlotLegends->Placed[{Sinc[π t],HoldForm[Sinc[π 2 t]]},Above],GridLines->{Table[i,{i,-4,4,0.5}],{1}},FrameTicks->{{None,1},{Table[i,{i,-4,4,0.5}],None}}];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-vs-sinc2.svg",plot];
plot

plot=Plot[{FT[Sinc[π t]],FT[Sinc[π 2 t]]},{ξ,0,1.25},PlotLegends->Placed[{HoldForm[ℱ[sinc[π t]]],HoldForm[ℱ[sinc[π 2 t]]]},Above],Ticks->{Table[i,{i,0,1.25,0.25}], Table[i,{i,0,1,0.25}]},Filling->Bottom];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-vs-sinc2-spectrum.svg",plot];
plot

Interpolating with sinc — an example

Our original function and its components.

fun

pploth[f_,color_]:=Plot[f, {t, -5, 5},PlotRange->{{-5,5},{-1,1}},Frame->True,FrameTicks->{{-5,5},{-1,1}},PlotStyle->color,LabelStyle->Black,ImageSize->Small,AspectRatio->1];
plot1=pploth[Sin[π t/5],ColorData[97,"ColorList"][[2]]];
Export["/home/bitonic/src/website/assets/images/lanczos-example-fun-harmonics-1.svg",plot1];
plot2=pploth[1/2*Cos[t π],ColorData[97,"ColorList"][[3]]];
Export["/home/bitonic/src/website/assets/images/lanczos-example-fun-harmonics-2.svg",plot2];
plot3 =pploth[1/3*Sin[2t π],ColorData[97,"ColorList"][[4]]];
Export["/home/bitonic/src/website/assets/images/lanczos-example-fun-harmonics-3.svg",plot3];
{plot1,plot2,plot3}

Its Fourier transform, made up of Dirac deltas.

FT[fun]

We can’t really plot the Dirac deltas, so let’s do it manually.

plot=ListPlot[{{{1/10, 1}},{{1/2,1/2}},{{1,1/3}}},Filling->Bottom,Ticks->{{#,InputForm[#]}&/@{1/10,1/2,1}, {#,InputForm[#]}&/@{1,1/2,1/3}},GridLines->{None,{1,1/2,1/3}},PlotStyle->{ColorData[97,"ColorList"][[2]],ColorData[97,"ColorList"][[3]],ColorData[97,"ColorList"][[4]]},AxesLabel->{"frequency","magnitude"}];
Export["/home/bitonic/src/website/assets/images/lanczos-example-fun-freqs.svg",plot];
plot

Show how we need to get past the highest-frequency Dirac delta to perfectly reconstruct the signal.

PlotReconstructed[f_,g_,{x_,min_,max_,ξ0_},n_,opts:OptionsPattern[]]:=
PlotConvolution[f,g,{x,min,max,ξ0},n,Evaluate[Join[{PlotLabel->Style[HoldForm[ξ=ξ0],Black,16],ImageSize->Medium,FrameTicks->None},{opts}]]]
SetAttributes[PlotReconstructed,HoldAll]

plot=With[
{n=1000},
Grid[{
{PlotReconstructed[fun, Sinc[# π]&, {t,-5,5,1},n],PlotReconstructed[fun, Sinc[# π]&, {t,-5,5,1.5},n]},
{PlotReconstructed[fun, Sinc[# π]&, {t,-5,5,2},n],PlotReconstructed[fun, Sinc[# π]&, {t,-5,5,2.01},n]}
}]
];
Export["/home/bitonic/src/website/assets/images/lanczos-reconstruct.svg",plot];
plot

The problem with sinc

Simple example of a jump discontinuity.

plot=Grid[{{Plot[Sign[t],{t, -5,5},PlotLegends->Placed[{Style[Sign[t],16]},Above],ImageSize->Medium],Plot[Evaluate[Abs[FT[Sign[t]]]],{ξ,0,1},Filling->Bottom,PlotLegends->Placed[{Style[ℱ[Sign[t]],16]},Above],PlotRange->{Automatic,{0,2}},ImageSize->Medium]}}];
Export["/home/bitonic/src/website/assets/images/lanczos-sign.svg",plot];
plot

Gibbs oscillations.

plot=With[
{n=1000},
Grid[{
{PlotReconstructed[Sign[t], Sinc[# π]&, {t,-3,3,1},n,SampleAtZero->False],PlotReconstructed[Sign[t], Sinc[# π]&, {t,-3,3,1.5},n,SampleAtZero->False]},
{PlotReconstructed[Sign[t], Sinc[# π]&, {t,-3,3,2},n,SampleAtZero->False],PlotReconstructed[Sign[t], Sinc[# π]&, {t,-3,3,4},n,SampleAtZero->False]}
}]
];
Export["/home/bitonic/src/website/assets/images/lanczos-reconstruct-sign.svg",plot];
plot

sinc -- chopped and screwed

Utility to truncate a function.

Truncate[a_,f_,t_]:=If[Abs[t]<=a,f,0];
SetAttributes[Truncate,HoldAll]

And our truncated (Subscript[sinc, 3]).

plot=Plot[Truncate[3,Sinc[π t],t], {t, -4, 4},PlotRange->{{-4,4},{-0.3,1.1}},Frame->True,PlotLegends->Placed[{(Subscript[sinc, 3])[π t]},Above],GridLines->{Table[i,{i,-4,4,1}],{1}},FrameTicks->{{None,1},{Table[i,{i,-4,4,1}],None}}];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-3-lobed.svg",plot];
plot

...which doesn’t interpolate so well.

plot=PlotConvolution[
Sign[t], Truncate[3,Sinc[# π],#]&, {t,-3,3,2},1000,
ImageSize->Medium,FrameTicks->None,SampleAtZero->False
];
Export["/home/bitonic/src/website/assets/images/lanczos-truncated-sinc-ringing.svg",plot];
plot

Gibbs oscillations redux -- this time in the spectrum of (Subscript[sinc, a]).

pplot=Hold[Plot[
Evaluate[{FT[Sinc[π t]],FT[Truncate[a,Sinc[π t], t]]}],
{ξ,0,0.75},
Ticks->{Table[i,{i,0,1.25,0.25}],{1}},
Filling->Axis,
ImageSize->Medium,
PlotLegends->Placed[{None,Style[HoldForm[ℱ[(Subscript[AngleBracket[sinc[π t]], a])]],FontSize->18]},Above],
AspectRatio->1,
LabelStyle->Directive[FontSize->14]
]];
plot=Grid[{{ReleaseHold[pplot/.a->3],ReleaseHold[pplot/.a->5],ReleaseHold[pplot/.a->10]}}];
Export["/home/bitonic/src/website/assets/images/lanczos-sinc-vs-truncated-spectrum.svg",plot];
plot

Error together with carrier wave.

plot=Plot[
Evaluate[{Abs[FT[Sinc[π t]]-FT[Truncate[3,Sinc[π t],t]]],Abs[Cos[π ξ 6]/20]}],{ξ,0,2},PlotRange->{Automatic,{0,0.15}},
PlotLegends->Placed[{
Abs[ℱ[Sinc[π t]]-ℱ[(Subscript[AngleBracket[sinc[π t]], 3])]],
HoldForm[Abs[Cos[2 π ξ 3]/20]]
},Above],
ImageSize->Medium,
Ticks->{Table[i,{i,1/12,2,1/6}],None},
AspectRatio->1/2.5
];
Export["/home/bitonic/src/website/assets/images/lanczos-carrier-wave.svg",plot];
plot

Smoothed spectrum using Lanczos’ method.

pplot=Hold[Plot[{FT[Sinc[π t]],Evaluate[FT[Truncate[a,Sinc[π t],t]]],Evaluate[a*Integrate[Evaluate[FT[Truncate[a,Sinc[π t],t]]/.ξ->x],{x,ξ-1/(2 a),ξ+1/(2 a)}]]},{ξ,0,0.75},Filling->Axis,Ticks->{{0,0.25,0.5,0.75},{1}},AspectRatio->1,ImageSize->Medium,LabelStyle->Directive[FontSize->14]]];
plot=Grid[{{ReleaseHold[pplot/.a->3],ReleaseHold[pplot/.a->5],ReleaseHold[pplot/.a->10]}}];
Export["/home/bitonic/src/website/assets/images/lanczos-smoothed-spectrum.svg",plot];
plot

pplot=Hold[Plot[{FT[Sinc[π t]],Evaluate[FT[Truncate[a,Sinc[π t],t]]],Evaluate[a*Integrate[Evaluate[FT[Truncate[a,Sinc[π t],t]]/.ξ->x],{x,ξ-1/(2 a),ξ+1/(2 a)}]]},{ξ,0,0.5},PlotRange->{{0,0.5},{0.9,1.1}},Filling->Axis,Ticks->{{0,0.25,0.5,0.75},{1}},ImageSize->Medium,LabelStyle->Directive[FontSize->14]]];
plot=Grid[{{ReleaseHold[pplot/.a->3],ReleaseHold[pplot/.a->5],ReleaseHold[pplot/.a->10]}}];
Export["/home/bitonic/src/website/assets/images/lanczos-smoothed-spectrum-zoom.svg",plot];
plot

sinc, (Subscript[sinc, 3]), and smoothed (Subscript[sinc, 3]) compared.

plot1=Plot[
{Sinc[π t],Truncate[3,Sinc[π t],t],Sinc[π t/3],Truncate[3,Sinc[π t]Sinc[π t/3],t]},
{t, -5,5},
PlotLegends->Placed[LineLegend[{None,HoldForm[(Subscript[AngleBracket[sinc[π t]], 3])],FractionToRow[Sinc[π t/3]],FractionToRow[HoldForm[(Subscript[AngleBracket[sinc[π t]], 3]) sinc[π t / 3]]]},LegendLayout->{"Row",1}],Above],
Frame->True,
GridLines->{Table[i,{i,-5,5,1}],{1}},FrameTicks->{{None,1},{Table[i,{i,-5,5,1}],None}},
PlotRange->{{-5,5},{-0.3,1.1}},
ImageSize->Medium,
PlotStyle->{Opacity[0.7,ColorData[97,"ColorList"][[1]]],ColorData[97,"ColorList"][[2]],Opacity[0.7,ColorData[97,"ColorList"][[4]]],ColorData[97,"ColorList"][[3]]}
];
plot2=Plot[
Evaluate[{
FT[Sinc[π t]],
FT[Truncate[3,Sinc[π t], t]],
FT[Truncate[3,Sinc[π t]Sinc[π t/3], t]]
}],
{ξ,0,1},
Filling->Axis,
ImageSize->Medium,
Ticks->{{0.25,0.5,0.75,1},{1}},
PlotLegends->Placed[LineLegend[{None,HoldForm[ℱ[(Subscript[AngleBracket[sinc[π t]], 3])]],FractionToRow[HoldForm[ℱ[(Subscript[AngleBracket[sinc[π t]], 3])sinc[π t /3]]]]},LegendLayout->{"Row",1}],Above],
PlotStyle->{Opacity[0.3,ColorData[97,"ColorList"][[1]]],ColorData[97,"ColorList"][[2]],ColorData[97,"ColorList"][[3]]}
];
plot=Grid[{{plot1,plot2}}];
Export["/home/bitonic/src/website/assets/images/lanczos-window.svg",plot];
plot

signplot[g_,gn_,n_]:=PlotConvolution[
Sign[t],g, {t,-2,2,2},n,
PlotLabel->Style[gn,Black,18],ImageSize->Medium,FrameTicks->None,SampleAtZero->False,
AspectRatio->1
];
plot1=signplot[Sinc[π #]&, sinc[t],1000];
plot2=signplot[Truncate[3,Sinc[π #],#]&, (Subscript[AngleBracket[sinc[t]], 3]),10];
plot3=signplot[Truncate[3,Sinc[π #]Sinc[π #/3],#]&, FractionToRow[HoldForm[(Subscript[AngleBracket[sinc[π t]], 3])sinc[π t /3]]],10];
plot=Grid[{{plot1,plot2,plot3}}];
Export["/home/bitonic/src/website/assets/images/lanczos-ringing-compare.svg",plot];
plot

Export["/home/bitonic/src/website/assets/other/lanczos.html", EvaluationNotebook[]];