Creating a function to get values for an s-shaped curve - python

I would like to create a pyhton script that simulates sunrise for some of my Philips Hue lights connected to Home Assistant.
What I'm trying to achieve is to follow a sigmoid / s-shaped curve for the brightness and kelvin values.
I would like the brightness to go from 1 to 100 (%), and the Kelvin values to go from 2500 to 4000.
My current script is doing this in a linear way:
#import time
def sunrise(entity_id, minutes, updatesecs=10, startbrightness=1, endbrightness=100, startkelvin=2500, endkelvin=4000):
# Set current brightness and kelvin to the staring values
currentbrightness=startbrightness
currentkelvin=startkelvin
# Calculate the needed iterations for the while loop
numberofiterations=minutes*60/updatesecs
kelvinincreasebyiteration=(endkelvin-startkelvin)/numberofiterations
i=0
while(i<=numberofiterations):
# Set new brightness value
currentbrightness = currentbrightness+endbrightness/numberofiterations
currentkelvin = currentkelvin+kelvinincreasebyiteration
if currentbrightness <= endbrightness:
#print(round(currentbrightness)) # This value will be used for setting the brightness
#print(round(currentkelvin))
service_data = {"entity_id": entity_id, "kelvin": currentkelvin, "brightness_pct": currentbrightness, "transition": updatesecs-1}
hass.services.call("light", "turn_on", service_data, False)
time.sleep(updatesecs)
else:
break
entity_id = data.get("entity_id")
minutes = data.get("minutes")
updatesecs = data.get("updatesecs")
sunrise(entity_id,minutes,updatesecs)
Any ideas for setting the brightness/kelvin with s-shaped values instead of linear is appreciated.

You could be able to simply iterate over the final df and use brightness and kelvin values, sleeping for a minute or so each interval and call your api.
import numpy as np
import seaborn as sns
import pandas as pd
import math
import matplotlib.pyplot as plt
def sigmoid(x):
return math.exp(-np.logaddexp(0, -x))
# You could change 60 to some other interval if you want
t = [(i,sigmoid(x)) for i,x in enumerate(np.linspace(-10,10,60))]
# df of time interval and y value
df = pd.DataFrame(t)
df.columns = ['time','sig']
# multiply sig by 100 to scale up to a percent for brightness
df['brightness'] = (df['sig'] * 100).astype(int)+1
# Scale sig values to 2500,4000 for kelvin
a = df.sig.values
df['kelvin'] = np.interp(a, (a.min(), a.max()), (2500, 4000)).astype(int)
fig, (ax1, ax2) = plt.subplots(ncols=2, sharey=False)
sns.lineplot(data=df,x='time',y='brightness', ax=ax1)
sns.lineplot(data=df,x='time',y='kelvin', ax=ax2)

Related

How to split data into two graphs with mat plot lib

I would be so thankful if someone would be able to help me with this. I am creating a graph in matplotib however I would to love to split up the 14 lines created from the while loop into the x and y values of P, so instead of plt.plot(t,P) it would be plt.plot(t,((P[1])[0]))) and
plt.plot(t,((P[1])[1]))). I would love if someone could help me very quick, it should be easy but i am just getting errors with the arrays
`
#Altering Alpha in Tumor Cells vs PACCs
#What is alpha? α = Rate of conversion of cancer cells to PACCs
import numpy as np
from scipy.integrate import odeint
import matplotlib.pyplot as plt
from google.colab import files
value = -6
counter = -1
array = []
pac = []
while value <= 0:
def modelP(x,t):
P, C = x
λc = 0.0601
K = 2000
α = 1 * (10**value)
ν = 1 * (10**-6)
λp = 0.1
γ = 2
#returning odes
dPdt = ((λp))*P*(1-(C+(γ*P))/K)+ (α*C)
dCdt = ((λc)*C)*(1-(C+(γ*P))/K)-(α*C) + (ν***P)
return dPdt, dCdt
#initial
C0= 256
P0 = 0
Pinit = [P0,C0]
#time points
t = np.linspace(0,730)
#solve odes
P = odeint(modelP,Pinit,t)
plt.plot(t,P)
value += 1
#plot results
plt.xlabel('Time [days]')
plt.ylabel('Number of PACCs')
plt.show()
`
You can use subplots() to create two subplots and then plot the individual line into the plot you need. To do this, firstly add the subplots at the start (before the while loop) by adding this line...
fig, ax = plt.subplots(2,1) ## Plot will 2 rows, 1 column... change if required
Then... within the while loop, replace the plotting line...
plt.plot(t,P)
with (do take care of the space so that the lines are within while loop)
if value < -3: ## I am using value = -3 as the point of split, change as needed
ax[0].plot(t,P)#, ax=ax[0]) ## Add to first plot
else:
ax[1].plot(t,P)#,ax=ax[1]) ## Add to second plot
This will give a plot like this.

Is it possible to specify different SPHI or SPLO limits for CVs for different parts of the horizon in GEKKO?

I would like to build a GEKKO model for dynamic schedule optimisation of a system. I am exploring GEKKO functionality with a toy problem (code attached below). I foresee that it would be required to specify different targets for some CV's for different parts of the horizon as depicted below.
I tried assigning an array to the SPLO parameter of the Level CV but it simply collapsed the SPHI and SPLO to the starting value of the CV.
I like the flexibility of using the objective function to drive the solution as opposed to 'hard' constraints. Can this be accomplished in a non-iterative implementation and if so how?
from gekko import GEKKO
import numpy as np
import json
import pandas as pd
from matplotlib import pyplot as plt
def G1_offline(timespace=100):
tk_lowlimit=[37]*100 #init low limit
tk_lowlimit[40:70]=[38]*30 #increase low limit for portion of horizon
m=GEKKO(remote=False)
#tk_lowlimit_hard=m.Param(tk_lowlimit)
rundown_schedule=[100]*timespace #init rundown schedule
rundown_schedule[40:45]=[95]*5 #adjust schedile for few points
m.time=np.linspace(0,timespace-1,timespace)
m.Unit1_Feed=m.MV(value=25,lb=0,ub=60,name='Unit1 Feed')
m.Unit2_Feed=m.MV(value=27,lb=0,ub=60,name='Unit2 Feed')
m.Fuel=m.MV(value=10,lb=0,ub=100,name='Fuel')
m.Rundown=m.MV(name='Rundown') #This is a DV
m.Efficiency=m.FV(value=0.99,lb=0.95,ub=1,name='Efficiency')
m.Rundown.value=rundown_schedule
m.Flare=m.SV(value=30,lb=0,ub=100,name='Flare')
m.TankLevel=m.CV(value=25, lb=0,ub=300,name='tklevel')
m.Consumers=m.MV(value=30,lb=0,ub=130,name='Consumers')
m.Product=m.Intermediate((m.Unit1_Feed+m.Unit2_Feed)*m.Efficiency,name='Product')
m.Balance=m.Intermediate(m.Product-m.Consumers,name='Balance')
m.Equation(m.TankLevel.dt()==m.Balance)
m.Equation(m.Flare==m.Rundown-(m.Unit1_Feed+m.Unit2_Feed+m.Fuel))
#m.Equation(m.Flare>=1)
#GLOBAL OPTIONS
m.options.IMODE=6 #control mode,dynamic control, simultaneous
m.options.NODES=2 #collocation nodes
m.options.SOLVER=1 # 1=APOPT, 2=BPOPT, 3=IPOPT
m.options.CV_TYPE=1 #2 = squared error from reference trajectory
m.options.CTRL_UNITS=3 #control time steps units (3= HOURS)
m.options.CTRL_TIME=1 #1=1 hour per time step
m.options.REQCTRLMODE=3 #3= CONTROL
#m.options.SCALING=2
m.options.RTOL=1e-6
m.options.OTOL=1e-6
#m.options.CV_WGT_START=5
m.options.CSV_WRITE=2
#MV/DV modes
m.Unit1_Feed.STATUS=1 #1 = can change
m.Unit2_Feed.STATUS=1 #1 = can change
m.Fuel.STATUS=1 #1 = can change
m.Consumers.STATUS=1 #1 = can change
m.Rundown.STATUS=0 #0 = cannot change, this is a DV
m.Efficiency.STATUS=0
m.Efficiency.FSTATUS=1
#CV Modes
m.TankLevel.STATUS=1 #1 = Control this CV
#m.Flare.STATUS=0 #0 = Do Not Control this CV
m.TankLevel.FSTATUS=1 #Allow Feedback
m.TankLevel.STATUS=1 #Control this CV
m.TankLevel.TAU=12 #Time constant for trajectory
m.TankLevel.SPHI=40 #Upper limit for trajectory
m.TankLevel.SPLO=37 #Lower limit for trajectory
m.TankLevel.WSPLO=20 #Penalty for crossing LO limit
m.TankLevel.WSPHI=20 #Penalty for crossing HI limit
m.TankLevel.TR_INIT=0 #0 -Do not re-center.
m.TankLevel.TR_OPEN=1 #Openi#ng shape of trajectory
m.Consumers.COST=-40
m.Unit1_Feed.COST=5
m.Unit2_Feed.COST=4
m.Fuel.COST=-2
#m.Flare.COST=0
m.Consumers.DCOST=15
m.Unit1_Feed.DCOST=5
m.Unit2_Feed.DCOST=5
m.Fuel.DCOST=1
m.Consumers.DMAX=10
m.Unit1_Feed.DMAX=10
m.Unit2_Feed.DMAX=8
m.Fuel.DMAX=10
m.Consumers.MV_STEP_HOR=1
m.Unit1_Feed.MV_STEP_HOR=1
m.Unit2_Feed.MV_STEP_HOR=1
m.Fuel.MV_STEP_HOR=1
m.solve(GUI=False)
with open(m.path+'//results.json') as f:
results = json.load(f)
#print(results)
results_df=pd.DataFrame(results)
print(results_df)
#results_df.to_excel(r'c:\data\toyproblem.xlsx')
fig = plt.figure(figsize=(14,6))
plt.plot(results_df['time'],results_df['tklevel'],color='red',label='Level')
plt.fill_between(x=results_df['time'],y1=results_df['tklevel.tr_lo'], y2=results_df['tklevel.tr_hi'],color='green',alpha=0.2, label='Tklevel CV bounds')
plt.xlabel('TIME')
plt.title('Controlled solution')
plt.ylabel('TankLevel')
plt.legend(bbox_to_anchor=(0.0, 1), loc='upper left', borderaxespad=0.5)
plt.minorticks_on()
plt.grid(color = 'b', linestyle = '--', linewidth = 0.5, axis='y')
plt.show()
fig = plt.figure(figsize=(14,6))
plt.plot(results_df['time'],results_df['unit1_feed'],color='red',label='Unit1')
plt.plot(results_df['time'],results_df['unit2_feed'],color='green',label='Unit2')
plt.plot(results_df['time'],results_df['consumers'],color='black',label='Consumers')
plt.plot(results_df['time'],results_df['flare'],color='orange',label='Flare')
plt.plot(results_df['time'],results_df['fuel'],color='blue',label='Fuel')
plt.plot(results_df['time'],results_df['rundown'],color='purple',label='Rundown')
plt.xlabel('TIME'), plt.ylabel('knm3/h'), plt.title('Independent variables'),
plt.legend(bbox_to_anchor=(0.0, 1), loc='upper left', borderaxespad=0.5)
plt.minorticks_on()
plt.grid(color = 'b', linestyle = '--', linewidth = 0.5, axis='y')
trj_hi=results_df['tklevel.tr_hi']
trj_lo=results_df['tklevel.tr_lo']
return m,results_df
#----main----
c1,results_df=G1_offline(100)
It is possible to customize SPHI and SPLO instead of a fixed target value. This is accomplished by redefining the CV as a difference between the current and target value. The target value can be a feedforward traj=m.Param() with the values updated each cycle of the controller with something like traj.value = [custom_setpoint]. There is an example of this approach in the Dynamic Optimization course (see bottom of the page).
# Error
e = m.CV(value=0,name='e')
m.Equation(e==v-traj)
# CV tuning
e.STATUS = 1 #add the CV to the objective
m.options.CV_TYPE = 1 #Dead-band
db = 2
e.SPHI = db #set point
e.SPLO = -db #set point
e.TR_INIT = 0 #dead-band
Some applications require a custom reference trajectory that does not fit a standard form. A custom reference trajectory is specified by creating a new error (e) variable that is the difference between the specified trajectory (sinusoidal, sawtooth, random, etc) and the model output. This error is specified as a controlled variable (CV) with an upper and lower dead-band denoted as SPHI and SPLO. The CV can also be a value of zero with a squared error objective (e.SP=0, m.options.CV_TYPE=2) to drive to a target instead of a dead-band range.
import numpy as np
from random import random
from gekko import GEKKO
import matplotlib.pyplot as plt
# initialize GEKKO model
m = GEKKO()
# time
m.time = np.linspace(0,20,41)
# constants
mass = 500
# Parameters
b = m.Param(value=50)
K = m.Param(value=0.8)
# Manipulated variable
p = m.MV(value=0, lb=-100, ub=100)
# Reference trajectory
sine = 10*np.sin(m.time/20*4*np.pi)
traj = m.Param(value=sine)
# Controlled Variable
v = m.SV(value=0,name='v')
# Error
e = m.CV(value=0,name='e')
# Equations
m.Equation(mass*v.dt() == -v*b + K*b*p)
m.Equation(e==v-traj)
m.options.IMODE = 6 # control
# MV tuning
p.STATUS = 1 #allow optimizer to change
p.DCOST = 0.1 #smooth out MV
p.DMAX = 50 #slow down change of MV
# CV tuning
e.STATUS = 1 #add the CV to the objective
m.options.CV_TYPE = 1 #Dead-band
db = 2
e.SPHI = db #set point
e.SPLO = -db #set point
e.TR_INIT = 0 #dead-band
# Solve
m.solve()
# get additional solution information
import json
with open(m.path+'//results.json') as f:
results = json.load(f)
# Plot solution
plt.figure()
plt.subplot(3,1,1)
plt.plot(m.time,p.value,'b-',lw=2,label='MV')
plt.legend(loc='best')
plt.ylabel('MV')
plt.subplot(3,1,2)
plt.plot(m.time,sine+db,'k-',label='SPHI')
plt.plot(m.time,sine-db,'k-',label='SPLO')
plt.plot(m.time,v.value,'r--',lw=2,label='CV')
plt.legend(loc='best')
plt.ylabel('CV')
plt.subplot(3,1,3)
plt.plot(m.time,results['e.tr_hi'],'k-',label='SPHI')
plt.plot(m.time,results['e.tr_lo'],'k-',label='SPLO')
plt.plot(m.time,e.value,'r--',lw=2,label='Error')
plt.legend(loc='best')
plt.ylabel('Error')
plt.xlabel('time')
plt.show()

Estimate joint density with 2d Gaussian kernel

I have the following data set where I have to estimate the joint density of 'bwt' and 'age' using kernel density estimation with a 2-dimensional Gaussian kernel and width h=5. I can't use modules such as scipy where there are ready functions to do this and I have to built functions to calculate the density. Here's what I've gotten so far.
import numpy as np
import pandas as pd
babies_full = pd.read_csv("https://www2.helsinki.fi/sites/default/files/atoms/files/babies2.txt", sep='\t')
#Getting the columns I need
babies_full1=babies_full[['gestation', 'age']]
x=np.array(babies_full1,'int')
#2d Gaussian kernel
def k_2dgauss(x):
return np.exp(-np.sum(x**2, 1)/2) / np.sqrt(2*np.pi)
#Multivariate kernel density
def mv_kernel_density(t, x, h):
d = x.shape[1]
return np.mean(k_2dgauss((t - x)/h))/h**d
t = np.linspace(1.0, 5.0, 50)
h=5
print(mv_kernel_density(t, x, h))
However, I get a value error 'ValueError: operands could not be broadcast together with shapes (50,) (1173,2)' which think is because different shape of the matrices. I also don't understand why k_2dgauss(x) for me returns an array of zeros since it should only return one value. In general, I am new to the concept of kernel density estimation I don't really know if I've written the functions right so any hints would help!
Following on from my comments on your original post, I think this is what you want to do, but if not then come back to me and we can try again.
# info supplied by OP
import numpy as np
import pandas as pdbabies_full = \
pd.read_csv("https://www2.helsinki.fi/sites/default/files/atoms/files/babies2.txt", sep='\t')
#Getting the columns I need
babies_full1=babies_full[['gestation', 'age']]
x=np.array(babies_full1,'int')
# my contributions
from math import floor, ceil
def binMaker(arr, base):
"""function I already use for this sort of thing.
arr is the arr I want to make bins for
base is the bin separation, but does require you to import floor and ceil
otherwise you can make these bins manually yourself"""
binMin = floor(arr.min() / base) * base
binMax = ceil(arr.max() / base) * base
return np.arange(binMin, binMax + base, base)
bins1 = binMaker(x[:,0], 20.) # bins from 140. to 360. spaced 20 apart
bins2 = binMaker(x[:,1], 5.) # bins from 15. to 45. spaced 5. apart
counts = np.zeros((len(bins1)-1, len(bins2)-1)) # empty array for counts to go in
for i in range(0, len(bins1)-1): # loop over the intervals, hence the -1
boo = (x[:,0] >= bins1[i]) * (x[:,0] < bins1[i+1])
for j in range(0, len(bins2)-1): # loop over the intervals, hence the -1
counts[i,j] = np.count_nonzero((x[boo,1] >= bins2[j]) *
(x[boo,1] < bins2[j+1]))
# if you want your PDF to be a fraction of the total
# rather than the number of counts, do the next line
counts /= x.shape[0]
# plotting
import matplotlib.pyplot as plt
from matplotlib.colors import BoundaryNorm
# setting the levels so that each number in counts has its own colour
levels = np.linspace(-0.5, counts.max()+0.5, int(counts.max())+2)
cmap = plt.get_cmap('viridis') # or any colormap you like
norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)
fig, ax = plt.subplots(1, 1, figsize=(6,5), dpi=150)
pcm = ax.pcolormesh(bins2, bins1, counts, ec='k', lw=1)
fig.colorbar(pcm, ax=ax, label='Counts (%)')
ax.set_xlabel('Age')
ax.set_ylabel('Gestation')
ax.set_xticks(bins2)
ax.set_yticks(bins1)
plt.title('Manually making a 2D (joint) PDF')
If this is what you wanted, then there is an easier way with np.histgoram2d, although I think you specified it had to be using your own methods, and not built in functions. I've included it anyway for completeness' sake.
pdf = np.histogram2d(x[:,0], x[:,1], bins=(bins1,bins2))[0]
pdf /= x.shape[0] # again for normalising and making a percentage
levels = np.linspace(-0.5, pdf.max()+0.5, int(pdf.max())+2)
cmap = plt.get_cmap('viridis') # or any colormap you like
norm = BoundaryNorm(levels, ncolors=cmap.N, clip=True)
fig, ax = plt.subplots(1, 1, figsize=(6,5), dpi=150)
pcm = ax.pcolormesh(bins2, bins1, pdf, ec='k', lw=1)
fig.colorbar(pcm, ax=ax, label='Counts (%)')
ax.set_xlabel('Age')
ax.set_ylabel('Gestation')
ax.set_xticks(bins2)
ax.set_yticks(bins1)
plt.title('using np.histogram2d to make a 2D (joint) PDF')
Final note - in this example, the only place where counts doesn't equal pdf is for the bin between 40 <= age < 45 and 280 <= gestation 300, which I think is due to how, in my manual case, I've used <= and <, and I'm a little unsure how np.histogram2d handles values outside the bin ranges, or on the bin edges etc. We can see the element of x that is responsible
>>> print(x[1011])
[280 45]

ZigZag Indicator Metastock Formula to Python

I would like to create a zigzag indicator for stocks in Python. I have this Metastock Formula.
I dicided to publish this problem here because I don't know any other foro.
I saw 2 stackoverflow posts with something like this but they are wrong.
As you can see, the indicator tooks the close prices.
Thanks for your help.
Python code:
from __future__ import division
import matplotlib.pyplot as plt
import numpy as np
def islocalmax(x):
"""Both neighbors are lower,
assumes a centered window of size 3"""
return (x[0] < x[1]) & (x[2] < x[1])
def islocalmin(x):
"""Both neighbors are higher,
assumes a centered window of size 3"""
return (x[0] > x[1]) & (x[2] > x[1])
def isextrema(x):
return islocalmax(x) or islocalmin(x)
def create_zigzag(col, p=0.05):
# Find the local min/max
# converting to bool converts NaN to True, which makes it include the endpoints
ext_loc = col.rolling(3, center=True).apply(isextrema, raw=False).astype(np.bool_)
# extract values at local min/max
ext_val = col[ext_loc]
# filter locations based on threshold
thres_ext_loc = (ext_val.diff().abs() > (ext_val.shift(-1).abs() * p))
# Keep the endpoints
thres_ext_loc.iloc[0] = True
thres_ext_loc.iloc[-1] = True
thres_ext_loc = thres_ext_loc[thres_ext_loc]
# extract values at filtered locations
thres_ext_val = col.loc[thres_ext_loc.index]
# again search the extrema to force the zigzag to always go from high > low or vice versa,
# never low > low, or high > high
ext_loc = thres_ext_val.rolling(3, center=True).apply(isextrema, raw=False).astype(np.bool_)
thres_ext_val =thres_ext_val[ext_loc]
return thres_ext_val
from pandas_datareader import data
# Only get the adjusted close.
serie = data.DataReader(
"AAPL", start='2018-1-1', end='2020-12-31', data_source='yahoo'
)
dfzigzag = serie.apply(create_zigzag)
data1_zigzag = dfzigzag['Close'].dropna()
fig, axs = plt.subplots(figsize=(10, 3))
axs.plot(serie.Close, '-', ms=4, label='original')
axs.plot(data1_zigzag, 'ro-', ms=4, label='zigzag')
axs.legend()
plt.show()
Python code Plot:
The indicator:
Metastock Formula:
{ Copyright (c) 2004, John Bruns and Financial Trading Inc. }
reversal:=Input("Reversal",0,100,5);
pc:=Input("Use Percentage?",0,1,1);
z:=If(pc,Zig(CLOSE,reversal,%),Zig(CLOSE,reversal,$));
peakbar:=LastValue(BarsSince((z>Ref(z,-1)AND Ref(Z,-1)<Ref(Z,-2)) OR (z<Ref(z,-1))AND Ref(Z,-1)>Ref(Z,-2)))+1;
lastpeak:=LastValue(Ref(z,-peakbar));
lastend:=LastValue(z);
bars:=Cum(1);
invalid:=If(pc,If(Abs(lastend-lastpeak)*100/lastpeak<reversal,1,0),If(Abs(lastend-lastpeak)<reversal,1,0));
If(bars>=LastValue(bars)-peakbar AND invalid,lastpeak,z);

Jello effect when displaying a filtered digital signal

I wish to display a mesured signal in real time with some basic filtering (band stop, band pass).
signal is stored in a numpy array (numpy.array)
a matplotlib graph is displaying the numpy array (matplotlib.animation.FuncAnimation)
for each FuncAnimation frame, some filters are applied on the signal (scipy.signal.butter, scipy.signal.filtfilt)
When I do it this way, I get some kind of jello effet (sorry for bad gif quality)
Even if it's not exactly what's going on, let's pretend I implemented this algorithm in pseudo-code:
signal = np.array(some_data)
plot = FuncAnimation(init_function, update_function)
for each frame:
- shift signal on the left # make space and discard oldest samples
- add new samples on the right
- filtered_signal = filter(signal) # using signal.butter and signal.filtfilt
- update_plot(filtered_signal) # FuncAnimation update function
I'm looking for techniques to get rid of this unwanted effect. Any idea?
EDIT 1
Without animation, this is what append for 20 consecutive filtered signals.
First plot is signal (raw signal)
Second plot contains the 20 last filtered_signal
Third plot contains the 20 last filtered_signal shifted for better visualization
EDIT 2
signal is a fixed-size buffer containing N=1000 samples
filtered_signal is created from scratch for each frame
sampling frequency is fs=250Hz
2 filters are applied: a 50Hz notch and a [0.5Hz, 120Hz] band pass
EDIT 3
Here is a full working example:
First plot is the raw signal
Second plot is the filtered signal (band pass [0.5Hz, 120Hz])
Source code:
import matplotlib.pyplot as plt
import numpy as np
from scipy import signal
import matplotlib.animation as animation
import time
N = 1000
fs = 250
last_update = time.time()
sample_id = 0
def all_samples(length=10000):
# generate a dummy signal
st = 1.0 / fs
t = np.arange(length) * st
sig1 = 1*np.sin(2*np.pi * 2*t) + 2
sig2 = 0.25*np.sin(2*np.pi * 3*t) + 4
sig3 = 2*np.sin(2*np.pi * 4*t) + 5
return sig1 + sig2 + sig3
def band_pass(low_cut, high_cut, order=2):
# compute butterworth b, a coefficients
band = np.array([low_cut, high_cut])
Wn = band / (float(fs/2.0))
b, a = signal.butter(order, Wn, 'bandpass')
return b, a
def filter(raw_signal):
# apply filter
b, a = band_pass(0.5, 120)
return signal.filtfilt(b, a, raw_signal)
def init():
# init function for FuncAnimation blit=True
global axe_raw, line_raw
global axe_filt, line_filt
line_filt.set_visible(False)
line_raw.set_visible(False)
axe_raw.set_xlim(0, 1000)
axe_raw.set_ylim(5, 15)
axe_filt.set_xlim(0, 1000)
axe_filt.set_ylim(-5, 5)
return line_raw, line_filt,
def update(n):
global raw_signal, axe_raw, line_raw
global axe_filt, line_filt
global last_update, fs, sample_id
if n == 1:
line_raw.set_visible(True)
line_filt.set_visible(True)
# add new samples
now = time.time()
sample_count = int((now - last_update) * fs)
raw_signal = np.roll(raw_signal, -sample_count)
raw_signal[-sample_count:] = all_samples[sample_id:sample_id + sample_count]
last_update = now
sample_id += sample_count
# update plot (raw + filtered)
line_raw.set_ydata(raw_signal)
line_filt.set_ydata(filter(raw_signal))
return line_raw, line_filt
all_samples = all_samples()
raw_signal = np.zeros(N)
# matplotlib animation
figure = plt.figure()
axe_raw = figure.add_subplot(211)
axe_filt = figure.add_subplot(212)
line_raw, = axe_raw.plot(raw_signal)
line_filt, = axe_filt.plot(np.zeros(N))
anim = animation.FuncAnimation(figure,
update,
init_func=init,
interval=5,
blit=True)
plt.show()

Categories

Resources