Issue with Spectrometer Snapping and GUI updating

조회 수: 8 (최근 30일)
Bera
Bera 2025년 2월 12일
댓글: Bera 2025년 2월 25일
Hey All
I'm currently working on a GUI to have a camera snapping a photo constantly processing it and then updating the plot on my gui. I've heard some stuff about using timers etc to fix the issue, but in all honesty, I have no clue how to get started. Could anyone give tips?
This is my code!
function StartStopLiveSpectrumButtonValueChanged(app, event)
% Load background average (if not already loaded)
if ~isfield(app, 'bckgrnd_avg')
load("Spectrometer_Settings.mat", "bckgrnd_avg");
data = load("Spectrometer_Settings.mat");
app.bckgrnd_avg = bckgrnd_avg;
end
% check if background photos have been snapped
pass = BackgroundPhotoExistenceCheck(app,"Live Spectrum");
if pass ~= 1
return
end
% Configure manual triggering
triggerconfig(app.vid_ASI, 'manual');
% Start the acquisition
start(app.vid_ASI);
% Init Wavelength
% Extract the grating value
grating = app.Spectrometer_gratting;
% Loop through all fields in the loaded data
fields = fieldnames(data);
for i = 1:numel(fields)
field_name = fields{i}; % Get the current field name
field_value = data.(field_name); % Get the value of the current field
% Check if the field value contains the grating value
if contains(field_name, num2str(grating)) && contains(field_name,"max")
wvlngth_end = field_value;
elseif contains(field_name, num2str(grating)) && contains(field_name,"min")
wvlngth_start = field_value;
end
end
wvlength = linspace(wvlngth_start, wvlngth_end, size(app.vid_ASI.VideoResolution, 1));
% Loop while button is pressed
while app.StartStopLiveSpectrumButton.Value
% Capture and process spectrum
try
% Trigger the camera and retrieve the frame
trigger(app.vid_ASI);
Emission_Reading_Img = getdata(app.vid_ASI, 1);
[spectrum_sum] = app.MyFuncs.ASI_Live_Feed_Snapping(Emission_Reading_Img,app.bckgrnd_avg);
catch ME
warning(ME.Identifier,'Failed to capture or process spectrum: %s', ME.message);
break; % Exit the loop if an error occurs
end
% Update UI axes
if isempty(app.PlotHandle) || ~isvalid(app.PlotHandle)
app.PlotHandle = plot(app.Spectrometer_Plot, wvlength, spectrum_sum);
xlabel(app.Spectrometer_Plot, 'Wavelength (nm)');
ylabel(app.Spectrometer_Plot, 'Arb. Counts');
else
set(app.PlotHandle,'YData', spectrum_sum);
drawnow limitrate; % Keep the GUI responsive
end
end
% Stop the acquisition when the loop ends
stop(app.vid_ASI);
% Flush the buffer to remove any leftover frames
flushdata(app.vid_ASI);

답변 (2개)

Anushka
Anushka 2025년 2월 19일
편집: Anushka 2025년 2월 20일
Hi @Bera,
As you have correctly mentioned about continuously updating the GUI, but using a while loop in a 'callback' function can make the app unresponsive. Instead, using a 'timer' is a better approach.
Below are the steps how can implement the 'timer':
1. Create a 'timer' in the App Startup or Initialization:
  • Define a 'timer' object that runs at a fixed interval.
  • Set the execution mode to 'fixedRate' so it continuously executes at a set period.
  • Assign a 'callback' function to capture and process images.
2. Start the 'timer' on the Button Press:
  • Start the 'timer' when the button is pressed.
  • Stop the 'timer' when the button is released.
Here is the modified code using 'timer' that you can refer to:
  1. Add this to your app properties:
properties(Access=private)
TimerObj
end
2. Modify your button callback:
function StartStopLiveSpectrumButtonValueChanged(app, event)
if app.StartStopLiveSpectrumButton.Value
app.TimerObj = timer('ExecutionMode', 'fixedRate', ...
'Period', 0.1, ...
'TimerFcn', @(~,~) UpdateLivePlot(app));
start(app.TimerObj);
else
stop(app.TimerObj);
delete(app.TimerObj);
end
end
3. Define the UpdateLivePlot function:
function UpdateLivePlot(app)
try
trigger(app.vid_ASI);
Emission_reading_img = getData(app.vid_ASI, 1);
spectrum_sum = app.MyFuncs.ASI_Live_Feed_Snapping(Emission_reading_img, app.bckgrnd_avg);
if isempty(app.PlotHandle) || ~isvalid(app.PlotHandle)
app.PlotHandle = plot(app.Spectrometer_Plot, app.wvlength, spectrum_sum);
xlabel(app.Spectrometer_Plot, 'Wavelength(nm)');
ylabel(app.Spectrometer_Plot, 'Arb.Counts');
else
set(app.PlotHandle, 'YData', spectrum_sum);
drawnow limitrate;
end
catch ME
warning('Failed to capture or process spectrum: %s', ME.message);
end
end
You can refer to the given documentation link to know more about 'timer':
Hope this helps!
  댓글 수: 1
Bera
Bera 2025년 2월 19일
Thank you so much, I will give these two a go and see if they work :)

댓글을 달려면 로그인하십시오.


Raag
Raag 2025년 2월 19일
Hi Bera,
Yes, using timers is a viable approach. At present, the while loop you previously implemented may run indefinitely because the condition based on "isStarting" will not update until the callback function completes its execution, resulting in an endless loop. Here's how you can get started with the timer method:
The first thing to do is using the button callback logic to manage the timer and camera operations:
function StartStopLiveSpectrumButtonValueChanged(app, event)
isStarting = app.StartStopLiveSpectrumButton.Value;
if isStarting
% Start camera
triggerconfig(app.vid_ASI, 'manual');
start(app.vid_ASI);
% Create timer
app.AcquisitionTimer = timer( ...
'ExecutionMode','fixedSpacing', ...
'Period',0.2, ... % e.g., acquire data 5 times per second
'TimerFcn',@(~,~) acquireAndUpdatePlot(app) );
start(app.AcquisitionTimer);
else
% Stop timer if it exists
if ~isempty(app.AcquisitionTimer) && isvalid(app.AcquisitionTimer)
stop(app.AcquisitionTimer);
delete(app.AcquisitionTimer);
app.AcquisitionTimer = [];
end
% Stop camera
stop(app.vid_ASI);
flushdata(app.vid_ASI);
end
end
Next, you can define the 'acquireAndUpdatePlot' function for handling the image acquisition and plotting, as shown below:
function acquireAndUpdatePlot(app)
try
trigger(app.vid_ASI);
Emission_Reading_Img = getdata(app.vid_ASI, 1);
spectrum_sum = app.MyFuncs.ASI_Live_Feed_Snapping(Emission_Reading_Img, app.bckgrnd_avg);
% Update plot
if isempty(app.PlotHandle) || ~isvalid(app.PlotHandle)
app.PlotHandle = plot(app.Spectrometer_Plot, app.WavelengthAxis, spectrum_sum);
xlabel(app.Spectrometer_Plot, 'Wavelength (nm)');
ylabel(app.Spectrometer_Plot, 'Arb. Counts');
else
set(app.PlotHandle, 'YData', spectrum_sum);
drawnow limitrate;
end
catch ME
warning('Acquisition:Error', '%s', ME.message);
end
end
For more details on using timers in MATLAB, you can refer to the timer documentation: https://www.mathworks.com/help/matlab/ref/timer.html
  댓글 수: 8
Bera
Bera 2025년 2월 23일
okay okay, thank you so much!
Bera
Bera 2025년 2월 25일
I just had the chance to test it and it still isn't working for some reason.
This is the error message I am getting
> In Raster_SpecificQD_LEDFinderGUI/acquireAndUpdatePlot (line 304)
In Raster_SpecificQD_LEDFinderGUI>@(~,~)acquireAndUpdatePlot(app) (line 1615)
In timer/timercb (line 90)
In timer/start (line 67)
In Raster_SpecificQD_LEDFinderGUI/StartStopLiveSpectrumButtonValueChanged (line 1616)
In matlab.apps.AppBase>@(source,event)executeCallback(ams,app,callback,requiresEventData,event) (line 62)
Warning: Cannot trigger OBJ while Logging is set to on.
Warning: Arrays have incompatible sizes for this operation.

댓글을 달려면 로그인하십시오.

카테고리

Help CenterFile Exchange에서 Graphics Performance에 대해 자세히 알아보기

제품


릴리스

R2024a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!

Translated by