简体   繁体   中英

Finding roots in data

I have data that look like this: 样本数据

These are curves of the same process but with different parameters.

I need to find the index (or x value) for certain y values (say, 10 ). For the blue curve, this is easy: I'm using min to find the index:

[~, idx] = min(abs(y - target));

where y denotes the data and target the wanted value.

This approach works fine since I know that there is an intersection, and only one. Now what to do with the red curve? I don't know beforehand, if there will be two intersections, so my idea of finding the first one and then stripping some of the data is not feasible.

How can I solve this?

Please note the the curves can shift in the x direction, so that checking the found solution for its xrange is not really an option (it could work for the data I have, but since there are more to come, this solution is probably not the best).

Shameless steal from here :

function x0 = data_zeros(x,y)

    % Indices of Approximate Zero-Crossings
    % (you can also use your own 'find' method here, although it has 
    %  this pesky difference of 1-missing-element because of diff...)
    dy = find(y(:).*circshift(y(:), [-1 0]) <= 0);   

    % Do linear interpolation of near-zero-crossings
    x0 = NaN(size(dy,1)-1,1);    
    for k1 = 1:size(dy,1)-1

        b = [[1;1] [x(dy(k1)); x(dy(k1)+1)]] \ ...   
            [y(dy(k1)); y(dy(k1)+1)]; 

        x0(k1) = -b(1)/b(2);   

    end

end

Usage:

% Some data
x = linspace(0, 2*pi, 1e2); 
y = sin(x);                 

% Find zeros
xz = data_zeros1(x,y);

% Plot original data and zeros found
figure(1), hold on

plot(x, y);
plot(xz, zeros(size(xz)), '+r');
axis([0,2*pi -1,+1]);

The gist: multiply all data points with their consecutive data points. Any of these products that is negative therefore has opposite sign, and gives you an approximate location of the zero. Then use linear interpolation between the same two points to get a more precise answer, and store that.

NOTE: for zeros exactly at the endpoints, this approach will not work. Therefore, it may be necessary to check those manually.

Subtract the desired number from your curve, ie if you want the values at 10 do data-10 , then use and equality-within-tolerance, something like

TOL = 1e-4;
IDX = 1:numel(data(:,1)); % Assuming you have column data
IDX = IDX(abs(data-10)<=TOL);

where logical indexing has been used.

I figured out a way: The answer by b3 in this question did the trick.

idx = find(diff(y > target));

Easy as can be :) The exact xvalue can then be found by interpolation. For me, this is fine since i don't need exact values.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM