How do I fix this uigetfile multiselect error?
    6 views (last 30 days)
  
       Show older comments
    
I have developed a script to process raw data from wind turbine noise. I am attempting to adapt it to automatically process a number of files as opposed to running the script for each file individually. The script is shown below:
function ruk_am_v1_OPTI
%%Initiatilise Variables and Setup Environment
% RenewableUK AM Assessment Program - V1 December 2013
% ########################################
% Clear all variables and workspace data from system memory   
clear all;
% Clear command window
clc;
% Clear all old figures
close all;
% Configure run and initialise all variables
repository          = 'C:\';
blockTime           = 10;   % Main analysis interval (here 10 sec)
sampPerSec          = 10;   % Number of Leq periods per second (here 10 Hz, or 100 msec)
maxBlocks           = 1440; % Maxiumum number of blocks program can process at once (4 hours)
%%Ask user to specify blade passing frequency
      bladePassingFrequency = 1.25;
%%Select data file using UI control
[filename,pathname] = uigetfile('*.txt','Select the TXT file to process',repository,'Multiselect','on');
if isequal(filename, 0)
 disp('User selected Cancel')
 return;
end
for n = 1:length(filename)
  % Create name for output file and open for output
  filename   = lower([pathname,filename(n)]);
  filenameOut= strrep(filename(n), 'txt', 'out');
  filenameOut= char(filenameOut);
  fid        = fopen(filenameOut, 'w');
    %%Read input data
    blockLength = blockTime * sampPerSec;
    % Open input TXT file and read first line, which contains number of items
    filename=char(filename);
    fidtxt = fopen(filename(n), 'r');
    dummy = fgetl(fidtxt);
    totalSamples = str2double(dummy);
    LeqWholePeriod = zeros(1,totalSamples);
end
% Create progress bar for reading input data
h = waitbar(0,'Reading LAeq,100msec levels from TXT file...');
for i = 1:totalSamples
    dummy = fgetl(fidtxt);
    LeqWholePeriod(1,i) = str2double(dummy);
    waitbar(i/totalSamples);
    end
close(h);
% Close input TXT data file
fclose(fidtxt);
% Determine how many 10 sec periods the input TXT file contains
numBlocks = max(1,floor(totalSamples / blockLength));
% Check that this is not more than maxBlocks, which is the maximum
if numBlocks > maxBlocks
  msgBox('Cannot process more than ''maxblocks'' blocks','Program Termination Warning','warn');
  return;
end
%%Put information on screen and in 'Out' file
for fileHandle = [1,fid]
  fprintf(fileHandle,'Input file name           %s\r\n',filename);
  fprintf(fileHandle,'Output file name          %s\r\n',filenameOut);
  fprintf(fileHandle,'Number of samples in file %9i\r\n',totalSamples);
  fprintf(fileHandle,'No of samples per sec.    %9i\r\n',sampPerSec);
  fprintf(fileHandle,'Duration of file          %9.2f s\r\n',totalSamples/sampPerSec);
  fprintf(fileHandle,'Length of data blocks     %9i s\r\n',blockTime);
  fprintf(fileHandle,'No of data blocks         %9i\r\n',numBlocks);
    % Detrend using 5th order polynomial
    fprintf(fileHandle,'Detrending Method.        Polynomial(');
    fprintf(fileHandle,'Order  5)\r\n');
    fprintf(fileHandle,'Blade passing frequency   %9.2f Hz (User chosen)\r\n',bladePassingFrequency);
end
% Print file headers for output 'Out' file
fprintf(fid,'\r\n');
fprintf(fid,'   Block No.|   Spec Line|      Frequency/Hz| Raw Spec Level/dB| Int Spec Level/dB\r\n');
%%Now loop over the whole input file in 'blockTime' second blocks
n2 = 0;
hold off
% Start processing each block in turn
for iblock = 1:numBlocks
  % Block counter
  disp(['Processing Block Number ',num2str(iblock),' of ',num2str(numBlocks)]);
  t = 0:1/sampPerSec:blockTime-(1/sampPerSec);
  n1 = 1 + n2;
  n2 = min(blockLength,totalSamples) + n2;
  Leq   = LeqWholePeriod(1,n1:n2);
  nsamp = length(Leq);
  time  = nsamp / sampPerSec;
  if blockLength ~= nsamp(1,1)
      msgbox('blockLength differs from nsamp!','Program Termination Warning','error');
  end
  if blockTime ~= time(1,1)
      msgbox('blockTime differs from time!','Program Termination Warning','error');
  end       
    %%Check for bad data
    % Calculate Leq for 'blockTime' seconds
    LeqTotal = 10*log10(1/sampPerSec*(sum(10.^(Leq/10)))/blockTime);
    % Test whether max value of Leq is > 10 dB more than mean
    % (implies non-stationarity rather than error) or data which
    % has spikes, i.e. overal level >= 60 dB(A)
    if max(Leq) - mean(Leq) > 10
        iBad = 1; % set to bad data
    elseif LeqTotal > 60
        iBad = 1; % set to bad data
    else
        iBad = 0;
    end
If block data NOT bad then proceed, otherwise discard it
    if iBad == 0
        %%Detrend and plot the Leq Data
        p = polyfit(t,Leq,5);
        deT = polyval(p,t);
        Leq = Leq - deT; % detrend data
        %%Now perform the spectral analysis of the detrended data
        % Create spectrum object and call its PSD method.
        h = spectrum.periodogram('Rectangular');
        hopts = psdopts(h,Leq);
        set(hopts,'Fs',sampPerSec,'SpectrumType','onesided');
        amspec = psd(h,Leq,hopts);
        % Extract results from object
        Fw = amspec.Frequencies;
        Pw = amspec.Data;
        FreqRes = Fw(2) - Fw(1);
        maxFreq = sampPerSec/2;
        Pw_max = 10.0;
        Pw_min = 0;
        % Convert spectrum results to dB levels
        ampMod = 2*sqrt(2*FreqRes*Pw);
        %%Integrate the spectrum to determine the 'true' level
        % Integrate the PSD to determine the energy in a critical band. The
        % critical band is defined as the +/-10% of the BPF
        critBand = 2 * 0.1 * bladePassingFrequency;
        % determine the number of frequency intervals this includes.
        windowSize = floor(critBand /FreqRes) + 1;
        if mod(windowSize,2) == 0
            halfWindow = windowSize/2;
        else
            halfWindow = (windowSize - 1)/2;
        end
        intAmpMod = zeros(1,length(Fw));
        % Calculate rolling sum over entire spectrum
        for j = 1:length(Fw)
            if j <= halfWindow
                % Portion of spectrum < halfWindow from beginning
                intAmpMod(j) = sum(Pw(1:j + halfWindow));
            elseif j >= length(Fw)- halfWindow + 1
                % Portion of spectrum < halfWindow from end
                intAmpMod(j) = sum(Pw(j - halfWindow:length(Fw)));
            else
                % rest of spectrum
                intAmpMod(j) = sum(Pw(j - halfWindow:j + halfWindow));
            end
        end
        % Convert to dB units, as before
        intAmpMod = 2 * sqrt(2 * FreqRes * intAmpMod);
        % Print out results to text file
        for j = 1:length(Fw)
            fprintf(fid,'%12i|%12i|%18.6f|%18.3f|%18.3f\r\n',iblock,j,Fw(j),ampMod(j),intAmpMod(j));
        end
    else %iBad ~= 0
        fprintf(fid,'%12i|  Bad data - affected by ',iblock);
        fprintf(fid,'high energy peaks - not analysed\r\n');
    end
end
%%Close all files and exit
% Turn warnings back on
warning('on','all');
% Close 'Out' text file
fprintf(fid,'\r\nRun Date: %s',datestr(now));
fclose(fid);
% Alert user that data processing is complete
msgbox('Data processing complete!','Warning Message!','warn');
The error I am receiving is as follows:
Error using fgets
Invalid file identifier. Use fopen to generate a valid file identifier.
Error in fgetl (line 33)
[tline,lt] = fgets(fid);
Error in ruk_am_v1_OPTI (line 52)
dummy = fgetl(fidtxt);
Does anyone know how to correct this?
Thanks.
0 Comments
Accepted Answer
  W. Owen Brimijoin
      
 on 21 Jan 2015
        Don't know if this is the cause of your problem, but I can say that uigetfile in 'MultiSelect' mode has the bothersome behavior where it returns a variable of a different class depending on whether the user picks one or more than one file. Very frustrating! In the first instance your variable 'filename' will be a char, so
fopen(filename{n}, 'r');
will fail, saying 'Cell contents reference from a non-cell array object.' Which is true, because it's not a cell array! Similarly if you use brackets:
fopen(filename(n), 'r');
will fail, but this time it's because you have specified the filename as the first letter in the name of the file. The first method works if the user has picked more than one file... so I would advise you to first check the number of files selected as follows:
n_files = numel(cellstr(filename));
because this will accurately report the number of files selected, instead of reporting the number of files as being the number of characters in the name of the one file you picked, then loop through n_files using an if statement for the special case of one file selected:
for file = 1:n_files,
    if n_files==1, 
        filenameOut = filename;
    else filenameOut = filename{file};
    end
      load(filenameOut)
      %load your shiny new data and do something here
  end
Does this make any sense?
14 Comments
  dpb
      
      
 on 13 Feb 2015
				Well, you show nor give no hint as to either the error(s) received nor even the code with which you tried to save the files, so, "no"...
More Answers (1)
  dpb
      
      
 on 19 Jan 2015
        
      Edited: dpb
      
      
 on 21 Jan 2015
  
      In future, please trim amount of code to include only significant sections...this is a lot to wade thru to find the pertinent lines only...
Here's your problem...
...
filename=char(filename);
fidtxt = fopen(filename(n), 'r');
...
Don't convert the full array to character; simply the one cellstring needed when need to...
fidtxt = fopen(filename{n}, 'r');
"Use the curlies, Luke..."
AMPLIFICATION
As mentioned, have to cleanup TMW's mess when use the multiselect option...the portion for the input file open would then look something like--
% Select data file using UI control
[filename,pathname] = uigetfile('*.txt', ...
           'Select the TXT file to process', ...
           repository, ...
           'Multiselect','on');
if isequal(filename, 0)
  disp('User selected Cancel')
  return;
end
% If user only selected one, it'll be a character string instead
% of cell string; simplest is to convert to cellstr for later
if isstr(filename), filename={filename}; end
% now length() is always over the cell array size as needed
for n = 1:length(filename)
  ...
  fidtxt=fopen(filename{n}, 'r');
  ...
ADDENDUM
Tutorial info--
Once you converted the whole array, then the subscript n refers only to a single character, not a cell. But, fopen and friends haven't been "smartened up" to know how to deal with a cellstring input so you have to ensure you return the character string stored in the cell, not the cellstring. Somewhat subtle, yes, but a critical difference to learn.
2 Comments
  dpb
      
      
 on 21 Jan 2015
				OK, W.Owen reminded me of the issue with uigetfile and the MultiSelect option being as I tend to say, "user belligerent" in that it returns a different class result depending on what the user does. This is a pit(proverbial)a(ppendage) and TMW should be seriously castigated for having done it to us...anyway, as he shows, you need to test the result when using the multiple selection option...
I have run into the same problem in the past but it's been long-enough ago that it slipped my mind earlier...
See the updated response for my solution that I think is a little simpler than his altho his does work...
See Also
Categories
				Find more on Logical in Help Center and File Exchange
			
	Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!

