Skip to content

Commit

Permalink
Merge pull request #95 from ImperialCollegeLondon/feat/bart
Browse files Browse the repository at this point in the history
Update software to v7.0.0
  • Loading branch information
mfacchinelli authored Dec 20, 2024
2 parents f9b177d + 98d219a commit 2a53a45
Show file tree
Hide file tree
Showing 71 changed files with 1,528,547 additions and 89 deletions.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
@@ -1 +1 @@
MAG_DATA_VISUALIZATION_VERSION=6.3.1
MAG_DATA_VISUALIZATION_VERSION=7.0.0
2 changes: 1 addition & 1 deletion .github/workflows/matlab.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
uses: matlab-actions/[email protected]
with:
release: ${{ matrix.release }}
products: Signal_Processing_Toolbox Statistics_and_Machine_Learning_Toolbox Text_Analytics_Toolbox
products: MATLAB_Test Signal_Processing_Toolbox Statistics_and_Machine_Learning_Toolbox Text_Analytics_Toolbox
- name: Run tests
uses: matlab-actions/[email protected]
with:
Expand Down
6 changes: 5 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,12 @@
"**/*~": true
},
"cSpell.words": [
"Bartington",
"downsample",
"Gradiometer",
"HELIOSWARM",
"IMAP",
"signedness",
"IMAP"
"SOLARORBITER"
]
}
8 changes: 5 additions & 3 deletions app/DataVisualization.m
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
function app = DataVisualization(mission)

arguments (Input)
mission string {mustBeScalarOrEmpty, mustBeMember(mission, ["HelioSwarm", "IMAP", "Solar Orbiter"])} = string.empty()
mission string {mustBeScalarOrEmpty, mustBeMember(mission, ["Bartington", "HelioSwarm", "IMAP", "Solar Orbiter"])} = string.empty()
end

% Create figure and other UI components.
Expand Down Expand Up @@ -110,19 +110,21 @@ function selectMission(app, mission)

arguments (Input)
app
mission string {mustBeScalarOrEmpty, mustBeMember(mission, ["HelioSwarm", "IMAP", "Solar Orbiter"])} = string.empty()
mission string {mustBeScalarOrEmpty, mustBeMember(mission, ["Bartington", "HelioSwarm", "IMAP", "Solar Orbiter"])} = string.empty()
end

% Ask which mission to load, if not provided.
if isempty(mission)

mission = uiconfirm(app.UIFigure, "Select the mission to load.", "Select Mission", Icon = "question", ...
Options = ["HelioSwarm", "IMAP", "Solar Orbiter", "Cancel"], DefaultOption = "IMAP", CancelOption = "Cancel");
Options = ["Bartington", "HelioSwarm", "IMAP", "Solar Orbiter", "Cancel"], DefaultOption = "IMAP", CancelOption = "Cancel");

closeProgressBar = app.AppNotificationHandler.overlayProgressBar("Initializing app..."); %#ok<NASGU>
end

switch mission
case "Bartington"
app.Provider = mag.app.bart.Provider();
case "Cancel"
error("User aborted.");
case "HelioSwarm"
Expand Down
11 changes: 10 additions & 1 deletion app/core/+mag/+app/Model.m
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

properties (SetAccess = protected)
% ANALYSIS Analysis results.
Analysis {mustBeScalarOrEmpty, mustBeA(Analysis, ["mag.hs.Analysis", "mag.imap.Analysis"])} = mag.imap.Analysis.empty()
Analysis mag.Analysis {mustBeScalarOrEmpty} = mag.imap.Analysis.empty()
end

properties (Dependent, SetAccess = private)
Expand Down Expand Up @@ -37,4 +37,13 @@
value = ~isempty(this.Analysis) && ~isempty(this.Analysis.Results);
end
end

methods (Access = protected)

function setAnalysisAndNotify(this, analysis)

this.Analysis = analysis;
this.notify("AnalysisChanged");
end
end
end
36 changes: 36 additions & 0 deletions app/mission/bart/+mag/+app/+bart/+control/Field.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
classdef Field < mag.app.Control & mag.app.mixin.StartEndDate
% FIELD View-controller for generating "mag.bart.view.Field".

properties (SetAccess = private)
Layout matlab.ui.container.GridLayout
end

methods

function instantiate(this, parent)

this.Layout = this.createDefaultGridLayout(parent);

% Start and end dates.
this.addStartEndDateButtons(this.Layout, StartDateRow = 1, EndDateRow = 2);
end

function command = getVisualizeCommand(this, results)

arguments (Input)
this
results (1, 1) mag.Instrument
end

arguments (Output)
command (1, 1) mag.app.Command
end

[startTime, endTime] = this.getStartEndTimes();
results = mag.app.internal.cropResults(results, startTime, endTime);

command = mag.app.Command(Functional = @(varargin) mag.bart.view.Field(varargin{:}).visualizeAll(), ...
PositionalArguments = {results});
end
end
end
60 changes: 60 additions & 0 deletions app/mission/bart/+mag/+app/+bart/+control/PSD.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
classdef PSD < mag.app.Control
% PSD View-controller for generating "mag.bart.view.PSD".

properties (SetAccess = private)
Layout matlab.ui.container.GridLayout
StartDatePicker matlab.ui.control.DatePicker
StartTimeField matlab.ui.control.EditField
DurationSpinner matlab.ui.control.Spinner
end

methods

function instantiate(this, parent)

this.Layout = this.createDefaultGridLayout(parent);

% Start date.
startLabel = uilabel(this.Layout, Text = "Start date/time:");
startLabel.Layout.Row = 1;
startLabel.Layout.Column = 1;

this.StartDatePicker = uidatepicker(this.Layout);
this.StartDatePicker.Layout.Row = 1;
this.StartDatePicker.Layout.Column = 2;

this.StartTimeField = uieditfield(this.Layout, Placeholder = "HH:mm:ss.SSS");
this.StartTimeField.Layout.Row = 1;
this.StartTimeField.Layout.Column = 3;

% Duration.
durationLabel = uilabel(this.Layout, Text = "Duration (hours):");
durationLabel.Layout.Row = 2;
durationLabel.Layout.Column = 1;

this.DurationSpinner = uispinner(this.Layout, Value = 1, ...
Limits = [0, Inf]);
this.DurationSpinner.Layout.Row = 2;
this.DurationSpinner.Layout.Column = [2, 3];
end

function command = getVisualizeCommand(this, results)

arguments (Input)
this
results (1, 1) mag.Instrument
end

arguments (Output)
command (1, 1) mag.app.Command
end

startTime = mag.app.internal.combineDateAndTime(this.StartDatePicker.Value, this.StartTimeField.Value);
duration = hours(this.DurationSpinner.Value);

command = mag.app.Command(Functional = @(varargin) mag.bart.view.PSD(varargin{:}).visualizeAll(), ...
PositionalArguments = {results}, ...
NamedArguments = struct(Start = startTime, Duration = duration));
end
end
end
90 changes: 90 additions & 0 deletions app/mission/bart/+mag/+app/+bart/+control/Spectrogram.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
classdef Spectrogram < mag.app.Control & mag.app.mixin.StartEndDate
% SPECTROGRAM View-controller for generating "mag.bart.view.Spectrogram".

properties (SetAccess = private)
Layout matlab.ui.container.GridLayout
FrequencyPointsSpinner matlab.ui.control.Spinner
OverlapSpinner matlab.ui.control.Spinner
WindowSpinner matlab.ui.control.Spinner
end

methods

function instantiate(this, parent)

this.Layout = this.createDefaultGridLayout(parent);

% Start and end dates.
this.addStartEndDateButtons(this.Layout, StartDateRow = 1, EndDateRow = 2);

% Frequency points.
frequencyPointsLabel = uilabel(this.Layout, Text = "Frequency points:", ...
Tooltip = "Number of discrete Fourier transform points.");
frequencyPointsLabel.Layout.Row = 3;
frequencyPointsLabel.Layout.Column = 1;

this.FrequencyPointsSpinner = uispinner(this.Layout, Value = 256, ...
Step = 1, Limits = [0, Inf]);
this.FrequencyPointsSpinner.Layout.Row = 3;
this.FrequencyPointsSpinner.Layout.Column = [2, 3];

% Overlap.
overlapLabel = uilabel(this.Layout, Text = "Overlap:", ...
Tooltip = "Overlap between segments.");
overlapLabel.Layout.Row = 4;
overlapLabel.Layout.Column = 1;

this.OverlapSpinner = uispinner(this.Layout, Value = double.empty(), AllowEmpty = true, ...
Step = 0.1, ValueDisplayFormat = "%.2f", ...
Limits = [0, 1], LowerLimitInclusive = false, ...
Placeholder = this.DynamicPlaceholder);
this.OverlapSpinner.Layout.Row = 4;
this.OverlapSpinner.Layout.Column = [2, 3];

% Window.
windowLabel = uilabel(this.Layout, Text = "Window:", ...
Tooltip = "Divide data into segments of this length and window each segment with a Hamming window.");
windowLabel.Layout.Row = 5;
windowLabel.Layout.Column = 1;

this.WindowSpinner = uispinner(this.Layout, Value = double.empty(), AllowEmpty = true, ...
Step = 1, Limits = [0, Inf], LowerLimitInclusive = false, ...
Placeholder = this.DynamicPlaceholder);
this.WindowSpinner.Layout.Row = 5;
this.WindowSpinner.Layout.Column = [2, 3];
end

function command = getVisualizeCommand(this, results)

arguments (Input)
this
results (1, 1) mag.Instrument
end

arguments (Output)
command (1, 1) mag.app.Command
end

[startTime, endTime] = this.getStartEndTimes();
frequencyPoints = this.FrequencyPointsSpinner.Value;

if isempty(this.OverlapSpinner.Value)
overlap = missing();
else
overlap = this.OverlapSpinner.Value;
end

if isempty(this.WindowSpinner.Value)
window = missing();
else
window = this.WindowSpinner.Value;
end

results = mag.app.internal.cropResults(results, startTime, endTime);

command = mag.app.Command(Functional = @(varargin) mag.bart.view.Spectrogram(varargin{:}).visualizeAll(), ...
PositionalArguments = {results}, ...
NamedArguments = struct(FrequencyPoints = frequencyPoints, Overlap = overlap, Window = window));
end
end
end
124 changes: 124 additions & 0 deletions app/mission/bart/+mag/+app/+bart/AnalysisManager.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
classdef AnalysisManager < mag.app.manage.AnalysisManager
% ANALYSISMANAGER Manager for analysis of HelioSwarm data.

properties (SetAccess = private)
AnalyzeSettingsLayout matlab.ui.container.GridLayout
LocationEditField matlab.ui.control.EditField
LocationEditFieldLabel matlab.ui.control.Label
BrowseButton matlab.ui.control.Button
Input1PatternEditField matlab.ui.control.EditField
Input1PatternEditFieldLabel matlab.ui.control.Label
Input2PatternEditField matlab.ui.control.EditField
Input2PatternEditFieldLabel matlab.ui.control.Label
GradiometerCheckBox matlab.ui.control.CheckBox
end

methods

function instantiate(this, parent)

% Create AnalyzeSettingsLayout.
this.AnalyzeSettingsLayout = uigridlayout(parent);
this.AnalyzeSettingsLayout.ColumnWidth = ["fit", "1x", "fit"];
this.AnalyzeSettingsLayout.RowHeight = ["1x", "1x", "1x", "1x", "1x", "1x"];

% Create LocationEditFieldLabel.
this.LocationEditFieldLabel = uilabel(this.AnalyzeSettingsLayout);
this.LocationEditFieldLabel.HorizontalAlignment = "right";
this.LocationEditFieldLabel.Layout.Row = 1;
this.LocationEditFieldLabel.Layout.Column = 1;
this.LocationEditFieldLabel.Text = "Location:";

% Create LocationEditField.
this.LocationEditField = uieditfield(this.AnalyzeSettingsLayout, "text");
this.LocationEditField.Layout.Row = 1;
this.LocationEditField.Layout.Column = 2;

% Create BrowseButton.
this.BrowseButton = uibutton(this.AnalyzeSettingsLayout, "push");
this.BrowseButton.ButtonPushedFcn = @(~, ~) this.browseButtonPushed();
this.BrowseButton.Layout.Row = 1;
this.BrowseButton.Layout.Column = 3;
this.BrowseButton.Text = "Browse";

% Create Input1PatternEditFieldLabel.
this.Input1PatternEditFieldLabel = uilabel(this.AnalyzeSettingsLayout);
this.Input1PatternEditFieldLabel.HorizontalAlignment = "right";
this.Input1PatternEditFieldLabel.Layout.Row = 2;
this.Input1PatternEditFieldLabel.Layout.Column = 1;
this.Input1PatternEditFieldLabel.Text = "Input 1 pattern:";

% Create Input1PatternEditField.
this.Input1PatternEditField = uieditfield(this.AnalyzeSettingsLayout, "text");
this.Input1PatternEditField.Layout.Row = 2;
this.Input1PatternEditField.Layout.Column = [2, 3];

% Create Input2PatternEditFieldLabel.
this.Input2PatternEditFieldLabel = uilabel(this.AnalyzeSettingsLayout);
this.Input2PatternEditFieldLabel.HorizontalAlignment = "right";
this.Input2PatternEditFieldLabel.Layout.Row = 3;
this.Input2PatternEditFieldLabel.Layout.Column = 1;
this.Input2PatternEditFieldLabel.Text = "Input 2 pattern:";

% Create Input2PatternEditField.
this.Input2PatternEditField = uieditfield(this.AnalyzeSettingsLayout, "text");
this.Input2PatternEditField.Layout.Row = 3;
this.Input2PatternEditField.Layout.Column = 2;

% Create GradiometerCheckBox.
this.GradiometerCheckBox = uicheckbox(this.AnalyzeSettingsLayout);
this.GradiometerCheckBox.Layout.Row = 3;
this.GradiometerCheckBox.Layout.Column = 3;
this.GradiometerCheckBox.Text = "Gradiometer";

% Reset.
this.reset();
end

function reset(this)

dummyAnalysis = mag.bart.Analysis();

this.LocationEditField.Value = string.empty();
this.Input1PatternEditField.Value = dummyAnalysis.Input1Pattern;
this.Input2PatternEditField.Value = dummyAnalysis.Input2Pattern;
this.GradiometerCheckBox.Value = dummyAnalysis.Gradiometer;
end

function options = getAnalysisOptions(this)

% Validate location.
location = this.LocationEditField.Value;

if isempty(location)
error("Location is empty.");
elseif ~isfolder(location)
error("Location ""%s"" does not exist.", location);
end

options = {"Location", this.LocationEditField.Value, ...
"Input1Pattern", this.Input1PatternEditField.Value, ...
"Input2Pattern", this.Input2PatternEditField.Value, ...
"Gradiometer", this.GradiometerCheckBox.Value};
end
end

methods (Access = protected)

function modelChangedCallback(~, ~, ~)
% do nothing
end
end

methods (Access = private)

function browseButtonPushed(this)

location = uigetdir(this.LocationEditField.Value, "Select Data Root");

if ~isequal(location, 0)
this.LocationEditField.Value = location;
end
end
end
end
Loading

0 comments on commit 2a53a45

Please sign in to comment.