```-----------------------------------------------------------------------------
-- |
-- Module      :  DSP.Filter.FIR.PolyInterp
--
-- Stability   :  experimental
-- Portability :  portable
--
-- Polynomial interpolators.  Taken from:
--
-- Olli Niemitalo (ollinie\@freenet.hut.fi), "Polynomial Interpolators for
-- High-Quality Resampling of Oversampled Audio" Search for "deip.pdf" with
-- Google and you will find it.
--
-----------------------------------------------------------------------------

-- TODO: limit the export list

-- TODO: figure out better way to create the coeficeints where you don't
-- have to explicitly state the number of interpolation points.

module DSP.Filter.FIR.PolyInterp where

import Data.Array

import Polynomial.Basic

-- | 'mkcoef' takes the continuous impluse response function (one of the
-- functions below, @f@) and number of points in the interpolation, @p@, time
-- shifts it by @x@, samples it, and creates an array with the interpolation
-- coeficients that can be used as a FIR filter.

mkcoef :: (Num a, Ix b, Integral b) => (a -> a) -- ^ f
-> b -- ^ p
-> a -- ^ x
-> Array b a -- ^ h[n]

mkcoef f p x = listArray (0,p-1) \$ map f [ x - fromIntegral i | i <- [p1..p2] ]
where p1 = -(p `div` 2 - 1)
p2 = p `div` 2

---------------------------------------------------------------------------------

-- The impulse responses, centered around zero

-- The following functions are named like

-- blah_ApBo or optimal_ApBoCx

-- A = number of points in the interpolation
-- B = the polynomial order
-- C = the oversampling rate that the function is designed for

---------------------------------------------------------------------------------

-- B-Splines

bspline_1p0o :: (Ord a, Fractional a) => a -> a
bspline_1p0o x | 0 <= x && x < 1 = polyeval [ 1 ] x
| otherwise       = 0

bspline_2p1o :: (Ord a, Fractional a) => a -> a
bspline_2p1o x | 0 <= x && x < 1 = polyeval [ 1, -1 ] x
| 1 <= x          = 0
| otherwise       = bspline_2p1o (-x)

bspline_4p3o :: (Ord a, Fractional a) => a -> a
bspline_4p3o x | 0 <= x && x < 1 = polyeval [ 2/3,  0, -1,  1/2 ] x
| 1 <= x && x < 2 = polyeval [ 4/3, -2,  1, -1/6 ] x
| 2 <= x          = 0
| otherwise       = bspline_4p3o (-x)

bspline_6p5o :: (Ord a, Fractional a) => a -> a
bspline_6p5o x | 0 <= x && x < 1 = polyeval [ 11/20,     0, -1/2,    0,  1/4,  -1/12 ] x
| 1 <= x && x < 2 = polyeval [ 17/40,   5/8, -7/4,  5/4, -3/8,   1/24 ] x
| 2 <= x && x < 3 = polyeval [ 81/40, -27/8,  9/4, -3/4,  1/8, -1/120 ] x
| 3 <= x          = 0
| otherwise       = bspline_6p5o (-x)

---------------------------------------------------------------------------------

-- Lagrange polynomials

lagrange_4p3o :: (Ord a, Fractional a) => a -> a
lagrange_4p3o x | 0 <= x && x < 1 = polyeval [ 1,  -1/2, -1,  1/2 ] x
| 1 <= x && x < 2 = polyeval [ 1, -11/6,  1, -1/6 ] x
| 2 <= x          = 0
| otherwise       = lagrange_4p3o (-x)

lagrange_6p5o :: (Ord a, Fractional a) => a -> a
lagrange_6p5o x | 0 <= x && x < 1 = polyeval [ 1,    -1/3, -5/4,   5/12,  1/4,  -1/12 ] x
| 1 <= x && x < 2 = polyeval [ 1,  -13/12, -5/8,  25/24, -3/8,   1/24 ] x
| 2 <= x && x < 3 = polyeval [ 1, -137/60, 15/8, -17/24,  1/8, -1/120 ] x
| 3 <= x          = 0
| otherwise       = lagrange_6p5o (-x)

---------------------------------------------------------------------------------

-- Hermite (1st-order-osculating) polynomials

hermite_4p3o :: (Ord a, Fractional a) => a -> a
hermite_4p3o x | 0 <= x && x < 1 = polyeval [ 1,  0, -5/2,  3/2 ] x
| 1 <= x && x < 2 = polyeval [ 2, -4,  5/2, -1/2 ] x
| 2 <= x          = 0
| otherwise       = hermite_4p3o (-x)

hermite_6p3o :: (Ord a, Fractional a) => a -> a
hermite_6p3o x | 0 <= x && x < 1 = polyeval [ 1,        0, -7/3,   4/3 ] x
| 1 <= x && x < 2 = polyeval [ 5/2, -59/12,    3, -7/12 ] x
| 2 <= x && x < 3 = polyeval [ -3/2,   7/4, -2/3,  1/12 ] x
| 3 <= x          = 0
| otherwise       = hermite_6p3o (-x)

hermite_6p5o :: (Ord a, Fractional a) => a -> a
hermite_6p5o x | 0 <= x && x < 1 = polyeval [ 1,     0, -25/12,   5/12, 13/12, -5/12 ] x
| 1 <= x && x < 2 = polyeval [ 1,  5/12,  -35/8,   35/8, -13/8,  5/24 ] x
| 2 <= x && x < 3 = polyeval [ 3, -29/4, 155/24, -65/24, 13/24, -1/24 ] x
| 3 <= x          = 0
| otherwise       = hermite_6p5o (-x)

---------------------------------------------------------------------------------

-- 2nd-order-osculating polynomials

sndosc_4p5o :: (Ord a, Fractional a) => a -> a
sndosc_4p5o x | 0 <= x && x < 1 = polyeval [  1, 0,   -1, -9/2,  15/2, -3 ] x
| 1 <= x && x < 2 = polyeval [ -4, 18, -29, 43/2, -15/2,  1 ] x
| 2 <= x          = 0
| otherwise       = sndosc_4p5o (-x)

sndosc_6p5o :: (Ord a, Fractional a) => a -> a
sndosc_6p5o x | 0 <= x && x < 1 = polyeval [  1,      0,   -5/4,  -35/12,  21/4, -25/12 ] x
| 1 <= x && x < 2 = polyeval [ -4,   75/4, -245/8,  545/24, -63/8,  25/24 ] x
| 2 <= x && x < 3 = polyeval [ 18, -153/4,  255/8, -313/24,  21/8,  -5/24 ] x
| 3 <= x          = 0
| otherwise       = sndosc_6p5o (-x)

---------------------------------------------------------------------------------

-- Misc

watte_4p2o :: (Ord a, Fractional a) => a -> a
watte_4p2o x | 0 <= x && x < 1 = polyeval [ 1, -1/2, -1/2 ] x
| 1 <= x && x < 2 = polyeval [ 1, -3/2,  1/2 ] x
| 2 <= x          = 0
| otherwise       = watte_4p2o (-x)

parabolic2x_4p2o :: (Ord a, Fractional a) => a -> a
parabolic2x_4p2o x | 0 <= x && x < 1 = polyeval [ 1/2, 0, -1/4 ] x
| 1 <= x && x < 2 = polyeval [ 1,  -1,  1/4 ] x
| 2 <= x          = 0
| otherwise       = parabolic2x_4p2o (-x)

---------------------------------------------------------------------------------

-- Optimal designs

optimal_2p3o2x :: (Ord a, Fractional a) => a -> a
optimal_2p3o2x x | 0 <= x && x < 1 = polyeval [ 0.80607906469176971, 0.17594740788514596,
-2.35977550974341630, 1.57015627178718420 ] x
| 1 <= x          = 0
| otherwise       = optimal_2p3o2x (-x)

optimal_2p3o4x :: (Ord a, Fractional a) => a -> a
optimal_2p3o4x x | 0 <= x && x < 1 = polyeval [ 0.88207975731800936, -0.10012219395448523,
-1.99054787320203810, 1.32598918957298410 ] x
| 1 <= x          = 0
| otherwise       = optimal_2p3o4x (-x)

optimal_2p3o8x :: (Ord a, Fractional a) => a -> a
optimal_2p3o8x x | 0 <= x && x < 1 = polyeval [ 0.94001491168487883, -0.51213628865925998,
-1.10319974084152170, 0.73514591836770027 ] x
| 1 <= x          = 0
| otherwise       = optimal_2p3o8x (-x)

optimal_2p3o16x :: (Ord a, Fractional a) => a -> a
optimal_2p3o16x x | 0 <= x && x < 1 = polyeval [ 0.96964782067188493, -0.74617479745643256,
-0.57923093055631791, 0.38606621963374965 ] x
| 1 <= x          = 0
| otherwise       = optimal_2p3o16x (-x)

optimal_2p3o32x :: (Ord a, Fractional a) => a -> a
optimal_2p3o32x x | 0 <= x && x < 1 = polyeval [ 0.98472017575676363, -0.87053863725307623,
-0.29667081825572522, 0.19775766248673177 ] x
| 1 <= x          = 0
| otherwise       = optimal_2p3o32x (-x)

optimal_4p2o2x :: (Ord a, Fractional a) => a -> a
optimal_4p2o2x x | 0 <= x && x < 1 = polyeval [ 0.50061662213752656, -0.04782068534965925,
-0.21343978756177684 ] x
| 1 <= x && x < 2 = polyeval [ 0.92770135528027386, -0.88689658749623701,
0.21303593243799016  ] x
| 2 <= x          = 0
| otherwise       = optimal_4p2o2x (-x)

optimal_4p2o4x :: (Ord a, Fractional a) => a -> a
optimal_4p2o4x x | 0 <= x && x < 1 = polyeval [ 0.33820365736567115, 0.2114449807519728,
-0.22865399531858188  ] x
| 1 <= x && x < 2 = polyeval [ 1.12014639874555470, -1.01414466618792900,
0.22858390767180370  ] x
| 2 <= x          = 0
| otherwise       = optimal_4p2o4x (-x)

optimal_4p2o8x :: (Ord a, Fractional a) => a -> a
optimal_4p2o8x x | 0 <= x && x < 1 = polyeval [ 0.09224718574204172, 0.59257579283164508,
-0.24005206207889518  ] x
| 1 <= x && x < 2 = polyeval [ 1.38828036063664320, -1.17126532964206100,
0.24004281672637814  ] x
| 2 <= x          = 0
| otherwise       = optimal_4p2o8x (-x)

optimal_4p2o16x :: (Ord a, Fractional a) => a -> a
optimal_4p2o16x x | 0 <= x && x < 1 = polyeval [ -0.41849525763976203, 1.36361593203840510,
-0.24506117865474364  ] x
| 1 <= x && x < 2 = polyeval [ 1.90873339502208310, -1.44144384373471430,
0.24506002360805534  ] x
| 2 <= x          = 0
| otherwise       = optimal_4p2o16x (-x)

optimal_4p2o32x :: (Ord a, Fractional a) => a -> a
optimal_4p2o32x x | 0 <= x && x < 1 = polyeval [ -1.42170796824052890, 2.87083485132510450,
-0.24755243839713828 ] x
| 1 <= x && x < 2 = polyeval [ 2.91684291662070860, -1.95043794419108290,
0.24755229501840223 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p2o32x (-x)

optimal_4p3o2x :: (Ord a, Fractional a) => a -> a
optimal_4p3o2x x | 0 <= x && x < 1 = polyeval [ 0.59244492420272321, 0.03573669883299365,
-0.78664888597764893, 0.36030925263849456 ] x
| 1 <= x && x < 2 = polyeval [ 1.20220428331406090, -1.60101160971478710,
0.70401463131621556, -0.10174985775982505 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p3o2x (-x)

optimal_4p3o4x :: (Ord a, Fractional a) => a -> a
optimal_4p3o4x x | 0 <= x && x < 1 = polyeval [ 0.60304009430474115, 0.05694012453786401,
-0.89223007211175309, 0.42912649274763925 ] x
| 1 <= x && x < 2 = polyeval [ 1.31228823423882930, -1.85072890189700660,
0.87687351895686727, -0.13963062613760227 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p3o4x (-x)

optimal_4p3o8x :: (Ord a, Fractional a) => a -> a
optimal_4p3o8x x | 0 <= x && x < 1 = polyeval [ 0.60658368706046584, 0.07280793921972525,
-0.95149675410360302, 0.46789242171187317 ] x
| 1 <= x && x < 2 = polyeval [ 1.35919815911169020, -1.95618744839533010,
0.94949311590826524, -0.15551896027602030 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p3o8x (-x)

optimal_4p3o16x :: (Ord a, Fractional a) => a -> a
optimal_4p3o16x x | 0 <= x && x < 1 = polyeval [ 0.60844825096346644, 0.07980169577604959,
-0.97894238166068270, 0.48601256046234864 ] x
| 1 <= x && x < 2 = polyeval [ 1.37724137476464990, -1.99807048591354810,
0.97870442828560433, -0.16195131297091253 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p3o16x (-x)

optimal_4p3o32x :: (Ord a, Fractional a) => a -> a
optimal_4p3o32x x | 0 <= x && x < 1 = polyeval [ 0.60908264223655417, 0.08298544053689563,
-0.99052586766084594, 0.49369595780454456 ] x
| 1 <= x && x < 2 = polyeval [ 1.38455689452848450, -2.01496368680360890,
0.99049753216621961, -0.16455902278580614 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p3o32x (-x)

optimal_4p4o2x :: (Ord a, Fractional a) => a -> a
optimal_4p4o2x x | 0 <= x && x < 1 = polyeval [ 0.58448510036125145, 0.04442540676862300,
-0.7586487041827807, 0.29412762852131868,
0.04252164479749607 ] x
| 1 <= x && x < 2 = polyeval [ 1.06598379704160570, -1.16581445347275190,
0.21256821036268256, 0.13781898240764315,
-0.04289144034653719 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p4o2x (-x)

optimal_4p4o4x :: (Ord a, Fractional a) => a -> a
optimal_4p4o4x x | 0 <= x && x < 1 = polyeval [ 0.61340295990566229, 0.06128937679587994,
-0.94057832565094635, 0.44922093286355397,
0.00986988334359864 ] x
| 1 <= x && x < 2 = polyeval [ 1.30835018075821670, -1.82814511658458520,
0.81943257721092366, -0.09642760567543440,
-0.00989340017126506 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p4o4x (-x)

optimal_4p4o8x :: (Ord a, Fractional a) => a -> a
optimal_4p4o8x x | 0 <= x && x < 1 = polyeval [ 0.62095991632974834, 0.06389302461261143,
-0.98489647972932193, 0.48698871865064902,
0.00255074537015887 ] x
| 1 <= x && x < 2 = polyeval [ 1.35943398999940390, -1.97277963497287720,
0.95410568622888214, -0.14868053358928229,
-0.00255226912537286 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p4o8x (-x)

optimal_4p4o16x :: (Ord a, Fractional a) => a -> a
optimal_4p4o16x x | 0 <= x && x < 1 = polyeval [ 0.62293049365660191, 0.06443376638262904,
-0.99620011474430481, 0.49672182806667398,
0.00064264050033187 ] x
| 1 <= x && x < 2 = polyeval [ 1.37216269878963180, -2.00931632449031920,
0.98847675044522398, -0.16214364417487748,
-0.00064273459469381 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p4o16x (-x)

optimal_4p4o32x :: (Ord a, Fractional a) => a -> a
optimal_4p4o32x x | 0 <= x && x < 1 = polyeval [ 0.62342449465938121, 0.06456923251842608,
-0.99904509583176049, 0.49917660509564427,
0.00016095224137360 ] x
| 1 <= x && x < 2 = polyeval [ 1.37534629142898650, -2.01847637982642340,
0.99711292321092770, -0.16553360612350931,
-0.00016095810460478 ] x
| 2 <= x          = 0
| otherwise       = optimal_4p4o32x (-x)

optimal_6p4o2x :: (Ord a, Fractional a) => a -> a
optimal_6p4o2x x | 0 <= x && x < 1 = polyeval [ 0.42640922432669054, -0.0052558029434142,
-0.20486985491012843, 0.00255494211547300,
0.03134095684084392 ] x
| 1 <= x && x < 2 = polyeval [ 0.30902529029941583, 0.37868437559565432,
-0.70564644117967990, 0.31182026815653541,
-0.04385804833432710 ] x
| 2 <= x && x < 3 = polyeval [ 1.51897639740576910, -1.83761742915820410,
0.83217835730406542, -0.16695522597587154,
0.01249475765486819 ] x
| 3 <= x          = 0
| otherwise       = optimal_6p4o2x (-x)

optimal_6p4o4x :: (Ord a, Fractional a) => a -> a
optimal_6p4o4x x | 0 <= x && x < 1 = polyeval [ 0.20167941634921072, -0.06119274485321008,
0.56468711069379207, -0.42059475673758634,
0.02881527997393852 ] x
| 1 <= x && x < 2 = polyeval [ -0.64579641436229407, 2.33580825807694700,
-1.85350543411307390, 0.51926458031522660,
-0.04250898918476453 ] x
| 2 <= x && x < 3 = polyeval [ 2.76228852293285200, -3.09936092833253300,
1.27147464005834010, -0.22283280665600644,
0.01369173779618459 ] x
| 3 <= x          = 0
| otherwise       = optimal_6p4o4x (-x)

optimal_6p4o8x :: (Ord a, Fractional a) => a -> a
optimal_6p4o8x x | 0 <= x && x < 1 = polyeval [ -0.17436452172055789, -0.15190225510786248,
1.87551558979819120, -1.15976496200057480,
0.03401038103941584 ] x
| 1 <= x && x < 2 = polyeval [ -2.26955357035241170, 5.73320660746477540,
-3.92391712129699590, 0.93463067895166918,
-0.05090907029392906 ] x
| 2 <= x && x < 3 = polyeval [ 4.84834508915762540, -5.25661448354449060,
2.04584149450148180, -0.32814290420019698,
0.01689861603514873 ] x
| 3 <= x          = 0
| otherwise       = optimal_6p4o8x (-x)

optimal_6p4o16x :: (Ord a, Fractional a) => a -> a
optimal_6p4o16x x | 0 <= x && x < 1 = polyeval [ -0.94730014688427577, -0.33649680079382827,
4.53807483241466340, -2.64598691215356660,
0.03755086455339280 ] x
| 1 <= x && x < 2 = polyeval [ -5.55035312316726960, 12.52871168241192600,
-7.98288364772738750, 1.70665858343069510,
-0.05631219122315393 ] x
| 2 <= x && x < 3 = polyeval [ 8.94785524286246310, -9.37021675593126700,
3.44447036756440590, -0.49470749109917245,
0.01876132424143207 ] x
| 3 <= x          = 0
| otherwise       = optimal_6p4o16x (-x)

optimal_6p4o32x :: (Ord a, Fractional a) => a -> a
optimal_6p4o32x x | 0 <= x && x < 1 = polyeval [ -2.44391738331193720, -0.69468212315980082,
9.67889243081689440, -5.50592307590218160,
0.03957507923965987 ] x
| 1 <= x && x < 2 = polyeval [ -11.87524595267807600, 25.58633277328986500,
-15.73068663442630400, 3.15288929279855570,
-0.05936083498715066 ] x
| 2 <= x && x < 3 = polyeval [ 16.79403235763479100, -17.17264148794549100,
6.05175140696421730, -0.79053754554850286,
0.01978575568000696 ] x
| 3 <= x          = 0
| otherwise       = optimal_6p4o32x (-x)

optimal_6p5o2x :: (Ord a, Fractional a) => a -> a
optimal_6p5o2x x | 0 <= x && x < 1 = polyeval [ 0.48217702203158502, -0.00127577239632662,
-0.3267507171395277, -0.02014846731685776,
0.14640674192652170, -0.04317950185225609 ] x
| 1 <= x && x < 2 = polyeval [ 0.35095903476754237, 0.53534756396439365,
-1.22477236472789920, 0.74995484587342742,
-0.19234043023690772, 0.01802814255926417 ] x
| 2 <= x && x < 3 = polyeval [ 1.62814578813495040, -2.26168360510917840,
1.22220278720010690, -0.31577407091450355,
0.03768876199398620, -0.00152170021558204 ] x
| 3 <= x          = 0
| otherwise       = optimal_6p5o2x (-x)

optimal_6p5o4x :: (Ord a, Fractional a) => a -> a
optimal_6p5o4x x | 0 <= x && x < 1 = polyeval [ 0.50164509338655083, -0.00256790184606694,
-0.36229943140977111, -0.04512026308730401,
0.20620318519804220, -0.06607747864416924 ] x
| 1 <= x && x < 2 = polyeval [ 0.30718330223223800, 0.78336433172501685,
-1.66940481896969310, 1.08365113099941970,
-0.30560854964737405, 0.03255079211953620 ] x
| 2 <= x && x < 3 = polyeval [ 2.05191571792256240, -3.19403437421534920,
1.99766476840488070, -0.62765808573554227,
0.09909173357642603, -0.00628989632244913 ] x
| 3 <= x          = 0
| otherwise       = optimal_6p5o4x (-x)

optimal_6p5o8x :: (Ord a, Fractional a) => a -> a
optimal_6p5o8x x | 0 <= x && x < 1 = polyeval [ 0.50513183702821474, -0.00368143670114908,
-0.36434084624989699, -0.06070462616102962,
0.22942797169644802, -0.07517133281176167 ] x
| 1 <= x && x < 2 = polyeval [ 0.28281884957695946, 0.88385964850687193,
-1.82581238657617080, 1.19588167464050650,
-0.34363487882262922, 0.03751837438141215 ] x
| 2 <= x && x < 3 = polyeval [ 2.15756386503245070, -3.42137079071284810,
2.18592382088982260, -0.70370361187427199,
0.11419603882898799, -0.00747588873055296 ] x
| 3 <= x          = 0
| otherwise       = optimal_6p5o8x (-x)

optimal_6p5o16x :: (Ord a, Fractional a) => a -> a
optimal_6p5o16x x | 0 <= x && x < 1 = polyeval [ 0.50819303579369868, -0.00387117789818541,
-0.36990908725555449, -0.06616250180411522,
0.24139298776307896, -0.07990500783668089 ] x
| 1 <= x && x < 2 = polyeval [ 0.27758734130911511, 0.91870010875159547,
-1.89281840112089440, 1.24834464824612510,
-0.36203450650610985, 0.03994519162531633   ] x
| 2 <= x && x < 3 = polyeval [ 2.19284545406407450, -3.50786533926449100,
2.26228244623301580, -0.73559668875725392,
0.12064126711558003, -0.00798609327859495   ] x
| 3 <= x          = 0
| otherwise       = optimal_6p5o16x (-x)

optimal_6p5o32x :: (Ord a, Fractional a) => a -> a
optimal_6p5o32x x | 0 <= x && x < 1 = polyeval [ 0.52558916128536759, 0.00010896283126635,
-0.42682321682847008, -0.04095676092513167,
0.25041444762720882, -0.08349799235675044 ] x
| 1 <= x && x < 2 = polyeval [ 0.33937904183610190, 0.80946953063234006,
-1.86228986389877100, 1.27215033630638800,
-0.37562266426589430, 0.04174912841630993 ] x
| 2 <= x && x < 3 = polyeval [ 2.13606003964474490, -3.48774662195185850,
2.28912105276248390, -0.75510203509083995,
0.12520821766375972, -0.00834987866042734  ] x
| 3 <= x          = 0
| otherwise       = optimal_6p5o32x (-x)

---------------------------------------------------------------------------------

{-------------------

Test routines

y = [ sin \$ 0.345 + 0.1234 * fromIntegral i | i <- [0..10] ]

h1 = mkcoef bspline_4p3o     4 0.2
h2 = mkcoef hermite_4p3o     4 0.2
h3 = mkcoef lagrange_4p3o    4 0.2
h4 = mkcoef hermite_4p3o     4 0.2
h5 = mkcoef sndosc_4p5o      4 0.2
h6 = mkcoef watte_4p2o       4 0.2
h7 = mkcoef parabolic2x_4p2o 4 0.2

h8  = mkcoef bspline_6p5o  6 0.2
h9  = mkcoef lagrange_6p5o 6 0.2
h10 = mkcoef hermite_6p3o  6 0.2
h11 = mkcoef hermite_6p5o  6 0.2
h12 = mkcoef sndosc_6p5o   6 0.2

h2p3o2x  = mkcoef optimal_2p3o2x  2 0.2
h2p3o4x  = mkcoef optimal_2p3o4x  2 0.2
h2p3o8x  = mkcoef optimal_2p3o8x  2 0.2
h2p3o16x = mkcoef optimal_2p3o16x 2 0.2
h2p3o32x = mkcoef optimal_2p3o32x 2 0.2

h4p2o2x  = mkcoef optimal_4p2o2x  4 0.2
h4p2o4x  = mkcoef optimal_4p2o4x  4 0.2
h4p2o8x  = mkcoef optimal_4p2o8x  4 0.2
h4p2o16x = mkcoef optimal_4p2o16x 4 0.2
h4p2o32x = mkcoef optimal_4p2o32x 4 0.2

h4p3o2x  = mkcoef optimal_4p3o2x  4 0.2
h4p3o4x  = mkcoef optimal_4p3o4x  4 0.2
h4p3o8x  = mkcoef optimal_4p3o8x  4 0.2
h4p3o16x = mkcoef optimal_4p3o16x 4 0.2
h4p3o32x = mkcoef optimal_4p3o32x 4 0.2

h4p4o2x  = mkcoef optimal_4p4o2x  4 0.2
h4p4o4x  = mkcoef optimal_4p4o4x  4 0.2
h4p4o8x  = mkcoef optimal_4p4o8x  4 0.2
h4p4o16x = mkcoef optimal_4p4o16x 4 0.2
h4p4o32x = mkcoef optimal_4p4o32x 4 0.2

h6p4o2x  = mkcoef optimal_6p4o2x  4 0.2
h6p4o4x  = mkcoef optimal_6p4o4x  4 0.2
h6p4o8x  = mkcoef optimal_6p4o8x  4 0.2
h6p4o16x = mkcoef optimal_6p4o16x 4 0.2
h6p4o32x = mkcoef optimal_6p4o32x 4 0.2

h6p5o2x  = mkcoef optimal_6p5o2x  4 0.2
h6p5o4x  = mkcoef optimal_6p5o4x  4 0.2
h6p5o8x  = mkcoef optimal_6p5o8x  4 0.2
h6p5o16x = mkcoef optimal_6p5o16x 4 0.2
h6p5o32x = mkcoef optimal_6p5o32x 4 0.2

interpolate y h = sum \$ zipWith (*) y (elems h)

x1  = sin \$ 0.345 + 0.1234 * 1.2
x1' = map (interpolate y) [ h1, h2, h3, h4, h5, h6, h7 ]

x2  = sin \$ 0.345 + 0.1234 * 2.2
x2' = map (interpolate y) [ h8, h9, h10, h11, h12 ]

The values of all these lists should be one, or nearly one.  They
aren't for the 6p4o optimal designs, but I'm not sure why.  Olli's
paper states that these are a little screwy, though.

h_test = map (sum . elems) [ h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11, h12 ]
h2p3o_test = map (sum . elems) [ h2p3o2x, h2p3o4x, h2p3o8x, h2p3o16x, h2p3o32x ]
h4p2o_test = map (sum . elems) [ h4p2o2x, h4p2o4x, h4p2o8x, h4p2o16x, h4p2o32x ]
h4p3o_test = map (sum . elems) [ h4p4o2x, h4p4o4x, h4p4o8x, h4p4o16x, h4p4o32x ]
h4p4o_test = map (sum . elems) [ h4p4o2x, h4p4o4x, h4p4o8x, h4p4o16x, h4p4o32x ]
h6p4o_test = map (sum . elems) [ h6p4o2x, h6p4o4x, h6p4o8x, h6p4o16x, h6p4o32x ]
h6p5o_test = map (sum . elems) [ h6p5o2x, h6p5o4x, h6p5o8x, h6p5o16x, h6p5o32x ]

-------------------}
```