Vývoj metody a konstrukce přístroje pro rychlé monitorování vysokoteplotní stability rostlin E003 – příloha 1: Skripty pro anlýzu kritických bodů fluorescenční a vodivostní křivky V Drásově dne 19.12.2013 do_curvature.R: #column vectors: #temp - vector of temperature series (column “temp” of *.txt ProfileCon result file) #Ft – vector of Ft measurements (column “Ft” of *.txt ProfileCon result file) #Cond - vector of Conductivity.MV1 measurements (column “Conductivity.MV1“ of *.txt ProfileCon result file) # must be defined in global environment before running this script source("fc_curv.r") source("fc_import.r") version<-"1.0.0.2" #1.0.0.2 - without normalization in fc_curv.r fitrange<-function(rng,config_rng){ if(rng[1]<config_rng[1]){ a<-config_rng[1] }else{ a<-rng[1] } if(rng[2]>config_rng[2]){ b<-config_rng[2] }else{ b<-rng[2] } c(a,b) } param<-ParImport("config.ini") #read Analyse parameters rng<-c(min(param["rangeC1"],param["rangeF1"]),max(param["rangeC2"],param["rangeF2"])) #resample and normalize rng_data<-fitrange(rng,c(min(temp),max(temp))) dat<-DataResample(range=rng_data,temp=temp,Ft=Ft,Cond=Cond) # #--------------------------------------# # #add columns with circle fits rng<-fitrange(rng_data,c(param["rangeF1"],param["rangeF2"])) #vezmi jen okno dle configu pro Ft winsize<-param["winsizeF"] Ft.curv<-CreateCircle("Ft",dat,rng) rng<-fitrange(rng_data,c(param["rangeC1"],param["rangeC2"])) #vezmi jen okno dle configu pro Ft winsize<-param["winsizeC"] Cond.curv<-CreateCircle("Conductivity.MV1",dat,rng) normdat<-cbind(dat,Ft.curv,Cond.curv) # #throw out NA's Ftres<-normdat[!is.na(normdat$Ft.r),] # # #find extrems #fileerror<-file("rlog.log") #sink(fileerror) Ft.ex<-LocalExtrems("Ft",Ftres) #write(geterrmessage(),file="rlog.tmp") # #plotcurves("Ft",normdat,Ft.ex,file) # # #find extrems on conductivity Condres<-normdat[!is.na(normdat$Conductivity.MV1.r),] Cond.ex<-LocalExtrems("Conductivity.MV1",Condres) # #plotcurves("Conductivity.MV1",normdat,Cond.ex,file) # normdat<-normdat[!is.na(normdat$Conductivity.MV1.r),] #output in data.table „normdat“ placed in global environment fc_curv.R: #ver 1.0 by Michal Sicner library("pracma") # need to be downloaded from r-project.org #****************************************************************** circlefit <- function (X, z, r) { #source: W.Gander et al. - Least squares fitting of circles and Ellipses #circlefit Geometric circle fit # # [z,r] <- circlefit (X, z, r) # fits the best circle by nonlinear least squares # for true geometric distance. # # X: given points <X(i,1), X(i,2)> - <temp or time,conductivity> # z, r: starting values for circle solution # # z, r: parameters for circle found u <- rbind(z1=z[1],z2= z[2] , r) # Starting values h <- u i<-0 #h[1,1]<-0 while (norm(h) > norm(u)*1e-10) { a <- u[1]-X[,1] b <- u[2]-X[,2] fak <- sqrt(diag(a%o%a) + diag(b%o%b)) J <- cbind(a/fak,b/fak,rep(-1,length(a))) f <- fak -u[3]; h <- mldivide(-J,f) #h[1,1]<-0 u <- u + h i<-i+1 } z <- u[1:2] r <- u[3] u } #****************************************************************** algebraic_circle<-function(X){ #source: W.Gander et al. - Least squares fitting of circles and Ellipses #algebraic_circle Algebraic circle fit # # [z, r] = algebraic_circle (X); # fits a circle by minimizing the "algebraic distance" # in the least squares sense a x'x + b'x + c = 0 # # X : given points <X(i,1, X(i,2)> # # z, r: center and radius of the found circle x<-X[,1] y<-X[,2] B<-cbind(diag(x%o%x)+diag(y%o%y),x,y,rep(1,length(x))) res<-svd(B) #[U,S,V] u<-res$v[,4] a<-u[1] b<-c(u[2],u[3]) c<-u[4] z<- -b/2/a r<- sqrt(norm(z,type="2")^2 - c/a) c("z"=z,"r"=r) } #****************************************************************** CreateCircle <- function (what,dat,range) { #matrix for whole the data circle_coord<-matrix(nrow=length(dat$temp),ncol=3) #calculate only for defined range n<-which(dat$temp==max(dat[dat$temp<=range[2],"temp"])) i<-which(dat$temp==min(dat[dat$temp>=range[1],"temp"])) #calculate osculating circle for all moving windows while(i<n-winsize-1){ #fit points coordinates X<-cbind(dat[i:(i+winsize),"temp"],dat[i:(i+winsize),what]) #get first starting point from algebraic circle fit alg<-algebraic_circle(X) #geometric fit circle_coord[i+winsize/2,]<-circlefit(X,c(alg["z1"],alg["z2"]),alg["r"]) i<-i+5 } v<-data.frame(circle_coord) colnames(v)<-c(paste0(what,".z1"),paste0(what,".z2"),paste0(what,".r")) 1/v } #****************************************************************** DataResample<-function(range=c(35,70),temp=NA,Ft=NA,Conductivity.MV1=NA) { # resample the measured signal for points xi interpolate <- function(what,dat,xi){ # not extrapolating # interp1(x=as.numeric(dat[,"temp"]), # y=as.numeric(dat[,what]), # xi=xi, # method="linear") a<-spline(x=as.numeric(dat[,"temp"]), y=as.numeric(dat[,what]), xout=xi) a$y } t<-data.frame(temp,Ft,Conductivity.MV1) # TAKE ONLY THE REQUIRED RANGE MINMAX u<-subset(t,subset=(temp<=range[2]&temp>=range[1])) #remove duplicates in temperature by averaging the values v<-aggregate(u,by=list(u[,"temp"]),FUN=mean) #create linear temerature scaled vector temp <- seq(range[1],range[2],by=.02) w<-as.data.frame(sapply(c("Ft","Conductivity.MV1"),interpolate,v,temp)) #normalize data Ft.norm<-normalize(w$Ft,range) Cond.norm<-normalize(w$Conductivity.MV1,range) a<-as.data.frame(cbind(temp,Ft=Ft.norm,Conductivity.MV1=Cond.norm)) a } #****************************************************************** normalize<-function(dat,range){ #set the same scaling factor for X and Y axis #scale <- (range[2]-range[1])/2 #scale*(dat-min(dat))/(max(dat)-min(dat)) dat } #****************************************************************** readrules<-function(configfile=""){ } #****************************************************************** #localize extrems of the function LocalExtrems<-function(what,dat){ u<-data.frame(matrix(nrow=5,ncol=3)) intervals<-vector(mode="numeric",length=5) intervals[1]<-min(dat[,"temp"]) if(what=="Ft"){ colnames(u)<-c("bounds","Ft","CurvFt") #maximum Ft curve intervals[5]<-max(dat[,"temp"]) idxmax<-which(dat[,what]==max(dat[,what],na.rm=T)) if(idxmax>40){ #40 is 0.1degC*40=4degC in temperature #first interval rage to 2 degrees below the Ftmaximum intervals[2]<-dat[idxmax,"temp"]-3 m<-subset(dat,subset=dat[,"temp"]<intervals[2]) u[1,"Ft"]<-m[which(m[,"Ft.r"]==max(m[,"Ft.r"],na.rm=T)),"temp"] u[1,"CurvFt"]<-m[which(m[,"Ft.r"]==max(m[,"Ft.r"],na.rm=T)),"Ft.r"] #first interval rage to 4 degrees above the maximum intervals[3]<-intervals[2]+6 m<-subset(dat,subset=dat[,"temp"]>intervals[2]&dat[,"temp"]<intervals[3]) u[2,"Ft"]<-m[which(m[,"Ft.r"]==max(m[,"Ft.r"],na.rm=T)),"temp"] u[2,"CurvFt"]<-m[which(m[,"Ft.r"]==max(m[,"Ft.r"],na.rm=T)),"Ft.r"] # find next local radius min behind Ftmax m<-subset(dat,subset=dat[,"temp"]>intervals[3]) if(dim(m)[1] != 0){ idxmin<-which(m[,"Ft.r"]==max(m[,"Ft.r"],na.rm=T)) u[4,"Ft"]<-m[idxmin,"temp"] u[4,"CurvFt"]<-m[idxmin,"Ft.r"] # 4 degrees before Ft curve max intervals[4] <- m[idxmin,"temp"]-4 #find radius min between ftmax and radiusmin last m<-subset(m,subset=m[,"temp"]<intervals[4]) if(dim(m)[1] != 0) { idxmin<-which(m[,"Ft.r"]==max(m[,"Ft.r"],na.rm=T)) u[3,"Ft"]<-m[idxmin,"temp"] u[3,"CurvFt"]<-m[idxmin,"Ft.r"] }else{ u[3,"Ft"]<-u[4,"Ft"] u[3,"CurvFt"]<-u[4,"CurvFt"] u[4,"Ft"]<-NA u[4,"CurvFt"]<-NA intervals[4]<-intervals[5] } } }else{ #last temperature = all temperatures intervals[2]<-max(dat[,"temp"]) } } if(what=="Conductivity.MV1"){ colnames(u)<-c("bounds","Cond","CurvCond") intervals[2]<-max(dat[,"temp"],na.rm=T) idxmin<-which(dat[,"Conductivity.MV1.r"]==max(dat[,"Conductivity.MV1.r"],na.rm=T)) u[1,"Cond"]<-dat[idxmin,"temp"] u[1,"CurvCond"]<-dat[idxmin,"Conductivity.MV1.r"] intervals[3:5]<-NA } u[,1]<-intervals u } #****************************************************************** fc_import.R: DataImport <-function(file =""){ colread<-function(colname,datatable){ datatable[,colname] } #file <- "c:/PSI/ProfileCon/Analysis/final.txt" #read data and resample #dat<-ReadRaw(file,what,range) #------------- read from file - example data-----------if (file.exists(file)){ a<-scan(file,what = "character",sep = "\n",blank.lines.skip=FALSE) # set decimal point type #p<-grep("Culture",a) #culture<-read.table(file,sep = "\t",skip=p-1,header=FALSE,nrows=1 )[2] decpoint<- "." #if(culture=="en-GB") { # decpoint<-"." #} #read culumn names and data idx_first <- grep("<DATA>", a)+2 #first row index of data lines <- grep("</DATA>", a)-idx_first #number of data rows units <-read.table(file,sep = "\t",skip=idx_first-2,header=TRUE,nrows=1 ) data <- read.table(file,sep = "\t",skip=idx_first,header=FALSE,nrows= lines-3,dec=decpoint) t<-data.frame(temp=data[,2],Ft=data[,5],Conductivity.MV1=data[,4]) } #return dataframe t } ParImport<-function(file="config.ini"){ def_range <- c(35,70) #default range for analysis def_filter<-100 if(file.exists(file)){ a<-try(scan(file,what = "character",sep = "\n",blank.lines.skip=FALSE),silent=T) #read range size r<-grep("Con_Range",a,value=TRUE) #first row index of data if(!length(r)) { warning("Con_Range=range_min,range_max not found in config.ini") rangeC<-def_range }else{ rmin<-as.numeric(sub(pattern=",","",regmatches(r,regexpr("[0-9]*,",r)))) rmax<-as.numeric(sub(pattern=",","",regmatches(r,regexpr(",[0-9]*",r)))) if(length(rmin)==0 || length(rmax)==0 || is.na(rmin) || is.na(rmax)){ warning("Con_Range has wrong format of data") rangeC<-def_range }else{ rangeC<-c(rmin,rmax) } } #read range size r<-grep("Ft_Range",a,value=TRUE) #first row index of data if(!length(r)) { warning("Ft_Range=range_min,range_max not found in config.ini") rangeF<-def_range }else{ rmin<-as.numeric(sub(pattern=",","",regmatches(r,regexpr("[0-9]*,",r)))) rmax<-as.numeric(sub(pattern=",","",regmatches(r,regexpr(",[0-9]*",r)))) if(length(rmin)==0 || length(rmax)==0 || is.na(rmin) || is.na(rmax)){ warning("Ft_Range has wrong format of data") rangeF<-def_range }else{ rangeF<-c(rmin,rmax) } } #read filter window size r<-grep("Con_FilterWindow",a,value=TRUE) #first row index of data if(!length(r)) { warning("Con_FilterWindow=filetrsize not found in config.ini") windowC<-def_filter }else{ f<-as.numeric(regmatches(r,regexpr("[0-9]*$",r))) if(is.na(f)){ warning("Con_FilterWindow has wrong format of data") windowC<-def_filter }else{ windowC<-f } } #read filter window size r<-grep("Ft_FilterWindow",a,value=TRUE) #first row index of data if(!length(r)) { warning("Ft_FilterWindow=filetrsize not found in config.ini") windowF<-def_filter }else{ f<-as.numeric(regmatches(r,regexpr("[0-9]*$",r))) if(is.na(f)){ warning("Ft_FilterWindow has wrong format of data") windowF<-def_filter }else{ windowF<-f } } }else{ rangeC<-def_range rangeF<-def_range windowC<-def_filter windowF<-def_filter warning("config.ini file not found in current directory") } c(rangeC=rangeC,rangeF=rangeF,winsizeC=windowC,winsizeF=windowF) }