-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
40 changed files
with
8,915 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
[submodule "IsothermFittingTool"] | ||
path = IsothermFittingTool | ||
url = https://github.com/ImperialCollegeLondon/IsothermFittingTool.git |
Submodule IsothermFittingTool
added at
9eed15
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
This folder contains files that are used for the experimental work of ERASE!! |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,226 @@ | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
% | ||
% Imperial College London, United Kingdom | ||
% Multifunctional Nanomaterials Laboratory | ||
% | ||
% Project: ERASE | ||
% Year: 2021 | ||
% MATLAB: R2020a | ||
% Authors: Ashwin Kumar Rajagopalan (AK) | ||
% Hassan Azzan (HA) | ||
% | ||
% Purpose: | ||
% | ||
% | ||
% Last modified: | ||
% - 2021-05-10, AK: Remove single gas calibration | ||
% - 2021-04-27, AK: Change the calibration model to linear interpolation | ||
% - 2021-04-23, AK: Change the calibration model to Fourier series based | ||
% - 2021-04-21, AK: Change the calibration equation to mole fraction like | ||
% - 2021-04-19, AK: Change MFC and MFM calibration (for mixtures) | ||
% - 2021-04-08, AK: Add ratio of gas for calibration | ||
% - 2021-04-07, AK: Modify for addition of MFM | ||
% - 2021-03-26, AK: Fix for number of repetitions | ||
% - 2021-03-19, HA: Add legends to the plots | ||
% - 2021-03-24, AK: Remove k-means and replace with averaging of n points | ||
% - 2021-03-19, HA: Add kmeans calculation to obtain mean ion current for | ||
% polynomial fitting | ||
% - 2021-03-18, AK: Fix variable names | ||
% - 2021-03-17, AK: Change structure | ||
% - 2021-03-17, AK: Initial creation | ||
% | ||
% Input arguments: | ||
% | ||
% Output arguments: | ||
% | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
function analyzeCalibration(parametersFlow,parametersMS) | ||
% Find the directory of the file and move to the top folder | ||
filePath = which('analyzeCalibration'); | ||
cd(filePath(1:end-21)); | ||
|
||
% Get the git commit ID | ||
gitCommitID = getGitCommit; | ||
|
||
% Load the file that contains the flow meter calibration | ||
if ~isempty(parametersFlow) | ||
flowData = load(parametersFlow); | ||
% Analyse flow data | ||
MFM = [flowData.outputStruct.MFM]; % MFM | ||
MFC1 = [flowData.outputStruct.MFC1]; % MFC1 | ||
MFC2 = [flowData.outputStruct.MFC2]; % MFC2 | ||
UMFM = [flowData.outputStruct.UMFM]; % UMFM | ||
% Get the volumetric flow rate | ||
volFlow_MFM = [MFM.volFlow]; | ||
volFlow_MFC1 = [MFC1.volFlow]; % Flow rate for MFC1 [ccm] | ||
setPt_MFC1 = [MFC1.setpoint]; % Set point for MFC1 | ||
volFlow_MFC2 = [MFC2.volFlow]; % Flow rate for MFC2 [ccm] | ||
setPt_MFC2 = [MFC2.setpoint]; % Set point for MFC2 | ||
volFlow_UMFM = [UMFM.volFlow]; % Flow rate for UMFM [ccm] | ||
% Find indices corresponding to pure gases | ||
indexPureHe = find(setPt_MFC2 == 0); % Find pure He index | ||
indexPureCO2 = find(setPt_MFC1 == 0); % Find pure CO2 index | ||
% Parse the flow rate from the MFC, MFM, and UMFM for pure gas | ||
% MFC | ||
volFlow_MFC1_PureHe = volFlow_MFC1(indexPureHe); | ||
volFlow_MFC2_PureCO2 = volFlow_MFC2(indexPureCO2); | ||
% UMFM for pure gases | ||
volFlow_UMFM_PureHe = volFlow_UMFM(indexPureHe); | ||
volFlow_UMFM_PureCO2 = volFlow_UMFM(indexPureCO2); | ||
% Calibrate the MFC | ||
calibrationFlow.MFC_He = volFlow_MFC1_PureHe'\volFlow_UMFM_PureHe'; % MFC 1 | ||
calibrationFlow.MFC_CO2 = volFlow_MFC2_PureCO2'\volFlow_UMFM_PureCO2'; % MFC 2 | ||
|
||
% Compute the mole fraction of CO2 using flow data | ||
moleFracCO2 = (calibrationFlow.MFC_CO2*volFlow_MFC2)./... | ||
(calibrationFlow.MFC_CO2*volFlow_MFC2 + calibrationFlow.MFC_He*volFlow_MFC1); | ||
indNoNan = ~isnan(moleFracCO2); % Find indices correponsing to no Nan | ||
% Calibrate the MFM | ||
% Fit a 23 (2nd order in mole frac and 3rd order in MFM flow) to UMFM | ||
% Note that the MFM flow rate corresponds to He gas configuration in | ||
% the MFM | ||
modelFlow = fit([moleFracCO2(indNoNan)',volFlow_MFM(indNoNan)'],volFlow_UMFM(indNoNan)','poly23'); | ||
calibrationFlow.MFM = modelFlow; | ||
|
||
% Also save the raw data into the calibration file | ||
calibrationFlow.rawData = flowData; | ||
|
||
% Save the calibration data into a .mat file | ||
% Check if calibration data folder exists | ||
if exist(['..',filesep,'experimentalData',filesep,... | ||
'calibrationData'],'dir') == 7 | ||
% Save the calibration data for further use | ||
save(['..',filesep,'experimentalData',filesep,... | ||
'calibrationData',filesep,parametersFlow,'_Model'],'calibrationFlow',... | ||
'gitCommitID'); | ||
else | ||
% Create the calibration data folder if it does not exist | ||
mkdir(['..',filesep,'experimentalData',filesep,'calibrationData']) | ||
% Save the calibration data for further use | ||
save(['..',filesep,'experimentalData',filesep,... | ||
'calibrationData',filesep,parametersFlow,'_Model'],'calibrationFlow',... | ||
'gitCommitID'); | ||
end | ||
|
||
% Plot the raw and the calibrated data (for pure gases at MFC) | ||
figure | ||
MFC1Set = 0:80; | ||
subplot(1,2,1) | ||
hold on | ||
scatter(volFlow_MFC1_PureHe,volFlow_UMFM_PureHe,'or') | ||
plot(MFC1Set,calibrationFlow.MFC_He*MFC1Set,'b') | ||
xlim([0 1.1*max(volFlow_MFC1_PureHe)]); | ||
ylim([0 1.1*max(volFlow_UMFM_PureHe)]); | ||
box on; grid on; | ||
xlabel('He MFC Flow Rate [ccm]') | ||
ylabel('He Actual Flow Rate [ccm]') | ||
subplot(1,2,2) | ||
hold on | ||
scatter(volFlow_MFC2_PureCO2,volFlow_UMFM_PureCO2,'or') | ||
plot(MFC1Set,calibrationFlow.MFC_CO2*MFC1Set,'b') | ||
xlim([0 1.1*max(volFlow_MFC2_PureCO2)]); | ||
ylim([0 1.1*max(volFlow_UMFM_PureCO2)]); | ||
box on; grid on; | ||
xlabel('CO2 MFC Flow Rate [ccm]') | ||
ylabel('CO2 Actual Flow Rate [ccm]') | ||
|
||
% Plot the raw and the calibrated data (for mixtures at MFM) | ||
figure | ||
x = 0:0.1:1; % Mole fraction | ||
y = 0:1:150; % Total flow rate | ||
[X,Y] = meshgrid(x,y); % Create a grid for the flow model | ||
Z = modelFlow(X,Y); % Actual flow rate from the model % [ccm] | ||
hold on | ||
surf(X,Y,Z,'FaceAlpha',0.25,'EdgeColor','none'); | ||
scatter3(moleFracCO2,volFlow_MFM,volFlow_UMFM,'r'); | ||
xlim([0 1.1*max(X(:))]); | ||
ylim([0 1.1*max(Y(:))]); | ||
zlim([0 1.1*max(Z(:))]); | ||
box on; grid on; | ||
xlabel('CO2 Mole Fraction [-]') | ||
ylabel('MFM Flow Rate [ccm]') | ||
zlabel('Actual Flow Rate [ccm]') | ||
view([30 30]) | ||
end | ||
|
||
% Load the file that contains the MS calibration | ||
if ~isempty(parametersMS) | ||
% Call reconcileData function for calibration of the MS | ||
[reconciledData, expInfo] = concatenateData(parametersMS); | ||
% Find the index that corresponds to the last time for a given set | ||
% point | ||
setPtMFC = unique(reconciledData.flow(:,5)); | ||
% Find total number of data points | ||
numDataPoints = length(reconciledData.flow(:,1)); | ||
% Total number of points per set point | ||
numPointsSetPt = expInfo.maxTime/expInfo.samplingTime; | ||
% Number of repetitions per set point (assuming repmat in calibrateMS) | ||
numRepetitions = floor((numDataPoints/numPointsSetPt)/length(setPtMFC)); | ||
% Remove the 5 min idle time between repetitions | ||
% For two repetitions | ||
if numRepetitions == 2 | ||
indRepFirst = numPointsSetPt*length(setPtMFC)+1; | ||
indRepLast = indRepFirst+numPointsSetPt-1; | ||
reconciledData.flow(indRepFirst:indRepLast,:) = []; | ||
reconciledData.MS(indRepFirst:indRepLast,:) = []; | ||
reconciledData.moleFrac(indRepFirst:indRepLast,:) = []; | ||
% For one repetition | ||
elseif numRepetitions == 1 | ||
% Do nothing % | ||
else | ||
error('Currently more than two repetitions are not supported by analyzeCalibration.m'); | ||
end | ||
% Find indices that corresponds to a given set point | ||
indList = ones(numRepetitions*length(setPtMFC),2); | ||
% Loop over all the set points | ||
for kk = 1:numRepetitions | ||
for ii=1:length(setPtMFC) | ||
% Indices for a given set point accounting for set point and | ||
% number of repetitions | ||
initInd = length(setPtMFC)*numPointsSetPt*(kk-1) + (ii-1)*numPointsSetPt + 1; | ||
finalInd = initInd + numPointsSetPt - 1; | ||
% Find the mean value of the signal for numMean number of points | ||
% for each set point | ||
indMean = (finalInd-parametersMS.numMean+1):finalInd; | ||
% MS Signal mean | ||
meanHeSignal((kk-1)*length(setPtMFC)+ii) = mean(reconciledData.MS(indMean,2)); % He | ||
meanCO2Signal((kk-1)*length(setPtMFC)+ii) = mean(reconciledData.MS(indMean,3)); % CO2 | ||
% Mole fraction mean | ||
meanMoleFrac(((kk-1)*length(setPtMFC)+ii),1) = mean(reconciledData.moleFrac(indMean,1)); % He | ||
meanMoleFrac(((kk-1)*length(setPtMFC)+ii),2) = mean(reconciledData.moleFrac(indMean,2)); % CO2 | ||
end | ||
end | ||
% Use a linear interpolation to fit the calibration data of the signal | ||
% ratio w.r.t He composition | ||
calibrationMS.ratioHeCO2 = fit((meanHeSignal./(meanCO2Signal+meanHeSignal))',meanMoleFrac(:,1),'linearinterp'); | ||
|
||
% Save the calibration data into a .mat file | ||
% Check if calibration data folder exists | ||
if exist(['..',filesep,'experimentalData',filesep,... | ||
'calibrationData'],'dir') == 7 | ||
% Save the calibration data for further use | ||
save(['..',filesep,'experimentalData',filesep,... | ||
'calibrationData',filesep,parametersMS.flow,'_Model'],'calibrationMS',... | ||
'gitCommitID','parametersMS'); | ||
else | ||
% Create the calibration data folder if it does not exist | ||
mkdir(['..',filesep,'experimentalData',filesep,'calibrationData']) | ||
% Save the calibration data for further use | ||
save(['..',filesep,'experimentalData',filesep,... | ||
'calibrationData',filesep,parametersMS.flow,'_Model'],'calibrationMS',... | ||
'gitCommitID','parametersMS'); | ||
end | ||
|
||
% Plot the raw and the calibrated data | ||
figure(1) | ||
plot(meanHeSignal./(meanHeSignal+meanCO2Signal),meanMoleFrac(:,1),'or') % Experimental | ||
hold on | ||
plot(0:0.001:1,calibrationMS.ratioHeCO2(0:0.001:1),'b') | ||
xlim([0 1]); | ||
ylim([0 1]); | ||
box on; grid on; | ||
xlabel('Helium Signal/(CO2 Signal+Helium Signal) [-]') | ||
ylabel('Helium mole frac [-]') | ||
set(gca,'FontSize',8) | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
% | ||
% Imperial College London, United Kingdom | ||
% Multifunctional Nanomaterials Laboratory | ||
% | ||
% Project: ERASE | ||
% Year: 2021 | ||
% MATLAB: R2020a | ||
% Authors: Ashwin Kumar Rajagopalan (AK) | ||
% Hassan Azzan (HA) | ||
% | ||
% Purpose: | ||
% Script to define inputs to calibrate flowmeter and MS or to analyze a | ||
% real experiment using calibrated flow meters and MS | ||
% | ||
% Last modified: | ||
% - 2021-07-23, AK: Add calibration model to the output | ||
% - 2021-07-02, AK: Bug fix for threshold | ||
% - 2021-05-10, AK: Convert into a function | ||
% - 2021-04-20, AK: Add experiment struct to output .mat file | ||
% - 2021-04-19, AK: Major revamp for flow rate computation | ||
% - 2021-04-13, AK: Add threshold to cut data below a given mole fraction | ||
% - 2021-04-08, AK: Add ratio of gas for calibration | ||
% - 2021-03-24, AK: Add flow rate computation and prepare structure for | ||
% Python script | ||
% - 2021-03-18, AK: Updates to structure | ||
% - 2021-03-18, AK: Initial creation | ||
% | ||
% Input arguments: | ||
% | ||
% Output arguments: | ||
% | ||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | ||
function analyzeExperiment(experimentStruct,flagCalibration,flagFlowMeter) | ||
% Get the git commit ID | ||
gitCommitID = getGitCommit; | ||
|
||
% Mode to switch between calibration and analyzing real experiment | ||
% Analyze calibration data | ||
if flagCalibration | ||
% Calibrate flow meter | ||
if flagFlowMeter | ||
% File with the calibration data to build a model for MFC/MFM | ||
experimentStruct = 'ZLCCalibrateMeters_20210419'; % Experimental flow file (.mat) | ||
% Call analyzeCalibration function for calibration of the MS | ||
analyzeCalibration(experimentStruct,[]) % Call the function to generate the calibration file | ||
% Calibrate MS | ||
else | ||
% Call analyzeCalibration function for calibration of the MS | ||
analyzeCalibration([],experimentStruct) % Call the function to generate the calibration file | ||
end | ||
% Analyze real experiment | ||
else | ||
% Call reconcileData function to get the output mole fraction for a | ||
% real experiment | ||
[outputStruct,~] = concatenateData(experimentStruct); | ||
|
||
% Clean mole fraction to remove negative values (due to calibration) | ||
% Replace all negative molefraction with eps | ||
outputStruct.moleFrac(outputStruct.moleFrac(:,2)<0,1)=eps; % CO2 | ||
outputStruct.moleFrac(:,1)=1-outputStruct.moleFrac(:,2); % Compute He with mass balance | ||
|
||
% Convert the MFM flow to real flow | ||
% Load the meter calibrations | ||
load(experimentStruct.calibrationFlow); | ||
% Get the MFM flow rate | ||
volFlow_MFM = outputStruct.flow(:,2); | ||
% Get the CO2 mole fraction for obtaining real flow rate | ||
moleFracCO2 = outputStruct.moleFrac(:,2); | ||
% Compute the total flow rate of the gas [ccm] | ||
% Round the flow rate to the nearest first decimal (as this is the | ||
% resolution of the meter) | ||
totalFlowRate = round(calibrationFlow.MFM(moleFracCO2,volFlow_MFM),1); | ||
|
||
% Input for the ZLC script (Python) | ||
% Find the index for the mole fraction that corresponds to the | ||
% threshold mole fraction | ||
moleFracThresholdInd = min([find(outputStruct.moleFrac(:,2)<experimentStruct.moleFracThreshold,1,'first'),... | ||
find(~isnan(totalFlowRate),1,'last')]); % Additional check to weed out nan flow due to interpolation | ||
% Set the final index to be the length of the series, if threshold not | ||
% reached | ||
if isempty(moleFracThresholdInd) | ||
moleFracThresholdInd = length(outputStruct.moleFrac(:,2)); | ||
end | ||
experimentOutput.timeExp = outputStruct.flow(1:moleFracThresholdInd,1); % Time elapsed [s] | ||
experimentOutput.moleFrac = outputStruct.moleFrac(1:moleFracThresholdInd,2); % Mole fraction CO2 [-] | ||
experimentOutput.totalFlowRate = totalFlowRate(1:moleFracThresholdInd)./60; % Total flow rate of the gas [ccs] | ||
experimentOutput.volFlow_MFM = volFlow_MFM; % Actual MFM flow rate of the gas [ccm] | ||
% Flow calibration model | ||
% p00 + p10*x + p01*y + p20*x^2 + p11*x*y + p02*y^2 + p21*x^2*y + p12*x*y^2 + p03*y^3 | ||
% x - mole fraction of CO2; y = volumetric flow rate from MFM [ccm] | ||
% This wilL be used in the simulateCombinedModel.py to compute the | ||
% correct flow accounting for the time lag in the concentration | ||
% due to the MS | ||
experimentOutput.flowCalibration = coeffvalues(calibrationFlow.MFM)'; % Coefficient of flow calibration | ||
% Save outputStruct to semiProcessedStruct | ||
semiProcessedStruct = outputStruct; % Check concatenateData for more (this is reconciledData there) | ||
% Save the experimental output into a .mat file | ||
% Check if runData data folder exists | ||
if exist(['..',filesep,'experimentalData',filesep,... | ||
'runData'],'dir') == 7 | ||
% Save the calibration data for further use | ||
save(['..',filesep,'experimentalData',filesep,... | ||
'runData',filesep,experimentStruct.flow,'_Output'],'experimentOutput',... | ||
'experimentStruct','semiProcessedStruct','gitCommitID'); | ||
else | ||
% Create the calibration data folder if it does not exist | ||
mkdir(['..',filesep,'experimentalData',filesep,'runData']) | ||
% Save the calibration data for further use | ||
save(['..',filesep,'experimentalData',filesep,... | ||
'runData',filesep,experimentStruct.flow,'_Output'],'experimentOutput',... | ||
'experimentStruct','semiProcessedStruct','gitCommitID'); | ||
end | ||
end | ||
end |
Oops, something went wrong.