Herken je dit? Je hebt een GPS track, van een tracklogger (in .gpx formaat) of van je Garmin horloge (in .tcx formaat), maar er zitten geen splits in, omdat je niet bij elke post op het knopje hebt gedrukt. En de club gebruikt niet Winsplits in combinatie met die ene specifieke server waar Quickroute mee praat, dus je kan de splits niet automatisch in Quickroute krijgen.
Herkenbaar? Je zult handmatig de tijden in moeten voeren, door op de juiste plaatsen op de kaart te klikken.
Of je schrijft een klein programmatje in Matlab (of gebruikt mijn code) om de .tcx files te voorzien van de splits die je eenvoudig van de Slitsbrowser pagina haalt (de regel in de Results Table met jouw naam er voor; copy – paste).
Heb je geen Garmin .tcx file, maar een generieke .gpx file van een tracklogger, maak er dan eerst een .tcx file van met GPSbabel.
gpsbabel -t -i gpx -f dit_track_bestand.gpx -o gtrnctr,course=0 -F het_nieuwe_bestand.tcx
En zo heb ik bijvoorbeeld deze kaart van Hamont gemaakt, met de controls direct op de juiste plek.
Er zit een slimmigheidje in de functie om te detecteren hoeveel tijdverschil er tussen de GPS gegevens zit en de start. Mocht dat niet werken, knip dan handmatig tevoren het stuk van de track tot vlak voor de start, en vlak na de finish af.
Mochten ze in QuickRoute het inladen van SplitsBrowser files ondersteuen, dan zal het wel op het QuickRoute Forum te lezen zijn. En dat is wellicht ook de plaats om om deze feature te vragen. Hoe meer mensen het hier over hebben, hoe groter de kans.
function splits2tcx(in_file,splits) % om een extra neutralisatie-post in mee te nemen die niet in de splits zat, voeg een % +0:17 (of andere tijd) toe op de plaats. % gpsbabel = 'c:\localdata\bin\gpsbabel\gpsbabel.exe' % CHECK various splits strings force_tcx_conversion = 1; % force gpsbabel to convert tcx to tcx (to fix for example Android Garmin Uploader files) if nargin support for %s files not yet implemented.\n',fe); end if nok error('err-> conversion to .tcx file failed'); else fprintf('done.\n'); % JHH end end fprintf('** acquiring splits **\n'); if nargin0) % absolute times if splits(1)~=splits(end) warning('I expected the total time (1st data point) to be equal to the finish time (last data point). Netralized leg compensation?'); end splittimes = [0 splits(2:end)]; else % relative times splittimes = [0 cumsum(splits)]; end fprintf('** using split times: "%s" **\n',reshape(strvcat(m2ms(splittimes'/60,1)',' '),1,[])); fprintf('** reading tcx file: "%s" **\n',tcx_file); t = []; tp = []; d = []; dp = []; ll = []; lp = []; [fid,err] = fopen(tcx_file,'r'); if fid failed opening file "%s" for reading, with error: %s',tcx_file,err); end arm = 0; while ~feof(fid) l = fgetl(fid); hms = sscanf(l,'%*[^<]<time>%*[^T]T%d:%d:%dZ</time>'); if ~isempty(hms) t(max(length(d),size(ll,1))+1) = [60*60 60 1]*hms; tp(max(length(d),size(ll,1))+1) = ftell(fid); arm = 1; else dm = sscanf(l,'%*[^<]%f'); if arm && ~isempty(dm) d(length(t)) = dm; dp(length(t)) = ftell(fid); if length(d)>length(t) l elseif length(d)<length(t) l end arm = 0; else la = sscanf(l,'%*[^<]%f'); if arm && ~isempty(la) ll(length(t),1) = la; lp(length(t)) = ftell(fid); else lo = sscanf(l,'%*[^<]%f'); if arm && ~isempty(lo) ll(length(t),2) = lo; else ls = sscanf(l,'%*[^<]'); if ~isempty(ls) arm = 0; end end end end end end if arm % last timepoint has no location or distance if ~isempty(d) t = t(1:length(d)); elseif ~isempty(ll) t = t(1:size(ll,1)); end end findmin = inline('min(find(a(:)==min(a(:))))','a'); if ~isempty(d) fprintf('%d timestamps; %d distances; %d splits; %d gaps\n',length(t),length(d),length(find(diff(t)==0)),length(find(diff(t)>1))); else fprintf('%d timestamps; %d distances; %d splits; %d gaps\n',length(t),length(ll),length(find(diff(t)==0)),length(find(diff(t)>1))); end lapsplit = find(diff(t)==0); t(lapsplit) = []; ll(lapsplit,:) = []; if ~isempty(d) d(lapsplit) = []; dd = diff(d); else [x,y] = deg2utm(ll(:,1),ll(:,2)); dd = sqrt(sum(diff([x y]).^2,2)); end dd = dd(:).'; if 1 %% dt = diff(t); if any(dt>1) fprintf('missing track-points at: \n%s',sprintf('%d:%02d : %d [s]\n',[round(m2ms((t(find(diff(t)>1))-t(1))/60)).';dt(dt>1)])); % if any(diff(t)>2) % error('only solves single missing points'); % end for ii = fliplr(find(dt>1)) dd(1:end+dt(ii)-1) = [dd(1:ii-1) repmat(dd(ii)/dt(ii),1,dt(ii)) dd(ii+1:end)]; end t = t(1):t(end); % t1(cumsum([1 (diff(t)>1)+1])) = t; % d1(cumsum([1 (diff(t)>1)+1])) = dd; % d1(find(~t1)) = d1(find(~t1)-1)/2; % d1(find(~t1)-1) = d1(find(~t1)); % t1(~t1) = t1(find(~t1)-1); end % comb = repmat(round(splittimes),2,1)+repmat([1:2]',1,length(splittimes)); % window(comb(:)) = 1; % xc = xcorr(window,dd); % those = length(xc)-length(dd)-[0:length(dd)-splittimes(end)]; % xcdt = detrend(xc(those),'linear',ceil(length(those)/2)); % %plot(xcdt) % offset = findmin(xcdt); % figure(12345); % s1=subplot(211);plot(dd);line(offset,0,'marker','o','color','r');line(offset+splittimes,0,'marker','s','color','g'); % s2=subplot(212);plot(xc(those));line(offset,xc(those(offset)),'marker','o','color','r'); % set(s2,'xlim',get(s1,'xlim')); %% m = 2; comb = repmat(round(splittimes),m,1)+repmat([1:m]',1,length(splittimes)); window = []; window(comb(:)) = 1; if length(window)>length(dd) dd = [zeros(1,2*(length(window)-length(dd))) dd zeros(1,2*(length(window)-length(dd)))]; end xc = xcorr(window,dd); those = length(xc)-length(dd)-[0:length(dd)-splittimes(end)]; xcdt = detrend(xc(those),'linear',ceil(length(those)/2)); %plot(xcdt) offset = findmin(xcdt)+floor(m/2) figure(12345); s1=subplot(2,4,1:4);plot(dd*3600/1000);line(offset,0,'marker','o','color','r');line(offset+splittimes,0,'marker','s','color','g'); s2=subplot(2,4,5:6);plot([1:length(those)],xc(those));line(offset-floor(m/2),xc(those(offset-floor(m/2))),'marker','o','color','r'); n = 20; x=reshape(offset+repmat(0*splittimes(:)',2*n+2,1)+repmat([-n:n nan]',1,length(splittimes)),1,[]); y=reshape(offset+repmat(splittimes(:)',2*n+2,1)+repmat([-n:n nan]',1,length(splittimes)),1,[]); s3=subplot(2,4,[7 8]);plot(x,dd(min(max(y,1),length(dd))));line(offset,0,'marker','s','color','r'); %% else %% [b,a] = butter(2,0.9); dd = filtfilt(b,a,dd); for ii = 1:(t(end)-t(1))-splittimes(end)+1 td(ii) = 0; ti = ii+(1:splittimes(end))-1; for jj = 1:length(splittimes) deze(jj) = findmin(abs((t(ti)-t(1))-splittimes(jj))); td(ii) = td(ii)+dd(deze(jj)); end end offset = t(max(find(abs(td)==min(abs(td)))))-t(1); %% end s = sprintf('Estimated offset of GPS (nr of seconds the GPS was started before the splittimer): %0.1f [s]',offset); fprintf('%s\n',s); new_offset = inputdlg(strvcat(s,'Keep this value, or enter a different offset (based on the graphs):'),'Corect estimated offset',1,{sprintf('%0.1f',offset)}); drawnow; if ~isempty(new_offset{1}), if isempty(str2num(new_offset{1})) error('err-> invalid value: "%s"',new_offset{1}); end offset = str2num(new_offset{1}); s3=subplot(2,4,[7 8]); line(offset,0,'marker','s','color','m'); end t_sync = t-t(1)-offset; for jj = 1:length(splittimes) splittimes_sync(jj) = t_sync(findmin(abs(t_sync-splittimes(jj)))); end splittimes_abs = splittimes_sync+t(1)+offset; fprintf('** finished reading tcx file **\n'); frewind(fid); [fp,fn,fe] = fileparts(in_file); outfile = fullfile(fp,[fn '_splits.tcx']); fprintf('** writing output file: "%s" **\n',outfile); fod = fopen(outfile,'w'); [fod,err] = fopen(outfile,'w'); if fod failed opening file "%s" for writing, with error: %s',outfile,err); end distance_offset = 0; phase = 0; % phases: % 0 header % 1 first track header, until first point to be included % 2 first trackpoints being included % 3 other trackpoints being included % 4 buffering last point of current lap % 5 obsolete lap header % 6 last trackpoint writing % 7 trackpoints after last trackpoint % 8 trailer trackpointbuffer = {}; lap = 0; while ~feof(fid) l = fgets(fid); if phase==0 lp = sscanf(l,'%*[^<]<Lap%s'); % StartTime=%s'); if ~isempty(lp) && phase==0 phase = 1; % do not parse from here end else lp = sscanf(l,'%*[^<]%c'); if ~isempty(lp) && phase>0 phase = 8; % do parse trailer from here else lp = sscanf(l,'%*[^<]<Creator%s'); if ~isempty(lp) && phase>0 phase = 8; % do parse trailer from here end end end if any(phase==[2 3 4]) lp = sscanf(l,'%*[^<]%c'); if ~isempty(lp) if any(phase==[2 3]) % not if phase is 4, since then already a lap was included here phase = 5; % do not parse from here, until next lap started elseif phase==4 % buffered, but continue including lap phase = 3; % continue writing; lap is OK here trackpointbuffer = {}; lap = lap+1; end end end laptext = [0 0]; if any(phase==[4 5 6]) lp = sscanf(l,'%*[^<]%c'); if ~isempty(lp) if phase==6 % last point passed, no output anymore except trailer phase = 7; fprintf(fod,l); l = ''; laptext = [0 1]; elseif phase==4 % copying last trackpoint for new track % inlude lap split fprintf(fod,l); laptext = [1 1]; % implicitly include trackpointbuffer elseif phase==5 % skip first trackpoint after lap, since it is identical phase = 3; l = ''; end end end hms = sscanf(l,'%*[^<]<time>%*[^T]T%d:%d:%dZ</time>'); if ~isempty(hms) timestr = sscanf(l,'%*[^<]<time>%[^Z]Z</time>'); if [60*60 60 1]*hms>=splittimes_abs(1) && phase=splittimes_abs(end) && phase=splittimes_abs(lap+1) && phase%f'); if ~isempty(lp) if phase==2 distance_offset = lp; end l = sprintf(' %0.7f\n',lp-distance_offset); end end if laptext(2) fprintf(fod,' \n'); fprintf(fod,' \n'); end if laptext(1) lap = lap+1; fprintf(fod,' \n',timestr); fprintf(fod,' %0.7f\n',diff(splittimes_abs(lap+[0:1]))); fprintf(fod,' Active\n'); fprintf(fod,' Manual\n'); fprintf(fod,' \n'); fprintf(fod,' \n'); end if phase==4 if all(laptext) fprintf(fod,'%s',trackpointbuffer{:}); trackpointbuffer = {}; phase = 3; else trackpointbuffer{end+1} = l; end end if any(phase==[0 2 3 4 6 8]) fprintf(fod,'%s',l); end end fclose(fod); fclose(fid); fclose('all'); fprintf('** finished successfully: splits were included in tcx file **\n'); function times = readtimes(in) times = []; offset = 0; for ii = 1:length(in) this = sscanf(in{ii},'%d%*[.:]%d%*[.:]%d'); if length(this)==2 if in{ii}(1)=='+' offset = offset+[60 1]*this; times(end+1) = times(end)+offset; else times(end+1) = [60 1]*this+offset; end elseif length(this)==3 if in{ii}(1)=='+' offset = offset+[60*60 60 1]*this; times(end+1) = times(end)+offset; else times(end+1) = [60*60 60 1]*this+offset; end end end % function strs = split(str,sep,include,num) % % SPLIT - split a string in substrings by separator % matches = [1 strfind(str,sep)+1 length(str)+2]; % for ii = 1:length(matches)-1 % strs{ii} = str(matches(ii)+(ii>1)*(size(sep,2)-1):matches(ii+1)-2); % end function [x,y,utmzone] = deg2utm(Lat,Lon) % ------------------------------------------------------------------------- % [x,y,utmzone] = deg2utm(Lat,Lon) % % Description: Function to convert lat/lon vectors into UTM coordinates (WGS84). % Some code has been extracted from UTM.m function by Gabriel Ruiz Martinez. % % Inputs: % Lat: Latitude vector. Degrees. +ddd.ddddd WGS84 % Lon: Longitude vector. Degrees. +ddd.ddddd WGS84 % % Outputs: % x, y , utmzone. See example % % Example 1: % Lat=[40.3154333; 46.283900; 37.577833; 28.645650; 38.855550; 25.061783]; % Lon=[-3.4857166; 7.8012333; -119.95525; -17.759533; -94.7990166; 121.640266]; % [x,y,utmzone] = deg2utm(Lat,Lon); % fprintf('%7.0f ',x) % 458731 407653 239027 230253 343898 362850 % fprintf('%7.0f ',y) % 4462881 5126290 4163083 3171843 4302285 2772478 % utmzone = % 30 T % 32 T % 11 S % 28 R % 15 S % 51 R % % Example 2: If you have Lat/Lon coordinates in Degrees, Minutes and Seconds % LatDMS=[40 18 55.56; 46 17 2.04]; % LonDMS=[-3 29 8.58; 7 48 4.44]; % Lat=dms2deg(mat2dms(LatDMS)); %convert into degrees % Lon=dms2deg(mat2dms(LonDMS)); %convert into degrees % [x,y,utmzone] = deg2utm(Lat,Lon) % % Author: % Rafael Palacios % Universidad Pontificia Comillas % Madrid, Spain % Version: Apr/06, Jun/06, Aug/06, Aug/06 % Aug/06: fixed a problem (found by Rodolphe Dewarrat) related to southern % hemisphere coordinates. % Aug/06: corrected m-Lint warnings %------------------------------------------------------------------------- % Argument checking % error(nargchk(2, 2, nargin)); %2 arguments required n1=length(Lat); n2=length(Lon); if (n1~=n2) error('Lat and Lon vectors should have the same length'); end % Memory pre-allocation % x=zeros(n1,1); y=zeros(n1,1); utmzone(n1,:)='60 X'; % Main Loop % for i=1:n1 la=Lat(i); lo=Lon(i); sa = 6378137.000000 ; sb = 6356752.314245; %e = ( ( ( sa ^ 2 ) - ( sb ^ 2 ) ) ^ 0.5 ) / sa; e2 = ( ( ( sa ^ 2 ) - ( sb ^ 2 ) ) ^ 0.5 ) / sb; e2cuadrada = e2 ^ 2; c = ( sa ^ 2 ) / sb; %alpha = ( sa - sb ) / sa; %f %ablandamiento = 1 / alpha; % 1/f lat = la * ( pi / 180 ); lon = lo * ( pi / 180 ); Huso = fix( ( lo / 6 ) + 31); S = ( ( Huso * 6 ) - 183 ); deltaS = lon - ( S * ( pi / 180 ) ); if (la<-72), Letra='C'; elseif (la<-64), Letra='D'; elseif (la<-56), Letra='E'; elseif (la<-48), Letra='F'; elseif (la<-40), Letra='G'; elseif (la<-32), Letra='H'; elseif (la<-24), Letra='J'; elseif (la<-16), Letra='K'; elseif (la<-8), Letra='L'; elseif (la<0), Letra='M'; elseif (la<8), Letra='N'; elseif (la<16), Letra='P'; elseif (la<24), Letra='Q'; elseif (la<32), Letra='R'; elseif (la<40), Letra='S'; elseif (la<48), Letra='T'; elseif (la<56), Letra='U'; elseif (la<64), Letra='V'; elseif (la<72), Letra='W'; else Letra='X'; end a = cos(lat) * sin(deltaS); epsilon = 0.5 * log( ( 1 + a) / ( 1 - a ) ); nu = atan( tan(lat) / cos(deltaS) ) - lat; v = ( c / ( ( 1 + ( e2cuadrada * ( cos(lat) ) ^ 2 ) ) ) ^ 0.5 ) * 0.9996; ta = ( e2cuadrada / 2 ) * epsilon ^ 2 * ( cos(lat) ) ^ 2; a1 = sin( 2 * lat ); a2 = a1 * ( cos(lat) ) ^ 2; j2 = lat + ( a1 / 2 ); j4 = ( ( 3 * j2 ) + a2 ) / 4; j6 = ( ( 5 * j4 ) + ( a2 * ( cos(lat) ) ^ 2) ) / 3; alfa = ( 3 / 4 ) * e2cuadrada; beta = ( 5 / 3 ) * alfa ^ 2; gama = ( 35 / 27 ) * alfa ^ 3; Bm = 0.9996 * c * ( lat - alfa * j2 + beta * j4 - gama * j6 ); xx = epsilon * v * ( 1 + ( ta / 3 ) ) + 500000; yy = nu * v * ( 1 + ta ) + Bm; if (yy<0) yy=9999999+yy; end x(i)=xx; y(i)=yy; utmzone(i,:)=sprintf('%02d %c',Huso,Letra); end function ms = m2ms(m,textout) % min to min:sec % if second argument is true, then text is output if nargin1 && ~~textout) if any(ms(:,1)>=60) f = '%d:%02d'; hms = [floor(ms(:,1)/60) mod(ms,60)]; else f = '%02d'; hms = ms; end if any(abs(m*60-round(m*60))>1e-3) f = [f ':%06.3f']; else f = [f ':%02.0f']; end if ~nargout fprintf([f '\n'],hms.'); clear ms; else ms = num2str(hms,f); end end |
Wie weet maak in nog een keer een .exe file hier van, of een online tool zodat je op mijn website jouw gpx/tcx files van splits kan voorzien. Laat hier onder, als commentaar, opmerkingen, wensen of suggesties achter. Mocht je handig zijn met Perl, PHP, Python, of zo, dan kan je wellicht deze, op zich redelijke simpele, code herschrijven.
Lijkt me reuze handig programmaatje, en wilde ‘m eens gaan proberen.
Helaas een Matlab-foutmelding: je gebruikt ‘explode’, en die functie is bij mij niet bekend.
Any suggestions…?
Ik had de functie explode.m inderdaad elders vandaan: Matlab Central. Ik heb mijn script hier boven nu aangepast zodat die externe functie niet meer nodig is.
Let op! Als een wedstrijd een NEUTRALISATIE post heeft, klopt de bewerkte track niet meer. Je raakt dan aan het eind een stukje kwijt, omdat de splits en stukje missen. Dit los je op door het verschil handmatig in de splits toe te voegen, maar dat vergt wel wat gepuzzel.
Intussen heb ik ook het script zelf aangepast (niet om dit op te lossen), en de laatste versie hier boven gezet.
Hallo, könnten Sie mir bitte erklären, wie ich aus dem Quelltext ein lauffähiges Programm machen kann?
Vielen Dank
It’s executable in Matlab. So typically I do not compile it; just start Matlab and call this function.
There are ways to make a stand-alone executable out of it, though. But that requires to have the MCR (Matlab Component Runtime) installed on the user’s PC.
I think the nicest solution would be to make a web-app, a site where you upload your gpx/tcx file, and provide a link to the splitsbrowser page and your name on that page; then the web function executes, retrieves the splits, finds the best match in the track file, modifies it and returns the gps track with the correct splits included. At the moment, I don’t have time to make that, however. Needs rewriting this function in php or python.
Vielen Dank für die schnelle Antwort.
Muß ich Matlab auf meinem PC installiert haben, um das Programm in Matlab zu starten?
Viele Grüße aus Bayern