How can I develop a matlab code which analyses and checks how thick the cracks of a wheel surface are?
    14 visualizzazioni (ultimi 30 giorni)
  
       Mostra commenti meno recenti
    
    Ramo
 il 20 Mag 2024
  
    
    
    
    
    Commentato: Image Analyst
      
      
 il 23 Mag 2024
            Recently I have done a measurement for a wheel to find out how overused it is by using the confocal sensor and the data recorder to check how deep the cracks on the surface are by the light distance.
The measured data looks like this e. g.:

With the green diagram you can see how long the distance of the measured light = how deep the cracks on the surface are. The red and the yellow ones are the high and low voltage level. 
Now the challenge is that I need to find out how thin/thick the cracks are using this data. Is there anyway I can use matlab to solve this problem?
I have already written a matlab code that checks how many cracks are there by adding a threshold or a mm light distance. But still have not found out a way yet how to find out how long/thick the cracks on the surface are...
Thanks a lot in advance for the help!
% Create PNRF reader OLE Automation server 
FromDisk = actxserver('Perception.Loaders.pNRF');
% Use the open file dialog to select a recording file 
[FileName,PathName] = uigetfile('*.pNRF','U:\SP90000_12_12_23');
if isequal(FileName,0)
    error('Benutzer hat die Auswahl abgebrochen.');
end
MyRecordingName = fullfile(PathName, FileName);
% Laden der Aufzeichnung
MyData = FromDisk.LoadRecording(MyRecordingName); % Zugriff auf den ersten Recorder
% Initialize channel arrays
channelNames = {};  % Initialisiert als leere Zelle
channel = {};       % Initialisiert als leere Zelle
% Loop through all recorders and channels to get the names of all channels 
indexer = 0; 
for r = 1: MyData.Recorders.Count
    % Get an interface to each recorder
    MyRecorder = MyData.Recorders.Item(r);
    % Get the channel collection from the recorder
    myChannels = MyRecorder.Channels; 
    % Loop through each channel in the recorder
    for i = 1:myChannels.Count 
        myChannel = myChannels.Item(i);
        channelNames{end+1} = string(myChannel.Name);
        channel{end+1} = myChannel;
    end 
end
% Show a modal selection list with all the channels so the operator can select a channel 
[indx, tf] = listdlg('ListString',channelNames); 
if ~tf
    error('Kein Kanal ausgewählt.');
end
myChannel = channel{indx}; 
SelectedChannelName = myChannel.Name;
% Now we get the DataSrc (data source) interface from the selected channel 
ItfData = myChannel.DataSource(3);
% Check if we have synchronous or asynchronous data by using the TimeInfo property
myTimeInfo = ItfData.TimeInfo;
isAsyncData = ~strcmp(myTimeInfo, 'DataSourceTimeInfo_Implicit');
% Get the sweeps collection from the datasource interface 
MySweeps = ItfData.Sweeps;
% Get the start and end time of the recorded data of the first channel 
dStartTime = MySweeps.StartTime; 
dEndTime = MySweeps.EndTime;
% Get the data segments collection between the start and end time 
SegmentsOfData = ItfData.Data(dStartTime, dEndTime); % Now the actual data is read.
% Take the first data segment 
myFirstSegment = SegmentsOfData.Item(1);
% Check the number of samples 
NumberOfSamples = myFirstSegment.NumberOfSamples;
if NumberOfSamples > 500000 
    NumberOfSamples = 500000; 
end
% Show the data in a diagram 
figure1 = figure('NumberTitle','off','Name', SelectedChannelName); 
% axes1 = axes('Parent',figure1,'Position',[0.2 0.05 0.6 0.9]); 
%set(figure1, 'Position', [100 100 1200 800]);
if isAsyncData
    [WaveformDateWithTimes, Times] = myFirstSegment.WaveformWithTimes(5, 1, NumberOfSamples, 1);
    plot(Times, WaveformDateWithTimes); 
    title('Not-Equidistant data points');
else 
    WaveformData = myFirstSegment.Waveform(5, 1, NumberOfSamples, 1);
    tEnd = myFirstSegment.StartTime + (NumberOfSamples - 1) * myFirstSegment.SampleInterval;
    t = myFirstSegment.StartTime: myFirstSegment.SampleInterval : tEnd;
    plot(t, WaveformData);
    title('Equidistant data points');
end
legend(SelectedChannelName);
xlabel(['Time (',ItfData.XUnit ,')']);
ylabel([SelectedChannelName, ' (', ItfData.YUnit ,')']);
% Create a Textbox to display data values from the information sheet
% myDataValues = MyData.DataValues;
% cInfo = ''; 
% for i = 1:myDataValues.Count 
%     myDataValue = myDataValues.Item(i); 
%     cInfo = sprintf('%s%s: %s %s\n', cInfo, myDataValue.Name, myDataValue.Value, myDataValue.Units); 
% end
% annotation(figure1, 'textbox', [0.66 0.05 0.32 0.9], 'String', cInfo, 'FitBoxToText', 'on');
% Schätze die Bildschirmgröße ab und positioniere das Fenster
screenSize = get(0, 'ScreenSize'); % Dies gibt [left bottom width height]
figureWidth = 1200;
figureHeight = 800;
figureLeft = (screenSize(3) - figureWidth) / 2; % Zentriert horizontal
figureBottom = (screenSize(4) - figureHeight) / 2; % Zentriert vertikal
set(figure1, 'Position', [figureLeft figureBottom figureWidth figureHeight]);
% Ersetzen oder fügen Sie nach der Plot-Erstellung hinzu
if isAsyncData
    [WaveformDateWithTimes, Times] = myFirstSegment.WaveformWithTimes(5, 1, NumberOfSamples, 1);
    plot(Times, WaveformDateWithTimes); 
    WaveformData = WaveformDateWithTimes; % Verwendung der asynchronen Daten für die Statistik
else 
    WaveformData = myFirstSegment.Waveform(5, 1, NumberOfSamples, 1);
    tEnd = myFirstSegment.StartTime + (NumberOfSamples - 1) * myFirstSegment.SampleInterval;
    t = myFirstSegment.StartTime: myFirstSegment.SampleInterval : tEnd;
    plot(t, WaveformData);
end
% Statistikberechnungen
averageValue = mean(WaveformData);
minValue = min(WaveformData);
maxValue = max(WaveformData);
numberOfPositiveValues = sum(WaveformData > 0);
% Anzahl der Werte größer als 0.25 mm
numberOfValuesAboveThreshold = sum(WaveformData > 0.25);
% Anzeige der berechneten Werte
disp(['Durchschnittswert: ', num2str(averageValue)]);
disp(['Minimaler Wert: ', num2str(minValue)]);
disp(['Maximaler Wert: ', num2str(maxValue)]);
disp(['Anzahl positiver Werte: ', num2str(numberOfPositiveValues)]);
disp(['Anzahl der Werte über 0.1 mm: ', num2str(numberOfValuesAboveThreshold)]);
0 Commenti
Risposta accettata
  Joe Vinciguerra
      
 il 20 Mag 2024
        
      Modificato: Joe Vinciguerra
      
 il 20 Mag 2024
  
      "Is there anyway I can use matlab to solve this problem?"
Yes.
However, you don't seem to have all the information you need to do so. You measured the depth with a confocal sensor, but there is no indication that you have any data that can provide the width (the dimension normal to the one you measured). You need something that measures the relative motion between the sensor and the wheel surface. This can be an encoder or a tachometer for example, depending on your measurement process and your required resolution.
Once you have a sensor that provides distance data [edit to add: or some way to convert time to distance] normal to your confocal sensor you can use matlab to find the rising and falling edges of the cracks, then calcuate the distance between them.
7 Commenti
  Joe Vinciguerra
      
 il 22 Mag 2024
				Your latest codes suggests you have encoder feedback. If that's true then you don't need velocity.
Between using AI to generate your code and not understanding what data-processing steps your project requires, I can't offer any more help. This forum is for matlab specific questions, not to explain line-by-line what the code you had generated does and if it will work for you application.
I'll just leave you with this for once you have the data you need. Here is one way to do it:
% this is just an example, you need to change this as appropriate for your
% application and requirements. I'm make a lot of assumptions for
% demonstration purposes.
% generate random sample data to represent confocal results
displacement_data = 0:0.001:0.2-0.001; % millimeters
confocal_data = zeros(size(displacement_data));
confocal_data(round(0.25*numel(confocal_data)):round(0.75*numel(confocal_data))) = 0.2;
confocal_data = confocal_data + randn(size(confocal_data))/500; % millimeters
% find the width of the crack
dConfocal = abs(diff(confocal_data));
indx = find(islocalmax(dConfocal, MinProminence=(max(dConfocal)-min(dConfocal))/2));
gap = displacement_data(indx);
width = diff(gap); % millimeters
% plot the data
figure(); nexttile(); hold on;
plot(displacement_data, confocal_data)
ylabel('crack depth (m)')
xlabel('crack width (mm)')
xline(gap)
text(0.4, 0.5, "← " + string(width) + " mm →", "units", "normalized")
Best wishes.
Più risposte (1)
  Image Analyst
      
      
 il 22 Mag 2024
        You can use regionprops, if you have the Image Processing Toolbox, to measure the number of cracks, their width, and the signal value in the cracks.  Just pass it your segmented (thresholded) signal.  regionprops works with 1-D signals too, not just 2-D images.
props = regionprops(binarySignal, originalSignal, 'Area', 'MeanIntensity')
numCracks = numel(props);
allCrackWidths = [props.Area];
allSignalsInCracks = [props.MeanIntensity];
You might have to transpose your signal since for 1-D signals I think regionprops requires either column vectors or row vectors (I forget which).  So if you don't get a bunch of results, then try transposing your signals.
4 Commenti
  Image Analyst
      
      
 il 23 Mag 2024
				Be sure to adjust the threshold for your data.  I didn't have or use your data so I just made up some and the threshold may not be best for your signal.
Thresholding tells you whether you are in a crack or not.  I'm not sure if the cracks are the high signal above the threshold or the low signal below the threshold so make sure you check on that.
regionprops gives you a list of the measurements you specify for all the "runs" of where the binary signal is true/1 (in other words all runs of where you're in a crack).  You can get the measurements either in a structure array, where each structure in the array has fields with the measurements you requested, OR you can get the measurements back in a table if you give 'table' as the first argument to regionprops.  Assuming you get the results in a structure array, you can either use that by itself or you can extract all the fields out of the structures into a simple double vector doing
allCrackWidths = [props.Area];
If you had the result in a table you'd do
allCrackWidths = props.Area;
instead (if you wanted to extract out the widths into their own vector instead of leaving them in the table).  Each element in the vector is the width for one "run" of crack.  It's just called area because it's mainly used for images but you have a 1-D signal so the "Area" is really the "length" of that region.
I don't know anything about encoder data but if you want to concatenate some other data onto the width vector, you can certainly do that.  You can build a matrix or table with columns representing anything you want.
Vedere anche
Categorie
				Scopri di più su Biological and Health Sciences in Help Center e File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!






