Commented and Cleaned version of the Noise Analysis Code that was used in Lenny's Thesis.
This commit is contained in:
commit
7c0eb7c9be
136
FourierTrafoAndRMSNoiseAnalysis.py
Normal file
136
FourierTrafoAndRMSNoiseAnalysis.py
Normal file
@ -0,0 +1,136 @@
|
||||
"""
|
||||
This Code can calculate the Discrete Fourier Transformation (DFT) of a Noise Signal of different formats calculate the
|
||||
RMS Noise level over a given bandwidth bandwidth.
|
||||
|
||||
|
||||
__author__ = "Lenny Hoenen"
|
||||
__email__ = "l.hoenen@posteo.de", "lennart.hoenen@stud.uni-heidelberg.de"
|
||||
|
||||
"""
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from scipy.fft import rfft, rfftfreq
|
||||
from scipy.signal.windows import blackman
|
||||
from scipy.integrate import simps
|
||||
import scipy.io.wavfile as wavfile
|
||||
import json
|
||||
|
||||
|
||||
def Average_Fourier_Uniform(Data, Samplingrate):
|
||||
"""
|
||||
Calculate the average FFT of multiple real, one dimensional signals with a given samplingrate and samplesize N.
|
||||
Returns the frequency range xf and the Linear Spectral Density of the signal over that range yf.
|
||||
Data is of the shape M x N, where M is the number of measurements to average and N is the Number of Data points in
|
||||
each measurement.
|
||||
The designation "Uniform" indicates, that no window function is used for the DFT. For Time Series consisting purely
|
||||
of noise, this should give the optimal results.
|
||||
"""
|
||||
N = len(Data[0])
|
||||
T = 1/Samplingrate
|
||||
yf_av = []
|
||||
for i in Data:
|
||||
yf = rfft(i)
|
||||
yf = (2 * np.abs(yf)**2) / (Samplingrate * N) #Calculates the Power Spectral Density of one measurement/signal see Lenny's Thesis 3.2.4
|
||||
yf_av.append(yf)
|
||||
yf_av = np.sqrt(np.average(yf_av, axis=0)) #Average and convert from Power Spectral Density to Linear Spectral Density see Lenny's Thesis 3.2.4
|
||||
xf = rfftfreq(N, T)
|
||||
return xf, yf_av
|
||||
|
||||
|
||||
def Calc_Power_Noise_RMS(LSD, maxFreq):
|
||||
"""
|
||||
Calculate the RMS Noise Power over a specified frequency range.
|
||||
As the impedance of the coils acts as a low pass filter, the current and thus the magnetic field cannot follow
|
||||
arbitrarily large frequencies. The Osci might measure high freq noise in the monitoring voltage, but this will hardly
|
||||
exist in the magnetic field. Therefore, one might want to limit the bandwidth to calculate the RMS noise in the current
|
||||
and thus in the magnetic field. The below functions allow to select a maximum Frequency (maxFreq) and calculate the RMS
|
||||
noise accordingly. LSD is the Linear Spectral Density as given by Average_Fourier_Uniform.
|
||||
For Discussions of the stability of a magnetic field, the Voltage Noise Density and its RMS value will be most
|
||||
meaningful. The result of the function Calc_Voltage_noise_RMS() is therefore more meaningful.
|
||||
See Lenny's Thesis 3.4
|
||||
|
||||
The desired max. frequency might not be part of the list of discrete frequencies in the space of the DFT. Therefore
|
||||
a closest match is found and selected.
|
||||
"""
|
||||
res = max(LSD)
|
||||
index = len(LSD)
|
||||
|
||||
for i in range(len(LSD)):
|
||||
if res > np.abs(maxFreq - LSD[i]):
|
||||
res = np.abs(maxFreq - LSD[i])
|
||||
index = i
|
||||
|
||||
print("You chose the maximum Frequency ", maxFreq, "Hz. The closest matching frequency contained in the DFT is ", LSD[index], "Hz with index ", index, ".")
|
||||
PowerNoiseRMS = simps(y_Final_av[0:index]**2, x_Final_av[0:index])
|
||||
|
||||
return PowerNoiseRMS
|
||||
|
||||
def Calc_Voltage_Noise_RMS(LSD, maxFreq):
|
||||
"""
|
||||
See explanation of Calc_Power_Noise_RMS() and Lenny's Thesis 3.4.
|
||||
"""
|
||||
PowerNoiseRMS = Calc_Power_Noise_RMS(LSD, maxFreq)
|
||||
VoltageNoiseRMS = np.sqrt(PowerNoiseRMS)
|
||||
|
||||
return VoltageNoiseRMS
|
||||
|
||||
"""
|
||||
HERE IS JUST SOME DIFFERENT WAYS TO OPEN OSCI DATA:
|
||||
|
||||
|
||||
|
||||
#OPEN wav files (wav is quite efficient and easy to handle for noise analysis)
|
||||
Samplingrate, Data = wavfile.read("Z:/Directory/File.wav")
|
||||
Data = Data * AbsoluteVoltageRange / NumberofBits
|
||||
With the Handyscope HS6Diff, the minimum Voltage Range was +/-200mV. Therefore the AbsoluteVoltageRange is 400mV. The
|
||||
highest resolution is 16Bit. Therefore the NumberofBits is 2**16
|
||||
|
||||
#OPEN JSON files
|
||||
f = open("Z:/Directory/File.json")
|
||||
jdata = json.load(f)[0]
|
||||
joutput = jdata["outputs"]
|
||||
JDATA = joutput[0]["data"]
|
||||
f.close()
|
||||
JDATA = np.array(JDATA)
|
||||
|
||||
#OPEN CSV files
|
||||
data = np.genfromtxt("Z:/Directory/file.csv", skip_header=9)
|
||||
data = data.T
|
||||
"""
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
"""
|
||||
EXAMPLE:
|
||||
"""
|
||||
samplingrateFinal, dataFinal = wavfile.read("Z:/Users/Lenny/Power Supply Mk.2/Noise Measurements/NoiseDensityHHCoilsFinalPowerSupplyWithPIBatteryInput.wav")
|
||||
dataFinal = dataFinal*0.4/2**16 #Correct conversion from bit values to physical data, for the used Voltae range and precision.
|
||||
dataFinalshaped = np.reshape(dataFinal, [5,4000000]) #Shape one long continuous measurement into 5 shorter measurements to be averaged
|
||||
|
||||
samplingrateshielding, datashielding = wavfile.read("Z:/Users/Lenny/Power Supply/TimeSeriesOP549/FinalMeasurements/NoiseDensitySingleTestCoilWithPIBatteryInputWithShielding.wav")
|
||||
datashielding = datashielding*0.4/2**16
|
||||
datashieldingshaped = np.reshape(datashielding, [10,2000000])
|
||||
|
||||
x_Final_av, y_Final_av = Average_Fourier_Uniform(dataFinalshaped, samplingrateFinal)
|
||||
x_shielding_av, y_shielding_av = Average_Fourier_Uniform(datashieldingshaped, samplingrateshielding)
|
||||
print(Calc_Voltage_Noise_RMS(x_Final_av, 25000))
|
||||
|
||||
plt.rcParams["figure.figsize"] = [7,5]
|
||||
plt.rcParams["font.size"] = 12
|
||||
plt.figure(1, figsize=[12,7])
|
||||
plt.loglog(x_Final_av, y_Final_av, linewidth=1, label="Noise Final Powersupply in Carton Box", alpha=0.7)
|
||||
plt.loglog(x_shielding_av, y_shielding_av, linewidth=1, label="Noise Prototype with Shielding", alpha=0.7)
|
||||
#plt.loglog(x_DC1V_av, y_DC1V_av, linewidth=1, label="Noise with FreqGen and Shielding", alpha=0.7)
|
||||
plt.legend()
|
||||
plt.grid(which="major")
|
||||
plt.grid(which="minor", alpha=0.2)
|
||||
plt.xlabel("Frequency [Hz]")
|
||||
plt.ylabel(r"Voltage Noise Spectrum [$V/ \sqrt{Hz}$]")
|
||||
plt.title("2 Measurements of 10M Samples at 6.52MHz averaged")
|
||||
plt.show()
|
||||
plt.close()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user