• Welcome to the new Internet Infidels Discussion Board, formerly Talk Freethought.

Correlation With Python

steve_bank

Diabetic retinopathy and poor eyesight. Typos ...
Joined
Nov 9, 2017
Messages
13,869
Location
seattle
Basic Beliefs
secular-skeptic
Correlation

rhttps://en.wikipedia.org/wiki/Cross-correlation


How it works. In the case of a sine wave when a frequency component of a signal matches the correlation sine the signs of each point match so the product is always positive. When signal components and correlation points do not match in sign the summation is zero or close to it.

w = 2*ma.pi*fr[f]/n divides the sine curve of the correlation function into n pieces.
for j in range(ncor):s = s + y[j+i]*ma.sin(w*j) does the correlation

Code:
import array as ar
import matplotlib.pyplot as plt
import math as ma
import random as rn

n = 1000
tmax = 1
dt = tmax/(n-1)
t = ar.array("d",n*[0])
for i in range(n):t[i] = (i-1)*dt
corr = ar.array("d",n*[0])
y = ar.array("d",n*[0])
fr = ar.array("i",n*[0])

A1 = 1.
A2 = 2.
A3 = 1.5
f1 = 4.
f2 = 8.
f3 = 10.
#3 signals andsone noise
for i in range(n):
        y[i] = A1*ma.sin(2.*ma.pi*f1*t[i])
        y[i] = y[i] + A2*ma.sin(2*ma.pi*f2*t[i])
        y[i] = y[i] + A3*ma.sin(2*ma.pi*f3*t[i])
        y[i] = y[i] + rn.random() *10

nfreqs = 10
for f in range(nfreqs):
        fr[f] = f+1
        s = 0
        w = 2*ma.pi*fr[f]/n #divide the argument into n peces
        for j in range(n):s = s + y[j]*ma.sin(w*j)
        corr[f] = 2.*abs(s)/n

print("Frequency \tCorrelation")
for i in range(nfreqs):
        print("%2d \t\t%.5f" %(fr[i],corr[i]))

[fig, p] = plt.subplots(2,1)
p[0].plot(t,y,color='k')
p[0].grid(which='major', color='k',linestyle='--', linewidth=.4)
p[1].vlines(fr,0,corr,colors = 'k')
p[1].grid(which='major', color='k',linestyle='--', linewidth=.4)
plt.show()

Frequency     Correlation
 1         0.10326
 2         0.08844
 3         0.00683
 4         0.99624
 5         0.11656
 6         0.22281
 7         0.09948
 8         2.09447
 9         0.12480
10         1.55338
 
A simple simulation of SONAR. You are on a sub and send out a SONAR pulse looking for the bad guys. The bad guys send a false echo but it is slightly off frequency, and transmits broad band acoustic noise.


Code:
import array as ar
import matplotlib.pyplot as plt
import math as ma
import random as rn


n = 10000
f1 = 10.5  #false echo frequency
f2 = 10     #echo frequency
ncor =1000
threshold = 480
v = 1.5  # speed of sound in water km/s
corr = ar.array("d",n*[0])
y = ar.array("d",n*[0])
detect = ar.array("d",n*[0])
distance = ar.array("d",n*[0])
tmax = 10
dt = tmax/(n-1)
t = ar.array("d",n*[0])
for i in range(n):t[i] = (i-1)*dt

tsum1 = 0
tsum2 = 0
for i in range(n):
    #false echo
    if t[i] > 2 and t[i] < 3:
        y[i] = ma.sin(2*ma.pi*f1*tsum1)
        tsum1 += dt
     #echo
    if t[i] > 6 and t[i] < 7:
        y[i] = ma.sin(2*ma.pi*f2*tsum2)
        tsum2 += dt
    y[i] += rn.random()
    distance[i] = t[i]*v

w = 2*ma.pi*f2/ncor
for i in range(n-ncor):
        s = 0
        for j in range(ncor):s = s + y[j+i]*ma.sin(w*j)
        corr[i] = abs(s)
        if corr[i] > threshold: detect[i] = 1
        
[fig, p] = plt.subplots(3,1)
p[0].plot(t,y,color='k')
p[0].grid(which='major', color='k',linestyle='--', linewidth=.4)
p[1].vlines(t,0,corr,colors = 'k')
p[1].grid(which='major', color='k',linestyle='--', linewidth=.4)
p[2].vlines(distance,0,detect,colors = 'k')
p[2].grid(which='major', color='k',linestyle='--', linewidth=.4)
p[2].set_xlabel("Target Range Kilometers")
plt.show()
 
Had a try at the correlation logic using vectorised functions.

Runs about 30% faster, which is not as much as I would have hoped for. Maybe it can be optimised further?

Python:
import matplotlib.pyplot as plt
import math
import numpy as np
import random

n = 10_000_000 # Takes about 33s to run on my machine.
nfreqs = 10
tmax = 1


def gen_signal(t):
    A1 = 1.0
    A2 = 2.0
    A3 = 1.5
    f1 = 4.0
    f2 = 8.0
    f3 = 10.0

    y = A1 * math.sin(math.tau * f1 * t)
    y = y + A2 * math.sin(math.tau * f2 * t)
    y = y + A3 * math.sin(math.tau * f3 * t)
    y = y + random.random() * 10
    return y


t = np.arange(0, n) / (n - 1)
y = np.vectorize(gen_signal)(t)
k = np.arange(0, n)
fr = range(1, nfreqs + 1)


def correlate(f, y):
    w = math.tau * f / n
    x = np.vectorize(lambda j: math.sin(w * j))(k)
    return 2.0 * abs(np.sum(y * x)) / n


corr = [correlate(f, y) for f in fr]

print("Frequency \tCorrelation")
for f, c in zip(fr, corr):
    print("%2d \t\t%.5f" % (f, c))
 
I do not know on optimization, I am not a Python expert. I post with it because it is a common tool people use. I stick to basic C like structure with Python.

My regular math tool was Scilab. You might want to take look at it, it is in the public domain. A compete package with graphics. Better for matrix operations than Python. Similar to Matlab but free.

For speed I would code in C/C++.
 
Back
Top Bottom