thesis: Add freq measurement notebook

This commit is contained in:
jaseg 2020-04-02 15:11:17 +02:00
parent 7f0041bf10
commit e104e5d2dc
9 changed files with 4650 additions and 9140 deletions

View file

@ -1,5 +1,12 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Grid frequency estimation"
]
},
{
"cell_type": "code",
"execution_count": 1,
@ -30,13 +37,23 @@
"%matplotlib widget"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 1: Setup\n",
"### Load data series information from sqlite capture file\n",
"\n",
"One capture file may contain multiple runs/data series. Display a list of runs and their start/end time and sample count, then select the newest one in `last_run` variable."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [],
"source": [
"db = sqlite3.connect('data/waveform-raspi-2-2.sqlite3')"
"db = sqlite3.connect('data/waveform-raspi-ocxo-2.sqlite3')"
]
},
{
@ -48,7 +65,9 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Run 000: 2020-03-25 16:07:36 - 2020-03-26 00:15:13 ( 8:07:37.266, 29261120sp)\n"
"Run 000: 2020-04-01 14:00:25 - 2020-04-01 15:09:31 ( 1:09:05.846, 4197664sp)\n",
"Run 001: 2020-04-02 11:56:41 - 2020-04-02 11:57:59 ( 0:01:18.544, 79552sp)\n",
"Run 002: 2020-04-02 12:03:51 - 2020-04-02 12:12:54 ( 0:09:03.033, 549792sp)\n"
]
}
],
@ -57,8 +76,16 @@
" foo = lambda x: datetime.datetime.fromtimestamp(x/1000)\n",
" start, end = foo(start), foo(end)\n",
" print(f'Run {run_id:03d}: {start:%Y-%m-%d %H:%M:%S} - {end:%Y-%m-%d %H:%M:%S} ({str(end-start)[:-3]:>13}, {count*32:>9d}sp)')\n",
"last_run, n_records = run_id, count\n",
"sampling_rate = 1000.0"
"last_run, n_records = run_id, count"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Setup analog parameters\n",
"\n",
"Setup parameters of analog capture hardware here. This is used to scale samples from ADC counts to analog voltages. Also setup sampling rate here. Nominal sampling rate is 1 ksps."
]
},
{
@ -67,9 +94,11 @@
"metadata": {},
"outputs": [],
"source": [
"sampling_rate = 1000.0 * 48.6 / 48\n",
"\n",
"par = lambda *rs: 1/sum(1/r for r in rs) # resistor parallel calculation\n",
"\n",
"# FIXME: These are for the first prototype only!\n",
"# Note: These are for the first prototype only!\n",
"vmeas_source_impedance = 330e3\n",
"vmeas_source_scale = 0.5\n",
"\n",
@ -92,20 +121,29 @@
"adc_count_to_vmeas = lambda x: (x*adc_val_to_voltage_factor - v0) / (v100-v0) * 100"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Load run data from sqlite3 capture file\n",
"\n",
"Load measurement data for the selected run and assemble a numpy array containing one continuous trace. "
]
},
{
"cell_type": "code",
"execution_count": 6,
"execution_count": 10,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "582c4360e293466e9baed5bc66a47883",
"model_id": "38970a137bed494d8c28c270471c73df",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(FloatProgress(value=0.0, max=914410.0), HTML(value='')))"
"HBox(children=(FloatProgress(value=0.0, max=17181.0), HTML(value='')))"
]
},
"metadata": {},
@ -115,7 +153,8 @@
"name": "stdout",
"output_type": "stream",
"text": [
"\n"
"\n",
"RMS voltage: 228.5564548966498\n"
]
}
],
@ -145,39 +184,44 @@
" # nans[:] = np.nan\n",
" # data = np.append(data, nans) FIXME\n",
" \n",
"data = (data * adc_val_to_voltage_factor - v0) / (v100-v0) * 100"
"data = (data * adc_val_to_voltage_factor - v0) / (v100-v0) * 100\n",
"\n",
"# https://stackoverflow.com/questions/6518811/interpolate-nan-values-in-a-numpy-array\n",
"nan_helper = lambda y: (np.isnan(y), lambda z: z.nonzero()[0])\n",
"\n",
"# data rarely may contain NaNs where the capture script failed to read and acknowledge capture buffers from the sensor board fast enough.\n",
"# For RMS calculation and overall FFT fill these NaNs with interpolated values from their neighbors.\n",
"data_not_nan = np.copy(data)\n",
"nans, x = nan_helper(data)\n",
"data_not_nan[nans]= np.interp(x(nans), x(~nans), data[~nans])\n",
"\n",
"print('RMS voltage:', np.sqrt(np.mean(np.square(data_not_nan))))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Show a preview of loaded data"
]
},
{
"cell_type": "code",
"execution_count": 7,
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"227.0922848236977"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"data_not_nan = data[~np.isnan(data)]\n",
"np.sqrt(np.mean(np.square(data_not_nan)))"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-33-4419e570bd12>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, (top, bottom) = plt.subplots(2, figsize=(9,6))\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "ecf3e3e261c54d87b169c1eb391a67f9",
"model_id": "6faa0da0b6b64d0094b9b683e5f2c434",
"version_major": 2,
"version_minor": 0
},
@ -191,7 +235,7 @@
],
"source": [
"fig, (top, bottom) = plt.subplots(2, figsize=(9,6))\n",
"fig.tight_layout(pad=3, h_pad=0.1)\n",
"fig.tight_layout(pad=3, h_pad=1.8)\n",
"\n",
"range_start, range_len = -300, 60 # [s]\n",
"\n",
@ -205,68 +249,85 @@
"peak = np.max(np.abs(data_not_nan - mean))\n",
"top.axhline(mean, color='red')\n",
"bbox = {'facecolor': 'black', 'alpha': 0.8, 'pad': 2}\n",
"top.text(0, mean, f'mean: {mean:.3f}', color='white', bbox=bbox)\n",
"top.text(0.02, 0.5, f'mean: {mean:.3f}', transform=top.transAxes, color='white', bbox=bbox, ha='left', va='center')\n",
"top.text(0.98, 0.2, f'V_RMS: {rms:.3f}', transform=top.transAxes, color='white', bbox=bbox, ha='right')\n",
"top.text(0.98, 0.1, f'V_Pk: {peak:.3f}', transform=top.transAxes, color='white', bbox=bbox, ha='right')\n",
"top.text(0.5, 0.9, f'Run {run_id}', transform=top.transAxes, color='white', bbox=bbox, ha='center', fontweight='bold')\n",
"\n",
"bottom.grid()\n",
"bottom.specgram(data_slice, Fs=sampling_rate)\n",
"top.set_ylabel('U [V]')\n",
"bottom.set_ylabel('F [Hz]')\n",
"bottom.set_xlabel('t [s]')\n",
"\n",
"top.set_title('Voltage waveform')\n",
"bottom.set_title('Voltage frequency spectrum')\n",
"None"
]
},
{
"cell_type": "code",
"execution_count": 9,
"cell_type": "markdown",
"metadata": {},
"outputs": [],
"source": [
"## Step 2: Calculate Short-Time Fourier Transform of capture"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Window length: 405 sp, zero-padded to 405 sp\n"
]
}
],
"source": [
"fs = sampling_rate # Hz\n",
"ff = 50 # Hz\n",
"\n",
"analysis_periods = 10\n",
"analysis_periods = 20\n",
"window_len = fs * analysis_periods/ff\n",
"nfft_factor = 4\n",
"nfft_factor = 1\n",
"sigma = window_len/8 # samples\n",
"\n",
"f, t, Zxx = signal.stft(data,\n",
" fs = fs,\n",
" window=('gaussian', sigma),\n",
" nperseg = window_len,\n",
" nfft = window_len * nfft_factor)"
" nfft = window_len * nfft_factor)\n",
"print(f'Window length: {window_len:.0f} sp, zero-padded to {window_len * nfft_factor:.0f} sp')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Show a preview of STFT results\n",
"\n",
"Cut out our approximate frequency range of interest"
]
},
{
"cell_type": "code",
"execution_count": 10,
"execution_count": 64,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"(200.0, 800.0)"
]
},
"execution_count": 10,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"window_len, window_len * nfft_factor"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-64-467ca72791b1>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots(figsize=(9, 3))\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "cc101709475d440ea77e68bcb56ce3b7",
"model_id": "95c94ad504b248febb55f81b0e919464",
"version_major": 2,
"version_minor": 0
},
@ -291,20 +352,34 @@
"None"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Step 3: Run Gasior and Gonzalez for precise frequency estimation\n",
"\n",
"Limit analysis to frequency range of interest. If automatic adaption to totally different frequency ranges\n",
"(e.g. 400Hz) would be necessary, we could switch here based on configuration or a lookup of the STFT bin\n",
"containing highest overall energy.\n",
"\n",
"As elaborated in the Gasior and Gonzalez Paper [1] the shape of the template function should match the expected peak shape.\n",
"Peak shape is determined by the STFT window function. As Gasior and Gonzalez note, a gaussian is a very good fit for a steep gaussian window."
]
},
{
"cell_type": "code",
"execution_count": 12,
"execution_count": 45,
"metadata": {},
"outputs": [
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "b0202d59643548cf83b6fa6fd7580d2d",
"model_id": "5443a7d157cc4a828cbffc91b2d645e3",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"HBox(children=(FloatProgress(value=0.0, max=292611.0), HTML(value='')))"
"HBox(children=(FloatProgress(value=0.0, max=2708.0), HTML(value='')))"
]
},
"metadata": {},
@ -322,61 +397,65 @@
"f_t = t\n",
"\n",
"n_f, n_t = Zxx.shape\n",
"# start, stop = 180, 220\n",
"# start, stop = 90, 110\n",
"# start, stop = 15, 35\n",
"# bounds_f = slice(start // 4 * nfft_factor, stop // 4 * nfft_factor)\n",
"# Frequency ROI\n",
"f_min, f_max = 30, 70 # Hz\n",
"# Indices of bins within ROI\n",
"bounds_f = slice(np.argmax(f > f_min), np.argmin(f < f_max))\n",
"\n",
"\n",
"# Initialize output array\n",
"f_mean = np.zeros(Zxx.shape[1])\n",
"\n",
"# Iterate over STFT time slices\n",
"for le_t in tnrange(1, Zxx.shape[1] - 1):\n",
" # Cut out ROI and compute magnitude of complex fourier coefficients\n",
" frame_f = f[bounds_f]\n",
" frame_step = frame_f[1] - frame_f[0]\n",
" time_step = f_t[1] - f_t[0]\n",
" #if t == 10:\n",
" # axs[-1].plot(frame_f, frame_Z)\n",
" frame_Z = np.abs(Zxx[bounds_f, le_t])\n",
" # frame_f = f[180:220]\n",
" # frame_Z = np.abs(Zxx[180:220, 40])\n",
" # frame_f = f[15:35]\n",
" # frame_Z = np.abs(Zxx[15:35, 40])\n",
" # plt.plot(frame_f, frame_Z)\n",
"\n",
" # peak_f = frame_f[np.argmax(frame)]\n",
" # plt.axvline(peak_f, color='red')\n",
"\n",
"# def gauss(x, *p):\n",
"# A, mu, sigma, o = p\n",
"# return A*np.exp(-(x-mu)**2/(2.*sigma**2)) + o\n",
"\n",
" # Template function. We use a gaussian here. This function needs to fit the window above.\n",
" def gauss(x, *p):\n",
" A, mu, sigma = p\n",
" return A*np.exp(-(x-mu)**2/(2.*sigma**2))\n",
"\n",
" f_start = frame_f[np.argmax(frame_Z)]\n",
" A_start = np.max(frame_Z)\n",
" # Calculate initial values for curve fitting\n",
" f_start = frame_f[np.argmax(frame_Z)] # index of strongest bin index\n",
" A_start = np.max(frame_Z) # strongest bin value\n",
" p0 = [A_start, f_start, 1.]\n",
" try:\n",
" # Fit template to measurement data STFT ROI \n",
" coeff, var = optimize.curve_fit(gauss, frame_f, frame_Z, p0=p0)\n",
" # plt.plot(frame_f, gauss(frame_f, *coeff))\n",
" #print(coeff)\n",
" A, mu, sigma, *_ = coeff\n",
" f_mean[le_t] = mu\n",
" _A, f_mean[le_t], _sigma, *_ = coeff # The measured frequency is the mean of the fitted gaussian\n",
" \n",
" except Exception as e:\n",
" # Handle fit errors\n",
" f_mean[le_t] = np.nan"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Produce a plot of measurement results\n",
"\n",
"Include measurements of mean, standard deviation and variance of measurement data"
]
},
{
"cell_type": "code",
"execution_count": 13,
"execution_count": 56,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-56-4e12d8913585>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots(figsize=(9, 5), sharex=True)\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "59d50a2876634433bdfb751a7a66d9ca",
"model_id": "c1c391d0577f4dbeb59db8d1fa9261de",
"version_major": 2,
"version_minor": 0
},
@ -392,49 +471,45 @@
"fig, ax = plt.subplots(figsize=(9, 5), sharex=True)\n",
"fig.tight_layout(pad=2.2, h_pad=0, w_pad=1)\n",
"\n",
"label = f'Run {last_run}'\n",
"ax.plot(f_t[1:-1], f_mean[1:-1])\n",
"\n",
"# b, a = signal.butter(3,\n",
"# 1/5, # Hz\n",
"# btype='lowpass',\n",
"# fs=1/time_step)\n",
"# filtered = signal.lfilter(b, a, f_mean[1:-1], axis=0)\n",
"# ax.plot(f_t[1:-1], filtered)\n",
"\n",
"ax.set_title(label, pad=-20)\n",
"# Cut off invalid values at fringes\n",
"ax.plot(f_t[1:-2], f_mean[1:-2])\n",
"ax.set_ylabel('f [Hz]')\n",
"ax.grid()\n",
"if not label in ['off_frequency', 'sweep_phase_steps']:\n",
" ax.set_ylim([49.90, 50.10])\n",
" var = np.var(f_mean[~np.isnan(f_mean)][1:-1])\n",
" ax.text(0.5, 0.08, f'σ²={var * 1e3:.3g} mHz²', transform=ax.transAxes, ha='center', color='white', bbox=bbox)\n",
" ax.text(0.5, 0.15, f'σ={np.sqrt(var) * 1e3:.3g} mHz', transform=ax.transAxes, ha='center', color='white', bbox=bbox)\n",
"\n",
"# ax.text(0.5, 0.2, f'filt. σ²={np.var(filtered) * 1e3:.3g} mHz', transform=ax.transAxes, ha='center')\n",
"else:\n",
" f_min, f_max = min(f_mean[1:-1]), max(f_mean[1:-1])\n",
" delta = f_max - f_min\n",
" ax.set_ylim(f_min - delta * 0.1, f_max + delta * 0.3)\n",
"var = np.var(f_mean[~np.isnan(f_mean)][1:-1])\n",
"mean = np.mean(f_mean[~np.isnan(f_mean)][1:-1])\n",
"ax.text(0.5, 0.95, f'Run {run_id}', transform=ax.transAxes, ha='center', fontweight='bold', color='white', bbox=bbox)\n",
"ax.text(0.05, 0.95, f'μ={mean:.3g} Hz', transform=ax.transAxes, ha='left', color='white', bbox=bbox)\n",
"ax.text(0.05, 0.89, f'σ={np.sqrt(var) * 1e3:.3g} mHz', transform=ax.transAxes, ha='left', color='white', bbox=bbox)\n",
"ax.text(0.05, 0.83, f'σ²={var * 1e3:.3g} mHz²', transform=ax.transAxes, ha='left', color='white', bbox=bbox)\n",
"\n",
"# Indicated missing values\n",
"for i in np.where(np.isnan(f_mean))[0]:\n",
" ax.axvspan(f_t[i], f_t[i+1], color='lightblue')\n",
"\n",
"formatter = matplotlib.ticker.FuncFormatter(lambda s, x: str(datetime.timedelta(seconds=s)))\n",
"ax.xaxis.set_major_formatter(formatter)\n",
"ax.set_xlabel('recording time t [s]')\n",
"ax.set_xlabel('recording time t [hh:mm:ss]')\n",
"None"
]
},
{
"cell_type": "code",
"execution_count": 14,
"execution_count": 57,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-57-8b77e38496af>:9: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, (ax2, ax1) = plt.subplots(2, figsize=(9,7))\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "95cfea97c3b946ed9cdf351b16c2c45e",
"model_id": "c1209b4895814c92a9b0fa01ad666667",
"version_major": 2,
"version_minor": 0
},
@ -444,6 +519,17 @@
},
"metadata": {},
"output_type": "display_data"
},
{
"ename": "IndexError",
"evalue": "index 0 is out of bounds for axis 0 with size 0",
"output_type": "error",
"traceback": [
"\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
"\u001b[0;31mIndexError\u001b[0m Traceback (most recent call last)",
"\u001b[0;32m<ipython-input-57-8b77e38496af>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m\u001b[0m\n\u001b[1;32m 56\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 57\u001b[0m \u001b[0;31m# Cut out first 10min of filtered data to give filters time to settle\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 58\u001b[0;31m \u001b[0mrms_slice\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mfiltered2\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwhere\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mf_t\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m>\u001b[0m \u001b[0;36m10\u001b[0m\u001b[0;34m*\u001b[0m\u001b[0;36m60\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 59\u001b[0m \u001b[0mrms\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msqrt\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mmean\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0msquare\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mrms_slice\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 60\u001b[0m \u001b[0max1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtext\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0.5\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m0.1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34mf'RMS (band-pass): {rms*1e3:.3f}mHz'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtransform\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0max1\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mtransAxes\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mcolor\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'white'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbbox\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0mbbox\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mha\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;34m'center'\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n",
"\u001b[0;31mIndexError\u001b[0m: index 0 is out of bounds for axis 0 with size 0"
]
}
],
"source": [
@ -512,7 +598,7 @@
},
{
"cell_type": "code",
"execution_count": 15,
"execution_count": 69,
"metadata": {},
"outputs": [],
"source": [
@ -531,49 +617,16 @@
},
{
"cell_type": "code",
"execution_count": 53,
"execution_count": 73,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-53-c54c3e4ac2be>:20: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots(figsize=(5, 2))\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "ad5454f664734681adb8640f480ce69a",
"version_major": 2,
"version_minor": 0
},
"text/plain": [
"Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"Text(20, 1, '50 Hz')"
]
},
"execution_count": 53,
"metadata": {},
"output_type": "execute_result"
}
],
"outputs": [],
"source": [
"# Number of samplepoints\n",
"N = len(data)\n",
"N = len(data_not_nan)\n",
"# sample spacing\n",
"T = 1.0 / sampling_rate\n",
"x = np.linspace(0.0, N*T, N)\n",
"yf = scipy.fftpack.fft(data * sig.blackman(N))\n",
"yf = scipy.fftpack.fft(data_not_nan * sig.blackman(N))\n",
"xf = np.linspace(0.0, 1.0/(2.0*T), N//2)\n",
"\n",
"yf = 2.0/N * np.abs(yf[:N//2])\n",
@ -590,21 +643,21 @@
},
{
"cell_type": "code",
"execution_count": 68,
"execution_count": 77,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-68-21b49a5af249>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
"<ipython-input-77-2f4bcf6b2d33>:1: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots(figsize=(6, 3))\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "4a3edb0925fe47eb8751150aa7da8c22",
"model_id": "8b689c4f96fa40ffb5012764afb57564",
"version_major": 2,
"version_minor": 0
},
@ -631,7 +684,7 @@
"ax.set_xlabel('f [Hz]')\n",
"ax.set_ylabel('Amplitude V [V]')\n",
"ax.grid()\n",
"ax.set_xlim([0.1, 500])\n",
"ax.set_xlim([0.001, 500])\n",
"fig.subplots_adjust(bottom=0.2)\n",
"\n",
"for le_f in (50, 150, 250, 350, 450):\n",
@ -646,21 +699,21 @@
},
{
"cell_type": "code",
"execution_count": 43,
"execution_count": 84,
"metadata": {},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"<ipython-input-43-2e31f0cb9460>:21: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
"<ipython-input-84-936ca777d145>:26: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).\n",
" fig, ax = plt.subplots()\n"
]
},
{
"data": {
"application/vnd.jupyter.widget-view+json": {
"model_id": "37e159955f114f36824dd42da060b9ea",
"model_id": "b58b8858dea1485fae236c9fbb6954d5",
"version_major": 2,
"version_minor": 0
},
@ -670,21 +723,15 @@
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"[<matplotlib.lines.Line2D at 0x7fafc108cdc0>]"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"# Number of samplepoints\n",
"newcopy = np.copy(f_mean[1:-2])\n",
"\n",
"nans, x = nan_helper(newcopy)\n",
"newcopy[nans]= np.interp(x(nans), x(~nans), newcopy[~nans])\n",
"\n",
"N = len(newcopy)\n",
"# sample spacing\n",
"T = 1.0 / 10\n",
@ -715,8 +762,8 @@
"#ax.text(1/60, 10,'60 s', ha='left')\n",
"ax.grid()\n",
"#ax.set_xlim([1/60000, 0.5])\n",
"ax.set_ylim([5e-7, 2e-2])\n",
"ax.plot(xf[1:], 2e-6/xf[1:])"
"#ax.set_ylim([5e-7, 2e-2])\n",
"#ax.plot(xf[1:], 2e-6/xf[1:])"
]
},
{
@ -744,6 +791,15 @@
"ax.plot(np.linspace(0, (len(f_mean)-3)/10, len(f_mean)-3) , f_mean[1:-2])\n",
"ax.grid()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## References\n",
"\n",
"1. **Gasior, M. & Gonzalez, J.** Improving FFT frequency measurement resolution by parabolic and gaussian interpolation *CERN-AB-Note-2004-021, CERN-AB-Note-2004-021, 2004*"
]
}
],
"metadata": {