Commit 60883d68 by Jenni Rinker

### fall 22 dates!

parent edf64fa7
Pipeline #31748 passed with stage
in 2 minutes and 17 seconds
 ... ... @@ -9,7 +9,7 @@ DTU Wind Energy CodeCamp Welcome to CodeCamp, a week-long, fun workshop dedicated to making you a better programmer! **** **** As engineers, we often spend much of our time in education learning about math, science and physics. Times, however, are changing, and ... ...
 ... ... @@ -14,9 +14,9 @@ Who, when, where CodeCamp is intended for new masters students to get them ready to go for their education at DTU Wind Energy. A special Python-only camp will be held in January, 2022. We will The 2022 CodeCamp will happen August 16-19 (Tu-Fr) at DTU Lyngby campus. We will offer the option to attend remotely to work with travel plans, but sitting in front of a computer for 8 hours a day for 5 days straight sitting in front of a computer for 8 hours a day for several days straight is suboptimal. Therefore we strongly encourage you to make plans to attend physically, if possible. ... ... @@ -81,4 +81,5 @@ Previous editions CodeCamp has been held before! Here is the list of previous editions: * January 24-28, 2022. Python. * August 16-20, 2021. Matlab/Python.
 # -*- coding: utf-8 -*- """Calcaulte damped and undamped natural frequencies and damping for Turbie """ import numpy as np from scipy.linalg import eig from turbie_helpers import get_turbie_system_matrices M, C, K = get_turbie_system_matrices() #%% Undamped eigenanalysis # get eigenvalues and eigenvectors lamda, v = eig(np.linalg.inv(M) @ K) # sort by increasing lambda magnitude sort_idx = np.argsort(np.abs(lamda)) v = v[:, sort_idx] lamda = lamda[sort_idx] # get natural frequencies from eigenvalues wn = np.sqrt(np.abs(lamda)) # natural freq in rad/s fn = wn / 2 / np.pi # in Hz print('\nUndamped eigenanalysis') print('----------------------') print(' fn ' + ' '.join(f' {f:.3f}' for f in fn)) print(' v1 ' + ' '.join(f'{v[0,i]:6.3f}' for i in range(2))) print(' v2 ' + ' '.join(f'{v[1,i]:6.3f}' for i in range(2))) #%% Damped eigenanalysis # assemble state-space matrix I, O = np.eye(2), np.zeros((2, 2)) A = np.block([[O, I], [-np.linalg.inv(M) @ K, -np.linalg.inv(M) @ C]]) # get eigenvalues and eigenvectors lamda, v = eig(A) # take only unique values lamda = lamda[::2] v = v[:2, ::2] # sort by increasing lambda magnitude sort_idx = np.argsort(np.abs(lamda)) v = v[:, sort_idx] lamda = lamda[sort_idx] # calculate frequencies and damping wd = np.imag(lamda) fd = wd / 2 / np.pi # calculate undamped natural frequencies and damping (percent critical) wn = np.abs(lamda) fn = wn / 2 / np.pi zeta = -np.cos(np.angle(lamda)) print('\nDamped eigenanalysis') print('----------------------------------------') print(' fd ' + ' '.join(f' {f:13.3f}' for f in fd)) print(' z ' + ' '.join(f' {z*100:12.3f}%' for z in zeta)) print(' v1 ' + ' '.join(f'{v[0,i]:14.3f}' for i in range(2))) print(' v2 ' + ' '.join(f'{v[1,i]:14.3f}' for i in range(2)))
 # -*- coding: utf-8 -*- """Load a simulation, calculate power spectrum and plot the time series and PSD """ import matplotlib.pyplot as plt import numpy as np from turbie_helpers import load_turbie_res, calculate_psd # ----- load the results from file ----- # txtpath = '../results/free_response_1.0_0.2_0.0_0.0.txt' txtpath = '../MATLAB_model/res_8_ms_TI_0.15.txt' t, x, u = load_turbie_res(txtpath) # ---- calculate psd ----- f, S, Su = calculate_psd(t, x, u) # ----- check the variance ----- # var_u = np.var(u) # sum_Su = np.trapz(Su, x=f) # print(f'Wind variance: {var_u:.3f}') # print('') # ---- plot ----- fig, axs = plt.subplots(2, 1, num=1, clear=True, figsize=(10, 6)) ax = axs[0] ax.plot(t, x[:, 0]) ax.plot(t, x[:, 1]) ax.set_ylabel('Free response [m]') ax.set_xlabel('Time [s]') ax.set_xlim([t[0], t[-1]]) ax = axs[1] ax.semilogy(f, S[:, 0], label='Blade (x1)') ax.semilogy(f, S[:, 1], label='Nacelle (x2)') ax.set_ylabel('PSD [m^2/Hz]') ax.set_xlabel('Frequency [Hz]') ax.set_xlim([0, 4]) ylim = ax.get_ylim() f1, f2 = 0.25, 0.63 ax.plot([f1, f1], ylim, '--', c='0.7', zorder=-2, label='Natural frequency') ax.plot([f2, f2], ylim, '--', c='0.7', zorder=-2) ax.set_ylim(ylim) ax.legend() fig.suptitle(f'Simulation: "{txtpath}"') plt.tight_layout()
 # -*- coding: utf-8 -*- """Simulate Turbie's response with no wind to initial conditions and save """ import numpy as np from scipy.integrate import solve_ivp from turbie_helpers import get_turbie_system_matrices, save_turbie_res def dqdt_homogeneous(t, q, M, C, K): """Differential function for Turbie with no wind""" I, O = np.eye(2), np.zeros((2, 2)) A = np.block([[O, I], [-np.linalg.inv(M) @ K, -np.linalg.inv(M) @ C]]) return A @ q # simulation settings dt = 0.01 # time step y0 = [1, 0.2, 0, 0] # initial condition [x1, x2, v1, v2] t_span = [0, 10] # time to simulate # ---- run simulation ----- M, C, K = get_turbie_system_matrices() t_eval = np.arange(t_span[0], t_span[1], dt) res = solve_ivp(dqdt_homogeneous, t_span, y0, args=(M, C, K), t_eval=t_eval) # ----- save results ----- txtpath = '../results/free_response_' + '_'.join(f'{x:.1f}' for x in y0) + '.txt' save_turbie_res(res, txtpath)
 # -*- coding: utf-8 -*- """Helper functions for Turbie exercises """ import numpy as np def calculate_psd(t, x, u=None): """Get the one-sided PSD of Turbie response (and forcing, if given)""" T = t[-1] + t[1] dt, df = T / t.size, 1 / T f = np.fft.rfftfreq(t.size, d=dt) S = np.abs(np.fft.rfft(x, axis=0))**2 / 2 / df if u is None: return f, S else: Su = np.abs(np.fft.rfft(u))**2 / 2 / df return f, S, Su def load_parameters(path='../turbie_parameters.txt'): """Load the parameters for Turbie from a text file""" path = '../turbie_parameters.txt' mb, mn, mh, mt, c1, c2, k1, k2, fb, ft, drb, drt, Dr, rho = \ np.loadtxt(path, comments='%') return mb, mn, mh, mt, c1, c2, k1, k2, fb, ft, drb, drt, Dr, rho def load_turbie_res(path): """""" res_arr = np.loadtxt(path, skiprows=1) t, u = res_arr[:, :2].T x = res_arr[:, 2:] return t, x, u def get_turbie_system_matrices(): """Assmble M, C and K for Turbie""" mb, mn, mh, mt, c1, c2, k1, k2, fb, ft, drb, drt, Dr, rho = load_parameters() m1 = 3*mb # mass 1 is 3 blades m2 = mh + mn + mt # mass 2 is hub, nacelle and tower M = np.array([[m1, 0], [0, m2]]) # mass matrix C = np.array([[c1, -c1], [-c1, c1+c2]]) # damping matrix K = np.array([[k1, -k1], [-k1, k1+k2]]) # stiffness matrix return M, C, K def save_turbie_res(res, path, wind=None): """Save Turbie results to a text file at the specified path. If forced response, pass tp and u(tp) in as wind=(tp, up).""" if wind is not None: tp, up = wind else: tp = res.t up = np.zeros(tp.size) save_arr = np.empty((res.t.size, 4)) save_arr[:, 0] = res.t save_arr[:, 1] = up save_arr[:, 2:] = res.y[:2, :].T np.savetxt(path, save_arr, fmt='%.3f', delimiter='\t', comments='', header='Time(s) V(m/s) xb(m) xt(m)') return
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!