Commit 60883d68 authored by Jenni Rinker's avatar Jenni Rinker
Browse files

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!
**<Python CodeCamp January 24-28 2022!!! Check announcements on Inside to register.>**
**<CodeCamp August 16-19 2022!!! Check announcements on Inside to register.>**
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!
Please register or to comment