## L505
## Joan Ginés i Ametllé

'''
Modify the functions D4trend(f) and D4fluct(f) to
functions D4trend(f,r=1) and D4fluct(f,r=1)
that compute the trend and fluctuation for any
level r. Ditto for D4 (iterative version).
Include examples for r=2 and r=3.
''' 

#import sys
#sys.path.append("/home/joan/CDI/module/")

import sympy as sy
from math import *
from numpy import *
from cdi_haar import *
from matplotlib.pyplot import *


splice= np.hstack
stack = np.vstack

# Daubechies transform (D4)
r2 = sqrt(2); r3 = sqrt(3)
d = 4*r2

a1 = (1+r3)/d; a2 = (3+r3)/d
a3 = (3-r3)/d; a4 = (1-r3)/d
[b1,b2,b3,b4] = [a4,-a3,a2,-a1]


def D4trend(f,r=1):
    N = len(f)
    f = list(f)
    if r == 0: return array(f)
    if N%2**r: return 'D4trend: %d is not divisible by 2**(%d)'%(N,r)
    if r == 1: 
        f += f[:2]
        return array([a1*f[2*j]+a2*f[2*j+1]+a3*f[(2*j+2)%N]+a4*f[(2*j+3)%N] for j in range (N//2)])
    else:
        return D4trend(D4trend(f),r-1)


def D4fluct(f,r=1):
    N = len(f)
    f = list(f)
    if r == 0: return zeros(N)
    if N%2**r: return 'D4fluct: %d is not divisible by 2**(%d)'%(N,r)
    if r == 1: 
        f += f[:2]
        return array([b1*f[2*j]+b2*f[2*j+1]+b3*f[(2*j+2)%N]+b4*f[(2*j+3)%N] for j in range (N//2)])
    else:
        return D4fluct(D4trend(f),r-1)

    
def D4(f,r=1):
    N = len(f)
    f = list(f)
    if r == 0: return array(f)
    if N%2**r: return 'D4: %d is not divisible by 2**(%d)'%(N,r)
    d = []
    while r >= 1:
        a = D4trend(f)
        d = splice([D4fluct(f),d])
        f = a
        r -= 1
    return splice([a,d])
    
# Examples 
F = lambda x: cos(32*atan(1)*x)*sin(8*atan(1)*x**2)

X = arange(0.0, 1.0, 0.001)
Y = [F(x) for x in X]

close('all')
fig, axes = subplots(nrows=3, ncols=1)
fig.tight_layout()

for r in range(1,4):
    D4Y = D4(Y,r)
    subplot(3,1,r, title = "D4 transform level " + str(r))
    plot(X, D4Y, color = 'g', lw = 1)
    grid('on')
    
