iccsa-21-wind

git clone https://git.igankevich.com/iccsa-21-wind.git
Log | Files | Refs

commit b0f5903d3345be34cb8288e6c9a06945f057931e
parent 37f99067dbc862580be7ca3355ad81e90b9fb283
Author: Ivan Gankevich <i.gankevich@spbu.ru>
Date:   Thu,  1 Apr 2021 16:30:22 +0300

Velocity distribution graph.

Diffstat:
.gitignore | 51++++++++++++++++++++++++++++++++++++++++++++++++---
Makefile | 5+++++
R/anal.R | 143+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
R/calibrate.R | 36------------------------------------
R/common.R | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
R/daily-stats.R | 23++++++-----------------
R/minmax.R | 17+++++++++++++++++
gnuplot/daily-rmse.gnuplot | 31+++++++++++++++++++++++++++++++
gnuplot/daily-stats.gnuplot | 2+-
gnuplot/velocity-dist-weibull2.gnuplot | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
gnuplot/velocity-dist.gnuplot | 107+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
guix/manifest.scm | 2++
main.tex | 62+++++++++++++++++++++++++++++---------------------------------
13 files changed, 498 insertions(+), 144 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,8 +1,8 @@ /build Rplots.pdf -# Created by https://www.toptal.com/developers/gitignore/api/vim,linux -# Edit at https://www.toptal.com/developers/gitignore?templates=vim,linux +# Created by https://www.toptal.com/developers/gitignore/api/vim,linux,r +# Edit at https://www.toptal.com/developers/gitignore?templates=vim,linux,r ### Linux ### *~ @@ -19,6 +19,51 @@ Rplots.pdf # .nfs files are created when an open file is removed but is still being accessed .nfs* +### R ### +# History files +.Rhistory +.Rapp.history + +# Session Data files +.RData + +# User-specific files +.Ruserdata + +# Example code in package build process +*-Ex.R + +# Output files from R CMD build +/*.tar.gz + +# Output files from R CMD check +/*.Rcheck/ + +# RStudio files +.Rproj.user/ + +# produced vignettes +vignettes/*.html +vignettes/*.pdf + +# OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 +.httr-oauth + +# knitr and R markdown default cache directories +*_cache/ +/cache/ + +# Temporary files created by R markdown +*.utf8.md +*.knit.md + +# R Environment Variables +.Renviron + +### R.Bookdown Stack ### +# R package: bookdown caching files +/*_files/ + ### Vim ### # Swap [._]*.s[a-v][a-z] @@ -39,4 +84,4 @@ tags # Persistent undo [._]*.un~ -# End of https://www.toptal.com/developers/gitignore/api/vim,linux +# End of https://www.toptal.com/developers/gitignore/api/vim,linux,r diff --git a/Makefile b/Makefile @@ -16,6 +16,8 @@ all: build/iccsa-21-wind-slides.pdf build/main.pdf: main.tex build/main.pdf: build/inkscape/anemometer.eps build/main.pdf: build/daily-stats.eps +build/main.pdf: build/daily-rmse.eps +build/main.pdf: build/gnuplot/velocity-dist.eps #build/main.pdf: build/gnuplot/anemometer.eps #build/main.pdf: build/gnuplot/anemometer.svg build/main.pdf: @@ -46,6 +48,9 @@ build/inkscape/%.eps: inkscape/%.svg build/daily-stats.svg: gnuplot/daily-stats.gnuplot build/daily-stats gnuplot -d $< +build/daily-rmse.svg: gnuplot/daily-rmse.gnuplot build/daily-rmse + gnuplot -d $< + #build/main.zip: build/gnuplot/*.eps main.tex build/main.zip: main.tex @mkdir -p build diff --git a/R/anal.R b/R/anal.R @@ -2,11 +2,13 @@ library(DBI) library(fitdistrplus) library(plotrix) library(sn) +library(doParallel) +library(foreach) +registerDoParallel(cores=detectCores()) -datetime_format <- "%FT%H:%M" +source("R/common.R") -# https://stackoverflow.com/questions/13023274/how-to-do-printf-in-r -printf <- function(...) cat(sprintf(...)) +datetime_format <- "%FT%H:%M" # https://stackoverflow.com/questions/32370485/convert-radians-to-degree-degree-to-radians rad2deg <- function(rad) {(rad * 180) / (pi)} @@ -31,6 +33,10 @@ power <- function(x,y) { #abs(x)**y } +rmse <- function(estimated, actual){ + sqrt(mean((estimated - actual)**2)) +} + dweibull2 <- function (x, a1=1, b1=1, c1=1, a2=1, b2=1, c2=1, g=0) { #ifelse(x<g, # a1* abs(c1*b1)*(abs(b1*(x-g))**(c1-1))* exp(-(abs(b1*(x-g))**c1)), @@ -56,9 +62,6 @@ dgumbel <- function (x, location=0, scale=1) { (1/scale) * exp(-(z + exp(-z))) } -drayleigh <- function (x, location=0, scale=1) { -} - # https://www.tutorialspoint.com/r/r_mean_median_mode.htm # https://stackoverflow.com/questions/2547402/how-to-find-the-statistical-mode getmode <- function(v) { @@ -209,6 +212,7 @@ fit_velocity_pdf <- function (xx, x, density, sign=-1, plot=TRUE, axis="x", dist }) pdf_x_est <- c[[2]]*dweibull(sign*pdf_x$x,scale=c[[1]],shape=2) } else { + x_mode <- find_max_x(pdf_x$x,pdf_x$density) c <- tryCatch( { model <- nls(pdf_x$density ~ c*dweibull(sign*pdf_x$x,scale=a,shape=b), @@ -216,7 +220,8 @@ fit_velocity_pdf <- function (xx, x, density, sign=-1, plot=TRUE, axis="x", dist start=list(a=1,b=1,c=1), control=list(warnOnly=TRUE), algorithm="port", - lower=c(0.1,0.1,0), upper=c(1000,1000,1000)) + lower=c(0.1,0.1,0), + upper=c(1000,1000,1000)) c = summary(model)$coefficients }, error=function(cond) { @@ -239,19 +244,20 @@ fit_velocity_pdf <- function (xx, x, density, sign=-1, plot=TRUE, axis="x", dist list(coefficients=c, actual_density=pdf_x$density, estimated_density=pdf_x_est, - x=pdf_x$x) + x=pdf_x$x, + residual=max(abs(pdf_x$density-pdf_x_est))) } } -fit_velocity_pdf_bilateral <- function (velocity, axis="x") { +fit_velocity_pdf_bilateral <- function (velocity, axis="x", timestamp=0, dist="weibull") { velocity_hist <- normalize_hist(hist(velocity, plot=FALSE, breaks=100)) x = velocity_hist$x; v = velocity_hist$density; d = density(velocity,adjust=0.5) dist_left <- fit_velocity_pdf(x[x<=0], v[x<=0], density=d$y[d$x<=0], - sign=-1, plot=FALSE, axis=axis, dist="weibull") + sign=-1, plot=FALSE, axis=axis, dist=dist) dist_right <- fit_velocity_pdf(x[x>=0], v[x>=0], density=d$y[d$x>=0], - sign=1, plot=FALSE, axis=axis, dist="weibull") + sign=1, plot=FALSE, axis=axis, dist=dist) #x <- c(dist_left$x, dist_right$x) actual_density <- c(dist_left$actual_density, dist_right$actual_density) estimated_density <- c(dist_left$estimated_density, dist_right$estimated_density) @@ -261,7 +267,17 @@ fit_velocity_pdf_bilateral <- function (velocity, axis="x") { #lines(x, estimated_density, col='red', lwd=2) lines(dist_left$x, dist_left$estimated_density, col='red', lwd=2) lines(dist_right$x, dist_right$estimated_density, col='blue', lwd=2) - dist_left$coefficients + #printf("RMSE %f\n", rmse(estimated_density, actual_density)) + path <- file.path('build', 'velocity', axis, dist) + dir.create(path, recursive=TRUE) + filename <- file.path(path, sprintf("%d", timestamp)) + write.table(data.frame(x=x,actual=actual_density,estimated=estimated_density), + filename, row.names=FALSE, quote=FALSE) + write("\n",file=filename,append=TRUE) + write.table(data.frame(x=d$x,density=d$y), filename, + row.names=FALSE, quote=FALSE, append=TRUE) + list(coefficients=dist_left$coefficients, + rmse=rmse(estimated_density, actual_density)) } fit_velocity_pdf_v2 <- function (x, sign=-1, plot=TRUE, axis="x") { @@ -316,50 +332,55 @@ fit_direction <- function (x, x_mode, plot=TRUE) { c } -mydb <- dbConnect(RSQLite::SQLite(), "samples/load-cell.sqlite3") - time_start = time_string_to_timestamp("2021-03-06T00:00") time_end = time_string_to_timestamp("2021-03-06T23:00") +#time_start = time_string_to_timestamp("2021-02-21T00:00") +#time_end = time_string_to_timestamp("2021-03-31T23:00") time_delta = 60*60*2 print(time_start) print(time_end) -cumulative_data <- data.frame(speed=numeric(0),direction=numeric(0), - x_mode=numeric(0),abs_x_mode=numeric(0),x_sd=numeric(0), - y_mean=numeric(0), - acf_x_a=numeric(0),acf_x_b=numeric(0),acf_x_c=numeric(0), - x_a=numeric(0),x_b=numeric(0),x_c=numeric(0), - x_d=numeric(0),x_e=numeric(0),x_f=numeric(0), - # Y - y_mode=numeric(0), - y_a=numeric(0),y_b=numeric(0),y_c=numeric(0), - y_d=numeric(0),y_e=numeric(0),y_f=numeric(0), - acf_y_a=numeric(0),acf_y_b=numeric(0),acf_y_c=numeric(0)) timestamps <- seq(time_start, time_end, time_delta) -pb <- txtProgressBar(min = 0, max = length(timestamps), style = 3) - -i <- 0 -for (timestamp in timestamps) { - velocity = dbGetQuery(mydb, +#pb <- txtProgressBar(min = 0, max = length(timestamps), style = 3) + +#i <- 0 +#for (timestamp in timestamps) { +cumulative_data <- foreach (timestamp=timestamps, .combine=rbind, .errorhandling='remove') %dopar% { + db <- dbConnect(RSQLite::SQLite(), "samples/load-cell.sqlite3") + cumulative_data <- data.frame(speed=numeric(0),direction=numeric(0), + x_mode=numeric(0),abs_x_mode=numeric(0),x_sd=numeric(0), + y_mean=numeric(0), + acf_x_a=numeric(0),acf_x_b=numeric(0),acf_x_c=numeric(0), + x_a=numeric(0),x_b=numeric(0),x_c=numeric(0), + x_d=numeric(0),x_e=numeric(0),x_f=numeric(0), + # Y + y_mode=numeric(0), + y_a=numeric(0),y_b=numeric(0),y_c=numeric(0), + y_d=numeric(0),y_e=numeric(0),y_f=numeric(0), + acf_y_a=numeric(0),acf_y_b=numeric(0),acf_y_c=numeric(0), + timestamp=numeric(0), + x_rmse=numeric(0), y_rmse=numeric(0), z_rmse=numeric(0)) + velocity = dbGetQuery(db, "SELECT x,y,z FROM samples WHERE timestamp BETWEEN :t0 AND (:t0 + :dt) ORDER BY timestamp", params = list(t0 = timestamp, dt=time_delta)) - velocity = dbGetQuery(mydb, + velocity = dbGetQuery(db, "SELECT x,y,z FROM samples WHERE timestamp BETWEEN :t0 AND (:t0 + :dt) - AND ABS(x-:xmean)<10000 AND ABS(y-:ymean)<10000 AND ABS(z-:zmean)<10000 + AND ABS(x-:xmean)<10000 AND ABS(y-:ymean)<10000 AND ABS(z-:zmean)<10000 ORDER BY timestamp", params = list(t0 = timestamp, dt=time_delta, xmean=mean(velocity$x), ymean=mean(velocity$y), zmean=mean(velocity$z))) + if (nrow(velocity) == 0) { next } + filename <- sprintf("build/rplot-%d.pdf", timestamp) + print(filename) + pdf(filename) old_mean_x <- max(abs(velocity$x)) - mean(velocity$x) - velocity$x = (velocity$x - mean(velocity$x)) - velocity$y = (velocity$y - mean(velocity$y)) - velocity$z = (velocity$z - mean(velocity$z)) - # convert energy to velocity (U^2 -> U) - velocity$x = sign(velocity$x)*sqrt(abs(velocity$x)) - velocity$y = sign(velocity$y)*sqrt(abs(velocity$y)) - velocity$z = sign(velocity$z)*sqrt(abs(velocity$z)) + coefficients <- calibration_coefficients() + velocity$x = sample_to_speed(velocity$x, coefficients$x1, coefficients$x2) + velocity$y = sample_to_speed(velocity$y, coefficients$y1, coefficients$y2) + velocity$z = sample_to_speed(velocity$z, coefficients$z1, coefficients$z2) x_mode <- getmode(velocity$x) y_mode <- getmode(velocity$y) #direction_mode <- getmode(velocity$direction) @@ -367,6 +388,7 @@ for (timestamp in timestamps) { velocity$speed = speed(velocity$x,velocity$y,velocity$z) velocity$direction = direction(velocity$x,velocity$y) new_row = nrow(cumulative_data)+1 + cumulative_data[new_row, "timestamp"] = timestamp cumulative_data[new_row, "x_mode"] = x_mode cumulative_data[new_row, "y_mode"] = y_mode cumulative_data[new_row, "speed"] = mean(velocity$speed) @@ -378,23 +400,31 @@ for (timestamp in timestamps) { #fit <- fitdist(velocity$x, "gumbel", start=list(a=1, b=1)) #plot(fit) # Velocity X - x_coefs <- fit_velocity_pdf_bilateral(velocity$x, axis="x") - cumulative_data[new_row, "x_a"] = x_coefs[[1]] - cumulative_data[new_row, "x_b"] = x_coefs[[2]] + #for (dist in c("weibull2")) { + # fit_velocity_pdf_bilateral(velocity$x, axis="x", timestamp=timestamp, dist="weibull2") + # fit_velocity_pdf_bilateral(velocity$y, axis="y", timestamp=timestamp, dist="weibull2") + # fit_velocity_pdf_bilateral(velocity$z, axis="z", timestamp=timestamp, dist="weibull2") + #} + x_model <- fit_velocity_pdf_bilateral(velocity$x, axis="x", timestamp=timestamp, dist="weibull") + cumulative_data[new_row, "x_a"] = x_model$coefficients[[1]] + cumulative_data[new_row, "x_b"] = x_model$coefficients[[2]] + cumulative_data[new_row, "x_rmse"] = x_model$rmse #cumulative_data[new_row, "x_c"] = x_coefs[[3]] #cumulative_data[new_row, "x_d"] = x_coefs[[4]] #cumulative_data[new_row, "x_e"] = x_coefs[[5]] #cumulative_data[new_row, "x_f"] = x_coefs[[6]] # Velocity Y - y_coefs <- fit_velocity_pdf_bilateral(velocity$y, axis="y") - cumulative_data[new_row, "y_a"] = y_coefs[[1]] - cumulative_data[new_row, "y_b"] = y_coefs[[2]] + y_model <- fit_velocity_pdf_bilateral(velocity$y, axis="y", timestamp=timestamp, dist="weibull") + cumulative_data[new_row, "y_a"] = y_model$coefficients[[1]] + cumulative_data[new_row, "y_b"] = y_model$coefficients[[2]] + cumulative_data[new_row, "y_rmse"] = y_model$rmse #cumulative_data[new_row, "y_c"] = y_coefs[[3]] #cumulative_data[new_row, "y_d"] = y_coefs[[4]] #cumulative_data[new_row, "y_e"] = y_coefs[[5]] #cumulative_data[new_row, "y_f"] = y_coefs[[6]] # Velocity Z - z_coefs <- fit_velocity_pdf_bilateral(velocity$z, axis="z") + z_model <- fit_velocity_pdf_bilateral(velocity$z, axis="z", timestamp=timestamp, dist="weibull") + cumulative_data[new_row, "z_rmse"] = z_model$rmse # ACF X x_coefs <- fit_velocity_acf(velocity$x, plot=TRUE, axis="x") cumulative_data[new_row, "acf_x_a"] = x_coefs[[1]] @@ -406,7 +436,7 @@ for (timestamp in timestamps) { cumulative_data[new_row, "acf_y_c"] = y_coefs[[3]] direction_coefs <- fit_direction(velocity$direction, direction_mode, plot=TRUE) - print(direction_coefs) + #print(direction_coefs) old_mar = par("mar") direction_hist <- hist(velocity$direction, plot=FALSE, breaks=100) @@ -418,19 +448,24 @@ for (timestamp in timestamps) { cumulative_data[new_row, "abs_x_mode"] = abs(x_mode) cumulative_data[new_row, "x_sd"] = sd(velocity$x) cumulative_data[new_row, "y_mean"] = mean(velocity$y) - i <- i + 1 - setTxtProgressBar(pb, i) + #i <- i + 1 + #setTxtProgressBar(pb, i) + dbDisconnect(db) + dev.off() + cumulative_data } -close(pb) +#close(pb) -print(cumulative_data) -print(summary(cumulative_data)) +rmse_table <- cumulative_data[c("timestamp","x_rmse","y_rmse","z_rmse","speed")] +write.table(rmse_table, "build/daily-rmse", row.names=FALSE, quote=FALSE) +#print(cumulative_data) +#print(summary(cumulative_data)) model <- nls(x_sd ~ a*speed+b, data=cumulative_data, control=list(warnOnly=TRUE), start=list(a=1,b=0)) coefs <- summary(model)$coefficients -print(coefs) +#print(coefs) x_sd_est <- sapply(cumulative_data$speed, function (x) { coefs[[1]]*x + coefs[[2]] }) plot(cumulative_data$speed, cumulative_data$x_sd) lines(cumulative_data$speed, x_sd_est, col='red') @@ -470,6 +505,7 @@ lines(cumulative_data$abs_x_mode_acf_x_c, bc_est, col='red') + #plot(cumulative_data$x_mode, cumulative_data$c) #plot(cumulative_data$x_mode, cumulative_data$acf_x_b**cumulative_data$c) @@ -491,4 +527,3 @@ with (cumulative_data, { plot(direction, direction(x_b**acf_x_c, y_b**acf_x_c)) }) -dbDisconnect(mydb) diff --git a/R/calibrate.R b/R/calibrate.R @@ -1,36 +0,0 @@ -# https://stackoverflow.com/questions/13023274/how-to-do-printf-in-r -printf <- function(...) cat(sprintf(...)) - -reference_value <- 2.045 # measured with commercial anemometer - -calc_origin <- function (filename="anemometer-no-wind") { - data <- read.table(filename, sep="", header=FALSE) - names(data) <- c("t", "x", "y", "z", "sx", "sy", "sz") - origin = list(x=mean(data$x), y=mean(data$y), z=mean(data$z)) - origin -} - -my_sqrt <- function (x) { sign(x) * sqrt(abs(x)) } - -calc_coefficient <- function (filename, axis) { - origin <- calc_origin(sprintf("%s-origin",filename)) - data <- read.table(filename, sep="", header=FALSE) - names(data) <- c("t", "x", "y", "z", "sx", "sy", "sz") - sign <- data[1,sprintf("s%s",axis)] - sign*my_sqrt(mean(data[[axis]])-origin[[axis]])/reference_value -} - -coefficient_x <- calc_coefficient("build/x", "x") -coefficient_x_reverse <- calc_coefficient("build/x-reverse", "x") -coefficient_y <- calc_coefficient("build/y", "y") -coefficient_y_reverse <- calc_coefficient("build/y-reverse", "y") -coefficient_z <- calc_coefficient("build/z", "z") -coefficient_z_reverse <- calc_coefficient("build/z-reverse", "z") -printf("-1 m/s is x %f y %f z %f\n", coefficient_x, coefficient_y, coefficient_z) -printf("1 m/s is x %f y %f z %f\n", coefficient_x_reverse, coefficient_y_reverse, coefficient_z_reverse) - -weight_0 = (calc_origin("build/z-fan")$z - calc_origin("build/z-fan-origin")$z) -weight_1 = (calc_origin("build/z-fan-and-wind")$z - calc_origin("build/z-fan-and-wind-origin")$z) -print(weight_0) -print(weight_1) -print(my_sqrt(weight_1-weight_0)/reference_value) diff --git a/R/common.R b/R/common.R @@ -0,0 +1,56 @@ +# https://stackoverflow.com/questions/13023274/how-to-do-printf-in-r +printf <- function(...) cat(sprintf(...)) + +reference_value <- 2.045 # measured with commercial anemometer + +calc_origin <- function (filename="anemometer-no-wind") { + data <- read.table(filename, sep="", header=FALSE) + names(data) <- c("t", "x", "y", "z", "sx", "sy", "sz") + origin = list(x=mean(data$x), y=mean(data$y), z=mean(data$z)) + origin +} + +abs_sqrt <- function (x) { sign(x) * sqrt(abs(x)) } + +calc_coefficient <- function (filename, axis) { + origin <- calc_origin(sprintf("%s-origin",filename)) + data <- read.table(filename, sep="", header=FALSE) + names(data) <- c("t", "x", "y", "z", "sx", "sy", "sz") + sign <- data[1,sprintf("s%s",axis)] + sign*abs_sqrt(mean(data[[axis]])-origin[[axis]])/reference_value +} + +calibration_coefficients <- function(debug=FALSE) { + # *1 --- negative, *2 --- positive, *reverse --- positive + cx1 <- calc_coefficient("build/x", "x") + cx2 <- calc_coefficient("build/x-reverse", "x") + cy1 <- calc_coefficient("build/y", "y") + cy2 <- calc_coefficient("build/y-reverse", "y") + cz1 <- calc_coefficient("build/z", "z") + cz2 <- calc_coefficient("build/z-reverse", "z") + if (debug) { + printf("-1 m/s is x %f y %f z %f\n", cx1, cy1, cz1) + printf("1 m/s is x %f y %f z %f\n", cx2, cy2, cz2) + } + list(x1=cx1, x2=cx2, y1=cy1, y2=cy2, z1=cz1, z2=cz2) + #weight_0 = (calc_origin("build/z-fan")$z - calc_origin("build/z-fan-origin")$z) + #weight_1 = (calc_origin("build/z-fan-and-wind")$z - calc_origin("build/z-fan-and-wind-origin")$z) + #print(weight_0) + #print(weight_1) + #print(abs_sqrt(weight_1-weight_0)/reference_value) +} + +# convert load cell anemometer sensor value to wind speed in m/s +sample_to_speed <- function(x, c1, c2) { + # remove linear trend + t <- c(1:length(x)) + reg <- lm(x~t) + x <- x - reg$fitted.values + #x <- x - mean(x) # convert from unsigned to signed sensor values + x <- sign(x)*sqrt(abs(x)) # convert from force to velocity + # scale sensor values to wind speed using calibration coefficients + x[x<0] = x[x<0] / -c1 + x[x>0] = x[x>0] / c2 + x +} + diff --git a/R/daily-stats.R b/R/daily-stats.R @@ -1,19 +1,6 @@ library(DBI) -source("R/calibrate.R") - -sample_to_speed <- function(x, coef, coef_reverse) { - x <- x - mean(x) # convert from unsigned to signed sensor values - x <- sign(x)*sqrt(abs(x)) # convert from force to velocity - # scale sensor values to wind speed using calibration coefficients - x[x<0] = x[x<0] / -coef - x[x>0] = x[x>0] / coef_reverse - # remove linear trend - t <- c(1:length(x)) - reg <- lm(x~t) - x <- x - reg$fitted.values - x -} +source("R/common.R") db <- dbConnect(RSQLite::SQLite(), "samples/load-cell.sqlite3") RSQLite::initExtension(db) @@ -30,13 +17,14 @@ i <- 0 result <- data.frame(interval=numeric(0),timestamp=numeric(0), x_sd=numeric(0),y_sd=numeric(0),z_sd=numeric(0), speed=numeric(0)) +c <- calibration_coefficients() unique_intervals <- unique(velocity$interval) pb <- txtProgressBar(min = 0, max = length(unique_intervals), style = 3) for (interval in unique_intervals) { v <- (velocity[velocity$interval==interval, ]) - v$x <- sample_to_speed(v$x, coefficient_x, coefficient_x_reverse) - v$y <- sample_to_speed(v$y, coefficient_y, coefficient_y_reverse) - v$z <- sample_to_speed(v$z, coefficient_z, coefficient_z_reverse) + v$x <- sample_to_speed(v$x, c$x1, c$x2) + v$y <- sample_to_speed(v$y, c$y1, c$y2) + v$z <- sample_to_speed(v$z, c$z1, c$z2) new_row = nrow(result)+1 result[new_row, "interval"] <- interval result[new_row, "timestamp"] <- min(v$timestamp) @@ -47,6 +35,7 @@ for (interval in unique_intervals) { i <- i + 1 setTxtProgressBar(pb, i) } +close(pb) write.table(result, "build/daily-stats", row.names=FALSE, quote=FALSE) dbDisconnect(db) diff --git a/R/minmax.R b/R/minmax.R @@ -0,0 +1,17 @@ +library(DBI) + +data <- read.table("build/daily-rmse", sep="", header=TRUE) +z_rmse_sorted <- sort(data$z_rmse, decreasing=TRUE) +print("MAX RMSE") +print(data[data$x_rmse == max(data$x_rmse), ]) +print(data[data$y_rmse == max(data$y_rmse), ]) +print(data[data$z_rmse == z_rmse_sorted[[1]], ]) +print(data[data$z_rmse == z_rmse_sorted[[2]], ]) +print("MIN RMSE") +print(data[data$x_rmse == min(data$x_rmse), ]) +print(data[data$y_rmse == min(data$y_rmse), ]) +print(data[data$z_rmse == min(data$z_rmse), ]) +print("AVG RMSE") +print(summary(data)) +print(cor(data)) +#print(data) diff --git a/gnuplot/daily-rmse.gnuplot b/gnuplot/daily-rmse.gnuplot @@ -0,0 +1,31 @@ +load 'gnuplot/paired.pal' +set terminal svg size 500,250 font 'Free Serif, 10' enhanced dynamic round +set xtics nomirror out rotate 90 offset 0,0.25 +set ytics nomirror out offset 0.5,0 +set border 1+2 +set key top center outside maxrows 1 + +stats 'build/daily-rmse' using 2 + +# time axis +set xdata time +set timefmt "%s" +set format x "%Y-%m-%d" +set xtics 0,60*60*24 +set mxtics 1 +localtime(t) = t+3*60*60 + +set output 'build/daily-rmse.svg' + +do for [timestamp in "1614546000 1614978000 1615496400 1616187600 1616274000 1616360400 1616533200"] { + t = int(timestamp) + set obj t rectangle behind from first localtime(t), first 0 to first localtime(t)+24*60*60, graph 1 back fillstyle solid 1.0 fillcolor '#f0f0c0' lw 0 +} + +plot \ + 'build/daily-rmse' using (localtime($1)):2 with lines lc '#c04040' title 'RMSE_x',\ + 'build/daily-rmse' using (localtime($1)):3 with lines lc '#40c040' title 'RMSE_y',\ + 'build/daily-rmse' using (localtime($1)):4 with lines lc '#4040c0' title 'RMSE_z',\ + STATS_mean with lines lc '#808080' dashtype 2 notitle + + diff --git a/gnuplot/daily-stats.gnuplot b/gnuplot/daily-stats.gnuplot @@ -1,5 +1,5 @@ load 'gnuplot/paired.pal' -set terminal svg size 500,400 font 'Free Serif, 10' enhanced dynamic +set terminal svg size 500,400 font 'Free Serif, 10' enhanced dynamic round set xtics nomirror out rotate 90 offset 0,0.25 set ytics nomirror out offset 0.5,0 set border 1+2 diff --git a/gnuplot/velocity-dist-weibull2.gnuplot b/gnuplot/velocity-dist-weibull2.gnuplot @@ -0,0 +1,107 @@ +load 'gnuplot/paired.pal' +set terminal svg size 500,500/3*2 font 'Free Serif, 10' enhanced round dynamic +set xtics nomirror out offset 0,0.25 +set ytics nomirror out offset 0.5,0 +set border 1+2 back +#set key top center outside Left reverse +unset key + +set output 'build/gnuplot/velocity-dist-weibull2.svg' + +# 258 1615914000 0.08700399 0.06517805 0.06370091 1.660843 +# timestamp x_rmse y_rmse z_rmse speed +# 295 1616187600 0.03527403 0.08648245 0.03217789 1.637611 +# timestamp x_rmse y_rmse z_rmse speed +# 399 1616958000 0.02882994 0.03539276 0.1744659 0.8539361 +# timestamp x_rmse y_rmse z_rmse speed +# 292 1616166000 0.06300805 0.02371221 0.094087 2.052675 +# [1] "MIN RMSE" +# timestamp x_rmse y_rmse z_rmse speed +# 322 1616382000 0.008555768 0.009697918 0.01404791 3.981209 +# timestamp x_rmse y_rmse z_rmse speed +# 115 1614877200 0.01305041 0.009301931 0.02022811 4.356801 +# timestamp x_rmse y_rmse z_rmse speed +# 39 1614330000 0.01867408 0.01648803 0.01133067 4.552804 + + +set xlabel 'υ_x' offset 0,1.0 +set yrange [0:1.2] +set rmargin 0 +set tmargin 1 +set multiplot layout 2,3 + +positive(x) = x<0 ? (1/0) : x +negative(x) = x>0 ? (1/0) : x + +set lmargin 5 +set title offset 0,-1 +set title sprintf('RMSE_x = %f', 0.08700399) +set xrange [-4:4] +plot \ +'build/velocity/x/weibull2/1615914000' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_x',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_x',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_x' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + +#set key top center outside Left reverse +set lmargin 5 +#set xrange [-3:3] +set xlabel 'υ_y' +set title sprintf('RMSE_y = %f', 0.08648245) +set xrange [-3:5] +plot \ +'build/velocity/y/weibull2/1616187600' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_y',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_y',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_y' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ +#unset key + +set rmargin 2 +set xrange [-4:4] +#set xtics -2,1,2 +set xlabel 'υ_z' +set title sprintf('RMSE_z = %f', 0.1744659) +plot \ +'build/velocity/z/weibull2/1616958000' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_z',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_z',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_z' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + +################################### +# second row +################################### +set bmargin 3 +set xrange [-10:10] +set yrange [0:0.4] +set ytics 0,0.1 +#set xtics -10,1 + +set lmargin 5 +set title sprintf('RMSE_x = %f', 0.008555768) +plot \ +'build/velocity/x/weibull2/1616382000' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_x',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_x',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_x' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + +set lmargin 5 +#set xrange [-3:3] +set xlabel 'υ_y' +set title sprintf('RMSE_y = %f', 0.009301931) +#set xrange [-3:5] +plot \ +'build/velocity/y/weibull2/1614877200' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_y',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_y',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_y' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + +set rmargin 2 +#set xtics -2,1,2 +set xlabel 'υ_z' +set title sprintf('RMSE_z = %f', 0.01133067) +plot \ +'build/velocity/z/weibull2/1614330000' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_z',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_z',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_z' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + diff --git a/gnuplot/velocity-dist.gnuplot b/gnuplot/velocity-dist.gnuplot @@ -0,0 +1,107 @@ +load 'gnuplot/paired.pal' +set terminal svg size 500,500/3*2 font 'Free Serif, 10' enhanced round dynamic +set xtics nomirror out offset 0,0.25 +set ytics nomirror out offset 0.5,0 +set border 1+2 back +#set key top center outside Left reverse +unset key + +set output 'build/gnuplot/velocity-dist.svg' + +# 258 1615914000 0.08700399 0.06517805 0.06370091 1.660843 +# timestamp x_rmse y_rmse z_rmse speed +# 295 1616187600 0.03527403 0.08648245 0.03217789 1.637611 +# timestamp x_rmse y_rmse z_rmse speed +# 399 1616958000 0.02882994 0.03539276 0.1744659 0.8539361 +# timestamp x_rmse y_rmse z_rmse speed +# 292 1616166000 0.06300805 0.02371221 0.094087 2.052675 +# [1] "MIN RMSE" +# timestamp x_rmse y_rmse z_rmse speed +# 322 1616382000 0.008555768 0.009697918 0.01404791 3.981209 +# timestamp x_rmse y_rmse z_rmse speed +# 115 1614877200 0.01305041 0.009301931 0.02022811 4.356801 +# timestamp x_rmse y_rmse z_rmse speed +# 39 1614330000 0.01867408 0.01648803 0.01133067 4.552804 + + +set xlabel 'υ_x' offset 0,1.0 +set yrange [0:1.2] +set rmargin 0 +set tmargin 1 +set multiplot layout 2,3 + +positive(x) = x<0 ? (1/0) : x +negative(x) = x>0 ? (1/0) : x + +set lmargin 5 +set title offset 0,-1 +set title sprintf('RMSE_x = %f', 0.08700399) +set xrange [-4:4] +plot \ +'build/velocity/x/weibull/1615914000' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_x',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_x',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_x' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + +#set key top center outside Left reverse +set lmargin 5 +#set xrange [-3:3] +set xlabel 'υ_y' +set title sprintf('RMSE_y = %f', 0.08648245) +set xrange [-3:5] +plot \ +'build/velocity/y/weibull/1616187600' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_y',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_y',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_y' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ +#unset key + +set rmargin 2 +set xrange [-4:4] +#set xtics -2,1,2 +set xlabel 'υ_z' +set title sprintf('RMSE_z = %f', 0.1744659) +plot \ +'build/velocity/z/weibull/1616958000' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_z',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_z',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_z' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + +################################### +# second row +################################### +set bmargin 3 +set xrange [-10:10] +set yrange [0:0.4] +set ytics 0,0.1 +#set xtics -10,1 + +set lmargin 5 +set title sprintf('RMSE_x = %f', 0.008555768) +plot \ +'build/velocity/x/weibull/1616382000' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_x',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_x',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_x' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + +set lmargin 5 +#set xrange [-3:3] +set xlabel 'υ_y' +set title sprintf('RMSE_y = %f', 0.009301931) +#set xrange [-3:5] +plot \ +'build/velocity/y/weibull/1614877200' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_y',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_y',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_y' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + +set rmargin 2 +#set xtics -2,1,2 +set xlabel 'υ_z' +set title sprintf('RMSE_z = %f', 0.01133067) +plot \ +'build/velocity/z/weibull/1614330000' index 0 using 1:2 with points pt 6 lc '#404040' title 'Observed PDF of υ_z',\ +'' index 0 using (positive($1)):3 with lines lw 2 lc '#c04040' title 'Estimated PDF of positive υ_z',\ +'' index 0 using (negative($1)):3 with lines lw 2 lc '#4040c0' title 'Estimated PDF of negative υ_z' +#'' index 1 using 1:2 with lines dashtype 1 lw 2 lc '#808080' notitle, \ + diff --git a/guix/manifest.scm b/guix/manifest.scm @@ -4,6 +4,8 @@ (@ (gnu packages statistics) r-rsqlite) (@ (gnu packages statistics) r-sn) (@ (gnu packages statistics) r-plotrix) + (@ (gnu packages statistics) r-foreach) + (@ (gnu packages statistics) r-doparallel) (@ (gnu packages cran) r-fitdistrplus) (@ (gnu packages statistics) r) (@ (gnu packages maths) gnuplot) diff --git a/main.tex b/main.tex @@ -237,15 +237,15 @@ listing~\ref{lst-sample-to-speed}. \begin{lstlisting}[label={lst-sample-to-speed},caption={The code that transforms raw load cell sensor values into wind speed projection to the corresponding axis.}] sampleToSpeed <- function(x, c1, c2) { - x <- x - mean(x) # convert from unsigned to signed sensor values - x <- sign(x)*sqrt(abs(x)) # convert from force to velocity - # scale sensor values to wind speed using calibration coefficients - x[x<0] = x[x<0] / c1 - x[x>0] = x[x>0] / c2 # remove linear trend t <- c(1:length(x)) reg <- lm(x~t) x - reg$fitted.values + x <- sign(x)*sqrt(abs(x)) # convert from force to velocity + # scale sensor values to wind speed using calibration coefficients + x[x<0] = x[x<0] / c1 + x[x>0] = x[x>0] / c2 + x } \end{lstlisting} @@ -315,41 +315,37 @@ statistics that is not distorted by the turbulence. \subsection{Verification of wind velocity distribution} -The data collected with three-axis anemometer showed that for each two-hour -interval the shape of the wind velocity distribution for each axis can be -approximated by~\eqref{eq-velocity-distribution}. If the wind blows in positive -\(x\) direction, then the right part of the distribution is steep and if the -wind blows in negative \(x\) direction, then the left part of the distribution -is steep. - -We failed to gather the data where the distribution is unimodal: in most -intervals the distribution is bimodal. However, the second peak is often small -enough to have small effect on least-squares fitting. Distributions for each -axis are presented in figure~\ref{fig-velocity-distributions} and their -parameters in table~\ref{tab-velocity-distributions}. +The wind speed data collected with three-axis anemometer was approimated by +Weibull distribution using least-squares fitting. Negative and positive wind +speed projections to each axis both have this distribution, but with different +parameters. Most of the data intervals contain only one mean wind direction, which +means that one of the distributions is for incident wind flow on the arm of the +anemometer and another one is for the turbulent flow that forms behind the arm. +For \(z\) axis both left and right distributions have similar shapes, for \(x\) +and \(y\) axes the distribution for incident flow is taller than the +distribution for turbulent flow. Distributions for each axis are presented in +figure~\ref{fig-velocity-distributions}. + +RMSE of the approximation has negative correlation with wind speed: the larger +the wind speed, the smaller the error and vice versa. Larger error for low wind +speeds is caused by larger skewness and kurtosis (see the first row of +figure~\ref{fig-velocity-distributions}). RMSE is reduced +when~\eqref{eq-velocity-distribution} is used as the distribution for both low +and high wind speeds. TODO \begin{figure} \centering - TODO - \caption{Per-axis wind velocity distributions fitted into the model - described by~\eqref{eq-velocity-distribution}. + \includegraphics{build/gnuplot/velocity-dist.eps} + \caption{Per-axis wind velocity distributions fitted into Weibull + distribution. Data intervals with the smallest error (the first row), - data intervals with the largest error (the second row). + data intervals with the largest error (the second row). Red line shows estimated + probability density of positive wind speed projections, blue line shows estimated + probability density of negative wind speed projections and circles denote observed + probability density of wind speed projections. \label{fig-velocity-distributions}} \end{figure} -\begin{table} - \centering - \begin{tabular}{ll} - \toprule - TODO \\ - \bottomrule - \end{tabular} - \caption{Model fitting errors for each graph in - figure~\ref{fig-velocity-distributions}.\label{tab-velocity-distributions}} -\end{table} - - \subsection{Verification of wind direction distribution} \cite{carta2008}