Doing THD calc
This commit is contained in:
Binary file not shown.
Binary file not shown.
BIN
__pycache__/fundamental_freq_meas.cpython-312.pyc
Normal file
BIN
__pycache__/fundamental_freq_meas.cpython-312.pyc
Normal file
Binary file not shown.
BIN
__pycache__/measurements.cpython-312.pyc
Normal file
BIN
__pycache__/measurements.cpython-312.pyc
Normal file
Binary file not shown.
Binary file not shown.
105
fft_meas.py
105
fft_meas.py
@@ -5,7 +5,11 @@ import fft
|
||||
|
||||
class fft_meas(object):
|
||||
"""docstring for fft_meas"""
|
||||
# 61000-4-7 says 200ms
|
||||
# 10-cycles for 50Hz
|
||||
# 12-cycles for 60Hz
|
||||
def __init__(self, fs=50e3, tn=0.2):
|
||||
|
||||
self.fs = fs
|
||||
self.ts = 1/fs
|
||||
self.tn = tn
|
||||
@@ -19,25 +23,94 @@ class fft_meas(object):
|
||||
self.b = 0
|
||||
self.c = 0
|
||||
self.Y_C = 0
|
||||
|
||||
# 61000-4-7: 3.2.3
|
||||
# Upto the 40 Harmonic per 3.3.1 Note 2
|
||||
# Harmonic order
|
||||
self.Y_H = np.zeros(40)
|
||||
# 61000-4-7: 3.2.3
|
||||
# Upto the 40 Harmonic per 3.3.2 Note 2
|
||||
# Grouped Harmonic order
|
||||
self.Y_g = np.zeros(40)
|
||||
# 61000-4-7: 3.2.2
|
||||
self.h = np.zeros(40)
|
||||
|
||||
self.THD = 0
|
||||
self.THDG = 0
|
||||
|
||||
|
||||
self.phi = 0
|
||||
|
||||
def step(self, data, time, f_H1, unit):
|
||||
|
||||
if time - self.time > self.ts:
|
||||
self.time = time
|
||||
self.idx += 1
|
||||
|
||||
self.data[self.idx] = data
|
||||
|
||||
if self.idx == self.N-1:
|
||||
self.base_freq = 0
|
||||
|
||||
|
||||
self.freq , self.a, self.b , self.c, self.Y_C, self.phi = fft.fft(x=self.data, fs=self.fs)
|
||||
def step(self, y, base_freq, unit):
|
||||
|
||||
self.idx = -1
|
||||
self.idx += 1
|
||||
|
||||
self.data[self.idx] = y
|
||||
|
||||
if self.idx == self.N-1:
|
||||
|
||||
self.freq , self.a, self.b , self.c, self.Y_C, self.phi = fft.fft(x=self.data, fs=self.fs)
|
||||
|
||||
self.calc_Y_H(base_freq)
|
||||
self.calc_THD()
|
||||
|
||||
self.calc_Y_g(base_freq)
|
||||
self.calc_THDG()
|
||||
|
||||
|
||||
|
||||
self.idx = -1
|
||||
|
||||
|
||||
def calc_Y_H(self, base_freq):
|
||||
# 61000-4-7: 3.2.3
|
||||
if np.abs(base_freq-50) < np.abs(base_freq-60):
|
||||
self.base_freq = 50
|
||||
else:
|
||||
self.base_freq = 60
|
||||
|
||||
if self.base_freq == 50:
|
||||
for k in range(len(self.Y_H)):
|
||||
self.Y_H[k] = self.Y_C[int(10*k)]
|
||||
self.h[k] = self.freq[int(10*k)]
|
||||
elif self.base_freq == 60:
|
||||
for k in range(len(self.Y_H)):
|
||||
self.Y_H[k] = self.Y_C[int(12*k)]
|
||||
self.h[k] = self.freq[int(12*k)]
|
||||
|
||||
def calc_THD(self):
|
||||
# 61000-4-7: 3.3.1
|
||||
self.THD = 0
|
||||
for k in range(2, len(self.Y_H)):
|
||||
self.THD += np.power(self.Y_H[k]/self.Y_H[1],2)
|
||||
self.THD = np.sqrt(self.THD)
|
||||
|
||||
def calc_Y_g(self, base_freq):
|
||||
# 61000-4-7: 3.2.4
|
||||
if np.abs(base_freq-50) < np.abs(base_freq-60):
|
||||
self.base_freq = 50
|
||||
else:
|
||||
self.base_freq = 60
|
||||
|
||||
if self.base_freq == 50:
|
||||
for k in range(len(self.Y_g)):
|
||||
self.Y_g[k] = self.Y_C[int(10*k)-1] + self.Y_C[int(10*k)] + self.Y_C[int(10*k)+1]
|
||||
self.h[k] = self.freq[int(10*k)]
|
||||
elif self.base_freq == 60:
|
||||
for k in range(len(self.Y_g)):
|
||||
self.Y_g[k] = self.Y_C[int(12*k)-1] + self.Y_C[int(12*k)] + self.Y_C[int(12*k)+1]
|
||||
self.h[k] = self.freq[int(12*k)]
|
||||
|
||||
def calc_THDG(self):
|
||||
# 61000-4-7: 3.3.1
|
||||
self.THDG = 0
|
||||
for k in range(2, len(self.Y_H)):
|
||||
self.THDG += np.power(self.Y_g[k]/self.Y_g[1],2)
|
||||
self.THDG = np.sqrt(self.THDG)
|
||||
print(self.THDG)
|
||||
|
||||
def plot(self):
|
||||
#fs, a, b, c, YC, phi = ftt.fft(Ph1, sample_freq)
|
||||
|
||||
@@ -47,3 +120,11 @@ class fft_meas(object):
|
||||
plt.title("Simple plot")
|
||||
plt.show()
|
||||
|
||||
def plot_Y_H(self):
|
||||
|
||||
plt.stem(self.h, self.Y_H, use_line_collection=True)
|
||||
plt.xlabel("Harmonic order h")
|
||||
plt.ylabel("RMS value Y_H,h")
|
||||
plt.title("Harmonic spectrum (IEC 61000-4-7: 3.2.3)")
|
||||
plt.grid(True)
|
||||
plt.show()
|
||||
51
fundamental_freq_meas.py
Normal file
51
fundamental_freq_meas.py
Normal file
@@ -0,0 +1,51 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
|
||||
class fundamental_freq_meas(object):
|
||||
"""docstring for fft_meas"""
|
||||
def __init__(self, fs=50e3, tn=10):
|
||||
self.fs = fs
|
||||
self.ts = 1/self.fs
|
||||
self.tn = tn
|
||||
self.time = 0
|
||||
self.y_old = 0
|
||||
self.tn_start_time = 0
|
||||
self.tn_end_time = 0
|
||||
self.zerocross_count = 0
|
||||
# Calculated Frequency
|
||||
self.freq = 50
|
||||
|
||||
self.t_zc = 0
|
||||
|
||||
def step(self, y, zerocross_flag):
|
||||
|
||||
# Integrate time
|
||||
self.time += self.ts
|
||||
|
||||
if zerocross_flag:
|
||||
denom = (y - self.y_old)
|
||||
if denom != 0.0: # avoid divide-by-zero
|
||||
# linear interpolation to find zero-crossing time
|
||||
frac = -self.y_old / denom
|
||||
self.t_zc = (self.time - self.ts) + frac * self.ts
|
||||
|
||||
# store first crossing time
|
||||
if self.zerocross_count == 0:
|
||||
self.tn_start_time = self.t_zc
|
||||
|
||||
self.zerocross_count += 1
|
||||
self.tn_end_time = self.t_zc # always keep last crossing time in this window
|
||||
|
||||
# window finished (independent of whether a crossing happened exactly here)
|
||||
if self.time >= self.tn:
|
||||
if self.zerocross_count >= 2 and self.tn_end_time > self.tn_start_time:
|
||||
self.freq = (self.zerocross_count - 1) / (self.tn_end_time - self.tn_start_time)
|
||||
|
||||
# reset window state
|
||||
self.zerocross_count = 0
|
||||
self.tn_start_time = 0.0
|
||||
self.tn_end_time = 0.0
|
||||
self.time -= self.tn # avoids drift vs. self.time = 0
|
||||
|
||||
self.y_old = y
|
||||
26
main.py
26
main.py
@@ -1,7 +1,6 @@
|
||||
|
||||
import numpy as np
|
||||
import fft_meas
|
||||
import zerocross_meas
|
||||
import measurements
|
||||
|
||||
|
||||
# to do
|
||||
@@ -12,32 +11,37 @@ import zerocross_meas
|
||||
def main():
|
||||
time = 0
|
||||
delta_t = 1e-6
|
||||
t_stop = 1.1
|
||||
t_stop = 1.2
|
||||
|
||||
ADC_sample_frequency = 50e3
|
||||
ADC_sample_period = 1/ADC_sample_frequency
|
||||
ADC_timer = 0
|
||||
|
||||
|
||||
|
||||
amplitude = 1
|
||||
base_freq = 50
|
||||
base_freq = 60
|
||||
|
||||
Meas_ADC = measurements.measurements(fs=ADC_sample_frequency)
|
||||
|
||||
fft_measurements = fft_meas.fft_meas(fs=50e3, tn=0.2)
|
||||
zerocross = zerocross_meas.zerocross_meas(fs=50e3, tn=1)
|
||||
|
||||
for i in range(0, int(t_stop/delta_t)+1):
|
||||
|
||||
|
||||
Ph1 = np.sin(2*np.pi*time*base_freq)
|
||||
|
||||
|
||||
zerocross.step(x=Ph1, time=time)
|
||||
if time - ADC_timer >= ADC_sample_period:
|
||||
ADC_timer += ADC_sample_period
|
||||
|
||||
fft_measurements.step(data=Ph1, time=time, f_H1=zerocross.freq, unit="I")
|
||||
Meas_ADC.Interupt(Ph1)
|
||||
|
||||
|
||||
|
||||
time += delta_t
|
||||
|
||||
|
||||
zerocross.print()
|
||||
#fft_measurements.plot()
|
||||
Meas_ADC.print()
|
||||
Meas_ADC.plot()
|
||||
|
||||
|
||||
|
||||
|
||||
58
measurements.py
Normal file
58
measurements.py
Normal file
@@ -0,0 +1,58 @@
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
import IIR_filter
|
||||
|
||||
import zerocross_meas
|
||||
import fundamental_freq_meas
|
||||
import fft_meas
|
||||
|
||||
|
||||
class measurements(object):
|
||||
"""docstring for fft_meas"""
|
||||
def __init__(self, fs=50e3):
|
||||
# Sample Frequency
|
||||
self.fs = fs
|
||||
# Sample Period
|
||||
self.ts = 1/self.fs
|
||||
|
||||
# Low Pass Filter
|
||||
# fs = Sample Frequency, fc = LP Cutoff Frequency
|
||||
self.LPfilter = IIR_filter.IIR_1_Order_LP(fs=self.fs, fc=200)
|
||||
|
||||
|
||||
|
||||
# Zero Crossing Algorithem
|
||||
# fs = Sample Frequency, fc = LP Cutoff Frequency
|
||||
self.zerocross = zerocross_meas.zerocross_meas()
|
||||
|
||||
# Fundamental Frequency Algorithem
|
||||
# fs = Sample Frequency, tn = Time Period for calculations
|
||||
self.base_freq = fundamental_freq_meas.fundamental_freq_meas(fs=self.fs, tn=1)
|
||||
|
||||
# FFT Algorithem
|
||||
# fs = Sample Frequency, tn = Time Period for calculations
|
||||
# 61000-4-7 says 200ms
|
||||
# 10-cycles for 50Hz
|
||||
# 12-cycles for 60Hz
|
||||
self.fft = fft_meas.fft_meas(fs=self.fs, tn=0.2)
|
||||
|
||||
|
||||
def Interupt(self, y):
|
||||
|
||||
# Filter Input
|
||||
y_hat = self.LPfilter.step(y)
|
||||
# Zerocross detection (self.zerocross.flag)
|
||||
self.zerocross.detect(y_hat)
|
||||
# Calculate the Fundamental frequency (self.base_freq.freq)
|
||||
self.base_freq.step(y_hat, self.zerocross.flag)
|
||||
# Calculate the FFT of the signal
|
||||
self.fft.step(y, self.base_freq.freq, unit="I")
|
||||
|
||||
|
||||
def print(self):
|
||||
print(self.base_freq.freq)
|
||||
|
||||
def plot(self):
|
||||
self.fft.plot_Y_H()
|
||||
|
||||
@@ -6,35 +6,25 @@ import IIR_filter
|
||||
|
||||
class zerocross_meas(object):
|
||||
"""docstring for fft_meas"""
|
||||
def __init__(self, fs=50e3, tn=1):
|
||||
self.fs = fs
|
||||
self.ts = 1/self.fs
|
||||
self.tn = tn
|
||||
self.time = 0
|
||||
self.freq = 0
|
||||
self.freq_ts = 0
|
||||
self.y = 0
|
||||
def __init__(self):
|
||||
|
||||
# Old value
|
||||
self.y_old = 0
|
||||
self.idx = 0
|
||||
self.LPfilter = IIR_filter.IIR_1_Order_LP(fs=self.fs, fc=200)
|
||||
|
||||
def step(self, x, time):
|
||||
|
||||
if time - self.time > self.ts:
|
||||
self.time = time
|
||||
self.y = self.LPfilter.step(x)
|
||||
|
||||
if self.y_old < 0 and self.y > 0:
|
||||
self.idx += 1
|
||||
# Zerocross flag
|
||||
self.flag = False
|
||||
|
||||
|
||||
if time - self.freq_ts > self.tn:
|
||||
self.freq = self.idx / self.tn
|
||||
self.freq_ts = time
|
||||
self.idx = 0
|
||||
def detect(self, y):
|
||||
|
||||
self.flag = 0
|
||||
|
||||
# If positive zerocross is detected
|
||||
if self.y_old < 0 and y > 0:
|
||||
self.flag = True
|
||||
|
||||
self.y_old = y
|
||||
|
||||
self.y_old = self.y
|
||||
|
||||
|
||||
def print(self):
|
||||
|
||||
Reference in New Issue
Block a user